[Chapter 6] 객체지향 프로그래밍 1_1

slchoi·2022년 1월 10일
0

자바의 정석

목록 보기
11/19
post-thumbnail

'자바의 정석 3rd Edition'를 공부하며 정리한 내용입니다.

1. 객체지향 언어


1.1 객체지향언어의 역사

  • 객체지향이론의 기본 개념: 실제 세계는 사물(객체)로 이루어져 있으며, 발생하는 모든 사건들은 사물간의 상호작용이다
    • 실제 사물의 속성과 기능을 분석한 다음, 데이터(변수)와 함수로 정의함으로써 실제 세계를 컴퓨터 속에 옮겨 놓은 것과 같은 가상 세계를 구현
  • 객체지향이론은 상속,, 캡슐화, 추상화 개념을 중심으로 점차 구체적으로 발전
  • 1960년대 중반 객체지향이론을 프로그래밍 언어에 적용한 시뮬라(Simula)라는 최초의 객체지향언어가 탄생
    • 당시에는 FORTRAN, COBOL과 같은 절차적 언어들이 주류를 이루었음
  • 1980년대 중반 C++을 비롯한 여러 객체지향언어가 발표되면서 객체지향언어가 관심을 끌긴했지만 사용자층을 넓히진 못함
  • 1995년 자바가 발표되고 1990년대 말에 인터넷의 발전과 함께 크게 유행하면서 객체지향언어는 프로그래밍언어의 주류로 자리 잡음

1.2 객체지향언어

  • 객체지향언어는 기존의 프로그래밍 언어에 새로운 규칙을 추가한 형태. 규칙들을 이요해 코드 간에 서로 관계를 맺어 줌으로써 유기적으로 프로그램을 구성하는 것이 가능해짐

객체지향언어의 주요 특징

1. 코드의 재사용성이 높음

  • 새로운 코드를 작성할 때 기존의 코드를 이용하여 쉽게 작성 가능

2. 코드의 관리가 용이

  • 코드간의 관계를 이용해서 적은 노력으로 쉽게 코드를 변경할 수 있음

3. 신뢰성이 높은 프로그래밍을 가능하게 함

  • 제어자와 메서드를 이용해서 데이터를 보호하고 올바른 값을 유지하도록 함
  • 코드의 중복을 제거하여 코드의 불일치로 인한 오동작을 방지할 수 있음

2. 클래스와 객체


2.1 클래스와 객체의 정의와 용도

1. 클래스의 정의와 용도

  • 클래스의 정의: 객체를 정의해 놓은것
  • 클래스의 용도: 객체를 생성하는데 사용됨

2. 객체의 정의와 용도

  • 객체의 정의: 실제로 존재하는 것. 사물 또는 개념
    • 프로그래밍에서의 객체는 메모리에 생성된 것을 의미
  • 객체의 용도: 객체가 가지고 있는 기능과 속성에 따라 다름
  • 유형의 객체: 책상, 의자, 자동차, TV와 같은 사물
  • 무형의 객체: 수학공식, 프로그램 에러와 같은 논리나 개념

3. 클래스와 객체의 관계

  • 클래스는 단지 객체를 생성하는데 사용될 뿐, 객체 그 자체는 아님
  • 원하는 기능의 객체를 사용하기 위해서는 먼저 클래스로부터 객체를 생성되는 과정이 선행되어야 함
    • 프로그래밍에서는 먼저 클래스를 작성한 다음, 클래스로부터 객체를 생성하여 사용
  • 클래스를 정의하고 클래스를 통해 객체를 생성하는 이유는 클래스를 한번만 잘 만들어 놓기만 하면, 매번 객체를 생성할 때마다 어떻게 객체를 만들어야 할지를 고민하지 않아도 됨
  • JDK에서는 프로그래밍을 위해 많은 수의 유용한 클래스(Java API)를 기본적으로 제공

2.2 객체와 인스턴스

  • 클래스의 인스턴스화(instantiate): 클래스로부터 객체를 만드는 과정
  • 인스턴스(instance): 어떤 클래스로부터 만들어진 객체
    • 객체는 모든 인스턴스를 대표하는 포괄적인 의미를 갖고 있으며, 인스턴스는 어떤 클래스로부터 만들어진 것인지를 강조하는 구체적인 의미를 가짐

