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

변수에서처럼 메서드 앞에 static이 붙어 있으면 클래스 메서드이고 붙어있지 않으면 인스턴스 메서드이다.

클래스 메서드도 클래스 변수처럼, 객체를 생성하지 않고도, 클래스 이름. 메서드 이름(매개변수)과 같은 식으로 호출이 가능하다.

반면에 인스턴스 메서드는 반드시 객체를 생성해야만 호출할 수 있다.

인스턴스 메서드는 인스턴스 변수와 관련된 작업을 하는, 즉 메서드의 작업을 수행하는데 인스턴스 변수를 필요로 하는 메서드이다.

반면에 메서드 중에서 인스턴스와 관계없는 메서드를 클래스 메서드(static메서드)로 정의한다.

 

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

- 생성된 각 인스턴스는 서로 독립적이기 때문에 각 인스턴스의 변수는 서로 다른 값을 유지한다.

그러나 모든 인스턴스에서 같은 값이 유지되어야 하는 변수는 static을 붙여서 클래스 변수로 정의해야 한다.

 

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

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

 

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

- 인스턴스변수는 인스턴스가 반드시 존재해야만 사용할 수 있는데, 클래스 메서드(static이 붙은 메서드)는 인스턴스 생성 없이 호출 가능하므로 클래스 메서드가 호출되었을 때 인스턴스가 존재하지 않을 수 있다. 그래서 클래스 메서드에서 인스턴스 변수의 사용을 금지한다.

반면에 인스턴스 변수나 인스턴스 메서드에서는 static이 붙은 멤버들을 사용하는 것이 언제나 가능하다. 인스턴스 변수가 존재한다는 것은 static변수가 이미 메모리에 존재한다는 것을 의미하기 때문이다.

 

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

- 메서드의 작업내용 중에서 인스턴스 변수를 필요로 한다면, static을 붙일 수 없다. 반대로 인스턴스 변수를 필요로 하지 않는다면 static을 붙이자. 메서드 호출시간이 짧아지므로 성능이 향상된다. static을 안 붙인 메서드(인스턴스 메서드)는 실행 시 호출되어야 할 메서드를 찾는 과정이 추가적으로 필요하기 때문에 시간이 더 걸린다.

- 클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있는지 살펴보고 있으면, 
  static을 붙여준다.
- 작성한 메서드 중에서 인스턴스 변수나 인스턴스 메서드를 사용하지 않는 메서드에 
  static을 붙일 것을 고려한다

random()과 같은 Math클래스의 메서드는 모두 클래스 메서드이다.(인스턴스를 만들 수 없다) Math크래스에는 인스턴스 변수가 하나도 없거니와 작업을 수행하는데 필요한 값들을 모두 매개변수로 받아서 처리하기 때문이다.

 

class MyMath2 {
	long a, b;
	
	long add()		{ return a + b;	}
	long subtract()	{ return a - b;	}
	long multiply()	{ return a * b;	}
	double divide()	{ return a / b;	}
	
	static long		add(long a, long b)			{ return a + b;	}
	static long		subtract(long a, long b)	{ return a - b;	}
	static long		multiply(long a, long b)	{ return a * b;	}
	static double	divide(double a, double b)	{ return a / b;	}
}

class MyMathTest2 {
	public static void main(String[] args) {
		System.out.println(MyMath2.add(200L, 100L));
		System.out.println(MyMath2.subtract(200L, 100L));
		System.out.println(MyMath2.multiply(200L, 100L));
		System.out.println(MyMath2.divide(200.0, 100.0));
		
		MyMath2 mm = new MyMath2();
		mm.a = 200L;
		mm.b = 100L;
		
		System.out.println(mm.add());
		System.out.println(mm.subtract());
		System.out.println(mm.multiply());
		System.out.println(mm.divide());
	}
}
300
100
20000
2.0
300
100
20000
2.0

인스턴스 메서드인 add(), subtract(), multiply(), divide()는 인스턴스 변수인 a와 b만으로도 충분히 작업이 가능하기 때문에, 매개변수를 필요하지 않으므로 괄호()에 매개변수를 선언하지 않았다.

