Hello, World πŸ’»/Java β˜•οΈ

Live Study - Java 상속 (Inheritance)

ohhhmycode 2020. 12. 23. 22:15

μ •λ¦¬ν•œ λ‚΄μš©
- Java 의 상속과 νŠΉμ§•
- Super
- μ˜€λ²„λΌμ΄λ”©
- μ œμ–΄μž
- λ‹€ν˜•μ„±
- Dynamic Method Dispatch
- 좔상 클래슀
- Object 클래슀


Java 의 상속(Inheritance)κ³Ό νŠΉμ§•

클래슀λ₯Ό 상속 λ°›λŠ” λ‹€λŠ” 것은 기쑴의 클래슀λ₯Ό μž¬μ‚¬μš©ν•΄μ„œ μƒˆλ‘œμš΄ 클래슀λ₯Ό μž‘μ„±ν•˜λŠ” 것이닀. 
μƒμ†μ˜ λͺ©μ λ„ κ²°κ΅­ μ€‘λ³΅μ˜ 제거인 것 κ°™λ‹€. ν”„λ‘œκ·Έλž˜λ°μ˜ λ§Žμ€ κ°œλ…μ€ μ½”λ“œμ˜ μž¬μ‚¬μš©μ„±μ„ 높이고, 쀑볡을 μ œκ±°ν•˜κΈ° μœ„ν•΄ λ§Œλ“€μ–΄μ§€κ³  λ°œμ „λ˜λŠ” 것듀이 정말 λ§Žμ€κ²ƒ κ°™κ³ , μƒμ†μ΄λΌλŠ” κ°œλ…λ„ κ·Έ κ³Όμ • μ†μ˜ 산물이라고 μƒκ°ν•œλ‹€.

Java μ—μ„œ 클래슀λ₯Ό 상속 λ°›κΈ° μœ„ν•΄μ„œλŠ” extends λΌλŠ” ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•œλ‹€.

class Product {
    String productCode;
    String productType;
}

public class Book extends Product {
    String author;
    String title;
    // ..
}


상속 λ°›λŠ” Book 같은 클래슀λ₯Ό Child(μžμ‹), Sub(ν•˜μœ„), Derived(νŒŒμƒ) 클래슀 라고 많이 ν‘œν˜„ν•˜κ³ , 상속을 ν•΄μ£ΌλŠ” Product 같은 클래슀λ₯Ό Parent(λΆ€λͺ¨), Super(μƒμœ„), Base(기반) 클래슀라고 자주 ν‘œν˜„ν•œλ‹€.

μžμ‹ ν΄λž˜μŠ€λŠ” λΆ€λͺ¨ 클래슀의 멀버 λ³€μˆ˜, λ©”μ†Œλ“œλ“€μ„ λͺ¨λ‘ 상속 λ°›κ²Œ λœλ‹€. 이 λ•Œ μ ‘κ·Ό μ œμ–΄μžλ‘œ 상속 λ°›μ§€ λͺ»ν•˜λŠ” μžμ›λ“€λ„ μžˆμ§€λ§Œ, λΆ€λͺ¨ 클래슀의 μžμ›μ„ μžμ‹ ν΄λž˜μŠ€μ—μ„œ μ‚¬μš©ν•  수 μžˆλ‹€. 그리고 상속 λ°›μ§€ λͺ»ν•˜λŠ” 것듀도 μžˆλŠ”λ°, μƒμ„±μžμ™€ μ΄ˆκΈ°ν™” 블둝은 μƒμ†λ˜μ§€ μ•ŠλŠ”λ‹€.

μžμ‹ ν΄λž˜μŠ€λŠ” λΆ€λͺ¨ 클래슀의 λͺ¨λ“  멀버λ₯Ό 상속 λ°›κΈ° λ•Œλ¬Έμ— 이λ₯Ό ν™•μž₯, Extend 라고 ν‘œν˜„ν•  수 있고, κ·Έλž˜μ„œ 상속 받을 λ•Œμ˜ ν‚€μ›Œλ“œκ°€ extends 인 이유라고 ν•œλ‹€.

class Product {
    String productCode;
    String productType;
}

class Book extends Product {
    String author;
    String title;
    
    void display() {
        System.out.printf("%s, %s, %s, %s%n", 
                this.productCode, this.productType, this.author, this.title);
    }
}

 

μƒμ†μ΄λΌλŠ”κ±΄ 어쨋든 클래슀 κ°„μ˜ 관계λ₯Ό λ§Œλ“€μ–΄μ„œ 쀑볡을 쀄이고 μž¬μ‚¬μš©μ„±μ„ 높인 방법이닀.
상속이 μ•„λ‹ˆλΌ 클래슀 κ°„μ˜ ν¬ν•¨μ΄λΌλŠ” 관계λ₯Ό λ§Ίμ–΄ 쒋은 ꡬ쑰의 μ½”λ“œλ₯Ό μž‘μ„±ν•  μˆ˜λ„ μžˆλ‹€.

class Car {
    Wheel[] wheels = new Wheel[4];
    // ..
}

class Wheel {
    String brand;
    String type;
}

μœ„μ˜ ν΄λž˜μŠ€λŠ” 'μžλ™μ°¨κ°€ 바퀴λ₯Ό κ°€μ§€κ³  μžˆλ‹€' 라고 ν‘œν˜„ν•  수 μžˆλ‹€. μžλ™μ°¨λΌλŠ” μ»€λŒ€ν•œ 클래슀λ₯Ό μž‘μ„±ν•˜λŠ” 것보닀 ꡬ성 μš”μ†Œ λ³„λ‘œ μ—¬λŸ¬κ°œμ˜ 클래슀λ₯Ό λ§Œλ“€κ³  포함 κ΄€κ³„λ‘œ μž¬μ‚¬μš©ν•˜λ©΄, 보닀 쒋은 ꡬ쑰의 ν”„λ‘œκ·Έλž¨μ„ λ§Œλ“€ 수 μžˆλŠ” 것 κ°™λ‹€.

