본문 바로가기

STUDY/국비과정

[JAVA 웹 개발 공부] 국비지원 18일차 - 상속, 다형성, 업캐스팅, 다운캐스팅, 오버라이딩, Object, super

상속

 

1. 상속

상속(inheritance)은 기존에 존재하는 클래스로부터 필드와 메소드를 이어받고, 필요한 기능을 추가할 수 있는 기법이다.

상속을 이용하면 여러 클래스에 공통적인 코드들을 하나의 클래스로 모을 수 있어서 코드의 중복을 줄일 수 있다.

 

2. 상속의 형식

자바에서 상속을 구현하는 방법은 새로 작성하고자 하는 클래스의 이름 뒤에 상속받고자 하는 클래스의 이름을 키워드 'extends'와 함께 써 주기만 하면 된다.

class 자식클래스 extends 부모클래스 {}

상속하는 클래스를 조상 클래스라고 하고 상속받는 클래스를 자손 클래스라고 한다.

*조상 클래스 : 부모(parent)클래스, 상위(super)클래스, 기반(base)클래스

*자손 클래스 : 자식(child)클래스, 하위(sub)클래스, 파생된(derived)클래스

 

3. 상속을 사용하는 이유

새로운 클래스를 생성해야 할 때, 우리가 원하는 코드를 가진 클래스가 이미 존재한다면 이 클래스를 상속받아서 새로운 클래스를 정의하면 된다. 이렇게 함으로써 직접 작성할 필요 없이 이미 존재하는 클래스의 필드와 메소드를 재사용할 수 있다. 또한, 상속을 사용하면 중복되는 부분도 최소화할 수 있고, 공통 부분은 하나로 정리되어서 관리하기 쉽고, 유지 보수와 변경도 쉬워졌다.

 

3. 자바 상속의 특징

다중 상속을 지원하지 않는다. 다중 상속이란 여러 개의 클래스로부터 상속받는 것이다. 자바에서는 금지되어 있다.

상속의 횟수에는 제한이 없다. 상속 계층 구조의 최상위에는 java.lang.Object 클래스가 있다.

 

ex)

부모 클래스 : 동물

자식 클래스 : 새, 비둘기

// 동물
// 이름
// 나이
class Animal {
	String name;
	int age;
}

// 새
// 날기
class Bird extends Animal {
	void fly() {
		System.out.println("새가 날아갑니다~");
	}
}

// 독수리
// 사냥하기
class Eagle extends Bird {
	void hunt() {
		System.out.println("독수리는 사냥을 합니다~");
	}
}

// 비둘기
// 소리내기
class Pigeon extends Bird {
	void googoo() {
		System.out.println("구구구");
	}
}

public class Main {
	public static void main(String[] args) {
		Bird b = new Bird();
		b.fly(); // 새가 날아갑니다~
		
		Eagle e = new Eagle();
		e.fly(); // 새가 날아갑니다~
		e.hunt(); // 독수리는 사냥을 합니다~
		
		Pigeon p = new Pigeon();
		p.fly(); // 새가 날아갑니다~
		p.googoo(); // 구구구
	}
}

 

 

 

다형성

 

다형성(polymorphism)은 "많은(poly) + 모양(morph)"이라는 의미로써 주로 프로그래밍 언어에서 하나의 식별자로 여러 개의 작업을 처리하는 것을 의미한다. 넓은 의미에서 "메소드 오버로딩"이나 "메소드 오버라이딩", 또 "제네릭 프로그래밍"도 다형성에 포함된다.

하지만 일반적으로 객체지향 프로그래밍에서 다형성이란 객체들이 똑같은 메시지를 받더라도 각자의 실제 타입에 따라서 서로 다른 동작을 하는 것을 말한다.

 

 

 

업캐스팅 vs 다운캐스팅

 

업캐스팅과 다운캐스팅은 일종의 형변환이다.

 

1. 업캐스팅(upcasting)

자식 클래스 → 부모 클래스

자식 객체를 부모 참조 변수로 참조하는 것이다. 업캐스팅은 묵시적으로 수행될 수 있다.

업캐스팅을 사용하면 부모 클래스의 멤버에 접근할 수 있다. 하지만 자식 클래스의 멤버는 접근이 불가능하다.

 

2. 다운캐스팅(downcasting)

부모 클래스 → 자식 클래스

부모 객체를 자식 참조 변수로 참조하는 것이다. 이것은 묵시적으로는 안 되고 명시적으로 하여야 한다.

 

ex) '부모 클래스 : 동물 / 자식 클래스 : 새, 비둘기' 가 있을 때 업캐스팅과 다운캐스팅하기 

// 독수리를 새로 업캐스팅
Bird e = new Eagle(); // 객체의 다형성. 형변환 '자식 -> 부모' 상향 형변환(업캐스팅)
e.fly();
e.hunt(); // 에러!

