IT 개발노트
변수와 메서드 본문
1. 변수와 메서드
1.1 선언위치에 따른 변수의 종류
- 변수의 선언위치가 변수의 종류와 범위를 결정한다.
- 인스턴스변수(instance variable)
-> 각 인스턴스의 개별적인 저장공간. 인스턴스마다 다른 값 저장가능
-> 인스턴스 생성 후, '참조변수.인스턴스변수명'으로 접근
-> 인스턴스를 생성할 때 생성되고, 참조변수가 없을 때 가비지컬렉터에 의해 자동제거됨
- 클래스변수(class variable)
-> 같은 클래스의 모든 인스턴스들이 공유하는 변수
-> 인스턴스 생성없이 '클래스이름.클래스변수명'으로 접근
-> 클래스가 로딩될 때 생성되고 프로그램이 종료될 때 소멸
- 지역변수(local variable)
-> 메서드 내에 선언되며, 메서드의 종료와 함께 소멸
-> 조건문, 반복문의 블럭{ } 내에 선언된 지역변수는 블럭을 벗어나면 소멸
1.2 클래스변수와 인스턴스변수
- 인스턴스변수는 인스턴스가 생성될 때마다 생성되므로 인스턴스마다 각기 다른 값을 유지할 수 있지만, 클래스변수는 모든 인스턴스가 하나의 저장공간을 공유하므로 항상 공통된 값을 갖는다.
1.3 메서드(method)
- 메서드란?
-> 작업을 수행하기 위한 명령문의 집합
-> 어떤 값을 입력받아서 처리하고 그 결과를 돌려준다.
( 입력받는 값이 없을 수도 있고 결과를 돌려주지 않을 수도 있다. )
- 메서드의 장점과 작성지침
-> 반복적인 코드를 줄이고 코드의 관리가 용이하다.
-> 반복적으로 수행되는 여러 문장을 메서드로 작성한다.
-> 하나의 메서드는 한 가지 기능만 수행하도록 작성하는 것이 좋다.
-> 관련된 여러 문장을 메서드로 작성한다.
- 메서드를 정의하는 방법 - 클래스 영역에만 정의할 수 있음
1.4 return문
- 메서드가 정상적으로 종료되는 경우
-> 메서드의 블럭{ }의 끝에 도달했을 때
-> 메서드의 블럭{ }을 수행 도중 return문을 만났을 때
- return문
-> 현재 실행 중인 메서드를 종료하고 호출한 메서드로 되돌아간다.
- return문 - 주의사항
-> 반환값이 있는 메서드는 모든 경우에 return문이 있어야 한다.
-> return문의 개수는 최소화하는 것이 좋다.
1.5 메서드의 호출
- 메서드의 호출방법
참조변수.메서드 이름(); // 메서드에 선언된 매개변수가 없는 경우
참조변수.메서드 이름(값1, 값2, ... ); // 메서드에 선언된 매개변수가 있는 경우
1.6 JVM의 메모리 구조
- 메서드영역(Method Area)
-> 클래스 정보와 클래스변수가 저장되는 곳
- 힙(heap)
-> 인스턴스가 생성되는 공간. new연산자에 의해서 생성되는 배열과 객체는 모두 여기에 생성된다.
- 호출스택(Call Stack)
-> 메소드의 작업공간. 메서드가 호출되면 메서드 수행에 필요한 메모리공간을 할당받고 메서드가 종료되면 사용하던 메모리를 반환한다.
- 호출스택의 특징
-> 메서드가 호출되면 수행에 필요한 메모리를 스택에 할당받는다.
-> 메서드가 수행을 마치면 사용했던 메모리를 반환한다.
-> 호출스택의 제일 위에 있는 메서드가 현재 실행중인 메서드다. (나머지 메서드는 대기상태)
-> 아래에 있는 메서드가 바로 위의 메서드를 호출한 메서드다.
1.7 기본형 매개변수와 참조형 매개변수
- 기본형 매개변수 : 변수의 값을 읽기만 할 수 있다.(read only)
- 참조형 매개변수 : 변수의 값을 읽고 변경할 수 있다.(read & write)
1.8 재귀호출(recursive call)
- 재귀호출이란?
-> 메서드 내에서 자기자신을 반복적으로 호출하는 것
-> 재귀호출은 반복문으로 바꿀 수 있으며 반복문보다 성능이 나쁨
-> 이해하기 쉽고 간결한 코드를 작성할 수 있다.
- 재귀호출의 예
-> 팩토리얼, 제곱, 트리운행, 폴더목록표시 등
class FactorialTest(
public static void main(String args[]) {
long result = factorial(4);
System.out.println(result);
}
static long factorial(int n) {
long result = 0;
if(n==1) {
result = 1;
} else {
result = n * factorial(n-1);
}
return result;
}
}
1.9 클래스메서드(static메서드)와 인스턴스메서드
- 인스턴스메서드
-> 인스턴스 생성 후, '참조변수.메서드이름()'으로 호출
-> 인스턴스변수나 인스턴스메서드와 관련된 작업을 하는 메서드
-> 메서드 내에서 인스턴스변수 사용가능
- 클래스메서드(static메서드)
-> 객체생성없이 '클래스이름.메서드이름()'으로 호출
-> 인스턴스변수나 인스턴스메서드와 관련없는 작업을 하는 메서드
-> 메서드 내에서 인스턴스변수 사용불가
-> 메서드 내에서 인스턴스변수를 사용하지 않는다면 static을 붙이는 것을 고려한다.
--> 메서드 작업 당시 인스턴스변수를 사용하면 인스턴스메서드, 인스턴스변수를 사용하지 않으면 클래스메서드라고 생각하자
class MyMath {
long a, b;
long add() { // 인스턴스메서드
return a + b;
}
static long add(long a, long b) { // 클래스메서드(static메서드)
return a + b;
}
}
class MyMathTest {
public static void main(String args[]) {
System.out.println(MyMath.add(200L, 100L); // 클래스메서드 호출
MyMath mm = new MyMath(); // 인스턴스 생성
mm.a = 200L;
mm.b = 100L;
System.out.println(mm.add()); // 인스턴스메서드 호출
}
}
1.10 멤버간의 참조와 호출
- 메서드의 호출
-> 같은 클래스의 멤버간에는 객체생성이나 참조변수 없이 참조할 수 있다. 그러나 static멤버들은 인스턴스멤버들을 참조할 수 없다.
class TestClass {
void instanceMethod() {} // 인스턴스메서드
static void staticMethod() {} // static메서드
void instanceMethod2() { // 인스턴스메서드
instanceMethod(); // 다른 인스턴스메서드를 호출한다.
staticMethod(); // static메서드를 호출한다.
}
static void staticMethod2() { // static메서드
instanceMethod(); // 에러!!! 인스턴스메서드를 호출할 수 없다.
staticMethod(); // static메서드는 호출 할 수 있다.
}
}
- 변수의 접근
class TestClass2 {
int iv; // 인스턴스변수
static int cv; // 클래스변수
void instanceMethod() { // 인스턴스메서드
System.out.println(iv); // 인스턴스변수를 사용할 수 있다.
System.out.println(cv); // 클래스변수를 사용할 수 있다.
}
static void staticMethod() { // static메서드
System.out.println(iv); // 에러!!!인스턴스변수를 사용할 수 없다.
System.out.println(cv); // 클래스변수를 사용할 수 있다.
}
}
2. 메서드 오버로딩
2.1 메서드 오버로딩(method overloading)이란?
-> 하나의 클래스에 같은 이름의 메서드를 여러 개 정의하는 것을 메서드 오버로딩, 간단히 오버로딩이라고 한다.
2.2 오버로딩의 조건
- 메서드의 이름이 같아야 한다.
- 매개변수의 개수 또는 타입이 달라야 한다.
- 매개변수는 같고 리턴타입이 다른 경우는 오버로딩이 성립되지 않는다.
(리턴타입은 오버로딩을 구현하는데 아무런 영향을 주지 못한다.)
2.3 오버로딩의 예
- System.out.println메서드
-> 다양하게 오버로딩된 메서드를 제공함으로써 모든 변수를 출력할 수 있도록 설계
- 매개변수의 이름이 다른 것은 오버로딩이 아니다.
int add(int a, int b) { return a + b; }
int add(int x, int y) { return x + y; }
- 리턴타입은 오버로딩의 성립조건이 아니다.
int add(int a, int b) { return a + b; }
long add(int a, int b) { return (long)(a + b); }
- 매개변수의 타입이 다르므로 오버로딩이 성립한다.
long add(int a, long b) { return a + b; }
long add(long a, int b) { return a + b; }
- 오버로딩의 올바른 예 : 매개변수는 다르지만 같은 의미의 기능수행
int add(int a, int b) { return a + b; }
long add(long a, long b) { return a + b; }
int add(int[] a) {
int result = 0;
for(int i=0; i<a.length; i++) {
result += a[i];
}
return result;
}