2.3 객체의 구성요소 - 속성과 기능

  • 객체는 속성과 기능의 집합이고 객체가 가지고 있는 속성과 기능을 그 객체의 멤버(구성원, member)라고 함

  • 클래스란 객체를 정의한 것이므로 클래스에는 객체의 모든 속성과 기능이 정의되어 있음

    • 클래스로부터 객체를 생성하면, 클래스에 정의된 속성과 기능을 가진 객체가 만들어지는 것
  • 속성과 기능의 여러 용어

    속성(property): 멤버변수(member variable), 특성(attribute), 필드(field), 상태(state)
    기능(function): 메서드(method), 함수(function), 행위(behavior)

  • 객체지향 프로그래밍에서는 속성과 기능을 각각 변수와 메서드로 표현

    • 멤버변수와 메서드를 선언하는데 있어 순서는 관계없지만, 멤버변수를 먼저 선언하고 멤버변수는 멤버변수끼리 메서드는 메서드끼리 모아 놓는 것이 일반적

2.4 인스턴스의 생성과 사용

  • 클래스로부터 인스턴스를 생성하는 방법
클래스명 변수명;		// 클래스 객체를 참조하기 위한 참조변수 선언
변수명 = new 클래스명();	// 클래스의 객체를 생성 후 객체의 주소를 참조변수에 저장	
 
 Tv = t;
 t = new TV();
  • 인스턴스는 참조변수를 통해서만 다룰 수 있으며, 참조변수의 타입은 인스턴스의 타입과 일치해야 함
  • 같은 클래스로부터 생성되었을지라도 각 인스턴스의 멤버변수는 서로 다른 값을 유지할 수 있으며, 메서드의 내용은 모든 인스턴스에 대해 동일
  • 참조변수에는 하나의 값(주소)만이 저장될 수 있으므로 둘 이상의 참조변수가 하나의 인스턴스를 가리키는 것은 가능하지만 하나의 참조변수로 여러 개의 인스턴스를 가리키는 것은 불가능

2.5 객체 배열

  • 객체 배열: 참조변수들을 하나로 묶은 참조변수 배열
  • 객체 배열 안에 객체가 저장되는 것은 아니고, 객체의 주소가 저장됨
Tv[] tvArr = new Tv[3];
  • 길이가 3인 객체 배열 생성
    • 각 요소는 참조변수의 기본값인 null로 자동 초기화
    • 객체 배열은 3개의 객체의 주소 저장 가능
// 객체를 생성해서 배열의 각 요소에 저장
tvArr[0] = new Tv();
tvArr[1] = new Tv();
tvArr[2] = new Tv();

// 배열의 초기화 블럭 사용
Tv[] tvArr = {new Tv(), new Tv(), new Tv()};

// 다뤄야할 객체의 수가 많을 때는 for문 사용
for (int i=0; i<tvArr.length; i++) {
	tvArr[i] = new Tv();
}
  • 객체를 다루기 위한 참조변수들이 만들어진 것일 뿐 객체가 저장되지 않음
    • 객체를 생성해서 객체 배열의 각 요소에 저장해야 함
  • 객체 배열도 같은 타입의 객체만 저장 가능
  • 여러 종류의 객체를 하나의 배열에 저장하기 위해서는 다형성(polymorphism)을 활용해야 함

2.6 클래스의 또 다른 정의

  • 클래스는 '객체를 생성하기 위한 틀이며 속성과 기능으로 정의되어 있다'는 정의는 객체지향이론의 관점에서 내린 정의

프로그래밍적 관점에서의 클래스의 정의와 의미

