다형성(Polymorphism)
하나의 참조변수로 여러 타입의 인스턴스를 저장하는 것을 다형성이라 한다. 같은 이름, 다른 형태를 가지며 메소드 오버로드가 같은 메소드를 여러 개 작성한다는 이치에서 다형성 형태를 가진다.
다형성은 부모 클래스를 저장하는 변수에 자식 클래스를 저장할 수 있다. 또한 자식 클래스로 만든 인스턴스를 부모 클래스의 참조변수에 담을 수 있다.
형변환)
객체의 경우 상속 관계에서만 형변환이 가능하다.
- Up cast : 자식 인스턴스를 부모 참조변수에 저장
- Down cast : 부모 참조변수에 저장된 인스턴스(자식)를 자식 참조변수로 되돌리는 것
여기서 부모 클래스로 만든 인스턴스는 자식 클래스로 만든 참조변수에 저장할 수 없다.
* instanceof : 어떤 클래스로 만든 인스턴스인지 구별하기 위한 명령어
추상화(Abstraction)
추상적 표현은 알고 있으나 정확하게 표현하기 힘든 것을 의미한다.
그런 의미에서 추상 클래스는 미완성 클래스라고 할 수 있다. 또한 반대로 완성 클래스라 하는 것은 모든 멤버 메소드의 정의가 완전하게 끝난 상태의 클래스이다. 더불어 추상 메소드는 정의부가 작성되지 않은 메소드를 지칭한다.
추상 클래스는 반드시 상속하여 자식 클래스로 만들어 사용한다. 이때 미완성된 메소드의 정의부를 작성해야 한다.
오버라이딩을 강제하기 때문에 정해진 메소드 이름으로 새로운 클래스를 작성해 전체 프로젝트를 병렬화할 수 있다.
형태)
반환형 메소드명() => 선언부
{
... => 정의부
}
public class AbstractTest {
public static void main(String[] args) {
Cat c = new Cat(); // 정상적으로 인스턴스 생성 가능
}
}
abstract class Animal {
String name;
int age;
String gender;
abstract void howl(); // 오버라이드가 필요한 메소드
void eat() {
System.out.println("먹는다.");
}
}
class Cat extends Animal {
@Override
void howl() { // 성공적으로 오버라이드한 모습
System.out.println("냐옹");
}
}
인터페이스(Interface)
인터페이스란 모든 메소드가 정의되지 않은 클래스, 즉 추상화 정도가 더 심한 클래스를 말한다.
추상 메소드 + 상소(final 변수) 형태를 가지며 인스턴스를 생성할 수 없다. 새로운 클래스 작성에 도움을 주는 것에 목적을 두며 클래스 작성의 표준을 제시해준다. 또한 코드 자동화(프레임워크)에 활용되기도 한다.
1. 인터페이스 작성법
- class라는 키워드 대신 interface 키워드를 사용
- 모든 메소드는 추상 메소드이며 재정의가 필요하기 때문에 public abstract가 앞에 붙음 => 메소드 정의는 하지 않음
- 모든 변수에는 public static final이 앞에 붙음
- 반드시 붙여야 하는 키워드는 생략할 수 있음
2. 제어자 간 조합
- 메소드에 static과 abstract를 함께 사용할 수 없음 => static - 인스턴스 없이 사용 가능 / abstract = 정의부 없음
- 클래스에 abstract와 final을 함께 사용할 수 없음 => abstract = 반드시 상속 / final = 상속할 수 없음
- abstract 메소드의 접근 제어자가 private일 수 없음 => private = 상속해도 사용할 수 없음 / abstract = 재정의 필요
- 메소드에 private와 final을 같이 사용할 필요 없음 => private 하나로 모두 처리 가능하기 때문에
* 일반적인 작성 순서는 접근제어자, 비접근제어자 순이다.
3. 제어자의 대상
- 클래스 : 접근제어자, abstract, final
- 메소드 : 접근제어자, final, abstract, static
- 멤버변수 : 접근제어자, final, static
- 지역변수 : final
public class AbstractTest {
public static void main(String[] args) {
InterClass ic = new InterClass();
TestInterface ft = ic; // 부모로서 다형성 취급 가능
}
}
interface TestInterface {
public static final int a = 10;
final int b = 20; // public static 생략
static int c = 20; // public final 생략
int d = 40; // 모두 생략 => 다 똑같은 상수!
public abstract void method1(); // abstract는 body를 가질 수 없다.
public void method2(); // abstract 생략
void method3(); // public abstract 생략
}
// implements : 부모 객체는 선언만 하며 정의(내용)은 자식에서 오버라이딩 (재정의) 해서 사용
class InterClass implements TestInterface {
@Override
public void method1() { }
@Override
public void method2() { }
@Override
public void method3() { }
}
기타 클래스
1. 내부 클래스(Inner Class)
클래스 내부에 작성하는 클래스를 내부 클래스라고 한다. 클래스가 멤버가 되며, 외부 클래스의 멤버를 자유롭게 사용할 수 있게 된다는 장점이 있다.
2. 익명 클래스
익명 클래스는 인터페이스로 새로운 클래스를 파생시킬 때 클래스의 이름 없이 바로 작성하여 인스턴스를 생성하는 클래스이다. 클래스의 이름이 없기 때문에 익명 클래스라고 하며, GUI 프로그래밍, 안드로이드 프로그래밍에서 많이 사용한다. 1회용, 전용 기능을 작성할 때 주로 사용한다.
GuiButton 예제 속 익명 클래스 예제)
//화면 요소를 담는 Container 생성.
Container c = getContentPane();
//화면 요소를 배치하는 레이아웃 설정.
c.setLayout(new FlowLayout());
JButton btn3 = new JButton("Action3");
c.add(btn3);
btn3.addActionListener(new ActionListener() {
// 익명 클래스(전용 기능 제공 객체)
@Override
public void actionPerformed(ActionEvent e) {
JButton b = (JButton)e.getSource();
if(b.getText().equals("Action3")){
b.setText("액션3");
} else {
b.setText("Action3");
}
setTitle(b.getText());
}
});