클래슀의 관계λ₯Ό κ²°μ •ν•  λ•Œ 'AλŠ” B이닀(is - a)', 'AλŠ” Bλ₯Ό κ°€μ§€κ³  μžˆλ‹€(has - a)' 에 λŒ€μž…ν•΄μ„œ 생각해보면 κ°€λ‹₯을 μž‘μ„ 수 μžˆλŠ” 것 κ°™λ‹€.

책은 μƒν’ˆμ΄λ‹€. (is - a)
μ°¨λŠ” 바퀴듀을 κ°€μ§€κ³  μžˆλ‹€. (has - a)

 

λ‹€μ‹œ μƒμ†μœΌλ‘œ λŒμ•„μ™€μ„œ, Java λŠ” ν•˜λ‚˜μ˜ 클래슀만 상속 받을 수 μžˆλ‹€. 단일 상속 이라고 ν‘œν˜„ν•œλ‹€. 닀쀑 상속을 ν—ˆμš©ν•˜λŠ” μ–Έμ–΄(C++, Python λ“±)도 μžˆλ‹€.

닀쀑 상속을 ν—ˆμš©ν•˜λŠ” 경우 μ—¬λŸ¬ ν΄λž˜μŠ€μ—μ„œ 상속을 받을 수 있게 λ˜λ―€λ‘œ 볡합적인 κΈ°λŠ₯을 κ°€μ§„ 클래슀λ₯Ό μ‰½κ²Œ μž‘μ„±ν•  수 있게 λ˜μ§€λ§Œ, 상속 λ°›λŠ” ν΄λž˜μŠ€λ“€ 쀑 같은 μ΄λ¦„μ˜ λ©”μ†Œλ“œκ°€ μžˆλŠ” 경우 κ΅¬λ³„ν•˜κΈ° μ–΄λ ΅λ‹€λŠ” 단점이 μžˆλ‹€. 

κ·Έλž˜μ„œ νŒŒμ΄μ¬μ—μ„œλŠ” Method Resolution Order (MRO) λΌλŠ” κ°œλ…μ΄ μžˆμ–΄μ„œ μ•žμ˜ μƒν™©μ—μ„œ μ–΄λ–€ λ©”μ†Œλ“œκ°€ μ‚¬μš©λ˜λŠ”μ§€μ— λŒ€ν•œ κ·œμΉ™μ΄ μžˆλ‹€. 


Java μ—μ„œλŠ” μœ„μ™€ 같은 이유둜 닀쀑 상속을 ν—ˆμš©ν•˜μ§€ μ•ŠλŠ”λ‹€. 클래슀 κ°„μ˜ 관계가 보닀 λͺ…ν™•ν•΄μ§€λŠ” μž₯점이 μžˆλ‹€.

 

Super

super λŠ” μžμ‹ ν΄λž˜μŠ€μ—μ„œ λΆ€λͺ¨ 클래슀의 μžμ›μ„ μ°Έμ‘°ν•˜λŠ”λ° μ‚¬μš©λ˜λŠ” λ³€μˆ˜λ‹€. 

λΆ€λͺ¨ 클래슀의 μžμ›λ„ this ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄ μ°Έμ‘°ν•  수 있고, μžμ‹ 클래슀의 μžμ›κ³Ό λΆ€λͺ¨ 클래슀의 μžμ›μ„ κ΅¬λ³„ν•΄μ„œ μ‚¬μš©ν•΄μ•Ό ν•  λ•Œ super ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ λœλ‹€.

class Product {
    String productCode;
    String type = "Product Type";

}

class Book extends Product {
    String author;
    String type = "Book Type";

    void displayType() {
        System.out.println(String.format("Super: %s, This: %s", super.type, this.type));
    }
}

public class SampleTest {

    public static void main(String[] args) {
        Book book = new Book();
        book.displayType();
    }

}

// 좜λ ₯κ²°κ³Ό
// Super: Product Type, This: Book Type


μ˜ˆμ œλŠ” λ³€μˆ˜μ— λŒ€ν•΄ super 둜 μ°Έμ‘°ν–ˆλŠ”λ°, λ©”μ†Œλ“œμ— λŒ€ν•΄μ„œλ„ super 둜 μ°Έμ‘°ν•  수 μžˆλ‹€.

super()

μƒμ„±μžμ—μ„œ λ‹€λ₯Έ μƒμ„±μžλ₯Ό 호좜 ν•  λ•Œ this() λ₯Ό μ‚¬μš©ν–ˆμ—ˆλ‹€. super() 도 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•  λ•Œ μ‚¬μš©ν•  수 μžˆλ‹€. λΆ€λͺ¨ 클래슀의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜λŠ” 방법이닀.

μžμ‹ 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜λ©΄, λΆ€λͺ¨ + μžμ‹μ΄ 된 ν•˜λ‚˜μ˜ μΈμŠ€ν„΄μŠ€κ°€ μƒμ„±λ˜λŠ” 것이기 λ•Œλ¬Έμ—, μžμ‹ 클래슀의 μƒμ„±μžκ°€ 호좜될 λ•Œ λΆ€λͺ¨ 클래슀의 μƒμ„±μžλ„ ν•¨κ»˜ 호좜이 λ˜μ–΄μ•Ό ν•œλ‹€.

μ΄λ•Œ μžμ‹ ν΄λž˜μŠ€μ—μ„œ λΆ€λͺ¨ 클래슀의 μžμ›μ„ μ‚¬μš©ν•  수 있기 λ•Œλ¬Έμ— μžμ‹ 클래슀 μƒμ„±μžμ˜ 첫 μ€„μ—μ„œλŠ” λΆ€λͺ¨ 클래슀의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•΄μ•Ό ν•œλ‹€. λ§Œμ•½ 첫 μ€„μ—μ„œ super() λ₯Ό ν˜ΈμΆœν•˜μ§€ μ•Šμ•˜λ‹€λ©΄ μ»΄νŒŒμΌλŸ¬κ°€ μžλ™μœΌλ‘œ μΆ”κ°€ν•΄μ€€λ‹€.

