추상클래스와 인터페이스
다형성 보장
부모가 명령을 내리면 자식이 반드시 동작(반응)을 해야한다.
정보 은닉, Override(재정의), Upcasting, 동적 바인딩의 다형성 전제조건 4가지를 필수로 만족해야한다.
반드시 재정의가 되어야 한다.
- 부모 클래스가 추상적으로 설정하면 무조건 자식 클래스에서 재정의를 해야한다.
- 재정의를 하면 다형성을 보장한다.
부모 클래스를 추상적으로 만든다.
추상 클래스(불완전한 클래스)
- 메서드의 구현부가 없는 메서드
- 반드시 자식이 완전하게 재정의를 통해 해야한다.
// 추상클래스(불완전한 클래스)
public abstract class Animal{
// 추상 메서드(불완전한 메서드) : 메서드의 구현부가 없다.
public abstract void eat();
}
public class IsNotOverride {
public static void main(String[] args) {
// 재정의를 안했기 때문에 -> 부모가 명령을 내리면(메세지를 보내면) 오동작을 한다.
// [다형성을 보장하지 않음] -> 그러면 다형성을 보장할려면?(재정의를 강제로 하도록 만들어 주면 된다)
// 추상클래스, 인터페이스 등장
// [다형성이 보장이 된다.]
Animal ani = new Dog();
ani.eat();
ani = new Cat();
ani.eat();
}
}
public class Cat extends Animal { // Animal->eat();
// 재정의를 하지 않음(x) --->오류입니다(재정의를 하세요)
// 부모가 추상적이기 때문에 재정의를 반드시 해야한다.-> 구현해야한다. 바디({ })를 만들면된다.
public void night(){
System.out.println("밤에 눈에서 빛이난다");
}
@Override
public void eat() {
System.out.println("고양이처럼먹다.");
}
}
추상클래스와 다형성
- 추상클래스란?
- 다형성을 일부 보장하기 위해서 등장
- 서로 비슷한 클래스의 공통 부분을 묶을 때 사용
- 단독으로 객체를 생성 할 수 없다.
- 부모의 역할로 사용한다.(Upcasting)
- 구현된 메서드를 가질 수 있다.
- 상속을 하다 보면 자연스럽게 추상클래스를 사용하게 된다.
- public abstract void eat();
// 추상클래스(불완전한 클래스)
public abstract class Animal{
// 추상 메서드(불완전한 메서드) : 메서드의 구현부가 없다.
public abstract void eat();
// 구현메서드
public void move(){
System.out.println("무리를 지어서 이동한다.");
}
}
public class AbstractClassTest {
public static void main(String[] args) {
// 추상클래스는 단독으로 객체를 생성할 수 없다.
// Animal ani = new Animal(); // cannot be instantiated(단독으로 객체를 생성 할 수 없다)
Animal ani = new Dog(); // 추상 클래스는 부모의 역할은 할 수 있다.
ani.eat(); // 개처럼 먹다
ani.move();
ani=new Cat();
ani.eat(); // 고양이처럼먹다.
ani.move();
((Cat)ani).night();
}
}
인터페이스
서로 다른 동작을 가지는 클래스를 상속관계로 만들어서 동작을 시켜야 한다고 가정해보자
- 서로 다른 동작의 클래스도 공통기능을 만들어서 상속구조로 사용이 가능할까?
일반 클래스
- 재정의를 해도 되고 안 해도 되기 때문에 다형성을 보장 할 수 없다.
추상 클래스
- 재정의를 하게 만들어서 다형성을 보장 할 수 있지만 구현 클래스를 가질 수 있어서 하위 클래스가 오동작 할 수 있다.
- 서로 다른 동작을 가지는 클래스 이기 때문에
- 재정의를 하게 만들어서 다형성을 보장 할 수 있지만 구현 클래스를 가질 수 있어서 하위 클래스가 오동작 할 수 있다.
인터페이스를 이용한 클래스 동작
- 다형성이 보장된다.
인터페이스
- 다형성을 100% 보장하기 위해서 등장
- 서로 다른 클래스의 공통부분을 묶을 때 사용
- 단독으로 객체를 생성 할 수 없다
- 부모의 역할로 사용한다.(Upcasting)
- 추상 메서드와 final static 상수만 올 수 있다.
- 구현된 메서드를 가질 수 없다.
- 다중 상속을 지원하기 위해 나타난 개념
인터페이스에서 사용하는 final static 상수
- 인터페이스 = 추상메서드 + final static 상수
- final은 최종 → 변경 불가
다중상속을 지원하는 인터페이스
자바는 단일 상속
// 자바는 단일 상속만 지원하지만 다중 상속처럼 보이게 할 수 있다. // Dog는 Animal 클래스를 상속 받고, Pet과 Robots 인터페이스를 구현했다. public class Dog extends Animal implements Pet, Robots{ } // 인터페이스가 인터페이스를 상속 public interface B extends A{ } public class C implements B{ } B obj = new C(); A obj = new C();
- 추상클래스 vs 인터페이스
- 추상 클래스 : 추상메서드 + 구현 메서드
- 인터페이스 : 추상메서드 + final static 상수
- 공통점
- 다형성을 보장 하기 위해서 등장 된 개념
- 추상 메서드를 가질 수 있다
- 단독으로 객체를 생성 할 수 없다
- 부모의 역할로 사용한다.(Upcasting)
- 차이점
- 서로 비슷한 클래스의 공통 부분을 묶을 때 사용 → 추상 클래스
- 추상 메서드와 구현 메서드를 가질 수 있다.
- 서로 다른 클래스의 공통 부분을 묶을 때 사용 → 인터 페이스
- 추상 메서드와 final static 상수를 가질 수 있다.
- 서로 비슷한 클래스의 공통 부분을 묶을 때 사용 → 추상 클래스
## 자바 최상위 클래스 Object
### Object 클래스를 이용하여 객체 생성하기
- 어떤 클래스 한 개를 만들 때 생략된 코드?
- default pakage ( import java.lang)
- java.lang.Object(최상위 클래스) : extends Object
- default 생성자 : public A(){ super() }
- Object 클래스에 업캐스팅을 하면 자식 클래스의 메서드를 사용할 수 없기 때문에 다운 캐스팅을 하여서 사용
```java
Object obj = new A(); // Upcasting
((A)obj).display(); // Downcasting
```
### Object 클래스 다형성 인수로 활용
- Object 타입으로 Upcasting되면 반드시 Downcasting을 하게 되어 있다.
```java
public class ObjectPolyArg {
public static void main(String[] args) {
A a = new A();
display(a);
B b = new B(); // Upcasting
display(b);
}
// Upcasting을 하면 Downcasting을 해야한다.
private static void display(Object obj) { // 다형성 인수 활용
if (obj instanceof A){
((A)obj).printGo(); // Downcasting
}
else{
((B)obj).printGo();
}
}
}
```
- 다형성 배열로 Object[] 배열 활용하기
```java
public class ObjectPolyArray {
public static void main(String[] args) {
// A, B 클래스를 저장할 배열을 생성하세요
Object[] obj = new Object[2]; // 다형성 배열
obj[0] = new A();
// ((A)obj[0]).printGo();
obj[1] = new B();
// ((B)obj[1]).printGo();
display(obj);
}
private static void display(Object[] obj) {
for (int i = 0; i < obj.length; i++) {
if (obj[i] instanceof A){
((A)obj[i]).printGo();
}else{
((B)obj[i]).printGo();
}
}
}
}
```
- Object 클래스의 toStirng()메서드
- toString()
- 객체의 번지를 문자열로 출력
- Object안의 toString은 보통 재정의 해서 사용
- `super.toString()); // 상위 클래스의 메서드 호출`
```java
public class ObjectTostring {
public static void main(String[] args) {
Board b = new Board();
b.setTitle("게시글입니다");
// System.out.println(b.getTitle());
System.out.println(b.toString()); // Object를 상속 받았기 때문에 b의 번지가 나온다.
// fc.java.poly.Board@776ec8df(재정의 하기 전)
// 게시글입니다 -> 재정의 한 후(toString())
}
}
public class Board extends Object{
private String title;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
// // Override
// public String toString(){
// return title;
// }
@Override
public String toString() {
System.out.println(super.toString()); // 상위 클래스의 메서드 호출
return "Board{" +
"title='" + title + '\'' +
'}';
}
}
```