IT world

Java 상속 본문

코딩/Java

Java 상속

엄킹 2019. 11. 28. 17:25


상속


현실에서 상속(Inheritance)은 부모가 자식에게 물려주는 행위를 말한다. 객체지향 프로그램에서도 부모클래스의 맴버를 자식클래스에게 물려줄 수 있다. 프로그램에서는 부모 클래스를 상위클래스, 자식 클래스를 하위클래스, 파생클래스라고 부른다.


상속은 이미 잘 개발된 클래스를 재사용해서 새로운 클래스를 만들기 때문에 코드의 중복을 줄여준다.


field1, field2, method1(), method2()를 가지는 클래스를 작성한다고 생각해보자. 4개를 모두 처음부터 작성하는 것보다는 field1과 method1()을 가지고 있는 클래스가 있다면 이것을 상속하고, field2와 method2()만 추가 작성하는 것이 보다 효율적이고 개발 시간을 절약시켜준다.


상속은 extends 를 사용해서 자식클래스에 작성하며 자바는 다중상속을 허용하지 않아 하나의 자식클래스는 하나의 부모클래스밖에 가질 수 없다.


실제로 B클래스를 객체 생성해서 다음과 같이 사용할 때에는 마치 B가 field1과 method1()을 가지고 있는 것 처럼 보인다.



//부모클래스 A

public class A {

int field1;

void method1() {...}

}


//자식클래스 B

public class B extends A { // 부모 상속

int field2;

void method2() {...}

}


//main


//B객체를 만들었지만 A로 부터 상속받은 필드와 메소드 사용

B b = new B();

b.fields1 = 10;

b.method1()


//B의 필드와 메소드

b.fields2 = 10;

b.method2()


상속을 해도 부모 클래스의 모든 필드와 메소드들을 물려받는 것은 아니다. 부모클래스에서 private 접근 제한을 갖는 필드와 메소드는 상속 대상에서 제외되며 부모 클래스와 자식클래스가 다른 패키지에 존재한다면 default 접근 제한을 갖는 필드와 메소드도 상속 대상에서 제외된다. 


상속을 사용하면 클래스의 수정을 최소화할 수 있다. 부모클래스의 수정으로 모든 자식클래스들의 수정효과를 가져오기 때문에 유지 보수시간을 최소화시켜준다.





메소드 재정의(override)


메소드 오버라이딩은 상속된 메소드의 내용이 자식 클래스에 맞지 않을 경우 자식 클래스에서 동일한 메소드를 재정의하는 것을 말한다.

메소드가 오버라이딩되었다면 부모 객체의 메소드는 숨겨지기 때문에 자식 객체에서 메소드를 호출하면 오버라이딩된 자식 메소드가 호출된다.


메소드를 오버라이딩할 때는 다음과 같은 규칙에 주의해서 작성해아한다

- 부모의 메소드와 동일한 시그너처(리턴 타입, 메소드이름, 매개변수리스트)를 가져야한다.

- 접근 제한을 더 강하게 오버라이딩할 수 없다.

- 새로운 예외(Exception)를 throws할 수 없다.



class Parent {

void method1() {...}

void method2() {...}

}


class Child extends Parent{

void method7() {...}


@Override      // 메소드 재정의

void method2() {...} // 재정의를 하였으므로 부모의 method2()가 아닌 자식의 method2()가 호출


void method3() {...}

}



[override 작성]



[출력 결과]


출력 결과를 보면 부모의 Method2()의 내용이 아니라 자식의 Method2()의 내용이 출력되어 오버라이딩이 되었음을 확인할 수 있다.


자식 클래스에서 부모 클래스의 메소드를 오버라이딩하게 되면 부모 클래스의 메소드는 숨겨지고 오버라이딩된 자식 메소드만 사용된다.  그러나 자식 클래스 내부에서 오버라이딩된 부모클래스의 메소드를 호출해야 하는 상황이 발생한다면 명시적으로 super 키워드를 붙여서 부모 메소드를 호출 할 수 있다.