λ§Œμ•½ λΆ€λͺ¨ ν΄λž˜μŠ€μ— κΈ°λ³Έ μƒμ„±μžκ°€ μ—†λŠ” κ²½μš°μ— μ»΄νŒŒμΌλŸ¬κ°€ μžμ‹ μƒμ„±μžμ—μ„œ super(); λ₯Ό μΆ”κ°€ν•˜λ©΄ μ—λŸ¬κ°€ λ°œμƒν•  수 있기 λ•Œλ¬Έμ— μ£Όμ˜ν•΄μ•Ό ν•œλ‹€. μ•„λž˜μ™€ 같은 κ²½μš°μ΄λ‹€.

class Product {
    String productCode;
    String productType;

    public Product(String productCode, String productType) {
        this.productCode = productCode;
        this.productType = productType;
    }
}

class Book extends Product {
    String author;
    String title;

    public Book(String productCode, String productType, 
                String author, String title) {
        this.author = author;
        this.title = title;
    }
}


μœ„μ˜ μ½”λ“œλŠ” λΆ€λͺ¨ ν΄λž˜μŠ€μ—λŠ” κΈ°λ³Έ μƒμ„±μžκ°€ μ—†λŠ”λ°, μžμ‹ μƒμ„±μžμ—μ„œ λΆ€λͺ¨ μƒμ„±μžλ₯Ό ν˜ΈμΆœν•˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ— μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.

class Book extends Product {
    String author;
    String title;

    public Book(String productCode, String productType, String author, String title) {
        super(productCode, productType); // μΆ”κ°€!
        this.author = author;
        this.title = title;
    }
}


λΆ€λͺ¨ 클래슀의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•΄μ€˜μ•Ό 문제 없이 μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 수 μžˆλ‹€.

 

μ˜€λ²„λΌμ΄λ”©, Overriding

λΆ€λͺ¨ ν΄λž˜μŠ€μ—μ„œ 상속받은 λ©”μ†Œλ“œλ₯Ό λ‹€μ‹œ μž‘μ„±ν•˜λŠ” 것을 μ˜€λ²„라이딩 μ΄λΌκ³  ν•œλ‹€. 

class Product {
    String productCode;
    String productType;

    String getDisplayData() {
        return String.format("Product Code: %s, Product Type: %s", productCode, productType);
    }
}

class Book extends Product {
    String author;
    String title;

    @Override
    String getDisplayData() {
        return String.format("Product Type: %s, Book Title: %s, Book author: %s", 
            productType, title, author);
    }
}


Product 클래슀λ₯Ό 상속받아 getDisplayData λ©”μ†Œλ“œλ₯Ό μ˜€λ²„λΌμ΄λ”© ν–ˆλ‹€. 

μ˜€λ²„λΌμ΄λ”©μ„ ν•œλ‹€λŠ” 것은 λ©”μ†Œλ“œμ˜ Body λΆ€λΆ„λ§Œ μž¬μž‘μ„± ν•˜λŠ” 것이기 λ•Œλ¬Έμ— μ„ μ–ΈλΆ€λŠ” μ™„μ „νžˆ 동일해야 ν•œλ‹€. λ©”μ†Œλ“œ λͺ…, λ§€κ°œλ³€μˆ˜, λ°˜ν™˜ νƒ€μž…μ΄ 동일해야 ν•œλ‹€. λŒ€λΆ€λΆ„μ˜ 경우 λΆ€λͺ¨ 클래슀의 선언뢀와 λ˜‘κ°™μ΄ μ‚¬μš©ν•˜μ§€λ§Œ μ ‘κ·Ό μ œμ–΄μžμ™€ μ˜ˆμ™ΈλŠ” 쑰건적으둜 λ³€κ²½ν•  수 μžˆλ‹€.

λΆ€λͺ¨ 클래슀의 λ©”μ†Œλ“œλ³΄λ‹€ 넓은 λ²”μœ„μ˜ μ ‘κ·Ό μ œμ–΄μžλ‘œ λ³€κ²½ν•  수 μžˆλ‹€. μ ‘κ·Ό μ œμ–΄μžμ˜ λ²”μœ„λŠ” public -> protected -> default -> private 순으둜 μ’ν˜€μ§„λ‹€.  예λ₯Ό λ“€λ©΄ λΆ€λͺ¨ 클래슀의 λ©”μ†Œλ“œκ°€ protected μ˜€μœΌλ©΄ μžμ‹ ν΄λž˜μŠ€λŠ” λ˜‘κ°™μ΄ protected μ΄κ±°λ‚˜, public 이어야 ν•œλ‹€λŠ” 것이닀. private 둜 λ³€κ²½ν•˜λ©΄ μ»΄νŒŒμΌλŸ¬κ°€ μ—λŸ¬λ₯Ό μ•Œλ €μ€€λ‹€.

그리고 λΆ€λͺ¨ 클래슀의 λ©”μ†Œλ“œλ³΄λ‹€ λ§Žμ€ 수의 μ˜ˆμ™Έλ₯Ό μ„ μ–Έν•  수 μ—†λ‹€. 예λ₯Ό λ“€μ–΄ λΆ€λͺ¨ λ©”μ†Œλ“œκ°€ IOException, IllegalArgumentException μ˜ˆμ™Έλ₯Ό λ˜μ§€λŠ” 경우 μžμ‹μ—μ„œλŠ” λ‘˜ 쀑 ν•˜λ‚˜μ˜ μ˜ˆμ™Έλ§Œ λ˜μ Έλ„ λœλ‹€. ν•˜μ§€λ§Œ λ‹€λ₯Έ μ˜ˆμ™Έλ₯Ό λ˜μ§€κ±°λ‚˜ ν•˜λ©΄ μ—­μ‹œ μ—λŸ¬κ°€ 생긴닀. 

 

μ œμ–΄μž, Modifier

μ œμ–΄μžλŠ” 클래슀, λ³€μˆ˜, λ©”μ†Œλ“œμ˜ 선언뢀에 μ‚¬μš©λ˜μ–΄ 뢀가적인 의미λ₯Ό λΆ€μ—¬ν•œλ‹€. 크게 μ ‘κ·Ό μ œμ–΄μžμ™€ μ ‘κ·Ό μ œμ–΄μžλ₯Ό μ œμ™Έν•œ μ œμ–΄μžλ“€μ΄ μžˆλ‹€.

