[메서드를 사용하는 이유 (중요)]
1. 높은 재사용성(reusability)
2. 중복된 코드 제거
3. 프로그램의 구조화
[Return문]
반환 타입이 void인 경우 return문을 안 써줘도 된다라고만 알고 있었으나, 원래는 모든 메서드에는 적어도 하나의 return문이 있어야 한다. 반환 타입이 void인 경우, 컴파일러가 마지막에 'return;'을 자동적으로 추가해줬기 때문에 return문을 쓰지 않아도 문제가 생기지 않았던 것이다.
[JVM의 메모리 구조]
(1) 메서드 영역
- 어떤 클래스가 사용되면 JVM은 해당 클래스 파일을 읽어 클래스 데이터를 이곳에 저장한다.
- 클래스 변수도 이 영역에 함께 생성된다.
- 메소드, 클래스, 인터페이스, 필드 등의 바이트 코드가 저장된다.
(2) Heap 영역
- 프로그램 실행 중 생성되는 인스턴스는 모두 이곳에 생성된다.
- 메서드 영역에 로드된 클래스만 생성이 가능하다.
(3) Stack 영역
- 메서드 호출 시마다 각각의 스택 프레임(그 메서드만을 위한 공간, 중괄호 {}로 묶인 공간)을 생성한다.
그리고 메소드 안에서 사용되는 값들을 저장하고, 호출된 메서드의 매개변수, 지역변수, 리턴 값 및 연산의 중간결과 값들을 임시로 저장한다. - 메소드 수행이 끝나면 프레임별로 삭제하여 할당되었던 메모리 공간은 비워진다. 그리고 메서드 안에서 호출된 값들은 다시 쓸 수 없게 된다.
2022.10.02 - [JAVA] - [JAVA] JVM이란? 개념 및 구조
[메서드 실행 시 호출스택의 변화]
1. 첫 번째 메서드가 호출되면 해당 메서드를 위한 메모리 공간을 스택에 할당되고 메서드가 수행된다.
2. 첫 번째 메서드 수행 중에 다른 메서드를 호출하면 첫 번째 메서드 위에 두 번째로 호출된 메서드를 위한 메모리 공간이 할당되고 두 번째 메서드가 수행된다. 이때 첫 번째 메서드는 두 번째 메서드가 수행을 마칠 때까지 대기한다.
3. 두 번째 메서드가 수행을 마치면 두 번째 메서드를 위한 호출 스택에 메모리 공간이 반환되며, 첫 번째 메서드는 다시 수행을 계속한다.
4. 첫 번째 메서드가 수행을 마치면 첫 번째 메소드를 위한 호출스택에 메모리공간이 반환되며 호출스택은 완전히 비워진다.
- 호출스택의 제일 위에 있는 메서드가 현재 실행 중인 메서드다.
- 아래에 있는 메서드가 바로 위에 메서드를 호출한 메서드다.
[기본형 / 참조형 매개변수]
class Data {
int x;
}
public class Test {
public static void main(String[] args){
Data data = new Data();
data.x = 10;
System.out.println(data.x); // 10
changeX(data.x);
System.out.println(data.x); // 10
changeData(data);
System.out.println(data.x); // 1000
}
static void changeX(int x){ // 기본형 매개변수
x = 1000;
}
static void changeData(Data d){ // 참조형 매개변수
d.x = 1000;
}
}
- changeX 메서드가 호출되며 매개변수 x 값이 변경.
메서드가 종료되면서 매개변수 x는 스택에서 제거되고 data는 여전히 x가10이라는 값이 담긴 주소를 참조한다. - changeData 메서드가 호출되면서 참조변수 data의 주소가 매개변수 d에 복사되며 같은 객체를 참조한다.
이제 d에 저장된 주소값으로 x에 접근과 값 변경이 가능해졌다.
메서드가 종료되면서 d는 스택에서 제거됐지만 data는 같은 객체를 참조하여 변경된 값을 불러올 수 있다.
메서드의 매개변수를 기본형으로 선언하면 단순히 저장된 값을 얻지만, 참조형으로 선언하면 값이 저장된 주소를 저장하기 때문에 값을 읽고 변경하는 것도 가능하다.
배열도 참조형변수이므로 sort 메서드에 배열을 넣어서 정렬을 하면 원래 배열에 방향에 영향을 미치는 것도 같은 원리다.
[재귀호출]
재귀호출은 매개변수 복사와 종료 후 복귀할 주소저장 등이 추가로 필요하기 때문에 반복문보다 수행 시간이 더 오래 걸린다. 재귀호출은 비효율적이므로 재귀호출에 드는 비용보다 재귀호출의 간결함이 주는 이득이 충분히 큰 경우에만 사용해야 한다.StackOverflowError가 발생하지 않도록 유효성 검사를 적절히 넣어야 한다.
[클래스 / 인스턴스 메서드]
클래스 메서드: 인스턴스 변수, 인스턴스 메서드를 사용하지 않는 메서드
인스턴스 메서드: 메서드 작업을 수행하는데 인스턴스 변수를 필요로 하는 메서드 (staitc 메소드 호출이 가능하다)
static 을 붙이는 기준:
1. 클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야 하는 변수에 static 붙일 것 고려
2. 인스턴스 변수나 인스턴스 메서드를 사용하지 않는 메서드에 static 붙일 것 고려
class Data {
int x, y;
int add(){
return x + y;
}
static int add(int x, int y){
return x + y;
}
}
public class Test {
public static void main(String[] args){
// 인스턴스 생성 x
System.out.println(Data.add(1,2)); // 3,
Data data = new Data();
data.x = 2;
data.y = 2;
System.out.println(data.add()); // 4
}
}
클래스 메서드 장점: 메서드 호출 시간이 짧음
인스턴스 메서드는 실행 시 호출되어야 할 메서드를 찾는 과정이 필요해 시간이 더 걸림
[클래스 멤버와 인스턴스 멤버간의 참조와 호출]
인스턴스 멤버 -> 클래스 멤버 (O)
클래스 멤버 -> 클래스 멤버 (O)
클래스 멤버는 클래스가 메모리에 올라갈 때 생성되므로 언제나 참조 또는 호출이 가능하기 때문에 인스턴스 또는 클래스 멤버가 클래스 멤버를 사용이 가능하다.
인스턴스 멤버 -> 인스턴스 멤버 (O)
하나의 인스턴스 멤버가 존재한다는 것은 인스턴스가 이미 생성되었다는 뜻이기 때문에 인스턴스 멤버 간의 참조와 호출도 가능하다.
클래스 멤버 -> 인스턴스 멤버 (X)
인스턴스 멤버가 존재하는 시점에 클래스 멤버는 항상 존재하지만, 클래스 멤버가 존재하는 시점에는 인스턴스 멤버가 존재하지 않을 수 있기 때문에 클래스 멤버에서 인스턴스 멤버를 사용할 수 없다.
'개인공부' 카테고리의 다른 글
생성자와 변수의 초기화 정리 (0) | 2022.12.13 |
---|---|
객체지향 4가지 특징 정리 (OOP) (0) | 2022.12.12 |
클래스 변수, 인스턴스 변수, 지역 변수 정리 (0) | 2022.12.06 |
클래스 / 객체 / 인스턴스 정리 (0) | 2022.12.06 |
2022.12.06 TIL (hibernate naming) (0) | 2022.12.06 |
댓글