상속 개념
•
현실에서 상속은 부모가 자식에게 재산을 물려주는 행위
•
객체 지향 프로그램에서 부모 클래스의 멤버를 자식 클래스에게 물려줄 수 있다.
◦
부모 클래스 = 상위 클래스
◦
자식 클래스 = 하위 클래스, 파생 클래스
•
상속의 이점
1.
이미 개발된 클래스를 사용하여 새로운 클래스를 만들기 때문에 코드의 중복을 줄인다.
•
private 접근 제한자로 선언된 멤버는 상속되지 않는다.
•
default 접근 제한자로 선언된 멤버는 다른 패키지에 존재하는 자식 클래스에게 상속되지 않는다.
2.
클래스의 수정을 최소화하여 유지 보수 시간을 단축한다.
•
부모 클래스의 수정이 모든 자식 클래스에게 동일한 효과를 끼친다.
클래스 상속
•
클래스를 생성할 때 상속받을 부모 클래스를 선택한다.
public class '자식클래스' extends '부모클래스' {
// 필드, 생성자, 메소드
}
Java
복사
•
오직 하나의 부모 클래스로부터 상속 받을 수 있다. → 다중 상속 미허용
부모 생성자 호출
•
자식 클래스로부터 객체를 생성하면, 우선 부모 객체가 먼저 생성된다.
•
생성자 호출 순서 : 자식 객체 생성자 호출 → 부모 객체 생성자 호출 → 부모 객체 생성 → 자식 객체 생성
public class '자식클래스' extends '부모클래스' {
public 자식클래스생성자() {
super(); // 부모의 생성자 호출
}
}
Java
복사
•
생성자를 명시하지 않은 경우, 컴파일러가 자동으로 기본 생성자 생성 → 부모 클래스의 기본 생성자 호출
•
생성자를 명시하는 경우, 자식 클래스의 생성자 첫 줄에 부모 클래스의 생성자를 호출하는 super(매개값, ...); 를 호출해야 한다.
◦
부모 클래스의 생성자 매개변수 타입과 일치하는 생성자를 명시 → 불일치시 컴파일 에러 발생
메소드 재정의
•
부모 클래스에 정의된 메소드를 자식 클래스에서 재정의하여 다양한 기능 수행 → 메소드 오버라이딩
메소드 재정의(@Override)
•
메소드 오버라이딩 : 부모 클래스에서 정의된 메소드를 자식 클래스에서 재정의 하는 것
•
메소드가 재정의되면 부모 객체의 원본 메소드는 숨겨지고 자식 객체의 재정의된 메소드가 호출된다.
•
메소드 오버라이딩 규칙
1.
부모 클래스의 메소드와 동일한 시그니처( 리턴 타입, 메소드 이름, 매개 변수 타입 )를 가져야 한다.
2.
접근 제한을 더 강하게 오버라이딩 할 수 없다. ( public < protected < default < private )
3.
새로운 예외를 throw 할 수 없다.
•
'@Override' 어노테이션 사용시, 정확히 오버라이딩 되었는지 컴파일러가 검사한다. (생략 가능)
class Parent {
void method1(매개값);
}
class Child extends Parent {
@Override
public void method1(매개값){
// 재정의
}
}
Java
복사
부모 메소드 호출(super)
•
자식 클래스에서 오버라이딩한 부모 클래스의 메소드를 호출할 때 super 키워드를 붙여서 호출할 수 있다.
super.부모메소드(); // 'super'는 부모 객체를 참조하고 있다.
Java
복사
final 클래스와 final 메소드
•
final 필드는 더 이상 값이 변경될 수 없음을 의미한다. → 클래스와 메소드에도 적용 가능
상속할 수 없는 final 클래스
•
final 클래스 선언 시 해당 클래스로부터 상속할 수 없다.
public final class '클래스' {
// 필드, 생성자, 메소드 ...
}
Java
복사
•
예 ) 자바 표준 API에서 제공하는 'String' 클래스
오버라이딩 할 수 없는 final 메소드
•
final 메소드 선언 시 자식 클래스가 해당 메소드를 오버라이딩 할 수 없다.
public final void '메소드'(매개값) {...}
Java
복사
protected 접근 제한자
•
protected : 같은 패키지의 클래스 혹은 다른 패키지의 자식 클래스에서 접근 가능
◦
필드, 생성자, 메소드에 적용 가능하다.
•
단, 다른 패키지의 자식 클래스에서 부모 클래스의 protected로 선언된 생성자를 호출 시
'new' 연산자가 아닌 'super()' 를 사용해야한다.
타입 변환과 다형성
•
다형성 : 같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질
•
자바는 부모 클래스로 타입 변환을 허용한다. → 부모 타입에 자식 객체를 대입할 수 있다.
public class Car {
// 'HankookTire'와 'KumhoTire' 클래스는 Tire 클래스의 자식 클래스
Tire t1 = new HankookTire();
Tire t2 = new KumhoTire();
}
Java
복사
•
기본 타입의 변환 : 데이터 타입을 다른 데이터 타입으로 변환하는 행위. ( byte → int )
•
클래스 타입의 변환 : 상속 관계에 있는 클래스 사이에서 발생하는 타입 변환 행위.
자식 타입 → 부모 타입으로 자동 타입 변환이 가능하다.
자동 타입 변환(Promotion)
•
자동 타입 변환 : 프로그램 실행 도중에 자동적으로 타입 변환이 일어나는 것
•
자식 클래스의 객체를 부모 클래스 타입 변수에 대입하면 자동 타입 변환이 발생한다.
부모클래스 변수 = 자식클래스타입;
Cat cat = new Cat();
Animal animal = cat;
Java
복사
•
참조 타입 변수 'cat'과 'animal'은 타입만 다를 뿐, 동일한 객체를 가리키고 있다.
•
상속 관계에서 상위 타입이라면 자동 타입 변환이 일어날 수 있다.
•
부모 타입으로 자동 타입 변환이 일어난 이후에는 부모 클래스에 선언된 필드와 메소드만 사용 가능
◦
단, 자식 클래스에서 오버라이딩된 메소드가 있는 경우 자식의 오버라이딩된 메소드가 호출된다.
필드의 다형성
•
자식 타입으로 사용하면 되는데 부모 타입으로 변환해서 사용하는 이유 → 다형성을 구현하는 기술적 방법
•
다형성 : 동일한 타입을 사용하지만 다양한 결과가 나오는 성질
•
필드의 타입은 변함이 없지만 어떤 객체를 저장하느냐에 따라서 실행 결과가 달라질 수 있다.
◦
상속, 오버라이딩, 자동 타입 변환을 사용하여 다양한 결과를 얻을 수 있다.
class Car {
Tire front = new Tire();
Tire back = new Tire();
void run() {
front.roll(); // Tire 클래스의 roll() 메소드 호출
back.roll();
}
}
Java
복사
Car car = new Car();
// HankookTire 와 KumhoTire는 Tire의 자식 클래스
car.front = new HankookTire(); // 자동 타입 변환
car.back = new KumhoTire(); // 자동 타입 변환
car.run(); // 재정의된 roll() 메소드 호출
// run() 메소드를 수정하지 않고 필드값을 교체하여 다양한 실행 결과를 얻을 수 있다.
Java
복사
하나의 배열로 객체 관리
•
필드를 여러 개 선언하여 객체 저장
하나의 배열에 여러 개의 객체 저장
Tire[] tires = {
new Tire("front"),
new Tire("back")
}
Java
복사
•
코드가 간결하고 관리하기 편하다.
매개 변수의 다형성
•
메소드 호출 시 매개 변수로 자식 타입 객체를 넘겨줄 수 있다.
class Driver {
void drive(Vehicle vehicle){
vehicle.run();
}
}
Java
복사
Driver driver = new Driver();
Vehicle vehicle = new Vehicle();
Bus bus = new Bus();
driver.drive(vehicle); // 일반적인 경우
driver.drive(bus); // 자식 타입 객체 넘김
Java
복사
•
매개 변수의 타입이 클래스인 경우, 해당 클래스와 자식 객체를 매개값으로 사용할 수 있다.
•
매개값으로 어떤 객체가 넘어오느냐에 따라서 다양한 실행 결과를 얻을 수 있다.
◦
자식 객체에서 메소드 오버라이딩을 한 경우
강제 타입 변환(Casting)
•
강제 타입 변환 : 부모 타입을 자식 타입으로 변환하는 것
◦
단, 자식 타입이 부모 타입으로 자동 타입 변환이 일어난 후에만 가능하다.
•
자식 타입이 부모 타입으로 자동 변환하면 부모 타입에 선언된 필드와 메소드만 사용 가능
◦
만약 자식 타입에 선언된 필드와 메소드를 사용해야 하는 경우 강제 타입 변환을 한다.
자식클래스 변수 = (자식클래스) 부모클래스타입;
Java
복사
객체 타입 확인(instanceof)
•
instanceof : 해당 객체가 어떤 클래스의 인스턴스인지 확인한다.
boolean result = '객체' instanceof '클래스';
Java
복사
•
자식 타입 → 부모 타입 자동 타입 변환이 일어난 경우에만 부모 타입 → 자식 타입으로 강제 타입 변환 가능
◦
부모 변수가 참조하는 객체가 부모 객체인지 자식 객체인지 확인하는 방법 → 자동 타입 변환 확인
public void method(Parent parent) {
if(parent instanceof Child) {
Child child = (Child) parent;
child.walk();
}
}
Java
복사
추상 클래스
•
추상 : 실제간에 공통되는 특성들을 추출한 것
◦
개, 고양이, 새 → 동물
•
실체 클래스 : 객체를 생성할 수 있는 클래스
•
추상 클래스 : 클래스들의 공통적인 특성을 추출해서 선언한 클래스
•
실체 클래스와 추상 클래스는 상속 관계
◦
실체 클래스(자식)는 추상 클래스(부모)의 특성을 물려받고 추가적인 특성을 가질 수 있다.
•
추상 클래스 특징
◦
'new' 연산자를 사용하여 객체를 생성할 수 없다.
◦
오직 부모 클래스로만 사용된다.
class '실체클래스' extends '추상클래스' {
// 필, 생, 메
}
Java
복사
추상 클래스의 용도
•
실체 클래스들의 공통된 필드와 메소드의 이름을 통일할 목적
◦
실체 클래스를 설계하는 사람마다 필드와 메소드의 이름을 다르게 선언한다.
◦
추상 클래스를 상속함으로써 공통된 필드와 메소드의 이름을 통일
•
실체 클래스를 작성할 때 시간을 절약
◦
설계자가 설계한 클래스를 코더가 작성하는 경우, 추상 클래스를 전달하고 코더는 해당 클래스를 상속받아 구체적인 클래스를 구현
추상 클래스 선언
•
abstract : 추상 클래스 선언에 사용되는 키워드
public abstract class '추상클래스' {
// 필, 생, 메
}
Java
복사
•
일반 클래스와 마찬가지로 필드, 생성자, 메소드를 선언할 수 있다.
•
추상 클래스를 상속받은 자식 객체가 생성될 때, 'super(매개값)' 를 호출해서 추상 클래스 객체를 생성
◦
추상 클래스도 생성자가 있어야 한다.
추상 메소드와 오버라이딩
•
추상 클래스는 실체 클래스가 공통적으로 가져야 할 필드와 메소드를 정의 → 실체 클래스의 멤버의 통일
•
메소드의 선언만 통일화 하고, 실행 내용은 실체 클래스마다 달라야 하는 경우
◦
추상 클래스에서 추상 메소드를 선언
•
추상 메소드는 추상 클래스에서만 선언할 수 있으며, 메소드의 선언부만 존재하고 중괄호가 없다.
◦
추상 클래스의 자식 클래스에서 직접 추상 메소드의 실행 내용을 작성하도록 강제하는 효과
◦
추상 메소드를 오버라이딩하지 않으면 컴파일 에러 발생
public abstract 리턴타입 메소드명(매개변수);
Java
복사
// Animal.java
public abstract class Animal {
// 추상 메소드 선언
public abstract void sound();
}
Java
복사
// Dog.java
public class Dog extends Animal {
@Override
public void sound() {
System.out.println("Bow Wow");
}
}
Java
복사
// Cat.java
public class Cat extends Animal {
@Override
public void sound() {
System.out.println("Meow");
}
}
Java
복사
// AnimalExample.java
public class AnimalExample {
public static void main(String[] args){
// 일반적인 객체 생성 및 메소드 호출
Dog dog = new Dog();
Cat cat = new Cat();
dog.sound();
cat.sound();
// 자동 타입 변환
Animal animal = null;
animal = new Dog();
animal.sound();
// 부모 타입의 매개 변수에 자식 객체를 대입 -> 메소드의 다형성
animalSound(new Cat());
}
public static void animalSound(Animal animal) {
animal.sound();
}
}
Java
복사