코딩딩/Java

자바의 다형성

전낙타 2023. 8. 18. 17:44

 

다형성

 

추상클래스

 

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) {
		
	}
	

}