μ ‘κ·Ό μ œμ–΄μž: public, protected, default, private
κ·Έ μ™Έ μ œμ–΄μž: static, final, abstract, native, transient, synchronized, volatile, strictfp

μ ‘κ·Ό μ œμ–΄μžλŠ” ν•œ λ²ˆμ— ν•˜λ‚˜λ§Œ μ‚¬μš©ν•  수 있고, κ·Έ μ™Έμ˜ μ œμ–΄μžλ“€μ€ μ—¬λŸ¬κ°€μ§€λ₯Ό μ‘°ν•©ν•΄μ„œ μ‚¬μš©ν•  수 μžˆλ‹€.

public static final int NUMBER = 10;


μ΄λ ‡κ²Œ μ‚¬μš©ν•  μˆ˜λŠ” μžˆμ§€λ§Œ, public private static μ΄λ ‡κ²Œ public κ³Ό private 을 ν•¨κ»˜ μ‚¬μš©ν•  μˆ˜λŠ” μ—†λ‹€.
μ œμ–΄μžλ“€μ„ μ‘°ν•©ν•΄μ„œ μ‚¬μš©ν•  λ•Œ, μ œμ–΄μžμ˜ μˆœμ„œλŠ” 상관이 μ—†λ‹€. 보톡 μ ‘κ·Ό μ œμ–΄μžλ₯Ό κ°€μž₯ μ™Όμͺ½μ— 두고, κ·Έ μ™Έμ˜ μ œμ–΄μžλ“€μ„ μ μ ˆν•˜κ²Œ μž‘μ„±ν•˜λ©΄ λœλ‹€.

μ ‘κ·Ό μ œμ–΄μž

μ ‘κ·Ό μ œμ–΄μžλŠ” 클래슀, λ³€μˆ˜, λ©”μ†Œλ“œμ— μ μš©ν•΄μ„œ μ™ΈλΆ€μ—μ„œ μ ‘κ·Όν•˜μ§€ λͺ»ν•˜λ„둝 μ œν•œν•˜λŠ” 역할을 ν•œλ‹€. 
μ™ΈλΆ€λ‘œλΆ€ν„° 데이터λ₯Ό λ³΄ν˜Έν•˜κΈ° μœ„ν•΄μ„œ, λΆˆν•„μš”ν•œ 뢀뢄을 감좔기 μœ„ν•΄μ„œ μ‚¬μš©ν•˜λŠ” 것이닀. 객체지ν–₯κ°œλ…μ˜ μΊ‘μŠν™” (Encapsulation)에 ν•΄λ‹Ήν•œλ‹€.

ν΄λž˜μŠ€μ—λŠ” public, default μ œμ–΄μžκ°€ ν—ˆμš©λ˜κ³ ,
λ³€μˆ˜μ™€ λ©”μ†Œλ“œμ—λŠ” public, protected, default, private μ œμ–΄μžκ°€ ν—ˆμš©λœλ‹€.

μ ‘κ·Ό μ œμ–΄μžλ₯Ό λ”°λ‘œ μ •μ˜ν•˜μ§€ μ•ŠλŠ” 경우, default μ œμ–΄μžκ°€ 기본으둜 μ μš©λœλ‹€.

public μ ‘κ·Ό μ œν•œμ΄ μ—†λ‹€.
protected 같은 νŒ¨ν‚€μ§€ λ‚΄μ—μ„œ, λ‹€λ₯Έ νŒ¨ν‚€μ§€μΈ 경우 μžμ‹ ν΄λž˜μŠ€μ—μ„œ 접근이 κ°€λŠ₯ν•˜λ‹€.
default 같은 νŒ¨ν‚€μ§€ λ‚΄μ—μ„œ 접근이 κ°€λŠ₯ν•˜λ‹€.
private 같은 클래슀 λ‚΄μ—μ„œλ§Œ 접근이 κ°€λŠ₯ν•˜λ‹€.


final

final μ œμ–΄μžλŠ” 클래슀, λ©”μ†Œλ“œ, λ³€μˆ˜ λͺ¨λ‘μ— 뢙일 수 μžˆλ‹€. 

ν΄λž˜μŠ€μ— 뢙이면 λ³€κ²½, ν™•μž₯ν•  수 μ—†λŠ” ν΄λž˜μŠ€κ°€ 되고, λ©”μ†Œλ“œμ— 뢙이면 μ˜€λ²„λΌμ΄λ”©μ„ 톡해 μž¬μ •μ˜ 될 수 μ—†κ³ , λ³€μˆ˜μ— 뢙이면 값을 λ³€κ²½ν•  수 μ—†λŠ” μƒμˆ˜κ°€ λœλ‹€.

final class FinalClass {
    final int MAX_VALUE = 1_000;
    
    final void getMaxValue() {
        return MAX_VALUE;
    }
}


final 이 뢙은 λ³€μˆ˜λŠ” μƒμˆ˜κ°€ 되기 λ•Œλ¬Έμ— 일반적으둜 μ„ μ–Έκ³Ό λ™μ‹œμ— μ΄ˆκΈ°ν™”λ₯Ό ν•œλ‹€. ν•˜μ§€λ§Œ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜μ— 뢙은 final λ³€μˆ˜λŠ” μƒμ„±μžμ—μ„œ μ΄ˆκΈ°ν™”ν•˜λ„λ‘ ν•  수 μžˆλ‹€.

λ§€κ°œλ³€μˆ˜λ₯Ό λ°›λŠ” μƒμ„±μžλ₯Ό μž‘μ„±ν•΄μ„œ μΈμŠ€ν„΄μŠ€λ₯Ό 생성할 λ•Œ final 이 뢙은 λ³€μˆ˜λ₯Ό μ΄ˆκΈ°ν™” ν•˜λŠ”λ° ν•„μš”ν•œ 값을 μ œκ³΅λ°›μ•„ μ΄ˆκΈ°ν™” ν•˜λŠ” 것이닀. μ΄λ•Œ κΈ°λ³Έ μƒμ„±μžκ°€ 있으면 μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.

class FinalClass {
    final int constValue;
    
    public FinalClass(int constValue) {
        this.constValue = constValue;
    }
}


상속을 λ§‰λŠ” 두 κ°€μ§€ 방법