1. 클래스 - 데이터와 함수의 결합

  • 프로그래밍언어에서 데이터 처리를 위한 데이터 저장형태의 발전과정은 아래와 같음

    변수 하나의 데이터를 저장할 수 있는 공간
    배열 같은 종류의 여러 데이터를 하나의 집합으로 저장할 수 있는 공간
    구조체 서로 관련된 여러 데이터를 종류에 관계없이 하나의 집합으로 저장할 수 있는 공간
    클래스 데이터와 함수의 결합 (구조체 + 함수)

  • 데이터와 함수가 서로 관계가 없는 것처럼 데이터는 데이터끼리, 함수는 함수끼리 따로 다루어져 왔지만, 함수는 데이터를 가지고 작업하기 때문에 많은 경우에 있어 데이터와 함수는 관계가 깊음
  • 객체지향언어에서는 변수(데이터)와 함수를 하나의 클래스에 정의해 서로 관계가 깊은 변수와 함수들을 함께 다룰 수 있게 함
  • 서로 관련된 변수들을 정의하고 이들에 대한 작업을 수행하는 함수들을 정의한 것이 클래스
    • C언어에서는 문자열을 문자의 배열로 다루지만, 자바에서는 String이라는 클래스로 문자열을 다룸. 클래스로 정의한 이유는 문자열과 문자열을 다루는데 필요한 함수들을 함께 묶기 위함

2. 클래스 - 사용자정의 타입(user-defined type)

  • 사용자정의 타입(user-defined type): 프로그래밍언어에서 자공하는 자료형외에 프로그래머가 서로 관련된 변수들을 묶어서 하나의 타입으로 새로 추가하는 것
  • 객체지향언어에서는 클래스가 곧 사용자 정의 타입
    • 기본형의 개수는 8개로 정해져 있지만 참조형의 개수가 정해져 있지 않아 프로그래머가 새로운 타입을 추가할 수 있음

3. 변수와 메서드


3.1 선언위치에 따른 변수의 종류

  • 변수는 클래스변수, 인스턴스변수, 지역변수가 있음
  • 변수의 종류를 결정짓는 중요한 요소는 변수의 선언된 위치. 변수의 종류를 파악하기 위해서는 변수가 어느 영역에 선언되었는지를 확인하는 것이 중요
  • 멤버변수를 제외한 나머지 변수들은 모두 지역 변수
  • 멤버변수 중 static이 붙은 것은 클래스 변수, 붙지 않은 것은 인스턴스 변수
class Variables
{
	int iv;		// 인스턴스 변수
 	static int cv;	// 클래스 변수(static 변수, 공유변수)
    
	void method()
	{
		int lv= 0;	// 지역변수
	}
}
  • ivcv는 클래스 영역에 선언되었으므로 멤버변수. cv는 static과 함께 선언되어 있으므로 클래스 변수, iv는 인스턴스 변수
  • lv는 메서드인 method()의 내부(메서드 영역)에 선언되어 있으므로 지역변수
변수의 종류선언위치생성시기
클래스변수(class vairable)클래스 영역클래스가 메모리에 올라갈 때
인스턴스변수(instance variable)클래스 영역인스턴스가 생성되었을 때
지역변수(local variable)클래스 영역 이외의 여역(메서드, 생성자, 초기화 블럭 내부)변수 선언문이 수행되었을 때

1. 인스턴스 변수(instance variable)

  • 클래스 여역에 선언되며, 클래스의 인스턴스를 생성할 때 만들어짐
  • 인스턴스 변수의 값을 읽어 오거나 저장하기 위해서는 먼저 인스턴스를 생성해야 함
  • 인스턴스는 독립적인 저장공간을 가지므로 서로 다른 값을 가질 수 있음
  • 인스턴스마다 고유한 상태를 유지해야하는 속성의 경우 인스턴스 변수로 선언

2. 클래스 변수(class variable)

  • 인스턴스 변수 앞에 static를 붙여 선언
  • 인스턴스를 생성하지 않고도 바로 사용 가능 (형식: '클래스이름.클래스변수')
  • 클래스가 메모리에 로딩될 때 생성되어 프로그램이 종료될 때까지 유지되며, public을 앞에 붙이면 같은 프로그램 내에서 어디서나 접근할 수 있는 전역변수(global variable)의 성격을 가짐
    • 참조변수의 선언이나 객체의 생성과 같이 클래스 정보가 필요할 때 클래스는 메모리에 로딩됨
  • 클래스 변수는 모든 인스턴스가 공통된 저장공간(변수)을 공유
  • 한 클래스의 모든 인스턴스들이 공통적인 값을 유지해야하는 속성의 경우 클래스 변수로 선언

