Java:Inheritance

aiden·2023년 9월 4일

Java

목록 보기
8/30

Inheritance

객체지향 언어에서 상속은 매우 중요한 개념이라고 할 수 있다. 상위 개념의 공통적 속성과 동작을 하나의 클래스로 만들고, 하위의 개념은 상위 개념 클래스를 상속하여 속성과 동작을 추가할 수 있다. 이 때 상위 개념이 되는 부모 클래스를 슈퍼 클래스, 하위 개념이 되는 자식 클래스를 서브 클래스라 부른다.
상속을 통해 중복되는 코드 작성을 피할 수 있으며 쉬운 확장이 가능해진다.

클래스의 상속은 다음과 같이 extends 키워드를 사용한다.

class Person{
	//슈퍼 클래스
}

class Teacher extends Person{
	//서브 클래스
}

class Student extends Person{
	//서브 클래스
}

class SchoolPresident extends Student{
	//서브 클래스 Student를 상속받은 서브 클래스
}

SchoolPresident 클래스와 같이 서브 클래스를 상속받는 것도 가능하며, 이 경우 Student 클래스의 멤버들을 상속받은 서브 클래스가 된다.

슈퍼 클래스의 객체와 서브 클래스의 객체를 생성하려면 일반적인 클래스 생성과 같은 방법으로 new 연산자를 사용하면 된다.

Person p = new Person();
Teacher t = new Teacher();
Student s = new Student();
SchoolPresident sp = new SchoolPresident();

이 때 각각 별개의 객체가 생성되며, 서브 클래스 객체들은 슈퍼 클래스의 멤버들을 모두 포함하고 있다.

❗자바에서는 클래스의 다중 상속을 지원하지 않는다.(C++에서는 가능) 또, 상속 횟수에 제한이 없다.

상속과 접근 지정

서브 클래스에서는 슈퍼 클래스의 멤버 중 private을 제외하고 모두 접근할 수 있다.

  • 슈퍼 클래스의 private 멤버는 오직 자기 자신 클래스에서만 접근할 수 있어야 하므로, 다른 클래스는 물론 서브 클래스에서도 접근 불가하다.

  • default 멤버는 같은 패키지 내 모든 클래스에서 접근 가능하며 서브 클래스라도 다른 패키지에 있다면 슈퍼 클래스의 default 멤버에 접근할 수 없다.

  • protected 멤버는 default 멤버와 같이 같은 패키지 내 모든 클래스에서 접근 가능하며 다른 패키지에 있는 서브 클래스에서도 접근할 수 있다.

  • public 멤버의 경우 패키지에 상관 없이 모든 클래스에서 접근 가능하다.

상속과 생성자

서브 클래스 객체 생성 시 슈퍼 클래스의 객체도 함께 호출된다. 생성자의 목적은 객체의 속성들을 초기화하는 데 있으므로 서브 클래스의 생성자가 호출된다고 슈퍼 클래스의 생성자가 호출되지 않으면 안된다. 객체 생성에 필요한 초기화를 각각 수행해야 한다.
이 때 슈퍼 클래스의 생성자가 먼저 실행된 후 서브 클래스의 생성자가 실행된다.

상속 관계에 있는 클래스 생성자의 호출 순서에 대해 알아보기 위해 다음 예시를 보자.

C의 생성자 호출 시 C부터 슈퍼 클래스로 거슬러 올라가며 생성자를 호출하며 실행은 호출 역순으로 상위 클래스부터 실행된다.

우리는 생성자를 공부할 때 여러 개의 생성자를 둘 수 있음을 공부했다. 그렇다면 자동으로 슈퍼 클래스의 생성자가 호출될 때 어떤 생성자를 호출하게 될 것인가?
서브 클래스의 생성자에서 호출될 슈퍼 클래스의 생성자를 따로 지정하지 않으면 자바 컴파일러에 의해 기본 생성자가 호출된다.

이 때, 슈퍼 클래스에 기본 생성자가 없으면 다음과 같이 오류가 발생한다.

서브 클래스 생성자에서 호출할 슈퍼 클래스의 생성자를 지정하고 싶은 경우 super()를 사용한다. 괄호 안에 인자를 전달할 수 있다. super()는 this()가 그랬듯 생성자의 첫 라인에 와야 한다.