super 키워드는 부모객체를 참조하고 있기 때문에 부모 메소드에 직접 접근할 수 있다.


//super.부모메소드();


class Parent {

void method2() {...}

}


class Child extends Parent{


@Override      // 메소드 재정의

void method2() {...} 


method2(); //재정의된 메소드 호출


super.method2(); // super 키워드로 인해 부모의 method()2 호출

}


[super키워드 사용예제]




[출력 결과]





다형성 


다형성은 같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질을 말한다. 다형성은 하나의 타입에 여러 객체를 대입함으로써 다양한 기능을 이용할 수 있도록 해준다. 


다형성을 위해 자바는 부모 클래스로 타입 변환을 허용한다. 즉 부모 타입에 모든 자식 객체가 대입될 수 있다.



public class Car {


Tire t1 = new HankookTire();

Tire t2 = new KumhoTire();


}


이렇게 하나의 타입으로 서로 다른 여러객체를 만들 수 있고 다형성의 특징이다.


클래스타입변환은 상속 관계에 있는 클래스 사이에서 발생하며 자식 타입은 부모 타입으로 자동 타입 변환이 가능하다. 

위의 예는 HankookTire와 KumhoTire는 Tire를 상속했기 때문에 Tire 변수에 대입 할 수 있는 것이다.


자동타입변환(Promotion)은 프로그램 실행 도중에 자동적으로 타입 변환이 일어나는 것을 말하며 부모클래서 변수 = 자식클래스 타입; 에서 자동타입변환이 일어나는 것을 확인할 수 있다. 


자동타입변환 개념은 자식은 부모의 특징과 기능을 상속받기 때문에 부모와 동일하게 취급될 수 있다는 것이다.


만약 Animal a = new Cat(); 으로 부모 타입으로 자식객체를 생성하였다면 a 참조변수는 Cat 클래스의 객체를 가리키고 있지만 Cat 클래스 객체의 필드값이나 메소드를 사용할 수 없고 부모인 Animal의 필드와 메소드를 사용해야한다. 


비록 변수는 자식 객체를 참조하지만 부모클래스에 선언된 필드와 메소드만 접근이 가능한 것이다. 하지만 예외로 만약 자식 클래스의 메소드가 오버라이딩이 되었다면 그떄는 자식 클래스의 메소드가 출력된다.



class Parent {

void method1() {...}

void method2() {...}

}


class Child extends Parent{

void method7() {...}


@Override      // 메소드 재정의

void method2() {...} 


void method3() {...}

}




//main

Child child = new Child();


Parent parent = child; // 자동 타입 변환


parent.method1(); //부모 메소드 호출

parent.method2(); //재정의된 자식메소드 호출


//parent.method3();  //호출 불가능 -> 자식의 객체를 참조하고 있지만 자식의 필드나 메소드는 사용할 수 없다.





* 강제 타입 변환(Casting) 


강제 타입 변환은 부모타입을 자식 타입으로 변환하는 것을 말한다. 그렇다고 해서 모든 부모 타입을 자식 클래스 타입으로 강제 변환할 수 있는 것은 아니다. 자식 타입이 부모 타입으로 자동 변환한 후 다시 자식 타입으로 변환할 때 강제 타입 변환을 사용할 수 있다.


자식클래스 변수 = (자식클래스) 부모클래스타입; // 부모클래스타입은 자식타입이 부모타입으로 변환된 상태


자식타입이 부모 타입으로 자동변환하면, 부모 타입에 선언된 필드와 메소드만 사용 가능하다는 제약 사항이 따른다. 만약 자식 타입에 선언된 필드와 메소드를 꼭 사용해야 한다면 강제 타입 변환을 해서 다시 자식 타입으로 변환한 다음 자식 타입의 필드와 메소드를 사용하면 된다. 



class Parent {}