두 κ°€μ§€ 방법 쀑 ν•˜λ‚˜λŠ” λ°”λ‘œ μœ„μ—μ„œ 봀던 final 을 class 에 λΆ™μ΄λŠ” 것이닀. 또 λ‹€λ₯Έ 방법은 클래슀의 μƒμ„±μžμ— private 을 λΆ™μ΄λŠ” 것이닀.

μžμ‹ ν΄λž˜μŠ€μ—μ„œ λΆ€λͺ¨ 클래슀의 μƒμ„±μžλ₯Ό ν˜ΈμΆœν•΄μ•Ό ν•˜λŠ”λ° λΆ€λͺ¨ 클래슀 μƒμ„±μžμ˜ μ ‘κ·Ό μ œμ–΄μžκ°€ private 이기 λ•Œλ¬Έμ— μžμ‹ ν΄λž˜μŠ€μ—μ„œ 접근이 λΆˆκ°€λŠ₯ν•œ 것이닀.

class FinalClass {

    private FinalClass() {
    }
    
}


ν•˜μ§€λ§Œ 이런 경우 λͺ…μ‹œμ μœΌλ‘œ class μ•žμ— final 을 μΆ”κ°€ν•˜λŠ” 것이 더 μ’‹κ² λ‹€.

μƒμ„±μžκ°€ private 인 경우 static public λ©”μ†Œλ“œλ₯Ό μž‘μ„±ν•΄μ„œ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•΄μ£ΌλŠ” μž‘μ—…μ„ ν•œλ‹€. μΈμŠ€ν„΄μŠ€μ˜ 개수λ₯Ό μ œν•œν•˜κ±°λ‚˜ ν•  λ•Œ 이런 방법을 μ‚¬μš©ν•œλ‹€.

 

λ‹€ν˜•μ„±, Polymorphism

객체지ν–₯κ°œλ…μ—μ„œ λ‹€ν˜•μ„±μ€ 'μ—¬λŸ¬ κ°€μ§€ ν˜•νƒœλ₯Ό κ°€μ§ˆ 수 μžˆλŠ” λŠ₯λ ₯'을 μ˜λ―Έν•œλ‹€. Java μ—μ„œλŠ” λ‹€ν˜•μ„±μ„ λΆ€λͺ¨ 클래슀의 μ°Έμ‘° λ³€μˆ˜λ‘œ μžμ‹ 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό μ°Έμ‘°ν•  수 μžˆλ„λ‘ κ΅¬ν˜„ν–ˆλ‹€.

class Product {
    private String productCode;
    private String productType;
}

class Book extends Product {
    private String author;
    private String title;
}


public class SampleTest {

    public static void main(String[] args) {
        Product bookProduct = new Book();
    }

}


bookProduct λŠ” Product λ₯Ό μ°Έμ‘°ν•  수 μžˆλŠ” μ°Έμ‘°λ³€μˆ˜μ΄μ§€λ§Œ, Product 클래슀λ₯Ό 상속 받은 Book 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό μ°Έμ‘°ν•  수 μžˆλ‹€.
μΈμŠ€ν„΄μŠ€λ₯Ό λΆ€λͺ¨ νƒ€μž…μ˜ μ°Έμ‘° λ³€μˆ˜λ‘œ μ°Έμ‘°ν•˜λŠ” 것과, μžμ‹ νƒ€μž…μ˜ μ°Έμ‘° λ³€μˆ˜λ‘œ μ°Έμ‘°ν•˜λŠ” 것은 μ‚¬μš©ν•  수 μžˆλŠ” μžμ›μ˜ λ²”μœ„μ—μ„œ 차이가 생긴닀.

class Product {
    private String productCode;
    private String productType;
    
    void showCode() {}
    void showType() {}
}

class Book extends Product {
    private String author;
    private String title;
    
    void showAuthor() {}
    void showTitle() {}
}


public class SampleTest {

    public static void main(String[] args) {
        Product bookProduct = new Book();
        bookProduct.showCode();
        bookProduct.showType();
        // bookProduct.showAuthor(); μ—λŸ¬!
    }

}



Product νƒ€μž…μ˜ μ°Έμ‘°λ³€μˆ˜λ‘œλŠ” λΆ€λͺ¨ ν΄λž˜μŠ€μ—μ„œ μ •μ˜λ˜μ–΄ μžˆλŠ” μžμ›λ“€μ— ν•œν•΄μ„œ μ ‘κ·Όν•  수 μžˆλ‹€.

μžμ‹ 클래슀의 λ ˆνΌλŸ°μŠ€λ‘œλŠ” λ‹Ήμ—°νžˆ Book μΈμŠ€ν„΄μŠ€μ˜ λͺ¨λ“  μžμ›μ— 접근이 κ°€λŠ₯ν•˜λ‹€.

 

 

 

λ°˜λŒ€λ‘œ μžμ‹ νƒ€μž…μ˜ μ°Έμ‘° λ³€μˆ˜λ‘œ λΆ€λͺ¨ 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό μ°Έμ‘°ν•  μˆ˜λŠ” μ—†λ‹€.

Book book = new Product(); // μ—λŸ¬!


μ°Έμ‘° λ³€μˆ˜μ˜ ν˜• λ³€ν™˜

μœ„μ—μ„œ Product 의 μ°Έμ‘° λ³€μˆ˜λ‘œλŠ” Book μΈμŠ€ν„΄μŠ€μ˜ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜μ§€ λͺ»ν–ˆλŠ”λ°, μ°Έμ‘° λ³€μˆ˜λ₯Ό ν˜• λ³€ν™˜ ν•΄μ„œ ν•΄κ²° ν•  수 μžˆλ‹€.

public static void main(String[] args) {
    Product bookProduct = new Book();
    bookProduct.showType();

    Book book = (Book) bookProduct;
    book.showAuthor();
}


