[Java] 자바 기초(6)

1. 자바 상속

1-1. 상속이란

상속이란 기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것이다.

자바에서 상속은 부모 클래스의 변수/메소드를 자식 클래스가 물려받아 그대로 사용 가능하게 해준다.
여기서 부모 클래스를 super class, 자식 클래스를 sub class라 부른다.

상속은 extends 키워드를 사용하며 상속의 형태는 다음과 같다.

자식클래스 extends 부모클래스
  • 사용 예
public class ParentClass {

	String parent = "parent";
    
    public void Parent() {
    	System.out.println("I am" + parent);
    }
}

public class ChildClass extends ParentClass{

	String child = "child";
    
    public void Child() {
    	Parent();
    	System.out.println("I am" + child);
        System.out.println("I inherited from" + parent); 
    }
}

public class Main {

	public static void main(String[] args) {
        ChildClass childClass = new ChildClass();
        childClass.Child();
    }
}
  • 실행 결과

    I am parent
    I am child
    I ingerited from parent

1-2. 자바 상속의 특징

  1. 자바에서는 단일 상속만 지원한다. 즉, 다중 상속을 지원하지 않는다.
    따라서 extends 키워드 뒤에는 단 하나의 부모 클래스만 올 수 있다.
  2. 자바에서는 상속의 횟수에 제한을 두지 않는다.
  3. 자바에서는 최상위 클래스가 Object 클래스이다.
    Object 클래스만이 유일하게 super class를 가지지 않으며 자바의 모든 클래스들은 Object 클래스의 자손이라고 볼 수 있다.
    (C++의 경우 최상위 클래스가 없다.)

2. super 키워드

super 키워드란 상위 클래스의 생성자를 호출하는 키워드로, Super();를 하지 않은 경우에도 자동으로 상위 클래스의 기본 생성자를 호출한다.

또한 상위 클래스의 멤버변수 혹은 메소드에 접근할 수 있다. 상위 클래스의 멤버변수 혹은 메소드를 사용하기 위해서는 super.변수명 혹은 super.메소드명()으로 접근한다.

  • this와 super의 차이

-this-
this(); // 자기 자신의 생성자를 호출
this(매개변수); // 자기 자신의 생성자(매개변수)를 호출
this.변수명; // 자기 자신의 변수를 호출
this.메소드명(); // 자기 자신의 메소드를 호출

-super-
super(); // 상위 클래스(부모 클래스)의 생성자를 호출
super(매개변수); // 상위 클래스(부모 클래스)의 생성자(매개변수)를 호출
super.변수명; // 상위 클래스(부모 클래스)의 변수를 호출
super.메소드명(); // 상위 클래스(부모 클래스)의 메소드를 호출

3. 메소드 오버라이딩

메소드 오버라이딩이란 상속을 기반으로 super 키워드로부터 상속받은 기능 중 특정 기능을 재정의하는 기법이다.

  • 메소드 오버라이딩 조건
  1. 상속받은 super 클래스의 메소드와 메소드명, 매개변수, 리턴타입이 반드시 같아야 한다.
  2. 접근지정자는 같거나 넓은 범위를 가져야 한다.
  • 상위 클래스의 메소드에 지정된 예외보다 많은 수의 예외를 선언할 수 없고, 상위에 있는 예외를 사용할 수 없다.

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

다이나믹 메소드 디스패치는 자바의 테크닉 중 하나로, 런타임 시점에 할당된 객체의 타입을 보고 메소드가 실행되는 것을 의미한다.

이는 참조 타입이 부모 타입인 경우에도 동작하므로 런타임 시점에 다형성을 만족하도록 할 수 있다.

  • 사용 예
public class Animal {

	public void move() {
    		System.out.println("Animals can move");
  	}
}

public class Dog extends Animal {

  	@Override
  	public void move() {
    		System.out.println("Dogs can walk and run");
  	}
}

public class Main {

	public static void main(String[] args) {
    		Animal a = new Animal(); // Animal 참조, Animal 객체
    		Animal b = new Dog(); // Animal 참조, Dog 객체

   		a.move(); // Animal 클래스에 정의된 메소드 실행
    		b.move(); // Dog 클래스에 정의된 메소드 실행됨(다이나믹 메소드 디스패치)
  }
}
  • 실행 결과

    Animals can move
    Dogs can walk and run