반면에 add(long a, long b), subtract(long a, long b)등은 인스턴스 변수 없이 매개 변수만으로 작업을 수행하기 때문에 static을 붙여서 클래스 메서드로 선언하였다.

MyMath2의 main메서드에서 보면, 클래스메서드는 객체 생성 없이 바로 호출이 가능했고, 인스턴스 메서드는 MyMath클래스의 인스턴스를 생성한 후에야 호출이 가능했다.

 

 

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

같은 클래스에 속한 멤버들 간에는 별도의 인스턴스를 생성하지 않고도 서로 참조 또는 호출이 가능하다. 단, 클래스 멤버가 인스턴스 멤버를 참조 또는 호출하고자 하는 경우에는 인스턴스를 생성해야 한다.

인스턴스 멤버가 존재하는 시점에 클래스 멤버는 항상 존재하지만, 클래스 멤버가 존재하는 시점에 인스턴스 멤버가 존재하지 않을 수도 있기 때문이다.

 

class MemberCall {
	int iv = 10;
	static int cv = 20;
	
	int iv2 = cv;
//	static int cv2 = iv;
	static int cv2 = new MemberCall().iv;
	
	static void staticMethod1() {
		System.out.println(cv);
//		System.out.println(iv);
		MemberCall c = new MemberCall();
		System.out.println(c.iv);
	}
	void instanceMethod1() {
		System.out.println(cv);	
		System.out.println(iv);	
	}
	
	static void staticMethod2() {
		staticMethod1();
//		instanceMethod1();
		MemberCall c = new MemberCall();
		c.instanceMethod1();
	}
	
	void instanceMethod2() {
		staticMethod1();
		instanceMethod1();
	}
}

//표시된 라인은 에러가 나는 라인이다.

클래스 멤버는 언제나 참조 또는 호출이 가능하기 때문에 인스턴스 멤버가 클래스 멤버를 사용하는 것은 아무런 문제가 안된다. 클래스 멤버 간의 참조 또는 호출 역시 아무런 문제가 없다.

그러나, 인스턴스멤버(인스턴스변수와 인스턴스 메서드)는 반드시 객체를 생성한 후에만 참조 또는 호출이 가능하기 때문에 클래스 멤버가 인스턴스 멤버를 참조, 호출하기 위해서는 객체를 생성하여야 한다.

 하지만, 인스턴스멤버간의 호출에는 아무런 문제가 없다. 하나의 인스턴스 멤버가 존재한다는 것은 인스턴스가 이미 생성되어있다는 것을 의미하며, 즉 다른 인스턴스 멤버들도 모두 존재하기 때문이다.

 

수학에서의 대입법처럼, c = new MemberCall()이므로 c.instanceMethod1();에서 c대신 new MemberCall()을 대입하여 사용할 수 있다.

 

	MemberCall c = new MemberCall();
	int result = c.instanceMetohd1();

이 코드를 요약하면

	int result = new MemberCall().instanceMetohd1();

대신 참조변수를 선언하지 않았기 때문에 생성된 MemberCall인스턴스는 더 이상 사용할 수 없다.

JVM의 메모리 구조 

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

 

1. 메서드 영역(method area)

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

 

2. 힙(heap)

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

즉, 인스턴스 변수(instance variable)들이 생성되는 공간이다.

 

3. 호출스택(call stack 또는 excution stack)

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

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

반환타입(return type)이 있는 메서드는 종료되면서 결괏값을 자신을 호출한 메서드(caller)에게 반환한다.

 

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

 

1~2. 위의 예제를 실행시키면, JVM에 의해서 main메서드가 호출됨으로써 프로그램이 시작된다. 이때, 호출 스택에는 main메서드를 위한 메모리 공간이 할당되고 main메서드의 코드가 수행되기 시작한다.

3.main메서드에서 firstMethod()를 호출한 상태이다. 아직 main메서드가 끝난 것은 아니므로 main메서드는 호출스택에 대기상태로 남아있고 firstMethod()의 수행이 시작된다.