3. 지역 변수(local variable)

  • 메서드 내에 선언되어 메서드 내에서만 사용 가능. 메서드가 종료되면 소멸되어 사용 불가
  • for문 또는 while문의 블럭 내에 선언된 지역변수는 선언된 {} 내에서만 사용가능하며 {}를 벗어나면 소멸되어 사용할 수 없게 됨

3.2 클래스 변수와 인스턴스 변수

class Card {
	String kind;	// 무늬
	int number;	// 숫자
    
	static int width = 100;	  // 폭
	static int height = 150;  // 높이
}
  • card 인스턴스는 무늬와 숫자를 유지하고 있어야 하므로 인스턴스 변수로 선언하고, 각 카드의 폭과 높이는 모든 인스턴스가 공통적으로 같은 값을 유지해야하므로 클래스 변수로 선언
    • 카드 폭을 변경해야할 경우, 모든 카드의 width값을 변경하지 않고 한 카드의 width 값만 변경해도 모든 카드의 width 값이 변경됨
  • 클래스 변수를 사용할 경우 Card.width와 같이 '클래스이름.클래스변수' 형태로 하는 것이 좋음
  • 인스턴스변수는 인스턴스가 생성될 때마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로 항상 공통된 값을 가짐

3.3 메서드

  • 메서드(method): 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것. 어떤 값을 입력하면 이 값으로 작업을 수행해 결과를 반환
    • 입력값 또는 출력값이 없을 수 있으며, 모두 없을 수도 있음

메서드 사용 이유
1. 높은 재사용성(reusablility)

  • 한번 만들어 놓은 메서드는 몇 번이고 호출이 가능하고 다른 프로그램에서도 사용 가능

2. 중복된 코드 제거

  • 반복되는 문장을 묶어서 하나의 메서드로 작성해 높으면, 반복되는 문장들 대신 메서드를 호출하는 한 문장으로 대체 가능
  • 전체 소스 코드의 길이도 짧아지고, 변경사항이 발생했을 대 수정해야할 코드의 양이 줄어들어 오류가 발생할 가능성도 낮아짐

3. 프로그램의 구조화

  • 큰 규모의 프로그램에서는 문장들을 작업단위로 나눠서 여러 개의 메서드에 담아 프로그램의 구조를 단순화시키는 것이 필수적
    • main 메서드는 프로그램의 전체 흐름이 한눈에 들어올 정도로 단순하게 구조화하는 것이 좋음
  • 처음 프로그램을 설계할 때 내용이 없는 메서드를 작업단위로 만들어 놓고, 하나씩 완성해가는 것도 프로그램을 구조화하는 좋은 방법

3.4 메서드의 선언과 구현

// 선언부(header, 머리)
반환타입 메서드이름 (타입 변수명, 타입 변수명, ...)

// 구현부(body, 몸통)
{
	// 메서드 호출시 수행될 코드
}

1. 메서드 선언부(method declaration, method header)

  • 메서드의 이름, 매개변수 선언, 반환타입으로 구성
  • 메서드가 작업을 수행하기 우해 어떤 값들을 필요로 하고 작업의 결과로 어떤 타입의 값을 반환하는지에 대한 정보를 제공
  • 변경사항이 발생하지 않도록 작성해야 함

2. 매개변수 선언(parameter declaration)

  • 매개변수: 메서드가 작업을 수행하는데 필요한 값들(입력)을 제공받기 위한 것
  • 필요한 값의 개수만큼 변수를 선언하며 각 변수간의 구분은 ','를 사용
  • 두 변수의 타입이 같아도 변수의 타입 생략 불가
  • 선언할 수 있는 매개변수의 개수는 거의 제한 없지만, 개수가 많은 경우 배열이나 참조변수를 사용하면 됨
  • 입력 받을 값이 없을 경우 ()안에는 아무것도 적지 않음