👉🏻생성자 관련 규칙

  • 객체 생성 시 1회만 실행된다.
  • 기본 생성자가 없으면 자동으로 생성/실행되고, 다른 생성자가 작성되어 있으면 기본 생성자는 자동으로 생성되지 않는다.
  • 하위 클래스에서 객체 생성 시 상위 클래스의 생성자도 실행된다.
  • 실행 할 상위의 생성자를 명시하지 않은 경우 기본 생성자가 실행되며 기본 생성자를 호출할 수 없는 경우 오류가 발생한다.
  • 호출 될 상위 생성자를 지정하는 경우 super()를 사용한다.

Casting

캐스팅이란 형 변환을 의미한다. 캐스팅에는 업캐스팅과 다운캐스팅이 있다.

Upcasting

다음과 같이 슈퍼 클래스의 레퍼런스로 서브 클래스 객체를 가리키는 것을 업캐스팅이라 한다.

class Person{
	//내용
}
class Student extends Person{
	//내용
}
Student s = new Student();
Person p = s; //Person 타입의 레퍼런스로 Student 타입의 객체 가리킴

이 때 주의할 점은 레퍼런스 p로는 Person 클래스의 멤버들만 접근할 수 있고 Student 클래스에 작성한 멤버들에 접근할 수 없다는 것이다.
즉, 업캐스팅한 레퍼런스로는 객체 내의 모든 멤버들에 접근할 수 없고 슈퍼 클래스의 멤버에만 접근할 수 있다.

Downcasting

서브 클래스의 레퍼런스로 슈퍼 클래스 객체를 가리키는 것을 다운캐스팅이라 한다. 다음과 같이 명시적 형 변환을 해주면 된다.

Person p = new Person();
Student s = (Student)p;

이렇게 되면 Student 타입 레퍼런스 s를 통해 Student 타입의 객체 전체에 접근할 수 있게 된다.

instanceof

업캐스팅을 하다보면 레퍼런스가 어떤 타입의 객체를 가리키고 있는 것인지 알기 어려운 경우가 있다. 다음과 같은 경우가 그 예시이다.

따라서 이 객체가 어떤 클래스의 객체인지 구별해야 할 때 instanceof 연산자를 사용한다. instanceof 연산자는 다음과 같이 사용한다.

레퍼런스 instanceof 클래스명

결과값은 true 혹은 false의 boolean값이다. instanceof는 클래스에만 적용되므로 기본 자료형이나 다른 값을 넣으면 안된다.

Overriding

슈퍼 클래스의 메소드를 서브 클래스에서 덮어쓰는 것이 메소드 오버라이딩이다. 서브 클래스에서 재작성하기 위해서는 메소드 이름, 리턴 타입, 매개 변수를 모두 동일하게 유지해야 한다.
이렇게 슈퍼 클래스의 메소드를 무시하고 서브 클래스에서 오버라이딩 된 메소드를 실행하는 것을 동적 바인딩이라 부른다.

👉🏻동적 바인딩 - 실행할 메소드를 컴파일 시에 결정하지 않고 런타임에 결정하는 것

아래는 오버라이딩을 설명할 때 자주 나오는 예시로, 슈퍼 클래스 Shape의 메소드 drow()를 세 서브 클래스에서 오버라이딩하고 있다.

이 때, 메소드 draw()의 호출을 살펴보자.

Line line = new Line();
line.draw();

위와 같은 경우 Line 클래스에서 오버라이딩한 draw()가 호출된다.

Shape shape = new Line();
shape.draw();

위의 경우는 업캐스팅을 한 경우이다. 이 때에도 동적 바인딩에 의해 Line 클래스에서 오버라이딩한 draw()가 호출된다.

호출 방식에 상관 없이, 무조건 오버라이딩 된 메소드가 호출된다.

만약 오버라이딩 된 메소드가 아닌 원래의 슈퍼 클래스의 메소드를 호출하고 싶은 경우, super 키워드를 사용하면 된다. 메소드 뿐만 아니라 필드의 경우에도 가능하다. 다음과 같이 작성하면 된다.

super.name = 10; //서브 클래스가 아닌 슈퍼 클래스의 필드 접근
super.draw(); //서브 클래스가 아닌 슈퍼 클래스의 메소드 접근

❗오버라이딩을 할 때, 슈퍼 클래스 메소드의 접근 지정자보다 접근의 범위를 넓힐 수는 있으나 좁힐 수는 없다.
접근 범위가 넓은 순으로 public > protected > default > private

❗static, private, final로 선언된 메소드는 오버라이딩 불가

추상 클래스

추상 메소드

추상 메소드란 선언만 되어있고 구현되지 않은 메소드이다. 다음과 같이 abstract 키워드를 앞에 붙이고 내용은 제외하고 작성한다.

public abstract int result(int a);
public abstract void show();