4. firstMethod()에서 다시 secondeMethod()를 호출했다. firstMethod()는 secondMethod()가 수행을 마칠 때까지 대기상태에 있게 된다. secondMethod()가 수행을 마쳐야 firstMetohd()의 나머지 문장들을 수행할 수 있기 때문이다.

5. secondMethod()에서 println()을 호출했다. println메서드에 의해 secondMethod()가 화면에 출력된다.

6. println메서드의 수행이 완료되어 호출스택에서 사라지고 자신을 호출한 second Method()로 되돌아간다. 대기 중이던 secondMethod()는 println()을 호출한 이후부터 수행을 재개한다.

7. secondMethod()에 더 이상 수행할 코드가 없으므로 종료되고, 자신을 호출한 firstMetohd()로 돌아간다.

8. firstMethod()에 더 이상 수행할 코드가 없으므로 종료되고, 자신을 호출한 main메서드로 돌아간다.

9. main메서드에도 더 이상 수행할 코드가 없으므로 종료되어, 호출 스택은 완전히 비워지게 되고 프로그램은 종료된다.

 

 

 

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

자바에서는 메서드를 호출할 때 매개변수로 지정된 값을 메서드의 매개변수에 복사해서 넘겨준다.

매개변수의 타입이 기본형(primitive type)일 때는 기본형 값이 복사되겠지만, 참조형(reference type)이면 인스턴스의 주소가 복사된다.

메서드의 매개변수를 기본형으로 선언하면 단순히 저장된 값만 얻지만, 참조형으로 선언하면 값이 저장된 곳의 주소를 알 수 있기 때문에 값을 읽어 오는 것은 물론 값을 변경하는 것도 가능하다.

기본형 매개변수 변수의 값을 읽기만 할 수 있다.(read only)
참조형 매개변수 변수의 값을 읽고 변경할 수 있다.(read & write)

 

 

public class PrimitiveParamEx_1 {
	public static void main(String[] args) {
		Data d = new Data();
		d.x = 10;
		System.out.println("main() : x = " + d.x);
		
		change(d.x);
		System.out.println("After change(d.x)");
		System.out.println("main() : x = " + d.x);
		
	}
	static void change(int x) {
		x = 1000;
		System.out.println("change1() : x = " + x);
	}
}
main() : x = 10
change1() : x = 1000
After change(d.x)
main() : x = 10

원본이 아니라 복사본이 변경된 것이라 원본에는 아무런 영향을 미치지 못한다.

 

 

public class ReferenceParamEx {
	public static void main(String[] args) {
		Data d = new Data();
		d.x = 10;
		System.out.println("main() : x = " + d.x);

	}

	static void change(Data d) {
		d.x = 1000;
		System.out.println("change() : x = " + d.x);

	}
}
main() : x = 10
change() : x = 1000
After change(x)
main() : x = 1000
public class ReferenceParamEx2 {
	public static void main(String[] args) {
		int[] x = {10};
		System.out.println("main() : x = "+ x[0]);
		
		change(x);
		System.out.println("After change(x)");
		System.out.println("main() : x = "+ x[0]);
	}
	
	static void change(int[] x) {
		x[0] = 1000;
		System.out.println("change() : x = " +x[0]);
	}
}
main() : x = 10
change() : x = 1000
After change(x)
main() : x = 1000

배열이 참조변수를 통해 데이터가 저장된 공간에 접근한다는 것을 배웠는데,

Data클래스의 인스턴스와 길이가 1인 배열을 선언해서 같은 객체를 가르키게 함으로써 값의 변경이 가능해진다.

 

 

참조형 반환타입

매개변수뿐만 아니라 반환타입도 참조형이 될 수 있다. 반환타입이 참조형이라는 것은 반환하는 값의 타입이 참조형이라는 얘기인데, 모든 참조형 타입의 값은 객체의 주소이므로 그저 정수값이 반환되는 것일 뿐 특별할 것이 없다.

반환타입이 참조형이라는 것은 메서드가 객체의 주소를 반환한다는 것을 의미한다.

 

 