3. 메서드의 이름(method name)

  • 변수의 명명규칙대로 작성
  • 이름만으로 메서드의 기능을 쉽게 알 수 있도록 함축적이면서도 의미있는 이름을 짓도록 노력해야 함

4. 반환 타입(return type)

  • 메서드의 작업수행 결과인 반환값의 타입을 적음
  • 반환값이 없는 경우 반환타입은 'void'로 적어야 함

5. 메서드의 구현부(method body, 메서드 몸통)

  • 메서드 선언부 다음에 오는 {}
  • 메서드를 호출했을 때 수행될 문장들을 적음

6. return문

  • 메서드 반환타입이 'void'가 아닌 경우, 구현부 안에 return 반환값;이 반드시 포함되어 있어야 함
  • 작업을 수행한 결과인 반환값을 호출한 메서드로 전달
  • return 값의 타입은 반드시 반환타입과 일치하거나 자동 형변환이 가능한 것이어야 함
  • return문은 단 하나의 값만 반환할 수 있는데, 메서드로의 입력은 여러 개일 수 있어도 출력은 최대 하나만 허용

7. 지역변수(local variable)

  • 메서드 내에 선언된 변수들은 그 메서드 내에서만 사용할 수 있음
  • 서로 다른 메서드라면 같은 이름의 변수를 선언해도 됨

3.5 메서드의 호출

  • 메서드를 정의했어도 호출하지 않으면 아무 일도 일어나지 않음. 메서드를 호출해야만 구현부의 문장들이 수행됨
    • main 메서드는 프로그램 실행시 OS에 의해 자동적으로 호출됨
메서드이름(1,1, ...);	// 메서드 호출 방법

1. 인자(argument)와 매개변수(parameter)

  • 인자(argument, 인수): 메서드를 호출할 때 괄호()안에 지정해준 값들
  • 인자의 개수는 호출된 메서드에 선언된 매개변수와 일치해야 함
  • 인자는 메서드가 호출되면서 매개변수에 대입되므로, 인자의 타입은 매개변수의 타입과 일치하거나 자동 형변환이 가능한 것이어야 함
  • 매개변수의 개수보다 인자의 개수가 많거나 타입이 다른 값을 넣으면 컴파일러가 에러를 발생시킴
  • 반환타입이 void가 아닌 경우, 메서드가 작업을 수행하고 반환한 값을 대입 연산자로 변수에 저장하는 것이 일반적이지만, 저장하지 않아도 됨

2. 메서드의 실행흐름

  • 같은 클래스 내의 메서드끼리는 참조변수를 사용하지 않고도 서로 호출이 가능하지 만 static메서드는 같은 클래스 내의 인스턴스 메서드를 호출할 수 없음
  • 메서드가 호출되면 지금까지 실행 중이던 메서드는 실행을 잠시 멈추고 호출된 메서드의 문장들이 실행됨. 호출된 메서드의 작업이 모두 끝나면 다시 호출한 메서드로 돌아와 이후의 문장들을 실행
  • 메서드는 호출시 넘겨받은 값으로 연산을 수행하고 그 결과를 반환하면서 종료됨
    • 반환된 값은 대입연산자에 의해서 변수에 저장됨
    • 메서드의 결과를 저장하기 위한 변수는 반환값과 같은 타입이거나 반환값이 자동 형변환되어 저장될 수 있는 타입이어야 함

3.6 return문

  • return문은 현재 실행중인 메서드를 종료하고 호출한 메서드로 되돌아감
  • 원래는 반환값의 유무에 관계없이 모든 메서드에는 적어도 하나의 return문이 있어야 함
    • 반환타입이 void인 경우, return문 없이도 아무런 문제가 없었던 이유는 컴파일러가 메서드의 마지막에 return;을 자동적으로 추가해주었기 때문
  • 반환타입이 void가 아닌 경우, 반드시 return문이 있어야 하며 없을 시 에러 발생
  • 반환값에는 주로 변수가 오긴 하지만 수식도 가능 (수식을 계산한 결과가 반환됨)

