자동차는 엔진 상속 불가-> 다양성 성립 X
자동차는 엔진의 기능을 사용하면 되니까 될거 같지만
상속을 말로만 들었을땐 부모의 변수를 물려받는것인데
이거 자체로만 인지하고 문법적으로 사용하면 좋은 아키텍처가 만들어지지 않는다
//아키텍처 : 시스텀 구조의 설계 유형
왜? 다형성에 어긋나서 추상화를 만족하지 못한다
반대로 강아지는 동물을 상속 받을 수 있다
판단할때 강아지야 너 동물이니? OK, 자동차야 너 엔진이니? NO
DIP : dependency inversion priniple
구체적인 대상에 의존하는게 아니라 추상적인 것에 의존하고 상속을 통한 객체를 찍어서 운영하자
왕과 모자장수가 아닌 재판관과 증인에 의존해서 유지보수에 용이하게 만들자
OCP : open closed principle
DIP를 사용하면 기존코드를 수정할 필요없이 객체만 새로 만들고 상속하면 되는데
이를 개방 폐쇄원칙이라 한다
메모리 관리(static, stack,heap)
static : 모든 코드의 바이트화, static 변수, 클래스
stack : 지역변수, 매개변수, 생성자를 포함한 메서드가 호출될때 마다 쌓인다, 자동 초기화 안된다
heap : 배열과 객체가 할당되는 영역, 자동초기화 된다
참고코드
//stakc과 heap
public class Main {
public static void main (String[] args){
Counter c = new Counter();
two(C);
int count = c.get();
}
public static void two(Counter c){
c.increment();
c.increment();
}
}
public class Counter{
private int state =0;
public void increment(){state ++;}
public int get(){return state;}
}
->public static void main (String[] args)
스택에 main호출, args생성
->Counter c = new Counter();
main에 참조변수 c(4byte)생성
counter생성자 호출 -> 스택에 counter()생성, this(1) 생성
heap에서 counter객체 생성,counter 안에 state(iv)생성하고 0으로 초기화,this(1)에 counter객체 주소 대입
스택에서 counter()사라지고 메인에 있는 c값에 heap에 존재하는 counter주소 기입
->two(C);
스택에 two라는 메서드가 메인 위에 쌓인다, 파라미터로 Counter c를 받기때문에 c를 생성하고
counter객체 주소가 담겨있다, 파라미터가 있으면 this생성 x
->increment();
스택에 two위에 increment가 쌓인다
this에는 객체 counter의 주소가 담겨있고 state++;를 수행한다
->int count = c.get();
스택에 존재하는 메인에 count생성하고
메인 위에 get()프레임 쌓는다
get()의 this는 c가 가지고 있는 counter주소를 가리키고 있다
-> return state
get()프레임이 사라지고 메인의 count에 state값이 기록된다
//GC(garbage collector)
public class Main {
public static void main (String[] args){
Counter c = make();
}
public static Counter make(){
Counter c = new Counter();
return new Counter();
}
}
public class Counter{
private int state =0;
public void increment(){state ++;}
public int get(){return state;}
}
->Counter c = make();
make()메서드 실행
->Counter c = new Counter();
참조변수 c에 새로운 객체(1) 주소 대입
->return new Counter();
근데 리턴할때 새로운 객체(2) 만들면서 리턴
->Counter c = make();
여기서의 c에 2번객체 주소 대입
--> stack은 함수가 종료되면 자동으로 삭제
--> heap은 이렇게 낭비되는 자원이 있는데 이를 GC가 처리
상속에서 메모리관리
heap(객체) -> 자식을 생성하면 부모도 생성된다
static(클래스)->자식의 클래스가 올라가면 부모의 설계도도 올라간다
Parent p1 = new Parent();
A a2 = new A();
->Parent p1 = new Parent();
static에는 부모 클래스가 stack에는 p1, heap에는 parent()객체가 생성된다
->A a2 = new A();
static에는 부모,자식 클래스가 stack에는 a2, heap에는 parent(),A()객체가 생성된다
이때 a2가 가리키는 주소는 부모와 자식 클래스 둘다 참고한다
출처 : https://blog.naver.com/roylove/189204286
<그림참조>상속, 다형성의 메모리 구조 이해하기
자바의 메모리는 크게 3부분으로 나눌 수 있다(9개 이상의 영역이 있다) 스택틱, 스택, 힙영역이 있다. 스...
blog.naver.com
동적바인딩
강아지 t1 = new 강아지()
동물 t1 = new 강아지()
강아지 t1 = new 동물() -> 이거는 안된다 -> 리모컨 타입이 가지는 멤버 개수가 객체가 가지는 멤버개수보다 많다
다형성의 원리
가장 앞에 있는것들이 타입을 결정한다
동물 t1 = new 강아지() -> 강아지가 동물을 상속한것 -> 메모리에 동물, 강아지 모두 존재해야 한다
동물과 강아지 둘다 RUN을 가지고 있다면
t1.RUN()을 실행할때 동물의 RUN은 무시되고 강아지의 RUN이 실행된다
부모의 메소드를 자식이 오버라이딩 하면 실행할때 부모의 메소드는 무시된다=동적바인딩
컴포지션 vs 상속
상속 : 추상화를 통한 다형성 사용 is-a -> class child extends parent : 강아지가 동물이냐? -> ok -> 강아지는 동물을 상속
컴포지션 : 결합을 통해 코드 재사용 has-a -> new car(new engine()) : 차가 엔진을 가지냐? ->ok->차는 엔진을 결합한다
다운캐스팅 vs 업캐스팅
☕ JAVA 업캐스팅 & 다운캐스팅 - 완벽 이해하기
자바의 참조형 캐스팅 하나의 데이터 타입을 다른 타입으로 바꾸는 것을 타입 변환 혹은 형변환(캐스팅) 이라고 한다. 자바의 데이터형을 알아보면 크게 두가지로 나뉘게 된다. 기본형(primitive ty
inpa.tistory.com
다형성==참조변수의 형변환 중 업캐스팅
다형성!= 참조변수의 형변환 중 다운캐스팅
업캐스팅에서 오버라이딩을 했으면 동적할당 작용
다운캐스팅은 업캐스팅한 객체를 다시 자손의 메서드를 사용하기 위해서
다형성 이자 업캐스팅의 예시 코드
변수는 동적할당 되지않고 가리키는 객체따라간다
다형성,업캐스팅,<->DIP,OCP 한쪽을 만족하게 코드를 짜면 반대쪽도 충분히 만족하게 짜면서 좋은코드가 나온다
class 해장국 {
public void 간맞추기() {
// 뭐든...
}
}
class 뼈해장국 extends 해장국 {
@Override public void 간맞추기() {
// 뼈해장국에는 들깨가루...
}
}
class 콩나물해장국 extends 해장국 {
@Override public void 간맞추기() {
// 콩나물 해장국에는 고춧가루...
}
}
class 취객 {
public void 해장국먹기(해장국 어떤해장국) {
어떤해장국.간맞추기();
}
}
public class CastingTest {
public static void main(String[] args) {
취객 취객1 = new 취객();
해장국 해장국한그릇 = new 뼈해장국();
취객1.해장국먹기(해장국한그릇);
}
}
상속 관계와 업캐스팅에 관해서 더 이해하기 쉬운 예시를 들기위해 한글로 클래스명을 쓰긴 했습니다만…
그런데 만약 이 코드에서 업캐스팅을 사용하지 않고 각각의 해장국 객체의 메서드를 호출한다면 어떻게 될까? 아래의 코드처럼 해장국 한그릇이 뼈해장국인지, 콩나물해장국인지 검사하는 조건문이 추가된 이후에야 각 조건에 맞는 객체의 메서드가 호출될 것이다.
public void 해장국먹기(해장국 어떤해장국) {
if (뼈해장국 타입?) {
뼈해장국.간맞추기();
} else if (콩나물해장국 타입?) {
콩나물해장국.간맞추기();
}
// ...해장국 메뉴가 더 추가된다면?
}
이처럼 업캐스팅은 다형성과 관련이 있다. 위 예제에서 해장국 먹기 메서드를 호출할 때는 그 해장국이 뼈해장국이든 콩나물해장국이든 그냥 해장국 한그릇만 넘겨주면 취객은 아무런 걱정없이(타입 검사 없이) 먹으면 된다.
출처 : https://madplay.github.io/post/java-upcasting-and-downcasting
싱글톤
class DoorMan {
// 1. private로 생성자 호출을 막는다
private DoorMan(){}
// 2. static으로 main 시작전에 new 한다.
public static DoorMan instance = new DoorMan();
}
public class SingleEx01 {
public static void main(String[] args) {
DoorMan d1 = DoorMan.instance;
DoorMan d2 = DoorMan.instance;
System.out.println(d1);
System.out.println(d2);
}
}
이미 인스턴스는 static에 생성되어 있고
- DoorMan d1 = DoorMan.instance;: DoorMan 클래스의 유일한 인스턴스를 d1 변수에 할당
- DoorMan d2 = DoorMan.instance;: 인스턴스를 다시 d2 변수에 할당
이러한 구조로 인해 DoorMan 클래스의 인스턴스는 단 하나만 생성되고, 어디서든지 그 인스턴스에 접근할 수 있다.
이렇게 하면 메모리 낭비를 방지하고, 객체의 일관성을 유지 할 수 있다
'SpringBoot > PNUMiniBootCamp' 카테고리의 다른 글
CH07,CH08 서블릿(PNU-BACKEND-BOOTCAMP) (1) | 2024.01.23 |
---|---|
CH04 소켓 통신(PNU-BACKEND-BOOTCAMP) (1) | 2024.01.23 |
CH02 통신,CHO3 스트림과 버퍼(PNU-BACKEND-BOOTCAMP) (1) | 2024.01.23 |