재귀호출(recursive call)

메서드 내부에서 메서드 자신을 호출하는 것을 재귀호출(recursive call)이라 하고, 재귀호출을 하는 메서드를 재귀 메서드라한다.

void method() {
	method;	//재귀호출. 메서드 자신을 호출한다.
}

대부분의 재귀호출은 반복문으로 작성하는것이 가능하다. 반복문은 그저 같은 문장을 반복해서 수행하는 것이지만, 메서드를 호출하는 것은 반복문보다 몇 가지 과정, 예를 들면 매개변수 복사와 종류 후 복귀할 주소저장 등,이 추가로 필요하기 때문에 반복문보다 재귀호출의 수행시간이 더 오래 걸린다.

반면에 재귀호출이 주는 논리적 간결함 때문에 특정 상황에서는 단순한구조로 만들어서 알아보기 쉽게 작성하는 것이 논리적 오류가 발생할 확률도 줄어들고 나중에 수정하기 좋다.

 

메서드의 선언과 구현

int add(int x, int y)
{
	int result = x + y;
    return result;	//작업 결과(반환값)을 반환한다.
}

메서드는 크게 두 부분, 선언부와 구현부로 이루어져 있다.

메서드를 정의한다는 것은 선언부와 구현부를 작성하는 것을 뜻하며 다음과 같은 형식으로 메서드를 정의한다

 

반환타입 메서드 이름 (타입 변수명, 타입 변수명, ...)	//선언부
{
	//메서드 호출시 수행될 코드(구현부)
}
int add(int a, int b)	// 선언부
{
	int result = a + b;	//구현부
    return result;	//구현부
}

 

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

메서드 선언부는 메서드의 이름과 매개변수 선언, 그리고 반환 타입으로 구성되어 있으며, 메서드가 작업을 수행하기 위해 어떤 값들을 필요로 하고 작업의 결과로 어떤 타입의 값을 반환하는지에 대한 정보를 제공한다.

int add(int x, int y) {
	int result = x + y;
    
    return result;	//결과를 반환
}

 

매개변수 선언(parameter declaration)

매개변수는 메서드가 작업을 수행하는데 필요한 값들(입력)을 제공받기 위한 것이며, 필요한 값의 개수만큼 변수를 선언하며 각 변수 간의 구분은 쉼표', '를 사용한다.

일반적인 변수선언과 달리 두 변수의 타입이 같아도 변수의 타입을 생략할 수 없다는 특징이 있다.

매개변수도 메서드 내에서 선언된 것으로 간주되므로 지역변수이다.

 

메서드의 이름(method name)

메서드의 이름도 앞서 배운 변수의 명명규칙대로 작성하면 된다.

메서드의 이름은'add'처럼 동사인 경우가 많으며, 이름만으로도 메서드의 기능을 쉽게 알 수 있도록 함축적이면서도 의미 있는 이름을 짓도록 노력해야 한다.

 

반환 타입(return type)

메서드의 작업 수행 결과인 반환 값의 타입을 적는다 반환 값이 없는 경우 반환 타입으로 void를 적어야 한다.

 

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

매서드의 선언부 다음에 오는 괄호{}를 메서드의 구현부라고 하는데, 여기에 메서드를 호출했을 때 수행될 문장들을 넣는다.

 

return문 

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

 

 

지역변수(local variable)

메서드 내에 선언된 변수들은 그 메서드 내에서만 사용할 수 있으므로 서로 다른 메서드라면 같은 이름의 변수를 선언해도 된다. 이처럼 메서드 내에 선언된 변수를 지역변수(local variable)라고 한다.

 

 

메서드의 호출

메서드를 정의했어도 호출되지 않으면 아무 일도 일어나지 않는다. 메서드를 호출해야만 구현부{}의 문장들이 수행된다.

그러나 main메서드는 프로그램 실행 시 OS에 의해 자동적으로 호출된다.

또한 메서드를 호출하는 방법은 다음과 같다.

메서드이름(값1,값2,...): // 메서드를 호출하는 방법