μ„œλ‘œ 상속 관계에 μžˆλŠ” 클래슀 μ‚¬μ΄μ—μ„œλ§Œ κ°€λŠ₯ν•˜λ‹€. μžμ‹ νƒ€μž…μ˜ μ°Έμ‘° λ³€μˆ˜λ₯Ό λΆ€λͺ¨ νƒ€μž…μ˜ μ°Έμ‘° λ³€μˆ˜λ‘œ, λΆ€λͺ¨ νƒ€μž…μ˜ μ°Έμ‘° λ³€μˆ˜λ₯Ό μžμ‹ νƒ€μž…μ˜ μ°Έμ‘° λ³€μˆ˜λ‘œ ν˜•λ³€ν™˜μ΄ κ°€λŠ₯ν•˜λ‹€.

μžμ† νƒ€μž…μ˜ μ°Έμ‘° λ³€μˆ˜λ₯Ό λΆ€λͺ¨ νƒ€μž…μ˜ μ°Έμ‘° λ³€μˆ˜λ‘œ ν˜•λ³€ν™˜ ν•˜λŠ” 것을 Up-Casting
λΆ€λͺ¨ νƒ€μž…μ˜ μ°Έμ‘° λ³€μˆ˜λ₯Ό μžμ‹ νƒ€μž…μ˜ μ°Έμ‘° λ³€μˆ˜λ‘œ ν˜•λ³€ν™˜ ν•˜λŠ” 것을 Down-Casting 라고 ν•œλ‹€.

μ—¬κΈ°μ„œ Up-Casting ν•  λ•ŒλŠ” ν˜•λ³€ν™˜ μ—°μ‚°μžλ₯Ό μƒλž΅ν•  수 μžˆλ‹€.

    public static void main(String[] args) {
        Product bookProduct = new Book();
        bookProduct.showType();

        Book book = (Book) bookProduct; // (Book) μƒλž΅ λΆˆκ°€
        book.showAuthor();

        Book book2 = new Book();
        Product bookProduct2 = book2; // (Product) μƒλž΅ κ°€λŠ₯
    }


ν˜•λ³€ν™˜ μ‹œ μ£Όμ˜ν•  것

public static void main(String[] args) {
    Product product = new Product();
    Book book = (Book) product;
}


μœ„μ™€ 같이 ν˜•λ³€ν™˜ ν•˜λ©΄ λŸ°νƒ€μž„ μ‹œ ClassCastException μ˜ˆμ™Έκ°€ λ°œμƒν•œλ‹€.
λ¬Έμ œλŠ” product κ°€ μ°Έμ‘°ν•˜λŠ” μΈμŠ€ν„΄μŠ€κ°€ Product νƒ€μž…μ΄κΈ° λ•Œλ¬Έμ— Book νƒ€μž…μ˜ μ°Έμ‘°λ³€μˆ˜λ‘œ ν˜•λ³€ν™˜ ν•  수 μ—†λ‹€.

μ°Έμ‘° λ³€μˆ˜κ°€ μ‚¬μš©ν•  수 μžˆλŠ” μžμ›μ˜ μˆ˜λŠ” μΈμŠ€ν„΄μŠ€μ˜ μžμ› μˆ˜λ³΄λ‹€ κ°™κ±°λ‚˜ 적어야 ν•˜λŠ”λ°, Book μ°Έμ‘°λ³€μˆ˜λ‘œλŠ” Product μ°Έμ‘° λ³€μˆ˜κ°€ μ°Έμ‘°ν•  수 μžˆλŠ” μžμ›λ³΄λ‹€ 더 λ§Žμ„ 수 있기 λ•Œλ¬Έμ— λ¬Έμ œκ°€ λ°œμƒν•˜λŠ” 것이닀.

κ·Έλž˜μ„œ 항상 μ°Έμ‘°λ³€μˆ˜λ₯Ό ν˜•λ³€ν™˜ ν•  λ•Œμ—λŠ” instanceof μ—°μ‚°μžλ₯Ό μ‚¬μš©ν•΄μ„œ μΈμŠ€ν„΄μŠ€μ˜ νƒ€μž…μ΄ 무엇인지 ν™•μΈν•˜λŠ” μž‘μ—…μ΄ μ€‘μš”ν•˜λ‹€.

public static void main(String[] args) {
    Product product = new Product();
    if (product instanceof Book) {
        Book book = (Book) product;
    }
}


Dynamic Method Dispatch

Dynamic Method Dispatch λŠ” μ˜€λ²„λΌμ΄λ”© 된 λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•  λ•Œ μ–΄λ–€ λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν• μ§€μ— λŒ€ν•œ 결정을 컴파일 μ‹œμ μ΄ μ•„λ‹ˆλΌ λŸ°νƒ€μž„ μ‹œμ μ— κ²°μ •ν•˜λŠ” λ©”μ»€λ‹ˆμ¦˜μ„ λœ»ν•œλ‹€.

λ§λΆ™μ—¬μ„œ μ„€λͺ…ν•˜λ©΄, λΆ€λͺ¨ 클래슀의 μ°Έμ‘° λ³€μˆ˜λ‘œ μ˜€λ²„λΌμ΄λ”© 된 λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν•˜λ €κ³  ν•˜λŠ” κ²½μš°μ— μ°Έμ‘°λ˜λŠ” μΈμŠ€ν„΄μŠ€μ˜ νƒ€μž…μ„ κΈ°μ€€μœΌλ‘œ μ–΄λ–€ λ©”μ†Œλ“œλ₯Ό μ‹€ν–‰ν• μ§€λ₯Ό κ²°μ •ν•˜λŠ” 것이닀. μΈμŠ€ν„΄μŠ€μ˜ νƒ€μž…μ„ 보고 κ²°μ •ν•˜κΈ° λ•Œλ¬Έμ— λŸ°νƒ€μž„ μ‹œμ μ— κ²°μ •ν•œλ‹€λŠ” 것이닀.

class Parent {
    void show() {
        System.out.println("Parent - show method is called.");
    }
}

class ChildA extends Parent {
    void show() {
        System.out.println("Child A - show method is called.");
    }
}

class ChildB extends Parent {
    void show() {
        System.out.println("Child B - show method is called.");
    }
}


public class SampleTest {

    public static void main(String[] args) {
        Parent parent = new Parent();
        ChildA childA = new ChildA();
        ChildB childB = new ChildB();

        Parent ref = null;

        ref = parent;
        ref.show(); // Parent - show method is called.

        ref = childA;
        ref.show(); // Child A - show method is called.

        ref = childB;
        ref.show(); // Child B - show method is called.
    }

}


