상속 (Inheritance)
상속이란 기존의 클래스를 재 사용하여 새로운 클래스를 만드는 것이다. 따라서 코드의 중복을 제거할 수 있다.
두 클래스를 상위 / 하위로 나누어 상위 클래스의 멤버들을 하위 클래스에게 상속시켜주는 것을 의미한다.
1. 생성자와 초기화 블럭은 상속되지 않는다 - 멤버들만 상속
2. 하위 클래스의 멤버 개수는 상위 클래스보다 항상 같거나 많다.
3. 자바에서는 단일 상속만을 허용한다.
* 상속 클래스의 관계는 상위-하위 / 부모-자식 / 기반(base) - 파생된(derived) 클래스로 표현할 수도 있다.
상속을 할때는 extends 키워드를 사용하며, 아래와 같이 정의할 수 있다.
class 상속클래스_이름 extends 상위클래스_이름
상위 클래스의 멤버 (필드, 메서드, 이너 클래스)를 그대로 하위 클래스에 물려주면서 하위 클래스는 그렇게
상속받은 멤버 + 자기 자신만의 멤버를 추가할 수 있다. 따라서 하위 클래스만의 특징을 가질 수 있다.
상속을 한 뒤에 하위 클래스의 인스턴스를 생성하면 상위 클래스의 멤버와 하위 클래스의 멤버가 합쳐진 하나의 인스턴스가 생성된다.
포함관계
상속 이외에도 클래스를 재사용 하는 방법이 있는데 '포함(Composite)' 관계를 맺어주는 것이다.
포함관계는 클래스의 멤버로 다른 클래스의 참조 변수를 선언하는 것을 의미한다.
class Vehicle
{
Engine engine = new Engine(); // 엔진
Door[] door = new Door[2]; // 문갯수 2개를 배열로 처리
//...
}
위의 코드를 보면 Vehicle 클래스를 작성하는 중에 Engine과 Door클래스를 미리 따로 만들어 놓고 이 둘을 Vehicle 클래스의 멤버 변수로써 선언해 포함관계를 만들었다.
이렇게 되면 Vehicle 안에서 필요한 필드를 Engine 클래스에서 정의한 필드 + Door 클래스에서 정의한 필드에서 가져와 쓸 수 있으므로 코드의 불 필요한 중복을 줄일 수 있다.
하나의 큰 클래스를 작성하는 것 보다 단위별로 여러 개의 클래스를 쪼개서 이것들을 포함관계로 연결시킨다면 훨씬 간결하고 쉽게 관리할 수 있을 것이다.
그렇다면 포함이랑 상속이랑 비슷해 보이는데 어떤 상황에서 뭘 쓸지 어떻게 정해야 할까?
>> 클래스간의 관계가 '~는 ~이다'의 관계인지, '~는 ~를 가지고 있다'의 관계인지 생각해보면 된다.
~는 ~이다가 성립하면 상속관계
~는 ~를 가지고 있다면 포함관계를 맺는것이 옳다.
위를 토대로 했을때 아래의코드를 다시 본다면 '자동차는 엔진 / 문 이다' 는 말이 안되는 관계이다. 하지만 '자동차는 엔진 / 문을 가지고 있다' 는 말이 되는 관계이므로 아래는 상속 보다는 포함 관계를 쓰는것이 옳다.
class Vehicle
{
Engine engine = new Engine(); // 엔진
Door[] door = new Door[2]; // 문갯수 2개를 배열로 처리
//...
}
아래 예시는 Me 클래스와 Human 클래스를 비교해본 것인데 '나는 사람을 가지고 있다' 보다 '나는 사람이다' 가 말이 되는 문장이므로 포함 관계가 아닌 상속 관계를 맺는것이 옳다.
class Human
{
int age;
int nationality;
String name;
...
...
}
------------------------------------
class Me //상속을 하지 않을경우 필드의 필요한 변수를 다시 선언해야함.
{
int age;
int nationality
String name;
...
...
String myHobby;
}
------------------------------------
//Human 클래스를 상속받은 경우 age,국적,이름 이라는 필드변수를 Me안에서 다시 정의할 필요가 없다.
//상속을 받아 왔으므로 쓸 수 있다.
class Me extends Human
{
String myHobby;
}
메서드 오버라이딩 (Method Overriding)
상위 클래스로부터 상속받은 메서드와 동일한 이름의 메서드를 다시 정의하는 것
오버라이딩 이라는 말에서 알 수 있듯이 덮어쓴다고 보면 될 것이다.
상속받은 메서드를 그대로 사용하기도 하지만 하위 클래스 자신에 맞게 변경해야 할 경우가 생길 때도 많다.
그럴 때 메서드 오버라이딩을 사용하게 된다.
public class Method_Overriding_Practice {
public static void main(String[] args) {
Dusty dusty = new Dusty();
dusty.sleepmode();
}
}
class Cat
{
void sleepmode()
{
System.out.println("zzzz...");
}
}
class Dusty extends Cat //Cat의 하위클래스 Dusty 생성
{
void sleepmode() //Dusty 에서 상위클래스에서 이미 정의된 sleepmode메서드를 다시 정의함
{
System.out.println("안자고 뭐해");
}
}
zzzz...가 아닌 "안자고 뭐해" 가 덮어씌워져 출력된다
메서드 오버라이딩을 하기 위해선 역시나 조건이 필요한데 지금 시점에서는 2,3번째 부분은 아직 안 배웠다. 배우고 나면 추가 정보 업데이트 하자.
1. 메서드의 선언 구조가 상위 클래스의 메서드 선언 구조와 일치해야 한다. (메서드명, 매개변수, 반환 타입)
2. 접근 제어자를 상위 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
3. 예외는 상위 클래스의 메서드보다 더 많이 선언할 수 없다.
4. 인스턴스_메서드를 클래스_메서드(static)으로 또는 그 반대로 변경할 수 없다.
여러 개의 객체를 생성한 뒤에 각각의 객체에서 메서드 오버라이딩을 하면 객체별로 다른 결과를 뽑을 수 있다.
더 나아가서 여러개의 객체를 생성한 뒤에 배열에 집어넣으면 더 직관적이다. 아래의 코드는 객체를 생성해서 배열에 넣은 뒤 반복문으로 각각의 객체를 출력한다. 상위 클래스인 Cat의 sleepmode 메서드를 호출했지만 하위 클래스들에서 method overriding을 했기 때문에 "zzzz...."가 나오지 않는다.
public static void main(String[] args) {
Cat[] cats = new Cat[] { new Dusty(), new Toto(), new Galbi()};
//배열을 만들고 각각의 인덱스에 새로 생성한 인스턴스를 넣는다.
for(int i = 0; i<cats.length; i++)
{
cats[i].sleepmode(); //배열 인덱스를 반복 출력
}
}
class Cat
{
void sleepmode()
{
System.out.println("zzzz...");
}
}
class Dusty extends Cat //하위 클래스 Toto 생성
{
void sleepmode() // Method Overriding
{
System.out.println("안자고 뭐해");
}
}
class Toto extends Cat //하위 클래스 Toto 생성
{
void sleepmode() // Method Overriding
{
System.out.println("토토 잔다");
}
}
class Galbi extends Cat //하위 클래스 Galbi 생성
{
void sleepmode() // Method Overriding
{
System.out.println("갈비 잔다");
}
}
안자고 뭐해
토토 잔다
갈비 잔다
super와 super( )
Super
super 는 참조 변수로써, 하위 클래스에서 상위 클래스로부터 상속받은 멤버를 참조할 때 사용된다.
class higherClass
{
public int x = 10; //멤버 변수
void callout()
{
System.out.println("EMPTY");
}
}
class lowerClass extends higherClass
{
public int x = 100; //멤버 변수
void callout()
{
System.out.println("x = " + x); //100 (메서드 오버라이딩)
System.out.println("this.x = " + this.x); //100 (메서드 오버라이딩)
System.out.println("super.x = " + super.x); //10 (상위클래스의 x)
super.callout(); // EMPTY 출력
}
}
위의 코드를 보면 x 와 this.x 는 하위 클래스의 x값을 출력하고, super.x 는 상위 클래스의 x를 출력하는 것을 볼 수 있다. 그리고 super. 를 통해 상위 클래스의 메서드를 호출할 수도 있다.
상위 클래스의 멤버와 자신의 멤버를 구별하는데 쓰인다는 부분만 빼면 this와 super는 같다고 볼 수 있다.
Super( )
super( )는 생성자 로써 하위 클래스에서 상위 클래스의 생성자를 호출할 때 사용된다.
public static void main(String[] args) {
lowerClass test = new lowerClass(1,5);
System.out.println(test.i +" "+ test.j);
}
class higherClass{
higherClass() { System.out.println("higher class Constructor");} //
}
class lowerClass extends higherClass {
int i,j;
lowerClass(int i, int j) {
super();
this.i = i;
this.j = j;
}
}
higher class
1 5
하위 클래스 에서 super( )를 통해 상위 클래스의 생성자를 호출하여 higher class Constructor가 출력된 것을 볼 수 있다.
this( ) 때와 마찬가지로 super( )도 반드시 첫줄에 선언되어야 한다. 상위 클래스의 멤버가 상위 클래스의 멤버를 사용할 수 있으므로 상위 클래스의 멤버들이 먼저 초기화가 이루어져야 하기 때문
만약에 super( )가 없으면 컴파일러가 첫줄에 자동으로 생성해준다. 이때 상위 클래스에 기본 생성자가 없으면 에러가 발생한다. super ( ) 자체는 매개변수가 없는 생성자를 의미하므로 기본 생성자나 매개변수가 없는 상위 클래스에 필요한 것이고 매개변수가 있는 생성자를 상위 클래스에서 호출하려면 super(매개변수)처럼 해야 한다.
Object 클래스
Object 클래스는 자바의 클래스 상속계층도(Class Hierarchy)의 최상위에 있는 상위 클래스이다.
그러면 아무 상속을 받지 않는 클래스는 뭐지?? 할 수 있지만 사실 다른 클래스로부터 상속받지 않는 모든 클래스는 자동적으로 extends Object 가 추가되어 Object 클래스를 상속 받게된다.
예를 들어 아래의 super( ) 예시 코드를 확인하면 다른클래스의 상위 클래스이므로 추가한 것이 없지만
class higherClass{
higherClass() { System.out.println("higher class Constructor");} //
}
class higherClass (extends Object가 자동 추가)
{
higherClass() { System.out.println("higher class Constructor");} //
}
컴파일러가 extends Object를 뒤에 붙여 Object로 부터 상속을 받게 한다. 다만 실제로 코드로 추가가 되어 보이진 않는다.
그동안 toString( ), equals ( )를 따로 정의하지 않고도 쓸 수 있었던 이유가 이것이다. 처음에 할 때는 몰랐는데 이제 좀 뭔가가 보이는 것 같다.
Object 클래스에는 모든 인스턴스들이 가져야 할 기본적인 메서드가 미리 정의되어있다. toString( )이나 equals( )처럼.
이 부분은 자바의 정석 9장에서 더 자세히 나온다.
Object (Java Platform SE 7 )
Called by the garbage collector on an object when garbage collection determines that there are no more references to the object. A subclass overrides the finalize method to dispose of system resources or to perform other cleanup. The general contract of fi
docs.oracle.com
'programming > JAVA' 카테고리의 다른 글
Java - 다형성 (0) | 2022.05.13 |
---|---|
Java - 캡슐화 (Encapsulation) (0) | 2022.05.12 |
Java - 생성자 (0) | 2022.05.11 |
Java - 메서드 (0) | 2022.05.10 |
Java - 필드와 변수 (0) | 2022.05.10 |