print99danAll();	// void print99danAll()을 호출
int result = add(3, 5);	// int add(int x, int y)를 호출하고, 결과를 result에 저장

 

 

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

메서드를 호출할 때 괄호() 안에 지정해준 값들을 인자(argument)또는 인수라고 하는데, 인자의 개수와 순서는 호출된 메서드에 선언된 매개변수와 일치해야 한다. 그리고 인자는 매서드가 호출되면서 매개변수에 대입되므로 인자의 타입은 매개변수의 타입과 일치하거나 자동 형 변환이 가능한 것이어야 한다.

 

메서드의 실행 흐름

같은 클래스 내의 메서드끼리는 참조 변수를 사용하지 않고도 서로 호출이 가능하지만 static메서드는 같은 클래스 내의 인스턴스 메서드를 호출할 수 없다.

public class MyMathTest {
	public static void main(String[] args) {
		MyMath mm = new MyMath();
		
		long result1 = mm.add(5L, 3L);
		long result2 = mm.subtract(5L, 3L);
		long result3 = mm.multiply(5L, 3L);
		double result4 = mm.divide(5L, 3L);
		
		System.out.println("add(5L, 3L) = " + result1);
		System.out.println("subtract(5L, 3L) = " + result2);
		System.out.println("multiply(5L, 3L) = " + result3);
		System.out.println("divide(5L, 3L) = " + result4);
	}

}

class MyMath {long add(long a, long b) {
	long result = a+b;
	return result;
	}

	long subtract(long a, long b) {return a -b;}
	long multiply(long a, long b) { return a * b;}
	double divide(double a, double b) {return a / b;}
}
add(5L, 3L) = 8
subtract(5L, 3L) = 2
multiply(5L, 3L) = 15
divide(5L, 3L) = 1.6666666666666667

MyMath클래스를 이용한 예제이다. divide에 선언된 매개변수 타입은 double형인데 이와 다른 long형의 값인 5L과 3L을 사용해서 호출하는 것이 가능하다.

 

return문

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

반환 값의 유무에 관계없이 모든 메서드에 넌 적어도 하나의 return문이 있어야 한다.

반환 값이 void인 경우 return문이 없어도 문제가 없던 이유는 컴파일러가 메서드의 마지막에 return을 자동적으로 추가하기 때문이다.

그러나 반환 타입이 void가 아니 경우, 반드시 return문이 있어야 한다.

 

매개변수의 유효성 검사

메서드를 작성하는 사람은 호출하는 쪽에서 알아서 적절한 값을 넘겨준다는 보장이 없으므로 가능ㅎ나 모든 경우의 수에 대해 고민하고 그에 대비한 코드를 작성해야 한다.

 

 

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

변수는 클래스 변수, 인스턴스 변수, 지역변수 모두 세 종류가 있다.

변수의 종류를 결정짓는 중요한 요소는 변수의 선언된 위치이므로 변수의 종류를 파악하기 위해서는 변수가 어느 영역에 선언되었는지를 확인하는 것이 중요하다.

멤버 변수를 제외한 나머지 변수들은 모두 지역변수이며 지금까지 계속 사용해왔다.

멤버 변수 중 static이 붙은 것은 클래스 변수, 붙지 않은 것은 인스턴스 변수이다.

class Variables
{
	int iv;		// 인스턴스변수
    static int cv;	// 클래스변수(static변수, 공유변수)
    
    void method()
	{
    
    	int lv = 0;	// 지역변수
	}
}

 

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

 

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

클래스 영역에 선언되며, 클래스의 인스턴스를 생성할 때 만들어진다.

 

2. 클래스 변수(class variable)

클래스 변수를 선언하는 방법은 인스턴스 변수 앞에 static을 붙이기만 하면 된다.

클래스 변수는 모든 인스턴스가 공통된 저장공간(변수)을 공유하게 된다.

한 클래스의 모든 인스턴스들이 공통적인 값을 유지해야 하는 속성의 경우, 클래스 변수로 선언해야 한다.

클래스 이름. 클래스 변수와 같은 형식으로 사용한다.

 