매개변수의 유효성 검사

  • 메서드의 구현부를 작성할 때, 제일 먼저 해야 하는 일이 매개변수의 값이 적절한 것인지 확인하는 것
  • 타입만 맞으면 어떤 값도 매개변수를 통해 넘어올 수 있기 때문에, 간으한 모든 경우의 수에 대해 고민하고 대비한 코드를 작성해야 함
  • 적절하지 않은 값이 매개변수를 통해 넘어온다면 매개변수의 값을 보정하던가, 보정하는 것이 불가능하다면 return문을 사용해서 작업을 중단하고 호출한 메서드로 되돌아가야함

3.7 JVM의 메모리 구조

  • 응용프로그램이 실행되면, JVM은 시스템으로부터 프로그램을 수행하는데 필요한 메모리를 할당받고 JVM은 이 메모리를 용도에 따라 여러 영역으로 나누어 관리

    사진 출처: https://gptjs409.github.io/java/2019/09/04/jvm.html

3가지 주요 영역(method area, call stack, heap)

  • 메서드 영역 (method area)
    • 프로그램 실행 중 어떤 클래스가 사용되면, JVM은 해당 클래스의 클래스파일(*.class)을 읽어서 분석하여 클래스에 대한 정보(클래스 데이터)를 이곳에 저장
    • 이 때, 클래스의 클래스 변수(class variable)도 이 영역에 함께 생성됨
  • (heap)
    • 인스턴스가 생성되는 공간
    • 프로그램 실행 중 생성되는 인스턴스는 모두 이곳에 생성됨
    • 인스턴스 변수(instance variable)들이 생성되는 공간
  • 호출스택 (call stack 또는 execution stack)
    • 메서드의 작업에 필요한 메모리 공간을 제공
    • 메서드가 호출되면, 호출스택에 호출된 메서드를 위한 메모리가 할당되며, 메모리는 메서드가 작업을 수행하는 동안 지역변수(매개변수 포함)들과 연산의 중간결과 등을 저장하는데 사용됨
    • 메서드가 작업을 마치면 할당되었던 메모리 공간은 반환되어 비어짐
  • 각 메서드를 위한 메모리상의 작업 공간은 서로 구별되며, 첫 번째로 호출된 메서드를 위한 작업공간이 호출스택의 맨 밑에 마련되고, 첫 번째 메서드 수행 중에 다른 메서드를 호출하면 첫 번째 메서드의 바로 위에 두 번째로 호출된 메서드를 위한 공간이 마련됨
    • 이 때 첫 번째 메서드는 수행을 멈추고, 두 번째 메서드가 수행되기 시작함
    • 두 번째로 호출된 메서드가 수행을 마치게 되면, 두 번째 메서드를 위해 제공되었던 호출스택의 메모리 공간이 반환되며, 첫 번째 메서드는 다시 수행을 계속 함
    • 첫 번째 메서드가 수행을 마치면, 제공되었던 메모리 공간이 호출스택에서 제거되며 호출스택은 완전히 비워지게 됨
  • 호출스택의 제일 상위에 위치하는 메서드가 현재 실행 중인 메서드이며, 나머지는 대기상태에 있게 됨
  • 호출스택을 조사해 보면 메서드 간의 호출관계와 현재 수행중인 메서드가 어느 것인지 알 수 있음
  • 반환타입이 있는 메서드는 종료되면서 결과값을 자신을 호출한 메서드에게 반환. 대기 상태에 있던 호출한 메서드는 넘겨받은 반환값으로 수행을 계속 진행

호출스택 특징

  • 메서드가 호출되면 수행에 필요한 만큼의 메모리를 스택에 할당받음
  • 메서드가 수행을 마치고나면 사용했던 메모리를 반환하고 스택에서 제거됨
  • 호출스택의 제일 위에 있는 메서드가 현재 실행 중인 메서드
  • 아래에 있는 메서드가 바로 위의 메서드를 호출한 메서드

