[Java] 6. 객체지향 프로그래밍 1 #2 변수와 메서드

2022. 4. 26. 18:09JAVA/Language

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

클래스 변수, 인스턴스 변수, 지역 변수의 위치

변수의 종류와 특징

변수의 종류 선언위치 생성시기
클래스 변수 클래스 영역 클래스가 메모리에 올라갈 때
인스턴스 변수 인스턴스가 생성될 때
지역 변수 클래스 영역 이외의 영역
(메서드, 생성자, 초기화 블럭 내부)
변수 선언문이 수행되었을 때

 

2. 클래스변수와 인스턴스변수

  • 클래스 변수 : 모든 인스턴스가 하나의 저장공간을 공유하며 공통된 값을 가짐
  • 인스턴스 변수 : 인스턴스마다 각기 다른 값을 가짐

 

3. 메서드(Method)

메서드란 무엇인가?

메서드는 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것을 의미합니다.

 

메서드의 사용 이유

  1. 높은 재사용성
  2. 중복된 코드의 제거
  3. 프로그램의 구조화
    • 기능들을 작업단위로 나누어 메서드로 정의하고 프로그램의 구조를 단순화시킴

 

4. 메서드의 선언과 구현

[접근제어자] [static] 반환타입 메서드이름(타입 변수명, 타입 변수명, ...)
{
	// 메서드 호출시 수행되는 코드
}

public int add(int a, int b)
{
	return a + b;
}

 

5. 메서드의 호출

메서드이름(값1, 값2, ...);

print99danAll();
int result = add(3, 5);

 

6. return문

return문은 현재 실행중인 메서드를 종료하고 호출한 메서드로 되돌아갑니다.

void printGugudan(int dan)
{
	for(int i=1; i<=9; i++)
    {
    	System.out.printf("%d * %d = %d\n", dan, i, dan*i);
    }
//  return;	// 반환타입이 void이므로 생략가능, 컴파일러가 자동추가
}
int multiply(int x, int y)
{
	int result = x * y;
	return result;	// 반환타입이 void가 아니므로 생략불가
}

 

7. JVM의 메모리 구조

JVM의 메모리 구조

7.1 메서드 영역(Method Area)

  • 프로그램 실행 중 어떤 클래스가 사용되면, JVM은 해당 클래스의 클래스파일(*.class)을 읽어서 분석하여 클래스에 대한 정보(클래스 데이터)를 이곳에 저장합니다. 이때, 그 클래스의 클래스 변수도 이 영역에 함께 생성됨

7.2 힙(Heap)

  • 인스턴스가 생성되는 공간, 프로그램 실행 중 생성되는 인스턴스는 모두 이곳에 생성됨

7.3 호출스택(Call Stack)

  • 호출스택은 메서드의 작업에 필요한 메모리 공간을 제공함
  • 메서드 호출시 호출스택에 호출된 메서드를 위한 메모리가 할당되며, 이 메모리는 메서드가 작업을 수행하는 동안 지역 변수(매개변수 포함)들과 연산의 중간 결과 등을 저장하는데 사영됨
  • 메서드가 작업을 마치면 할당되었던 메모리공간은 반환되어 비워짐

호출 스택의 특징

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

 

호출 스택의 예제

/**
 * 호출 스택 예제
 * 
 * 호출스택 변화
 * 1. empty
 * 2. main
 * 2. main -> firstMethod
 * 3. main -> firstMethod -> secondMethod
 * 4. main -> firstMethod -> secondMethod => println
 * 5. main -> firstMethod -> secondMethod
 * 6. main -> firstMethod
 * 7. main
 * 8. empty
 */
public class Driver {

	public static void main(String[] args) {
		System.out.println("start main");
		firstMethod();
		System.out.println("end main");
	}
	
	public static void firstMethod() {
		System.out.println("start firstMethod");
		secondMethod();
		System.out.println("end firstMethod");
	}
	
	public static void secondMethod() {
		System.out.println("start secondMethod");
		System.out.println("secondMethod()");
		System.out.println("end secondMethod");
	}
}
start main
start firstMethod
start secondMethod
secondMethod()
end secondMethod
end firstMethod
end main

 

8. 기본형 매개변수와 참조형 매개변수

기본형 매개변수

메서드 호출시 매개변수의 타입이 기본형 데이터 타입(Primitive Data Type)인 경우 전달한 값을 복사해서 저장함

 

참조형 매개변수

메서드 호출시 매개변수의 타입이 참조형 데이터 타입(Reference Data Type)인 경우 전달된 객체의 주소가 복사됩니다. 즉, 매개변수로 받은 변수는 전달된 객체가 저장된 곳을 가리키게 됩니다.

 

기본형 매개변수 예제

public class Driver {

	public static void change(int x)
	{
		x = 1000;
		System.out.printf("change() : x = %d\n", x);
	}
	
	public static void main(String[] args) {
		Data d = new Data();
		
		d.x = 10;
		System.out.printf("main() : x = %d\n", d.x);
		
		change(d.x);
		System.out.printf("After change(d.x)\n");
		System.out.printf("main() : x = %d", d.x);
		
		
	}
}
main() : x = 10
change() : x = 1000
After change(d.x)
main() : x = 10