show() λ©”μ†Œλ“œλŠ” 호좜 μ‹œμ— μ°Έμ‘°λ˜λŠ” μΈμŠ€ν„΄μŠ€μ˜ νƒ€μž…μ— λ”°λΌμ„œ λΆ€λͺ¨μ˜ show() ν˜Ήμ€ μžμ‹μ˜ show() 쀑 μ–΄λ–€ λ©”μ†Œλ“œλ₯Ό ν˜ΈμΆœν• μ§€ κ²°μ •ν•˜λŠ” 것이닀.

Dynamic Method Dispatch λŠ” 멀버 λ³€μˆ˜μ— λŒ€ν•΄μ„œλŠ” μ μš©λ˜μ§€ μ•ŠλŠ”λ‹€. μ–΄λ–€ μΈμŠ€ν„΄μŠ€μΈμ§€κ°€ μ•„λ‹ˆλΌ μ–΄λ–€ μ°Έμ‘° λ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜κ³  μžˆλŠ”μ§€λ₯Ό 보고 κ²°μ •λœλ‹€.

class Parent {
    int num = 100;
}

class ChildA extends Parent {
    int num = 200;
}

public class SampleTest {

    public static void main(String[] args) {
        Parent p = new ChildA();
        ChildA c = new ChildA();

        System.out.println("Parent Ref: " + p.num); // Parent Ref: 100
        System.out.println("Child Ref: " + c.num); // Child Ref: 200
    }

}


좔상 클래슀

좔상 ν΄λž˜μŠ€λŠ” 좔상 λ©”μ†Œλ“œλ₯Ό κ°€μ§„ 클래슀λ₯Ό λœ»ν•œλ‹€. 좔상 λ©”μ†Œλ“œλŠ” μ œμ–΄μžμ—μ„œ 봀던 abstract ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•΄ λ§Œλ“€ 수 μžˆλ‹€.

abstract class AbstractClass {
    abstract void doSomething();
}


좔상 λ©”μ†Œλ“œκ°€ μžˆλŠ” ν΄λž˜μŠ€μ— abstract μ œμ–΄μžκ°€ μ—†μœΌλ©΄ μ—λŸ¬κ°€ λ°œμƒν•œλ‹€. 

좔상 λ©”μ†Œλ“œλŠ” 아직 μ™„μ„±λ˜μ§€ μ•Šμ€ λ©”μ†Œλ“œλ₯Ό λœ»ν•˜κ³ , 좔상 ν΄λž˜μŠ€μ—μ„œ 좔상 λ©”μ†Œλ“œλŠ” μ„ μ–ΈλΆ€λ§Œ μ‘΄μž¬ν•œλ‹€. μœ„μ—μ„œλ„ doSomething(); μ΄λ ‡κ²Œ λλ‚œκ±Έ λ³Ό 수 μžˆλ‹€.

좔상 클래슀λ₯Ό μƒμ†λ°›λŠ” μžμ‹ ν΄λž˜μŠ€μ—μ„œ ν•΄λ‹Ή 좔상 λ©”μ†Œλ“œμ˜ μ •μ˜λ₯Ό κ°•μ œν•œλ‹€. 이 같은 이유둜 좔상 클래슀λ₯Ό μΈμŠ€ν„΄μŠ€λ‘œ 생성할 수 μ—†λ‹€. μ •μ˜λ˜μ§€ μ•ŠλŠ” λ©”μ†Œλ“œκ°€ μžˆλŠ” μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€ μˆ˜λŠ” μ—†κΈ° λ•Œλ¬Έμ΄λ‹€.

abstract class Machine {
    abstract void run();
    abstract void stop();
}

class Tv extends Machine {
    @Override
    void run() {
        System.out.println("Tv Run");
    }

    @Override
    void stop() {
        System.out.println("Tv Stop");
    }
} 

public class SampleTest {

    public static void main(String[] args) {
        // Machine m = new Machine(); μ—λŸ¬!
        Tv tv = new Tv();
        Machine tv2 = new Tv(); // 좔상 ν΄λž˜μŠ€λ„ λ‹€ν˜•μ„± 적용이 κ°€λŠ₯ν•˜λ‹€.
    }

}


좔상 ν΄λž˜μŠ€λŠ” 좔상 λ©”μ†Œλ“œκ°€ μžˆλ‹€λŠ” 것 λ§κ³ λŠ” 일반 ν΄λž˜μŠ€μ™€ λ‹€λ₯Ό 것은 μ—†λ‹€. λ˜‘κ°™μ΄ λ³€μˆ˜, λ©”μ„œλ“œλ₯Ό μž‘μ„±ν•  수 μžˆλ‹€.

 

Object 클래슀

Object ν΄λž˜μŠ€λŠ” λͺ¨λ“  클래슀의 졜고 쑰상이 λ˜λŠ” ν΄λž˜μŠ€μ΄λ‹€. λͺ¨λ“  ν΄λž˜μŠ€λŠ” 사싀 Object 클래슀λ₯Ό 상속받고 μžˆλŠ” 것이닀. λ”°λ‘œ extends ν•΄μ„œ 상속 λ°›λŠ” ν΄λž˜μŠ€κ°€ μ—†μ—ˆλ‹€λ©΄ μžλ™μœΌλ‘œ Object 클래슀λ₯Ό 상속 λ°›κ²Œλœλ‹€.

Object ν΄λž˜μŠ€λŠ” java.lang νŒ¨ν‚€μ§€μ— μžˆλŠ”λ° μžλ°” ν”„λ‘œκ·Έλž˜λ°μ—μ„œ κ°€μž₯ 기본이 λ˜λŠ” ν΄λž˜μŠ€λ“€μ„ ν¬ν•¨ν•˜κ³  μžˆλ‹€. java.lang ν•˜μœ„μ˜ ν΄λž˜μŠ€λ“€μ€ λ”°λ‘œ import ν•˜μ§€ μ•Šμ•„λ„ μ‚¬μš©μ΄ κ°€λŠ₯ν•˜λ‹€. 


