객체와 메모리
객체 생명주기
- 객체 생성
- new 키워드를 사용하여 메모리에 객체 할당
- 생성자를 사용하여 메모리에서 객체 초기화
- 객체 사용
- 메소드 호출
- In use or reachable(사용 중) : 객체가 생성되어 다른 객체에 의해 참조되어 있는 경우 Strong referenced 상태
- Invisble (사용 중이며 접근 불가) : Strong referenced이며 접근이 불가능한 상태이며 가바지 컬렉터 대상이 되지 않음
- Unreachable (사용되지 않음) : Strong reference가 존재 하지않고 가비지 컬렉션의 대상
- 객체 제거
객체와 범위
- 지역 값의 수명은 서언된 범위에 연결됨
- 동적 객체의 수명은 해당 범위에 연결되지 않음
- 보다 긴 수명
- 소멸 시기가 명확히 결정되지 않음
가비지 컬렉션
- 객체는 명시적으로 소멸시킬 수 없음
- Java는 객체 생성 키워드와 반대의 동작을 하는 키워드 (delete 등)가 없음
- 명시적 삭제 기능은 다른 언어에서 치명적 어류의 주요 원인이 됨
- 가비지 컬렉션이 프로그래머를 대신하여 객체를 제거
- 도달할 수 없는 객체를 찾아 자동으로 제거
- 사용되지 않은 Heap 메모리로 되돌리고 마무리함
- 일반적으로 메모리가 부족할 대 가비지 컬렉션 작업을 수행
검토
서브 클래스 작성
클래스 확장
- 한 클래스에서 파생되는 클래스를 생성
- 파생되는 서브 클래스는 슈퍼 클래스의 대부분의 요소를 상속함
- 파생되는 서브 클래스는 슈퍼 클래스 보다 낮은 가시성을 가질 수 없음
1
2
3
4
5
6
7
8
9
| public class Product {
protected String name;
}
class IDCard extends Product{
public String getTitle(){
return name;
}
}
|
슈퍼 클래스 맴버에 엑세스
- protected 맴버는 암시적으로 파생된 클래스에 상속됨
- 파생된 클래스의 메소드에서 상속된 protected 맴버에 엑세스 할 수 있음 ```java public class Product { protected String name;
} public class External {
void access(Product product) { String name = product.name; } }
1
2
3
4
5
6
7
8
9
10
|
```java
package packageA;
import packageB.Product;
public class External {
void access(Product product){
product.name;
}
}
|
같은 패키지일 경우 접근 가능하지만 외부 패키지 일경우 상속관계가 아닐경우 private 처럼 동작하여 컴파일 오류가 발생한다.
슈퍼 클래스 생성자 호출
- 생성자는 반드시 super 키워드를 사용해서 호출
- private 생성자는 파생 클래스에서 엑세스 할 수 없음
- super 키워드로 식별자 범위 한정
1
2
3
4
5
6
7
8
9
10
| class Product{
protected Product(String name){
...
}
}
class IDCard extends Product{
public IDCard(String name){
super(name);
}
}
|
위와 같이 사용하여야 한다.
가상 메소드
- 클래스 계층구조 내에서 같은 시그너처로 하위 클래스에서 오버라이딩 될 수 있는 메소드
- 객체 지향 프로그래밍의 다향성에서 아주 중요한 부분
- Java의 모든 메소드는 가상 메소드로 동작
메소드 오버라이딩
- 서브 클래스에서 슈퍼 클래스의 메소드와 같은 시그너처로 정의
- 서브 클래스에서 오버라이드하는 메소드는 슈퍼 클래스의 가상 메소드보다 낮은 가시성을 가질 수 없음
1
2
3
4
5
6
| class Product{
public String getName(){return "Product";};
}
class IDCard extends Product{
public String getName(){return "IDCard";};
}
|
위와 같이 오버라이딩은 슈퍼 클래스가 정의한 메소드를 재정의 할 수 있다.
final 메소드
- final로 선언된 메소드는 서브 클래스에서 오버라이드 할 수 없음
1
2
3
4
5
6
| class Product{
final String getName(){return "Product";};
}
class IDCard extends Product{
public String getName(){return "IDCard";};// 컴파일 오류
}
|
컴파일 시도시 오류가 발생한다.
인터페이스 선언
1
2
3
4
5
6
7
8
9
10
| public interface BinartOp {
int apply(int right, int left);
}
class Adder implements BinartOp{
@Override
public int apply(int right, int left) {
return right+left;
}
}
|
위와 같이 interface에 있는 메소드를 정의 해야 한다.
다중 인터페이스 구현
- 클래스는 하나 이상의 인터페이스를 구현할 수 있음
- 인터페이스는 하나 이상의 인터페이스를 확장할 수 있음
- 클래스는 인터페이스의 메소드를 반드시 구현해야 함
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| interface Flyable {
void fly();
}
interface Suckable {
void suckle();
}
class Bat implements Flyable, Suckable {
@java.lang.Override
public void fly() {...}
public void suckle() {...}
}
|
인터페이스 메소드 구현
- 구현되는 메소드는 인터페이스의 메소드와 시그너처가 같아야 함
- 구현 메소드 역시 가상 메소드로, 파생되는 클래스에서 오버라이드 할 수 없음
- 클래스에서 구현되는 메소드는 인터페이스의 추상 메소드보다 좁은 가시성을 가질 수 없음
인터페이스에서 static 메소드 구현
- 인터페이스에서 static 메소드를 구한 후 사용
- 호출시 메소드의 전체 이름을 사용
추상 클래스 선언
- 클래스 인스턴스를 생성할 수 없음
- 선언이 아닌 구현을 상속하는 형태로 사용
- abstract 키워드를 사용해서 선언
1
2
3
4
5
6
7
8
9
| abstract class Factory{
...
}
class Test{
public static void main(String[] args) {
Factory factory = new Factory();// 추상 클래스 이기 때문에 컴파일 에러
}
}
|
추상 클래스와 인터페이스
- 유사점
- 인스턴스화 될 수 없음
- 파생 방지로 선언될 수 없음
- 차이점
- 인터페이스는 같은 타입으로서의 구현을 강제
- 추상 클래스는 데이터와 구현을 상속하고 확장을 유도
- 인터페이스는 인터페이스 외에는 확장할 수 없음
추상 메서드 구현
- 추상 클래스에서 구현이 없는 메소드 선언
- abstract 키워드 사용
- 추상 클래스에서만 추상 메소드를 선언할 수 있음