korean IT student

[Java-Live-Study] 6주차 - 상속 본문

back-end/JAVA

[Java-Live-Study] 6주차 - 상속

현창이 2021. 9. 27. 17:58

 

목표

자바의 상속에 대해 학습하세요.

학습할 것 (필수)

  • 자바 상속의 특징
  • super 키워드
  • 메소드 오버라이딩
  • 다이나믹 메소드 디스패치 (Dynamic Method Dispatch)
  • 추상 클래스
  • final 키워드
  • Object 클래스

 

1. 자바 상속의 특징

class 자식클래스명 extends 부모클래스명{}
  • 상속이란 상위클래스에서 정의한 필드와 메서드를 하위클래스도 동일하게 사용할 수 있게 물려받는 것이다.
  • extends 키워드를 사용하여 상속
class 자식클래스명 extends 부모클래스명1, 부모클래스명2{} // 불가능하다.
  • 위와 같이 두 개의 클래스를 상속받는 것은 불가능
    • 다중상속을 허용하면 여러 클래스로부터 상속받을 수 있기 때문에 복합적인 기능을 가진 클래스를 쉽게 작성할 수 있다는 장점이 있지만, 클래스간의 관계가 복잡해지소 서로 다른 클래스로부터 상속받은 멤버의 이름이 같은 경우 구별할 수 있는 방법이 없어서 자바에서는 다중상속을 포기하고 단일상속만 허용함.
  • 부모 메소드를 자식 클래스에서 재정의(오버라이딩) 가능
  • 부모의 private 접근 제한을 갖는 멤버는 상속 불가능
    • private 제한자는 오로지 선언된 클래스 내부에서만 접근 가능하므로 외부에서 사용할 수 있게 하는 상속은 불가능 만약 상속이 필요할 경우, 다른 접근 제한자(public, protected) 사용
  • 자바의 모든 클래스는 Object 클래스의 자식/자손 클래스
    • 자바의 최상의 클래스는 Object 클래스 클래스 선언 시 다른 클래스를 상속받지 않으면 암시적으로 java.lang.Object 클래스를 상속
    • java.lang 패키지는 자바에서 가장 기본적인 동작을 수행하는 클래스들의 집합, 따라서 자바에서는 java.lang 패키지의 클래스들은 import 문을 사용하지 않아도 클래스 이름만으로 바로 사용가능합니다.

2. super 키워드

class Parent {
    String name;
    int age;
    
    public Parent() {
    }
    
    public Parent(String name, int age) {
        this.name = name;
        this.age = age;
    }   
}

class Child extends Parent {
    
    public Child() {
    }
    
    public setName(String name) {
        super.name = name; // 부모 클래스의 필드
    }
    
    public setAge(int age) {
        super.age = age;  // 부모 클래스의 필드
    }
    
}
  • 자식이 부모 메소드를 호출해야하는 경우 super 키워드 사용
  • 부모 객체를 참고하고 있기 때문에 부모에 직접 접근 가능

 

class Parent {
	
    public Parent() {

    }
    
}

class Child extends Parent {
// 자식클래스의 생성자 함수에 super()가 없어도 컴파일러가 넣어준다.
    public Child() {
    //  super(); 
    }
}



========================

class Parent {
	
	String userName;
    
    public Parant(String userName){
    	this.userName = userName;
    }
	
    
}

class Child extends Parent {

// 부모 클래스에 기본 생성자가 없기 때문에 컴파일 에러가 남
    public Child() {
       //  super(); 
    }
    
// 부모 클래스의 생성자가 정확히 호출 되므로 에러가 없다.
    public Child() {   
        super("changHyun"); 
    }
    
}
  • super() 를 통해 부모 클래스의 생성자가 호출
  • 자식 클래스에서 super()를 명시적으로 작성하지 않아도 컴파일러가 자동으로 추가
  • 부모 클래스에서 기본 생성자가 없고 매개변수를 갖는 생성자만 있다면 자식 클래스에서 반드시 super(매개값) 명시

3. 메소드 오버라이딩

class Parent {
  void method1() {}

  void method2() {}
}

class Child extends Parent {
  @Override
  void method2() {}

  void method3() {}
}


class Example {
  public static void main(String[] args) {
    Child child = new Child();

    child.method1();  // 상속 받은 부모 메소드 호출
    child.method2();  // 재정의한 자식 메소드 호출
    child.method3();  // 자식 메소드 호출
  }
}
  • 메소드를 오버라이딩하면 자식 객체의 메소드 호출 시 부모 기능은 숨겨지고 자식이 재성의한 기능 실행

4. 다이나믹 메소드 디스패치 (Dynamic Method Dispatch)

  • 메소드 디스패치란, 메소드를 어떻게 호출할 지를 정해서 호출하는 것, 대표적으로 static, dynamic이 있다.

정적 메소드 디스패치(Static Method Dispatch)

class Parent {
  void method1() {}
}