Object ν΄λž˜μŠ€λŠ” λͺ¨λ“  클래슀의 쑰상이 되기 λ•Œλ¬Έμ— Object 클래슀의 멀버듀을 λͺ¨λ“  ν΄λž˜μŠ€μ—μ„œ μ‚¬μš©μ΄ κ°€λŠ₯ν•˜λ‹€.

Object ν΄λž˜μŠ€λŠ” 멀버 λ³€μˆ˜λŠ” μ—†κ³ , 11 개의 λ©”μ†Œλ“œλ§Œ κ°€μ§€κ³  μžˆλ‹€.

clone() 객체 μžμ‹ μ˜ 볡사본 λ°˜ν™˜
equals() 객체 μžμ‹ κ³Ό 같은 객체인지 boolean νƒ€μž…μœΌλ‘œ λ°˜ν™˜
finalize() 객체가 μ†Œλ©Έλ  λ•Œ GC 에 μ˜ν•΄ μžλ™μ μœΌλ‘œ 호좜, μ†Œλ©Έμ‹œ μˆ˜ν–‰ν•΄μ•Όν•  μž‘μ—…μ΄ 있으면 μž¬μ •μ˜ ν•˜λ©΄ λœλ‹€. (거의 μ‚¬μš©ν•˜μ§€ μ•ŠμŒ)
getClass() 객체의 클래슀 정보λ₯Ό λ‹΄κ³  μžˆλŠ” Class μΈμŠ€ν„΄μŠ€ λ°˜ν™˜
hashCode() 객체의 hash code λ°˜ν™˜
toString() 객체의 정보λ₯Ό λ¬Έμžμ—΄λ‘œ λ°˜ν™˜
notify() 객체λ₯Ό μ‚¬μš©ν•˜λ €λŠ” Thread λ₯Ό ν•˜λ‚˜λ§Œ κΉ¨μš΄λ‹€.
notifyAll() 객체λ₯Ό μ‚¬μš©ν•˜λ €λŠ” λͺ¨λ“  Thread λ₯Ό κΉ¨μš΄λ‹€.
wait() λ‹€λ₯Έ Thread κ°€ notify(), notifyAll() λ₯Ό ν˜ΈμΆœν•  λ•ŒκΉŒμ§€ ν˜„μž¬ Thread λ₯Ό κΈ°λ‹€λ¦¬κ²Œ ν•œλ‹€.
λ¬΄ν•œν•˜κ²Œ ν˜Ήμ€ μ§€μ •λœ μ‹œκ°„λ™μ•ˆ κΈ°λ‹€λ¦¬κ²Œ ν•  수 μžˆλ‹€. (timeout 은 1/1000 초, nanos λŠ” 1/10^9 초)
wait(long timeout)()
wait(long timeout, int nanos)


equals(Object obj)

λ§€κ°œλ³€μˆ˜λ‘œ μ°Έμ‘° λ³€μˆ˜λ₯Ό λ°›μ•„μ„œ 같은 μ°Έμ‘° λ³€μˆ˜μΈμ§€ κ²°κ³Όλ₯Ό boolean νƒ€μž…μœΌλ‘œ μ•Œλ €μ€€λ‹€.
μ£Όμ†Œ 값이 μ•„λ‹ˆλΌ μ‹€μ œ μΈμŠ€ν„΄μŠ€μ˜ λ‚΄μš©μ„ λΉ„κ΅ν•˜κ³  싢은 경우 equals λ₯Ό μž¬μ •μ˜ν•œλ‹€. String 클래슀의 equals() λ©”μ†Œλ“œλŠ” μ‹€μ œ λ¬Έμžμ—΄ 값을 λΉ„κ΅ν•˜λ„λ‘ λ˜μ–΄μžˆλ‹€.

hashCode()
hashCode() λ©”μ†Œλ“œλŠ” 객체의 μœ μΌν•œ ν•΄μ‹œ μ½”λ“œ 값을 λ§Œλ“€μ–΄ λ°˜ν™˜ν•œλ‹€. Object 클래슀의 hashCode() λ©”μ†Œλ“œλŠ” 객체의 μ£Όμ†Œ 값을 μ΄μš©ν•œλ‹€. 
같은 ν•΄μ‹œμ½”λ“œκ°€ μ‘΄μž¬ν•  수 μžˆμ§€λ§Œ Object 의 hashCode() λ©”μ†Œλ“œλŠ” 객체의 μ£Όμ†Œ 값을 μ‚¬μš©ν•΄μ„œ μ½”λ“œλ₯Ό λ§Œλ“€κΈ° λ•Œλ¬Έμ— 두 κ°μ²΄λŠ” κ²°μ½” 같은 값을 κ°€μ§ˆ 수 μ—†λ‹€. μΈμŠ€ν„΄μŠ€ λ‚΄μš©μ„ κ°€μ§€κ³  ν•΄μ‹œ μ½”λ“œλ₯Ό λ§Œλ“€κ³  μ‹Άλ‹€λ©΄ μž¬μ •μ˜ν•΄μ•Όν•œλ‹€. 

μΈμŠ€ν„΄μŠ€ κ°’μœΌλ‘œ 두 객체λ₯Ό λΉ„κ΅ν•˜κ³  μ‹Άλ‹€λ©΄ equals, hashCode 두가지 λ©”μ†Œλ“œλ₯Ό λͺ¨λ‘ 적절히 μž¬μ •μ˜ν•΄μ•Όν•œλ‹€.

toString()
μΈμŠ€ν„΄μŠ€μ— λŒ€ν•œ 정보λ₯Ό λ¬Έμžμ—΄λ‘œ μ œκ³΅ν•œλ‹€. μž¬μ •μ˜ ν•˜μ§€ μ•ŠμœΌλ©΄ 클래슀 이름과 16μ§„μˆ˜ ν•΄μ‹œ μ½”λ“œκ°€ λ°˜ν™˜λœλ‹€. 적절히 μž¬μ •μ˜ ν•˜λŠ” 것이 μ’‹λ‹€.

 

References

https://www.geeksforgeeks.org/dynamic-method-dispatch-runtime-polymorphism-java/
μžλ°”μ˜ 정석 (www.yes24.com/Product/Goods/24259565)