이 글은 남궁성님의 자바의 정석 3/e를 기반으로 공부한 내용을 정리한 글입니다.
기본형 매개변수 변수의 값을 읽기만 할 수 있다. (read only)
참조형 매개변수 변수의 값을 읽고 변경할 수 있다. (read & write)
class PrimitiveParamEx {
public static void main(String[] args) {
Data d = new Data(); // 인스턴스 생성
d.x = 10; // 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("change() : x = " + x);
}
}
실행결과
main() : x = 10
change() : x = 1000
After chage(d.x)
main() : x = 10
change메서드에서 main메서드로부터 넘겨받은 d.x의 값을 1000으로 변경했는데도 main메서드에서는 d.x의 값이 그대로다.
class Data { int x; }
class ReferenceParamEx {
public static void main(String[] args) {
Data d = new Data();
d.x = 10;
System.out.println("main() : x = " + d.x);
change(d);
System.out.println("After chanage(d)");
System.out.println("main() : x = " + d.x);
}
static void change(Data d){
//매개변수가 첨조형이기 때문에 x의 값이 아닌 주소가 매개변수 d에 복사되었다.
d.x = 1000;
// main메서드의 참조변수 d와 change메서드의 참조변수 d는 같은 객체를 가리킨다.
System.out.println("change() : x = " + d.x);
}
}
실행결과
main() : x = 10
change() : x = 1000
After change(d)
main() : x = 1000
참조형 매개변수
값이 아닌 '값이 저장된 주소'를 넘겨주면 값을 읽어오는 것뿐만 아니라 변경하는 것도 가능하다.
class ReferenceOaranEx2 {
public static void main(String[] args) {
int[] x = {10}; // 크기가 1인 배열. x[0] = 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
배열도 객체와 같이 참조변수를 통해 데이터가 저장된 공간에 접근하기 때문에 참조형 매개변수와 같은 결과를 얻을 수 있다.
임시적으로 간단히 처리할 때는 별도의 클래스를 선언하는 것보다 이처럼 배열을 이용할 수도 있다.
매개변수뿐만 아니라 반환타입도 참조형이 될 수 있다.
반환타입이 참조형이라는 것은 메서드가 '객체의 주소'를 반환한다는 것을 의미한다.
메서드의 내부에서 메서드 자신을 다시 호출하는 것을 '재귀호출'이라 한다.
void method() {
method(); // 재귀호출. 메서드 자신을 호출한다.
}
오로지 코드가 재귀호출 뿐이라면, 무한반복에 빠지게 된다. 무한반복부이 조건문과 함께 사용되어야하는 것처럼, 재귀호출도 조건문이 필수적으로 따라다닌다.
void method(int n) {
if(n == 0)
return; // n의 값이 0일 때, 메서드를 종료한다.
System.out.println(n);
method(--n); // 재귀호출. method(int n)을 호출
}
재귀호출은 반복문과 유사한 점이 많으며, 대부분의 재귀호출은 반복문으로 작성하는 것이 가능하다.
반복문보다 재귀호출의 수행시간이 더 오래 걸린다.
논리적 간결함 때문
f(n) = n * f(n-1), 단 f(1) = 1
class FactorialTest {
public static void main(String args[]) {
int result = factorial(4);
System.out.println(result);
}
static int factorial(int n) {
int result = 0;
if(n == 1)
result = 1;
else
result = n * factorial(n-1); // 다시 메서드 자신을 호출한다.
return result;
}
}
'호출하는 사람이 당연히 알아서 적절한 값을 인자로 주겠지.' 라는 막연한 믿음을 가져서는 안 된다. 매개변수의 유효성검사는 중요하다.
인스턴스 메서드는 인스턴스 변수와 관련된 작업을 하는, 즉 메서드의 작업을 수행하는데 인스턴스 변수를 필요로 하는 메서드이다.
반면에 메서드 중에서 인스턴스와 관계없는(인스턴스 변수나 인스턴스 메서드를 사용하지 않는) 메서드를 클래스 메서드(static메서드)로 정의한다.
클래스를 설계할 때, 멤버변수 중 모든 인스턴스에 공통으로 사용하는 것에 static을 붙인다.
모든 인스턴스에서 같은 값이 유지되어야 하는 변수는 static을 붙여서 클래스변수로 정의해야 한다.
클래스 변수는 인스턴스를 생성하지 않아도 사용할 수 있다.
클래스 메서드(static메서드)는 인스턴스 변수를 사용할 수 없다.
클래스 메서드가 호출되었을 때 인스턴스가 존재하지 않을 수도 있다.
메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.
메서드 호출시간이 짧아지므로 성능이 향상된다.
클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있는지 살펴보고 있으면, static을 붙여준다.
작성한 메서드 중에서 인스턴스 변수나 인스턴스 메서드를 사용하지 않는 메서드에 static을 붙일 것을 고려한다.
클래스안에 멤버변수를 사용하지 않는 메서드(매개변수만 받는 메서드)에는 static을 붙일 것을 고려한다.
class MyMath2 {
long a, b;
// 인스턴스변수 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; }
}
public 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.dvide(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