// 새를 독수리로 다운캐스팅
Eagle eagle = (Eagle) e; // 다운캐스팅은 자동적으로 이루어지지 않음. 명시적으로 캐스팅해야함.
eagle.hunt();

 

 

instanceof 연산자

 

자바에서는 변수의 타입만 보고는 변수가 가리키는 실제 타입을 알 수 없다.

변수가 가리키는 객체의 실제 타입을 알고 싶으면 instanceof 연산자를 사용하면 된다.

 

if (obj instanceof Rectangle) { ... }

Bird[] birds = { new Eagle(), new Pigeon() };

for (int i = 0; i < birds.length; i++) {
    birds[i].fly();                  
    if (birds[i] instanceof Eagle) { // 인스턴스가 해당 타입이 맞는지 확인
        ((Eagle) birds[i]).hunt();   // 타입이 맞을 경우(true) 다운캐스팅
    }
}

 

 

 

종단 클래스

 

종단 클래스(final class)는 상속을 시킬 수 없는 클래스를 말한다. 종단 클래스가 필요한 이유는 보안상의 이유 때문이다.

자바에서는 이론상으로는 중요한 클래스의 서브 클래스를 만들어 서브 클래스로 하여금 시스템을 파괴하도록 할 수 있기 때문에 자바 시스템은 중요한 클래스에 대해서는 종단 클래스로 선언하고 있다. 대표적인 것이 String 클래스이다.

String 클래스는 컴파일러에서 많이 쓰이기 떄문에 종단 클래스로 선언되어 있다. 종단 클래스로 선언하려면 클래스의 선언 맨 앞에 final을 붙인다.

 

 

 

메소드 오버라이딩

 

메소드 오버라이딩(method overriding)은 자식 클래스가 부모 클래스의 메소드를 자신의 필요에 맞추어서 재정의하는 것이다.

이때 메소드의 이름이나 매개 변수, 반환형은 동일하여야 한다.

오버라이딩은 부모 클래스의 메소드를 무시하고 덮어씌운다는 의미이다. 자식 객체에서 해당 메소드를 실행하면 오버라이딩된 메소드가 실행된다.

 

+) 이클립스 Override 자동완성

클래스안 우클릭 > Source > Override/Implement Methods... > Select > OK

 

 

오버라이딩 vs 오버로딩

 

1. 오버로딩(overloading)

기존에 없는 새로운 메서드를 정의하는 것(new)

같은 메소드명을 가진 여러 개의 메소드를 작성하는 것

 

2. 오버라이딩(overriding)

상속받은 메서드의 내용을 변경하는 것(change, modify)

부모 클래스의 메소드를 자식 클래스가 다시 정의하는 것

 

 

 

Object

 

Object 클래스는 모든 클래스 상속계층도의 최상위에 있는 조상클래스이다. 다른 클래스로부터 상속 받지 않는 모든 클래스들은 자동적으로 Object 클래스로부터 상속받게 함으로써 이것을 가능하게 한다.

자바의 모든 클래스들은 Object 클래스의 멤버들을 상속 받기 때문에 Object 클래스에 정의된 멤버들을 사용할 수 있다.

toString()이나 equals(Object o)와 같은 메서드를 따로 정의하지 않고도 사용할 수 있었던 이유는 이 메서드들이 Object 클래스에 정의된 것들이기 때문이다.

 

 

 

super, super()

 

1. super

super 는 자손 클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수이다.

멤버변수와 지역변수의 이름이 같을 때 this를 붙여서 구별했듯이 상속받은 멤버와 자신의 멤버와 이름이 같을 때는 super 를 붙여서 구별할 수 있다.

조상 클래스로부터 상속받은 멤버도 자손 클래스 자신의 멤버이므로 super 대신 this를 사용할 수 있다. 그래도 조상 클래스의 멤버와 자손클래스의 멤버가 중복 정의되어 서로 구별해야하는 경우에만 super를 사용하는 것이 좋다.

 

2. super()

this()와 마찬가지로 super() 역시 생성자이다. this()는 같은 클래스의 다른 생성자를 호출하는 데 사용되지만, super()는 조상 클래스의 생성자를 호출하는데 사용된다. 

자손 클래스의 인스턴스를 생성하면, 자손의 멤버와 조상의 멤버가 모두 합쳐진 하나의 인스턴스가 생성된다. 그래서 자손 클래스의 인스턴스가 조상 클래스의 멤버들을 사용할 수 있는 것이다. 이 때 조상 클래스 멤버의 초기화 작업이 수행되어야 하기 때문에 자손 클래스의 생성자에서 조상 클래스의 생성자가 호출되어야 한다.

Object 클래스를 제외한 모든 클래스의 생성자 첫 줄에 생성자, this() 또는 super(), 를 호출해야 한다. 그렇지 않으면 컴파일러는 생성자의 첫 줄에 'super();'를 자동적으로 추가할 것이다.