3 지역변수(local variable)

메서드 지역 내에 선언되어 메서드 내에서만 사용 가능하며, 메서드가 종료되면 소멸되어 사용할 수 없게 된다.

 

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

public class CardTest {
	public static void main(String[] args) {
		System.out.println("Card.width = " + Card.width);
		System.out.println("Card.width = " + Card.height);
		
		Card c1 = new Card();
		c1.kind = "Heart";
		c1.number = 7;
		
		Card c2 = new Card();
		c2.kind = "Spade";
		c2.number = 4;
		
		System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 (" + c1.width + ", " + c1.height + ")");
		System.out.println("c2은 " + c2.kind + ", " + c2.number + "이며, 크기는 (" + c2.width + ", " + c2.height + ")"); //c1 c2를Card로 바꿔도 값이 같다
		System.out.println("c1의 width와 height를 각각 50, 80으로 변경합니다.");
		
		c1.width = 50;
		c1.height = 80;
		
		System.out.println("c1은 " + c1.kind + ", " + c1.number + "이며, 크기는 (" + c1.width + ", " + c1.height + ")") ;
		System.out.println("c2은 " + c2.kind + ", " + c2.number + "이며, 크기는 (" + c2.width + ", " + c2.height + ")") ;
	}
}

Card클래스의 클래스변수(static변수)인 width, heitht는 Card클래스의 인스턴스를 생성하지 않고도 클래스 이름. 클래스 변수와 같은 방식으로 사용할 수 있다.

Card인스턴스인 c1과 c2는 클래스변수인 width와 height를 공유하기 때문에, c1의 width와 height를 변경하면 c2의 width와 height값도 바뀐 것과 같은 결과를 얻는다.

Card, width, c1.width, c2.width는 모두 같은 저장공간을 참조하므로 항상 같은 값을 같게 된다.

 

클래스 변수를 사용할 때는 Card.width와 같이 클래스이름.클래스변수의 형태로 하는 것이 좋다. 참조변수 c1, c2를 통해서도 클래스변수를 사용할 수 있지만 이렇게 하면 클래스변수를 인스턴스 변수로 오해하기 쉽기 때문이다.

인스턴스변수는 인스턴스가 생성될 때 마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만,
클래스 변수는 모든 인스턴스가 하나의 저장공간을 공유하므로, 항상 공통된 값을 갖는다.

 

메서드

메서드는 특정 작업을 수행하는 일련의 문장들을 하나로 묶은 것이다. 기본적으로 수학에서 함수의 역할과 비슷하며

어떤 값을 입력하면 이 값으로 작업을 수행해서 결과를 반환한다. 

예를들면 제곱근을 구하는 메서드 Math.sqrt()에 4.0을 입력하면, 2.0을 결과로반환한다.

 

메서드란것은 작업을 수행하는데 필요한 값을 넣고 원하는 결과를 얻으면 될 뿐, 이 메서드가 내부적으로 어떤 과정을 거쳐 결과를 만들어내는지 전혀 몰라도 된다.

sqrt()외에도 println()이나 random()과 같은 메서드도 마찬가지로 내부동작을 알지 못해도 사용하는데 어려움이 없다.

 

 

 

메서드를 사용하는 이유 

메서드를 통해서 얻는 이점은 여러가지가 있지만 그 중에서 대표적인 세가지는 다음과같다

1. 높은 재사용성(resuability)
	Java API에서 제공하는 메서드와 같이 한번 만들어 놓은 메서드는 몇 번이고 호출할 수 있으며,
    다른 프로그램에서도 사용이 가능하다.
    
2. 중복된 코드의 제거
	반복되는 문장들을 묶어서 하나의 메서드로 작성해 놓으면, 반복되는 문장들 대신
	메서드를 호출하는 한 뭉장으로 대체할 수 있다.
    
3. 프로그램의 구조화
	큰 규모의 프로그램에서는 문장들을 작업단위로 나눠서 여러 개의 메서드에 담아
	프로그램의 구조를 단순화시키는것이 필수적이다.

+ Recent posts