다형성
추상클래스
package oop.polymorphism;
/*
* 추상클래스
* => 상위클래스의 역할을 하는 클래스
* => 객체를 생성할 수 없는 클래스(미완성된 클래스)
* => 내용이 구현되어 있지 않은 메소드를 포함하고 있는 클래스를 추상 클래스라 한다.
* -----------------------
* 추상 메소드(body가 없는 메소드)
* 1) 추상 메소드를 선언하는 방법
* 접근제어자 abstract 리턴타입 메소드명 (매개변수1, 매개변수2....);
* 2) 추상클래스의 특징
* - 추상메소드가 하나라도 정의되어 있으면 추상클래스가 된다. 추상클래스는 선언부에 abstract을 추가한다.
* - 추상 클래스에는 추상 메소드와 일반 메소드를 모두 정의할 수 있다.
* - 추상 클래스는 객체생성을 할 수 없는 클래스
* - 추상 클래스를 상속받는 클래스는 extends하면 에러가 발생
* => Child 클래스가 Parent를 상속받는다.
* Parent클래스의 모든 멤버(메소드, 필드)가 Child의 소유가 된다.
* Child 클래스는 Parent클래스의 일반 메소드인 test 메소드와 추상메소드인 display를 소유하므로 Child 클래스도
* 추상 클래스가 된다.
* [ 에러처리 ]
* 1. Child 클래스에 abstract을 추가한다.
* 2. Child가 상소고받은 추상메소드를 재정의한다. (오버라이딩)
*
* - abstract 클래스는 상위 클래스로 사용하기 위해서 정의(상위클래스로 사용할 목적으로 정의되며 실제 타입으로 선언되어 사용)
* - abstract 메소드는 하위 클래스에서 반드시 오버라이딩 되어야 한다는 것을 문법적으로 제시
*/
abstract class Parent{
// 추상 메소드는 추상 클래스에서만 선언할 수 있으며 추상 클래스에는 일반 메소드를 선언할 수 있다.
public void test() {
System.out.println("test - 일반메소드");
}
// 추상메소드
public abstract void display(String msg);
}
class Child extends Parent {
@Override
public void display(String msg) {
System.out.println(msg);
}
}
public class AbstractTest {
public static void main(String[] args) {
// 추상 클래스는 직접적으로 객체를 생성할 수 없음.
// Parent obj = new Parent();
Parent obj = new Child();
obj.display("test");
}
}
타입 변환과 다형성
package oop.polymorphism;
import java.util.AbstractCollection;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Stack;
import java.util.Vector;
// 객체의 형변환
// 참조형에서의 형변환은 상속관계에서만 성립한다.
class Super{
String data = "상위 data";
public void display() {
System.out.println("상위 클래스의 display");
}
}
class Sub extends Super{
String data = "하위 data";
public void display() {
System.out.println("하위 클래스의 display");
}
public void test() {
System.out.println("하위 클래스의 test");
}
}
public class RefTypeCastingTest1 {
public static void main(String[] args) {
// AbstractCollection c1 = new Vector();
// AbstractList c2 = new Vector();
// AbstractList c3 = new Stack();
// Vector c4 = new Stack();
// 상속관계에 속해있지 않아 에러가 발생한다.
// ArrayList c5 = new Vector();
System.out.println("1. Super 타입의 참조 변수로 Super 객체를 사용.");
Super obj = new Super();
obj.display();
System.out.println(obj.data);
System.out.println("-------------------------------");
System.out.println("2. Sub 타입의 참조 변수로 Sub 객체를 사용.");
Sub obj2 = new Sub();
obj2.display(); // 오버라이딩된 메소드가 우선으로 호출된다.
System.out.println(obj2.data); // obj2 변수가 어떤 타입이냐에 따라서 해당 타입이 갖고 있는 변수값을 가져온다.
// 상속관계에서 동일한 타입의 변수가 있는 경우 상위타입보다는 나의 변수가 우선 인식
System.out.println("-------------------------------");
System.out.println("3. Super 타입의 참조 변수로 Sub 객체를 사용.");
// 자동 형변환
// obj3 참조변수가 Super 타입이므로 Super의 멤버만 접근할 수 있다.
// 단, Sub객체를 참조하므로 오버라이딩된 메소드가 있는 경우 오버라이딩된 메소드가 먼저 실행
// new Sub가 가능한 이유는 Sub객체가 참조변수 타입인 Super 정보를 가지고 있으므로 가능
Super obj3 = new Sub();
obj3.display();
System.out.println(obj3.data);
// obj3이 Super 타입이르모 Super의 멤버만 사용 가능하지만 참조하는 객체가 Sub 타입이므로 명시적 형변환이 가능
((Sub)obj3).test();
System.out.println(((Sub)obj3).data);
System.out.println("-------------------------------");
System.out.println("4. Sub 타입의 참조 변수로 Super 객체를 사용.");
// 실제 사용되는 변수의 타입에 대한 정보가 생성되는 객체에 없기 때문에 사용할 수 없다.
// Sub obj4 = new Super(); -------- 에러 발생
System.out.println("-------------------------------");
System.out.println("5. Sub 변수 = Super 객체를 참조하는 변수.");
// 명시적으로 캐스팅을 하면 컴파일러는 속일 수 있으나(상속관계에 있어야만 속는다.)
// obj1이 참조하는 객체가 Super이므로 실행할때 캐스팅 오류가 발생한다.
// Sub obj5 = (Sub)obj;;
System.out.println("-------------------------------");
System.out.println("6. Sub 변수 = Super 객체를 참조하는 변수.");
// obj3은 Super타입이므로 자동캐스팅은 불가능
// 명시적으로 캐스팅하면 가능 - obj1과 다르게 실제 참조하는 객체가 Sub타입이므로 참조변수의 모든 정보를 갖고 있으므로 가능
Sub obj6 = (Sub)obj3;;
}
}
인터페이스
package oop.polymorphism;
/*
* [[ 인터페이스 ]]
* => 추상메소드만 보관하는 특별한 클래스
* 인터페이스를 사용하면 다형성을 적용할 수 있고 다중상속을 구현할 수 있다.
* 인터페이스는 상위타입으로 사용되는 특별한 클래스
*
* 1. 인터페이스를 정의하는 방법은 interface 키워드를 이용해서 정의
* 2. 인터페이스는 추상 메소드만 정의하는 특별한 클래스이므로
* - 인터페이스에 정의하는 메소드는 public과 abstract 은 생략이 가능(abstract을 추가하지 않아도 추상 메소드로 인식)
* - 하위 클래스에서 오버라이딩 될때 자동으로 public이 추가되고
* - 나머지 리턴타입이나 매개변수는 일반 메소드와 동일
*
* 3. 클래스가 인터페이스를 상속하는 경우 implements 키워드를 이용해서 구현
* 4. 인터페이스가 인터페이스를 상속하는 경우 extends 키워드를 이용해서 구현
* - 인터페이스끼리 상속하는 경우 다중 상속이 가능
* - ,를 이용해서 상속할 인터페이스를 정의
* 5. 클래스가 인터페이스를 상속하는 경우 다중상속이 가능하다.
* - ,로 구분한다.
* 6. 클래스가 인터페이스와 클래스를 모두 상속하는 경우 클래스상속이 인터페이스 상속보다 먼저 정의되어야 한다.
* Class A extends Super implement InterA {
* -------
* implements보다 먼저 정의되어야 한다.
* }
*/
interface SuperInterfaceA {
void show(); // public abstract void show() 로 정의한것으로 인식
int test(String name);
}
interface InterA{
void test();
}
interface InterB{
void change();
}
interface ChildInter extends InterA, InterB{
}
class MyClass implements SuperInterfaceA{
@Override
public void show() {
// TODO Auto-generated method stub
}
@Override
public int test(String name) {
// TODO Auto-generated method stub
return 0;
}
}
public class MyInterFaceTest {
public static void main(String[] args) {
}
}
'코딩딩 > Java' 카테고리의 다른 글
모던 자바 인 액션 Chapter 1 (0) | 2024.08.15 |
---|---|
List에 담긴 Entity를 DTO로 변환하며 정렬하는 방법 (0) | 2024.01.11 |
스프링 컨테이너와 스프링 빈 (0) | 2023.08.18 |
Static Member, 상속 (0) | 2023.08.17 |
Setter Getter Constructor (0) | 2023.08.16 |