더블 디스패치(Double Dispatch)

더블 디스패치란 다이나믹 디스패치를 두번 하는 것이다.

5. 추상 클래스

추상 클래스는 abstract 키워드가 추가된 클래스이다. 이 클래스는 추상 메소드 포함하고 있거나, 포함하지 않을 수 있다.
추상 클래스 자체는 인스턴스화를 할 수 없지만, 서브 클래싱을 할 수는 있다.

추상 메소드는 다음과 같이 선언할 수 있다. 특이점으로는 구현하지 않고 {} 대신 세미콜론(;)이 온다는 특징이 있다.

abstract void moveTo(double deltaX. double deltaY);

클래스에 추상 메소드가 포함된 경우에는 반드시 그 클래스는 추상 클래스이어야 한다.

public abstract class GraphicObject {
	
    abstract void draw();
}

추상 클래스가 서브 클래싱될 때, 서브 클래스는 보통 부모 클래스의 추상 메소드를 구현하여 제공한다. 그러나 그렇지 않은 경우에는 역시 추상 클래스라고 볼 수 있다.

참고로 abstract 키워드를 인터페이스에서 사용하지 않는 이유는 default, static을 제외한 모든 메소드는 암시적으로 abstract 키워드가 붙어있다고 판단하기 때문이다. 따라서 사용할 수 있지만 붙이지 않는다.

6. final 키워드

자바에서 final 키워드는 변경 불가능의 의미를 가진다.

변수의 경우에는 읽기 전용이라고 생각하면 된다.

메소드의 경우에는 오버라이드 불가를 의미한다. 특히 생성자에서 호출되는 메소드는 final로 선언하는 편이 바람직하다. 왜냐하면 오버라이딩으로 동작을 변경할 수 있기 때문이다. (의도치 않게 영향을 받을 수 있다.)

클래스에 선언된 final 키워드는 서브 클래싱 할 수 없다. 즉, 확장이 불가능하게 막는다.

7. Object 클래스

Object 클래스는 자바에서 굉장히 특별한 의미를 갖는 클래스이다. 모든 클래스의 직・간접적 슈퍼 클래스이고, java.lang 패키지에 존재한다.

Object 클래스는 매개변수 없는 생성자를 가지고 있다.

Object 클래스에서 상속되는 메소드는 다음과 같다.

  • protected Object clone() throws CloneNotSupportedException : 이 객체의 복사본을 만들고 반환하는 메소드
    예외가 발생하는 경우는 복제 불가능한 경우이다.
    간단하게는 Cloneable 인터페이스를 구현해서 사용할 수 있다.
    기본 형태는 native 메소드라 확인할 수 없다.
  • public boolean equals(Object obj) : 다른 댁체와 비교해서 다른 댁체와 이 객체가 같은지를 나타내는 동등성 비교를 수행한다.
    참고로 내부 구현은 == 동일성 비교여서 오버라이딩을 해주지 않으면 기본적을 ㅗ동일성 비교를 수행한다.
    이 메소드를 오버라이딩해서 동등성 비교의 기준을 마련할 수 있으며, 이 메소드를 오버라이딩 할 때에는 아래에 설명할 hashCode() 메소드 또한 오버라이딩 해야한다.
  • protected void finalize() throws Throwable : 가비지 컬렉터가 객체에 대한 참조가 없는 경우 호출하는 메소드다.
    실행될지 불확실 하기 때문에 크리티컬한 코드를 여기에 두면 안된다.
  • public final Class getClass() : 객체의 런타임 클래스를 호출한다.
    Reflection을 사용할 때, 종종 사용하게 된다.
  • public int hashCode() : 객체의 해시코드 값을 반환한다.
    두 객체가 같으면 해시코드도 같아야 하기 때문에 equals()를 오버라이딩 할 때, hashCode() 또한 오버라이딩 해야한다.
  • public String toString() : 객체의 문자열 형태를 반환한다.
    기본적으로는 거의 의미없는 정보를 보여주기에 프로그래머는 이 메소드의 오버라이딩을 통해 객체가 유용한 정보를 반환하도록 정의해야한다.

그리고 오버라이딩 할 수 없도록 final로 선언된 notify(), notifyAll(), wait() 메소드는 독립적으로 실행되는 스레드간의 동기화에 사용된다.

profile
성장ing

0개의 댓글