위 결과를 보면 change() 메서드를 호출하여 x값을 넘겼음에도 Data 타입 객체 d의 x값은 변하지 않았습니다. 왜냐하면 매개변수로 넘긴 값이 int형 타입이기 때문입니다.

 

참조형 매개변수 예제

public class Driver {

	public static void change(Data d)
	{
		d.x = 1000;
		System.out.printf("change() : x = %d\n", d.x);
	}
	
	public static void main(String[] args) {
		Data d = new Data();
		
		d.x = 10;
		System.out.printf("main() : x = %d\n", d.x);
		
		change(d);
		System.out.printf("After change(d.x)\n");
		System.out.printf("main() : x = %d", d.x);
		
		
	}
}
main() : x = 10
change() : x = 1000
After change(d.x)
main() : x = 1000

위 결과를 보면 change() 메서드 호출시 매개변수로 객체 d 자체를 넘겨서 x값을 수정하였기 때문에 change() 메서드가 끝났음에도 x값이 1000을 저장한 것을 볼 수 있습니다.

 

9. 참조형 반환타입

메서드의 반환타입으로 참조형 데이터 타입(클래스 타입)으로 설정할 수 있습니다.

public class Driver {

	public static Data copy(Data d)
	{
		Data tmp = new Data();
		tmp.x = d.x;
		return tmp;
	}
	
	public static void main(String[] args) {
		Data d = new Data();
		d.x = 10;
		
		Data d2 = copy(d);
		System.out.printf("d.x = %d\n",d.x);
		System.out.printf("d2.x = %d\n",d2.x);
	}
}
d.x = 10
d2.x = 10

 

10. 재귀호출(recursive call)

재귀호출이란 무엇인가?

재귀호출은 메서드의 내부에서 메서드 자신을 다시 호출하는 것을 재귀호출이라고 합니다.

void method(){
	method();
}

 

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

클래스 메서드(static 메서드)

  • 객체를 생성하지 않고 "클래스이름.메서드이름(매개변수)"와 같은 식으로 호출이 가능함
  • 인스턴스와 관계없는(인스턴스 변수나 인스턴스 메서드를 사용하지 않는) 메서드를 클래스 메서드로 정의함

인스턴스 메서드

  • 인스턴스 메서드는 인스턴스 변수와 관련된 작업을 하는, 즉 메서드의 작업을 수행하는데 인스턴스 변수를 필요로 하는 메서드
  • 인스턴스 메서드는 인스턴스를 생성해야만 호출할 수 있음

 

클래스 메서드 및 클래스 변수의 특징

  • 클래스 설계시, 멤버변수 중 모든 인스턴스에 공통으로 사용하는 것에 static을 붙임
  • 클랫스 변수(static 변수)는 인스턴스를 생성하지 않아도 사용할 수 있음
  • 클래스 메서드는 인스턴스 변수를 사용할 수 없음
  • 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려함

 

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

같은 클래스에 속한 멤버들 간에는 별도의 인스턴스를 생성하지 않고도 서로 참조 또는 호출이 가능합니다. 단, 클래스 멤버가 인스턴스 멤버를 참조 또는 호출하고자 하는 경우에는 인스턴스를 생성해야 합니다. 그 이유는 인스턴스 멤버가 존재하는 시점에 클래스 멤버는 항상 존재하지만, 클래스 멤버가 존재하는 시점에 인스턴스 멤버가 존재하지 않을 수도 있기 때문입니다.

 

public class MemberCall {
	int iv = 10;		// 인스턴스 변수
	static int cv = 20;	// 클래스 변수
	
	int iv2 = cv;
//	static int cv2 = iv;	// 에러, 클래스변수는 인스턴수 변수를 사용할 수 없음
	static int cv2 = new MemberCall().iv;	// 객체를 생성후에 사용할 수 있음
	
	public static void staticMethod1()
	{
		System.out.println(cv);
//		System.out.println(iv);	// 에러, 클래스메서드에서 인스턴스 변수 사용불가
		MemberCall c= new MemberCall();
		System.out.println(c.iv);	// 객체를 생성한후에 사용 가능
	}
	
	public void instanceMethod1() 
	{
		System.out.println(cv);
		System.out.println(iv);	// 인스턴스 메서드에서는 인스턴스변수 사용가능
	}
	
	public static void staticMethod2()
	{
		staticMethod1();
//		instanceMethod1();	// 에러, 클래스메서드에서는 인스턴스 메서드 호출 불가능
		MemberCall c = new MemberCall();
		c.instanceMethod1(); // 객체를 생성한 후에 호출 가능함
	}
	
	public void instanceMethod2()
	{
		staticMethod1();	// 인스턴스 메서드는 클래스 메서드 호출 가능
		instanceMethod1();	// 인스턴스 메서드는 인스턴스 메서드 호출 가능
	}
	
}

 

References

source code : https://github.com/yonghwankim-dev/java_study
Java의 정석, 남궁 성 지음