class Child extends Parent {
  @Override
  void method1() {}
}

class Example {
  public static void main(String[] args) {
    Child child = new Child();

    child.method1();  // 재정의한 자식 메소드 호출

  }
}
  • 메인 함수에서 child.method1()를 호출했을 때 우리는 재정의한 자식 메소드를 호출하는것을 알고 있다. 컴파일러 역시 이 메소드를 호출하고 실행시켜야되는 것을 명확하게 알고 있는데 이를 정적 메소드 디스패치라 부른다.
  • -> 컴파일러 시점

동적 메소드 디스패치(Dynamic Method Dispatch)

interface Family{
  void method1() {}
}

class Parent implements Family {
  @Override
  void method1() {}
}

class Child implements Family{
  @Override
  void method1() {}
}

class Example {
  private Family family
  
  Example(Family family){
  	this.family = family;
  }
  
  void print(){
  	System.out.println(family.method1());
  }
  
}
  • 상위 개념인 Interface 혹은 Abstract Class에서 정의된 abstract method를 호출하는 경우에 해당
  • 정적 디스패치와 반대로 컴파일러가 어떤 메서드를 호출하는지 모르는 경우
  • 동적 디스패치는 호출할 메서드를 런타임 시점에서 결정한다.
  • Example 클래스의 생성자 인자로 넘오오는 매개값의 타입이 parant, child인지는 실행 시 확인가능
    • 실행 시 동적으로 확인해서 다이나믹 디스패치

5. 추상클래스

abstract class 클래스이름 {
	abstract 반환타입 메소드이름();
}
  • 자바에서는 하나 이상의 추상메소드를 포함하는 클래스를 가리켜 추상클래스라 정의한다.
abstract class Family{
  void with() {}
}

class Parent extends Family {
  @Override
  void with() {}
}


class Example {
 public static void main(String[] args) {
        // Family f = new Family(); 에러!
        Parent parant = new Parent();
        Family family = new Parent(); // 추상 클래스도 다형성 적용이 가능하다.
    }
  
}
  • 추상 클래스를 상속받은 자식 클래스에서 해당 추상 메소드의 정의를 강제한다.
  • 추상 클래스를 인스턴스로 생성할 수 없다. -> 정의되지 않은 메소드가 있는 인스턴스를 만둘 수는 없기 때문

6. final 키워드

  • 클래스, 필드, 메소드 선언 시 사용 가능한 키워드 해당 선언이 최종 상태이고, 더 이상 수정될 수 없음을 의미

final 클래스

  • 클래스 선언 시 final 키워드를 사용하면, 이 클래스는 상속할 수 없는 클래스임을 의미 부모 클래스가 될 수 없으며 자식 클래스를 만들 수 없는 클래스

final 메소드

  • 메소드 정의 시 final 키워드를 사용하면, 이 메소드는 오버라이딩할 수 없는 메소드임을 의미 상속받은 부모 클래스의 final 메소드는 자식 클래스에서 재정의 불가능

7. Object 클래스

  • 자바의 최상위 클래스는 Object 클래스
  • 클래스 선언 시 다른 클래스를 상속받지 않으면 암시적으로 java.lang.Object 클래스를 상속
  • .Object 클래스는 필드가 없고 메소드들로 구성

Object 클래스의 메소드는 다음과 같습니다.

protected Object clone() 해당 객체의 복제본을 생성하여 반환함.
boolean equals(Object obj) 해당 객체와 전달받은 객체가 같은지 여부를 반환함.
protected void finalize() 해당 객체를 더는 아무도 참조하지 않아 가비지 컬렉터가 객체의 리소스를 정리하기 위해 호출함.
Class<T> getClass() 해당 객체의 클래스 타입을 반환함.
int hashCode() 해당 객체의 해시 코드값을 반환함.
void notify() 해당 객체의 대기(wait)하고 있는 하나의 스레드를 다시 실행할 때 호출함.
void notifyAll() 해당 객체의 대기(wait)하고 있는 모든 스레드를 다시 실행할 때 호출함.
String toString() 해당 객체의 정보를 문자열로 반환함.
void wait() 해당 객체의 다른 스레드가 notify()나 notifyAll() 메소드를 실행할 때까지 현재 스레드를 일시적으로 대기(wait)시킬 때 호출함.
void wait(long timeout) 해당 객체의 다른 스레드가 notify()나 notifyAll() 메소드를 실행하거나 전달받은 시간이 지날 때까지 현재 스레드를 일시적으로 대기(wait)시킬 때 호출함.
void wait(long timeout, int nanos) 해당 객체의 다른 스레드가 notify()나 notifyAll() 메소드를 실행하거나 전달받은 시간이 지나거나 다른 스레드가 현재 스레드를 인터럽트(interrupt) 할 때까지 현재 스레드를 일시적으로 대기(wait)시킬 때 호출함.

-참고 : http://tcpschool.com/java/java_api_object

Comments