선언만 있고 구현은 하지 않는다.

클래스 앞에 abstract 키워드를 붙이면 추상 클래스가 된다. 이 때, 클래스는 추상 메소드를 포함할 수 있고 포함하지 않을 수 있다. 추상 메소드가 하나라도 있는 경우 반드시 추상 클래스로 선언되어야 한다.

추상 클래스는 객체를 생성할 수 없다. 다음과 같이 추상 클래스의 레퍼런스 변수는 선언할 수 있으나 객체 생성은 불가하다.

abstract class Ab{
	//내용
}

Ab ab; //오류 발생하지 않음. 레퍼런스 변수 선언 가능
ab = new Ab(); //오류 발생. 추상 클래스의 객체 생성 불가

추상 클래스의 상속

추상 클래스를 상속 받는 클래스는 추상 클래스가 된다. 추상 클래스를 상속 받는 서브 클래스에도 abstract 키워드를 붙여주어야 한다.

추상 클래스의 구현

추상 클래스의 목적은 다양한 구현에 있다. 추상 클래스의 구현이란 슈퍼 클래스에 선언된 모든 추상 메소드를 서브 클래스에서 오버라이딩하여 구현하는 것을 말한다.

아까의 예시에서 슈퍼 클래스 Shape를 추상 클래스로 선언하고 서브 클래스에서 구현하면 다음과 같다.

추상 클래스 구현 시에도 키워드 extends를 사용한다.

이렇게 추상 클래스를 작성하면 설계와 구현을 분리할 수 있다는 장점이 있다. 추상 클래스에서 공통 구조를 설계하고 서브 클래스에서 이를 각각에 맞게 구체화한다.

Interface

여기 또 다른 골격/규격에 대한 개념이 있다. 상수와 메소드로 이루어진 인터페이스는 다음과 같이 interface 키워드를 통해 선언한다.

인터페이스의 멤버로는 5가지 형태의 멤버만 가능하다.

  • 상수
  • 추상 메소드
  • default 메소드
  • private 메소드
  • static 메소드

❗필드는 멤버로 올 수 없다. 추상 메소드는 public abstract만 가능하며 다른 접근 지정은 불가하고, 생략 가능하다. 상수의 경우 public static final로 접근 지정하고 생략 가능하다. default, private, static 메소드의 경우에는 인터페이스 내에 구현되어 있어야 한다. default 메소드의 접근 지정은 public이며 private 메소드는 인터페이스 내에서만 호출 가능하다. static 메소드의 경우 접근 지정자가 생략되면 public이며 private으로 지정 가능하다.

인터페이스 또한 객체를 생성할 수 없으며 인터페이스의 레퍼런스 변수는 선언 가능하다.

인터페이스 구현

인터페이스 구현 시 implements 키워드를 사용한다. 이 때 인터페이스의 모든 추상 메소드를 구현해야 한다. 인터페이스를 구현한 클래스에는 메소드를 추가로 작성할 수 있으며 인터페이스에 이미 구현되어 있는 default, private, static 메소드의 경우 따로 다시 작성하지 않아도 된다. 이 경우 이미 구현되어있는 메소드를 그대로 사용하게 된다.

인터페이스 상속

클래스의 경우 인터페이스를 상속받을 수 없고 구현해야 한다. 인터페이스끼리만 상속 가능하며 extends 키워드를 사용한다. 자바에서 인터페이스를 다중 상속할 수 있다. 다음과 같이 여러 인터페이스를 나열하여 상속하면 된다.

인터페이스 다중 구현

클래스는 여러 인터페이스를 구현할 수 있다. 인터페이스를 나열하여 구현하고, 각 인터페이스에 선언된 모든 추상 메소드를 구현해야 한다.

클래스 상속과 함께 인터페이스 구현

클래스를 상속 받으면서 동시에 인터페이스를 구현할 수 있다. 다음과 같은 구조가 가능하다.

class A extends B implements C, D{
	//내용
}

인터페이스의 필요성

인터페이스는 다중 구현을 지원한다. 클래스는 다중 상속이 불가하므로 다중 구현을 통해 다중 상속을 대신할 수 있다. 설계를 위한 선언과 구현을 분리할 수 있다. 따라서 하나의 인터페이스로 필요에 맞게 다양하게 구현할 수 있다. 인터페이스를 공동으로 사용하더라도 다른 개발자의 메소드 구현부를 볼 수 없도록 할 수 있다. 이는 보안 측면 상에서 이점을 가진다.

profile
파인애플 좋아하세요?

0개의 댓글