3.8 기본형 매개변수와 참조형 매개변수

  • 매개변수의 타입이 기본형일 때는 기본형 값이 복사되지만, 참조형일 경우 잉ㄴ스턴스의 주소가 복사됨
  • 매개변수를 기본형으로 선언하면 단순히 저장된 값을 얻지만, 참조형으로 선언하면 값이 저장된 곳의 주소를 알 수 있기 때문에 값을 읽어 오는 것은 물론 값 변경이 가능

3.9 참조형 반환타입

  • 반환타입이 참조형이라는 것은 반환하는 값의 타입이 참조형이라는 의미
    • 모든 참조형 타입의 값은 '객체의 주소'이므로 정수값이 반환되는 것
  • 반환타입이 참조형이라는 것은 메서드가 객체의 주소를 반환한다는 것을 의미

3.10 재귀호출(recursive call)

  • 재귀호출(recursive call): 메서드의 내부에서 메서드 자신을 다시 호출하는 것
    • 재귀호출을 하는 메서드를 재귀 메서드라 함
 void method() {
 	method();	// 재귀호출. 메서드 자신을 호출
 }
  • 호출된 메서드는 값에의한 호출(call by value)을 통해, 원래의 값이 아닌 복산된 값으로 작업하기 때문에 호출된 메서드와 관계없이 독립적인 작업수행이 가능
  • 코드에 재귀호출뿐이면 무한히 자기 자신을 호출하기 때문에 무한 반복에 빠짐. 따라서 재귀호출도 조건문이 필수적으로 따라 다님
// 재귀호출 버전
void method(int n){
	if(n==0)   return;
	
	System.out.println(n);
	method(--n);	// 재귀호출
}

//반복문 버전
void method(int n){
	while(n!=0){
		System.out.println(n--);
    }
}
  • 대부분의 재귀호출은 반복문으로 작성하는 것이 가능
    • 반복문은 같은 문장을 반복해서 수행하는 것이지만, 메서드 호출은 반복문보다 몇 가지 과정(ex. 매개변수 복사와 종료 후 복귀한 주소저장 등)이 추가로 필요하기 때문에 재귀호출의 수행시간이 더 오래 걸림
  • 재귀호출을 사용하는 이유는 재귀호출이 주는 논리적 간결함 때문
    • 몇 겹의 반복문과 조건문으로 복잡하게 작성된 코드가 재귀호출로 작성하면 단순한 구조로 바뀔 수도 있음
    • 효율적으로 알아보기 힘들게 작성하는 것보다 비효율적이더라도 알아보기 쉽게 작성하는 것이 논리적 오류가 발생할 확률도 줄어들고 나중에 수정하기에도 좋음
  • 재귀호출은 비효율적이므로 재귀호출에 드는 비용보다 재귀호출의 간결함이 주는 이득이 큰 경우에만 사용해야 함

3.11 클래스 메서드(static 메서드)와 인스턴스 메서드

참고: 멤버변수

  • 멤버 변수: 클래스 영역에 선언된 변수
  • 클래스 변수(static 변수) + 인스턴스 변수로 구성
    • 클래스 변수(static 변수): 멤버변수 중 static이 붙은 것
    • 인스턴스 변수: 멤버변수 중 static이 붙지 않은 것
  • 메서드 앞에 static이 붙어 있으면 클래스 메서드, 없어면 인스턴스 메서드
  • 클래스 메서드는 객체를 생성하지 않고 클래스이름.메서드이름(매개변수)와 같은 식으로 호출이 가능. 반면에 인스턴스 메서드는 반드시 객체를 생성해야만 호출 가능
  • 인스턴스 메서드: 인스턴스 변수와 관련된 작업을 하는, 즉 메서드의 작업을 수행하는데 인스턴스 변수를 필요로 하는 메서드
    • 인스턴스 변수는 인스턴스를 생성해야만 만들어지므로 인스턴스 메서드 역시 인스턴스를 생성해야만 호출 가능
  • 클래스 메서드(static 메서드): 인스턴스와 관계없는(인스턴스 변수나 인스턴스 메서드를 사용하지 않는) 메서드
    • 인스턴스 변수를 사용하지 않는다고 해서 반드시 클래스 메서드로 정의해야하는 것은 아니지만 특별한 이유가 없는 한 이렇게 하는 것이 일반적