class Child extends Parent{}


//main

Child child = new Child();


Parent parent = child; // 자동 타입 변환


Child cc = (Child) parent; // 강제 타입 변환 // parent는 자식타입이 부모타입으로 변환된 참조변수이기 때문에 변환이 가능






추상클래스(abstract)


클래스들의 공통적인 특성을 추출해서 선언한 클래스를 추상 클래스라고 한다. 추상클래스와 실체 클래스는 상속의 관계를 가지고 있다. 추상클래스가 부모이고 실체클래스가 자식으로 구현되어 추상클래스의 모든 특성을 물려받고 추가전인 특성을 가질 수 있다.


추상클래스는 실체클래스의 공통되는 필드와 메소드를 추출해서 만들었기 때문에 객체를 직접 생성해서 사용할 수 없다.

다시 말해 추상 클래스는 new 연산자를 사용해서 인스턴스를 생성할 수 없다.


추상클래스는 새로운 실체클래스를 만들기 위해 부모로만 사용되고 extends 뒤에만 올 수 있는 클래스이다.


*추상클래스를 만든 이유

- 실체 클래스들의 공통된 필드와 메소드의 이름을 통일할 목적

설계자가 여럿일 경우 클래스마다 필드와 메소드가 제각기 다른 이름을 가질 수 있다. 동일한 데이터와 기능임에도 불구하고 이름이 다르다 보니 사용방법이 달라진다. 이러한 불편함을 통일하기위해 부모 클래스에 선언하고 상속받음으로써 이름을 통일한다.

- 실체 클래스를 작성할 때 시간을 절약

공통적인 특성은 추상클래스에 선언해두고 실체 클래스마다 다른점만 실체클래스에 선언하게 되면 실체클래스를 작성하는 시간을 절약할 수 있다.



//추상클래스 선언

pubilc abstract class 클래스 {

//필드

//생성자

//메소드

}



*추상 메소드와 오버라이딩

추상클래스는 실체클래스가 공통적으로 가져야할 필드와 메소드들을 정의해 놓은 추상적인 클래스이므로 공통된 특성들은 추상 클래스에 작성하는 것이 좋다. 하지만 메소드의 선언만 통일화하고 실행내용은 실체 클래스마다 달라야하는 경우가 있다


예를 들어 모든 동물은 소리를 내기 대문에 Animal 추상 클래스에서 sound()라는 메소드를 정의했지만 모든 동물들이 동일한 소리를 내는 것이 아니므로 각각의 실체 클래스에서 재정의를 해줘야한다.


이런 경우 추상 클래스에서 추상 메소드를 선언하여 실제 메소드의 내용은 자식 클래스들이 정의하도록 한다. 


추상클래스에서 메소드의 선운부만 있고 실행내용인 중괄호{} 가 없는 메소드를 말하며 추상클래스를 설계할 때 반드시 하위클래스가 실행 내용을 채우도록 강요하고 자식은 반드시 추상 메소드를 재정의해서 내용을 작성해야한다.


[public] abstract 리턴타입 메소드명(매개변수, ..);         //함수의 시그니처만 작성하여 자식에게 실제내용을 작성하도록 한다.


public abstract class Animal {

public abstract void sound();

}


public class Dog extends Animal {

@Override

public void sound(){

System.out.println("멍멍"); //오버라이드를 통해 추상메소드의 내용을 작성

}

}


어떤 소리를 내는지 결정할 수 없지만 동물은 소리를 낸다는 공통적인 특징이 있으므로 sound()메소드를 추상메소드로 선언하고 하위 클래스들은 sound()를 재정의한다.

















'코딩 > Java' 카테고리의 다른 글

Java 클래스  (0) 2019.11.28
객체지향 프로그래밍(OOP)  (0) 2019.11.27
Java - 참조타입1  (0) 2019.11.27
Java란  (0) 2019.11.25
Java - 정수와 실수  (0) 2019.03.14
Comments