inblog logo
|
eunmouse
    java

    동적 바인딩과 추상화

    (미완)
    Aug 19, 2024
    동적 바인딩과 추상화
    Contents
    1. 프로젝트 생성2. 객체지향의 핵심3. 상속과 컴퍼지션

    1. 프로젝트 생성

     
    최상단 메뉴바에서 File → New → Project 를 통해 프로젝트를 생성해보자.
     
    notion image
     
    소스코드가 들어가는 폴더를 Package라 부른다. (src 는 소스코드를 의미한다.)
    src 에서 Package 부터 만들고, 동일한 방법으로 패키지 안에 Java Class 도 만들어본다.
     
    notion image
     

    2. 객체지향의 핵심

     
    💡
    객체는 상태와 행위를 가진다. 상태는 행위를 통해서만 변경한다.
     
    여기서 상태는 변수다. stack에 있는 변수가 아니라, 객체가 만들어질 때(생성될 때) 지니고 있는 변수를 의미한다.
    ‘객체’ 라는건 상태와 행위 두 가지를 같이 가진다.
    상태만 가진 것은 그저 데이터 덩어리임, 객체라고 부르긴하지만 엄밀히 따지면 객체가 아니다.
    아래의 int 목마름; 은 그저 데이터 덩어리인 것이다.
     
    class 앨리스 { int 목마름; }
     
    int 목마름 은 상태이다. static 이 안붙어있으니, 메모리에 뜨지 않는다. 띄우려면 heap 메모리에 띄워야 한다.
    엘리스를 이 세상에 태어나게 하려면 new 를 통해 heap 메모리에 올려야 한다.
     
    package ex00; class 엘리스 { private int 목마름; // 객체는 상태를 직접 변경 못함, 상태를 직접 변경하지 못하도록 private 붙임 // -> static 안붙어있으니까 heap } public 엘리스(int 목마름) { // 객체는 생성자로 초기화 하는거야 this.목마름 = 목마름; } public class Mem01 { public static void main(String[] args) { 엘리스 e = new 엘리스(100); } }
     

    2-1. JVM 의 메모리 공간

     
    notion image
     
    RAM을 8GB 라 할 때, 절반인 4GB 로 나뉘어 일반적으로 운영체제(OS)가 절반을 사용하고,
    남은 공간 중 JVM 은 500MB 를 차지한다고 보면 된다.
    여기서 한 칸(의 용량)은 8bit = 1byte 이다.
    byte단위는 문자 하나를 의미하는 것으로, 영어 letter 하나를 의미.
     
    JVM 이 쓰는 공간은 아래와 같이 나뉘어진다.(효율적으로 메모리를 나눠쓰려기 위함)
     
    notion image
    JVM 공간에서 main 이 실행되면, new 할 때마다 heap 에 채우고, stack과 static 한테 물어보고 너네 자리남니? 슥슥 늘릴 수도 있다. 하지만, 자리 없으면 못늘림.
    stack에 더 이상 늘어날 자리가 없으면, stackoverflow error가 발생하는 것이다.
     
    💡
    static 메서드는 클래스명.메서드이름(); 으로 호출한다.
     
    Mem01.hello(); 로 main 에서 메서드가 실행되면 stack 메모리에 뜬다.
    int 는 4byte이고, 4byte가 stack에 쌓이게 된다.
    11번 라인에서 stack 종료되면 4byte 는 날아가고,
    14번 라인에서 hello 호출하면 stack이 호출되고 hello 만들어지고 그 안에 4byte 할당 하고 있는데,
    11번 라인에서 stack 종료되면서 4byte 는 해제된다.
     
    notion image
     
    package ex00; class 엘리스 { private int 목마름; // 객체는 상태를 직접 변경 못함, 상태를 직접 변경하지 못하도록 private 붙임 // -> static 안붙어있으니까 heap } public 엘리스(int 목마름) { // 객체는 생성자로 초기화 하는거야 this.목마름 = 목마름; } public class Mem01 { static void hello() { // hello stack 생김 int num = 10; // 4byte // hello(); // -> 이러면 메서드가 종료가 안되니까 stack 에 계속 쌓임, stack 이 모지라니까 StackOverflowError 가 발생함 } public static void main(String[] args) { // Mem01.hello(); 엘리스 e = new 엘리스(100); // 엘리스 e1 = new 엘리스(목마름: 100); // e.목마름 = 100; 가 되지 않도록 // 1. 값 변경 (행위) e.물마시기(); // -> 의도한 결과가 나옴. 0 // 2. 값 확인 int 목마름 = e.목마름확인하기(); System.out.println(목마름); } }
     
    상태를 직접 변경하지 못하도록 private 을 붙이는데,
    private 이 붙은 변수에 접근하려면 getter 가 필요하다.
    setter: 상태를 변경하는 애 / getter: 상태를 확인하는 애
     
    static 은 여러 공간 띄우는게 불가하나, heap 은 여러 공간 띄우는 것이 가능.
    static 안붙어있으면 다 heap 에 뜬다.
    new 할때 뜨는 heap.
     

    2-2. 정리

    변수는 heap 변수 / static 변수 / stack 변수 로만 생각하면 된다.
    매개변수() 도 메서드의 stack 변수
    생성자도 생긴 모양새가 메서드이니 stack 변수(실행 시에 뜨니까)
     
    2진수 10진수 변환 방법(정리하기)
    변수들 heap, static, stack 정리
     
     

    3. 상속과 컴퍼지션

     

    3-1. 다형성

    notion image
    다형성: 하나의 대상을 두고 여러가지 이름으로 부를 수 있다.(최주호, 사람, 강사)
     
    💡
    has → 포함 / is → 동일
    notion image
    스포츠카이자 자동차, 이것이 다형성이다.
    자동차야 너 엔진이니? → No. (다형성X)
     
    정확히 상속은 다형성으로 보일 수 있는 타입을 물려받는 것이다.
    자동차를 상속하면 다형성으로 보일 수 있어야 한다.
    스포츠카야, 너 자동차니? → Yes.
    자동차야, 스포츠카니? → No.
    부모가 자식에게 타입을 물려주는 것, 두 가지로 불릴 수 있게.
    (의존성 주입 형태도 있으나, 여기서 다루지 않음)
     

    3-2. 다형성 적용

     
    레이싱 메서드를 매번 매개변수를 바꿔서 만들 수 없으니, 부모인 Car 를 매개변수로 만들었다.
     
    package ex00; class Car { // car 상태 // car 행위 int carNum = 10; } class Sonata extends Car { // 다형성 // Sonata 상태 // Sonata 행위 int sonataNum = 20; } class Genesis extends Car { // Genesis 상태 // Genesis 행위 } public class Mem02 { /* static void 레이싱(Sonata s1) { } static void 레이싱(Genesis g1) { } */ static void 레이싱(Car g1) { } public static void main(String[] args) { // Sonata s1 = new Sonata(); // Sonata, Car Car s1 = new Sonata(); // System.out.println(s1.carNum); // System.out.println(s1.sonataNum); System.out.println(s1.carNum); Car g1 = new Genesis(); // Genesis, Car 레이싱(s1); 레이싱(g1); } }
     
    레이싱을 하나로 통일 할 수 있었던 이유는 다형성 때문이다.
    만약 extends 하지 않으면, 타입 인식이 안되니 불가능하다. extends 필수
     
    static void 레이싱(Car g1) { }
    public static void main(String[] args) { // Sonata s1 = new Sonata(); // Sonata, Car Car s1 = new Sonata(); Car g1 = new Genesis(); // Genesis, Car 레이싱(s1); 레이싱(g1); }
     
    instanceof 는 타입 검사
     
    static void 레이싱(Car car) { if(car instanceof Sonata) { System.out.println("소나타 달린다~~~"); } else if(car instanceof Genesis) { System.out.println("제네시스 달린다~~~"); } }
     
    위의 방법을 사용한다면 tico … 늘어날 때마다
    매번 else if 로 써야하니까 몹시 번거롭다.
     

    3-3. 동적바인딩

    notion image
     
    생성자의 첫줄에 super() 로 부모 생성해주고, 부모 타입을 제일 먼저 생성해줘야 한다.
     
    자식이 부모가 가진 메서드를 똑같이 만들었어(재정의)
    동적바인딩
    부모의 메서드를 호출하면 오버라이드됨(무효화됨)
    부모의 메서드가 호출되어도 자식이 재정의한 메서드가 나옴(동적바인딩)
    무효화되었기 때문.
     
    상속으로 타입을 일치 시킬 수 있다. is-a 관계로 만들면 추상화 할 수 있다. (Car 로)
    추상화가 안되면 소나타, 제네시스… 매번 매개변수만 다른 메서드를 여러개를 만들어야하는데,
    추상화를 시키면 부모인 Car 만 메서드의 매개변수로 만들면 된다.
    동적바인딩으로 car.run() 만 해도된다.
    Car 는 소나타와 제네시스를 묶는 타입을 묶는 용도로만 썼다.
    Car c = new Car(); 라고 new 할 필요가 없음
    추상화시키면 부를 때 굉장히 편하거든’
    Car의 역할은 그게 다야~ 모든 자동차가 다 달리게 해~
    자동차는 이 세상에 존재하지 않는 추상적인 것. new를 못하게 막자 abstract 로 정의하면 됨(실수를 하지 않게)
    {} 어떻게 달리는지 모르겠을 때 이렇게 만들지, 몸체를 안만드는 것 (→ 추상메서드)
    이때 void run() {} 가 아닌 abstract void run() {} 으로 만드는거야
    추상적인건 이 세상에 존재하지않는다. 이 세상에 존재하지 않는 것을 heap 에 띄울 수 없음
     
     
     
    Share article
    Contents
    1. 프로젝트 생성2. 객체지향의 핵심3. 상속과 컴퍼지션

    eunmouse

    RSS·Powered by Inblog