정리
1. 클래스를 설계할 때, 멤버변수 중 모든 인스턴스에 공통으로 사용하는 것에 static를 붙임

  • 생성된 각 인스턴스는 서로 독립적이기 때문에 각 인스턴스의 변수는 서로 다른 값을 유지
  • 모든 인스턴스에서 같은 값이 유지되어야 하는 변수는 static을 붙여서 클래스변수로 정의해야 함

2. 클래스 변수(static 변수)는 인스턴스를 생성하지 않아도 사용할 수 있음

  • static이 붙은 변수(클래스 변수)는 클래스가 메모리에 올라갈 때 이미 자동적으로 생성되기 때문

3. 클래스 메서드 (static 메서드)는 인스턴스 변수를 사용할 수 없음

  • 인스턴스 변수는 인스턴스가 반드시 존재해야만 사용 가능하지만 클래스 메서드는 인스턴스 생성 없이 호출가능하므로 클래스 메서드가 호출되었을 때 인스턴스가 존재하지 않을 수 있음. 따라서 클래스 메서드에서 인스턴스 변수의 사용을 금지
  • 인스턴스 변수나 인스턴스 메서드에서는 static이 붙은 멤버들을 사용하는 것은 언제나 가능. 인스턴스 변수가 존재한다는 것은 static 변수가 이미 메모리에 존재한다는 것을 의미하기 때문

4. 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려

  • 메서드의 작업내용 중에서 인스턴스 변수를 필요로 한다면, static을 붙일 수 없음
  • 인스턴스변수를 필요로 하지 않는다면 static을 붙임. 메서드 호출시간이 짧아지므로 성능이 향상됨
    • static을 아 붙인 메서드는 실행 시 호출되어야할 메서드를 찾는 과정이 추가적으로 필요하기 때문에 시간이 더 오래 걸림
  • 클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있는지 살펴보고 있으면 static을 붙임
  • 작성한 메서드 중 인스턴스 변수나 인스턴스 메서드를 사용하지 않는 메서드에 static을 붙일 것을 고려

3.12 클래스 멤버와 인스턴스 멤버간의 참조와 호출

  • 같은 클래스에 속한 멤버들 간에는 별도의 인스턴스를 생성하지 않고도 서로 참조 또는 호출이 가능
  • 단, 클래스 멤버가 인스턴스 멤버를 참조 또는 호출하고자 하는 경우에는 인스턴스를 생성해야 함
    • 이유: 인스턴스 멤버가 존재하는 시점에 클래스 멤버는 항상 존재하지만, 클래스 멤버가 존재하는 시점에 인스턴스멤버가 존재하지 않을 수도 있기 때문
  • 클래스멤버는 언제나 참조 또는 호출이 가능하기 때문에 인스턴스 멤버가 클래스 멤버를 사용하는 것은 문제가 되지 않음. 클래스 멤버간의 참조 또는 호출 역시 문제 없음
  • 인스턴스 멤버는 객체를 생성한 후에 참조 또는 호출이 가능하기 때문에 클래스 멤버가 인스턴스 멤버를 참조, 호출하기 위해서는 객체를 생성해야 함
  • 인스턴스 멤버간의 호출에는 문제가 없음
    • 이유: 하나의 인스턴스 멤버가 존재한다는 것은 인스턴스가 이미 생성되었다는 것을 의미하며, 즉 다른 인스턴스 멤버들도 모두 존재하기 때문

알아두면 좋아요!

  • c = new MemberCall()이므로 c.instanceMethod1();에서 c 대신 new MemberCall()을 대입하여 사용할 수 있음
MemberCall c = new MemberCall();
int result = c.instanceMethod1();
  • 위 코드를 한 줄로 표현 가능
int result = new MemberCall().instanceMethod1();
  • 단, 참조변수를 선언하지 않았기 때문에 생성된 MemberCall 인스턴스는 더 이상 사용 불가
profile
예비 백엔드 개발자

0개의 댓글