15일차 다형성, 추상클래스, 인터페이스

타입변환과 다형성

(1)다형성 (多形性, Polymorphism)

-같은 타입이지만 실행 결과가 다양한 객체 대입(이용) 가능한 성질
1)부모 타입에는 모든 자식 객체가 대입 가능
(자식 타입은 부모 타입으로 자동 타입 변환)
2)효과: 객체 부품화 가능

(2)자동 타입 변환(Promotion)

-프로그램 실행 도중에 자동 타입 변환이 일어나는 것
-바로 위의 부모가 아니더라도 상속 계층의 상위면 자동 타입 변환 가능
(변환 후에는 부모 클래스 멤버만 접근 가능)

(3)필드의 다형성

-다형성을 구현하는 기술적 방법
1)부모 타입으로 자동 변환 (다형성1)
2)재정의된 메소드(오버라이딩) (다형성2)

---------------------부모 클래스 형성 ------------------------
package polymorphismex;

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class Animal01 {

	void sound() { //자식객체에 물려줄 인스턴스 메소드 
		System.out.println("Animal::sound() invoked.");
	}//sound 
	
	
}//end class
---------------------자식 클래스 형성 ------------------------
package polymorphismex;

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class Dog02 extends Animal01 {
	
	
	
	@Override
	void sound() {
		System.out.println("Dog::sound() invoked.");

	}//sound
	
	void dogMethod() {
		System.out.println("bow - wow");
	}// dogMethod
	
	
}//end class
---------------------부모 클래스2 형성 ------------------------
package polymorphismex;

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class Cat03 extends Animal01 {
	
	
	
	@Override
	void sound() {
		System.out.println("Cat::sound() invoked.");

	}//sound
	
	void catMethod() {
		System.out.println("CCCCCCAAAAAAAAKKKKKKK");
	}// dogMethod

	
	
}//end class
-----------------------------다형성 실행---------------------------
package polymorphismex;

public class PPP04 {

	public static void main(String[] args) {
		
		// 1. 다형성-1: 부모타입의 참조변수에 모든 자식객체 대입이 가능
		Animal01 animal = new Dog02(); // OK
		System.out.println("1)animal: " + animal);
		
		//2. 다형성-2: 부모타입의 참조변수의 메소드를 호출할 때, 
		// 			   무조건 자식객체가 재정의한 메소드가 호출된다. 
//		animal.dogMethod(); xx
		animal.sound();
		
//		----
		animal = new Cat03(); // 클래스 본판 변경!
		System.out.println("2)animal: " + animal);
	
//		animal.catMethod(); xx
		animal.sound();
		
	}//main

}//end class

(4)매개변수의 다형성

-매개변수가 클래스 타입일 경우
1)해당 클래스의 객체 대입이 원칙이나 자식 객체 대입하는 것도 허용
(자동 타입 변환)(매개변수의 다형성)

---------------------------부모 클래스 형성-------------------------
package polymorphismex02;

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class Vehicle {
	
	public void run() {
		
		System.out.println("Vehicle::run() invoked.");
	}//run
}// end class
---------------------------자식 클래스 형성-------------------------
package polymorphismex02;

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class Bus02 extends Vehicle{

	@Override
	public void run() {
			
		System.out.println("Bus::run() invoked.");
	}//run

	
}//end class
---------------------------자식 클래스 형성-------------------------
package polymorphismex02;

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class Taxi03 extends Vehicle{

	@Override
	public void run() {
			
		System.out.println("Taxi::run() invoked.");
	}//run

	
}//end class
---------------------------매개변수 다형성 실행-------------------------
package polymorphismex02;

public class DriverEx05 {

	public static void main(String[] args) {
		DriverEx05 dr = new DriverEx05();

		Bus02 bus = new Bus02(); 		 // 자식객체 생성
	    Taxi03 taxi = new Taxi03();		 // 자식객체 생성
	    
	    dr.drive(bus);				// 매개변수는 부모클래스 자식객체를 인자로 전달
	    dr.drive(taxi);  			// 매개변수는 부모클래스 자식객체를 인자로 전달
	}//main

	
	public void drive(Vehicle vehicle) {
		
		System.out.println("Driver::drive(vehicle) invoked.");
		
		vehicle.run();
		
	}// drive
	
	
	
}// end class

(5)강제 타입 변환(Casting)

-부모 타입을 자식 타입으로 변환하는 것

-조건
자식 타입을 부모 타입으로 자동 변환 후, 다시 자식 타입으로 변환할 때

-강제 타입 변환 이 필요한 경우
1)자식 타입이 부모 타입으로 자동 변환
(부모 타입에 선언된 필드와 메소드만 사용 가능)
2)자식 타입에 선언된 필드와 메소드를 다시 사용해야 할 경우

---------------------------자식 클래스 형성-------------------------
package ex_04_12.casting;

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class Child extends Parent{
	public String field2;
	

	public void method3() {
		System.out.println("parent::method3 invoked.");
	}// me3
	
}// class end
---------------------------자식 클래스 2 형성-------------------------
package ex_04_12.casting;

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class Child2 extends Parent{
	public String field3;
	

	public void method4() {
		System.out.println("parent::method3 invoked.");
	}// me3
	
}// class end
---------------------------부모 클래스 형성-------------------------

package ex_04_12.casting;

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class Parent {
	public String field1;
	
	public void method1() {
		System.out.println("parent::method1 invoked.");
		
	}//me1
	public void method2() {
		System.out.println("parent::method2 invoked.");
	}// me2
	
}// class end
--------------------------- Casting-------------------------

package ex_04_12.casting;

public class ChildEx {

	public static void main(String[] args) {
		Parent parent = new Child();
		
		parent.field1 = "data1";
		parent.method1();
		parent.method2();
		
//		-----------
		
//		parent.field2 = "data2"; 에러 
//		parent.method3() ;    에러  
// 		이유: 부모클래스에는 해당 필드와 메소드가 없고 이를 참조타입으로 삼았기 때문에 안됌.
     		
//		-------
		
		// 자식객체 고유의 필드와 메소드를 사용해야 할 때에는 어떻게 합니까 ? 
		Child child =(Child) parent; // 다형성-1이 전제조건하에서 ,  자식객체를 빼낼 때 필요
		//단 child 1인지 2인지 3인지 자식이 무수히 많을 때 정확하지 않을 수도 있다. 
		
		
		child.field2 = "yyy";  //가능
		child.method3();  //
		
		
		
//		-------정확하지 않음에 검사해주는 instanceof를 사용한다. 
		if(parent instanceof Child) {
			Child child2  =  (Child) parent;
			
			child2.field2 = "yyy";  //가능
			child2.method3();  //가능
		}// if 
		// 이는 자바에 엄청나게 부담이 되기때문에 이를 해결하기위해 제네릭이 나옴
		
	}//main

}//end class

추상 클래스(Abstract Class)

(1)추상 클래스 개념

  • 실체들 간에 공통되는 특성을 추출한 것

  • 추상 클래스(abstract class)
    1)실체 클래스들의 공통되는 필드와 메소드 정의한 클래스
    2)추상 클래스는 실체 클래스의 부모 클래스 역할 (단독 객체 X)

(2)추상 클래스의 용도

-실체 클래스의 공통된 필드와 메소드의 이름 통일할 목적
(1)실체 클래스를 설계자가 여러 사람일 경우,
(2)실체 클래스마다 필드와 메소드가 제각기 다른 이름을 가질 수 있음

-실체 클래스를 작성할 때 시간 절약
(1)실체 클래스는 추가적인 필드와 메소드만 선언

-실체 클래스 설계 규격을 만들고자 할 때
(1)실체 클래스가 가져야 할 필드와 메소드를 추상 클래스에 미리 정의
(2)실체 클래스는 추상 클래스를 무조건 상속 받아 작성

(3)추상 클래스 선언(abstract 키워드 )

-New 연산자로 객체 생성하지 못하고 상속 통해 자식 클래스만 생성 가능

(4)추상 메소드와 오버라이딩(재정의)

-메소드 이름 동일하지만, 실행 내용이 실체 클래스마다 다른 메소드

-구현 방법
1)추상 클래스에는 메소드의 선언부만 작성 (추상 메소드)
2)실체 클래스에서 메소드의 실행 내용 작성(오버라이딩(Overriding))

----------------------------추상클래스/메소드 선언 ---------------------------
package ex_04_12.abstractex;

public abstract class Animal { //객체를 직접 생성 불가 
	public String kind;
	
	public void breathe() {
		System.out.println("Animal::breathe() invoked.");
	} // breathe
	
	//추상메소드란? 구현 block이 없이 메소드 선언부만 있는 경우를 의미 
	public abstract void sound(); // 추상메서드 : 강제규격 (To 자식 재정의를...) 
	
}// end class
---------------------------오버라이딩 및 추상메서드 구현------------------------
package ex_04_12.abstractex;

public class Cat extends Animal { 
	
	
	
	public Cat() {
		this.kind= "포유류";
	}
	
	
// 	무조건 재정의 하거나 자식도 abstract 지정해준다.
	@Override
	public void sound() {
		System.out.println("야옹");
	};  
	
}// end class

인터페이스

(1)인터페이스

-개발 코드와 객체가 서로 통신하는 접점
(개발 코드는 인터페이스의 메소드만 알고 있으면 된다.)

-인터페이스의 역할
개발 코드가 객체에 종속되지 않게 -> 객체 교체할 수 있도록 하는 역할
개발 코드 변경 없이 리턴값 또는 실행 내용이 다양해 질 수 있음 (다형성)

(2)인터페이스 선언

-interface 식별자 관례 - class 규칙 따르면서 앞에 i를 붙여서 인터페이스임을 구별
-인터페이스에 선언된 필드는 모두 public static final
-선언과 동시에 초기값 지정(static { } 블록 작성 불가)
-추상 메소드 선언
-디폴트 메소드 선언
-정적 메소드 선언

--------------------------인터페이스 선언 ---------------------------
package ex_04_12.interfaceex;

//1. member : static final 상수 선언
//2. member : 추상 메소드 선언
//3. member : default 메소드 (기본 메소드 )
//4. member : static 메소드 (공용 메소드 )
public interface RemoteControl {
	
	public static final int MAX_VOLUME =10;
	
	int MIN_VOLUME =0;  // interface에서는 접근제한자 static final이 생략된다. 컴파일러가 자동으로 붙임
	//하지만 이렇게 적어주지말자 오해한다. 
	
	//추상메서드 : 자식클래스에서 반드시 재정의시킬 강제 규격
	void turnOn(); // public abstract가 생략 가능 하지만 생략하지마라!
	public abstract void turnOff();
	public abstract void setVolume(int volume);
	
	
	//default 메소드 
	public default void setMute(boolean mute) {
		if(mute) {
			System.out.println("무음을 처리합니다");
		} else {
			System.out.println("무음을 해제합니다");
		}// if - else
	}//setmute
	
	
	
	//정적 메소드 
	public static void changeBattery() {
		System.out.println("베터리를 교체합니다");
		
	}//changeBattery
	
	
} // end interface

(3)인터페이스 구현

-구현 객체와 구현 클래스
(인터페이스의 추상 메소드 대한 실체 메소드를 가진 객체 = 구현 객체)
(구현 객체를 생성하는 클래스 = 구현 클래스)

-구현 클래스 선언
자신의 객체가 인터페이스 타입으로 사용할 수 있음(implements 키워드)

-추상 메소드의 실체 메소드를 작성하는 방법
메소드의 선언부가 정확히 일치해야한다.
(일부만 재정의할 경우, 추상 클래스로 선언)

------------------------------인터페이스 구현 클래스1 생성------------------------
package ex_04_12.interfaceex;

import lombok.NoArgsConstructor;

//인터페이스: "부모", 구현클래스: "자식"
@NoArgsConstructor
public class Television implements RemoteControl{
	//필드 
	private int volume;
	
	
	
	@Override
	public void turnOn() {
		System.out.println("Audio를 켭니다.");
	}; 
	@Override
	public  void turnOff() {
		System.out.println("Audio를 끕니다.");
	};
	@Override
	public  void setVolume(int volume) {
		if(volume > RemoteControl.MAX_VOLUME) {
			this.volume = RemoteControl.MIN_VOLUME;
		} else if(volume < RemoteControl.MIN_VOLUME) {
			this.volume = RemoteControl.MAX_VOLUME;
		}else {
			++volume;
		}
		
	}// setVolume
	
}// end class
------------------------------인터페이스 구현 클래스2 생성------------------------
package ex_04_12.interfaceex;

import lombok.NoArgsConstructor;

//인터페이스: "부모", 구현클래스: "자식"
@NoArgsConstructor
public class Audio implements RemoteControl{
	//필드 
	private int volume;
	
	
	
	@Override
	public void turnOn() {
		System.out.println("Audio를 켭니다.");
	}; 
	@Override
	public  void turnOff() {
		System.out.println("Audio를 끕니다.");
	};
	@Override
	public  void setVolume(int volume) {
		if(volume > RemoteControl.MAX_VOLUME) {
			this.volume = RemoteControl.MIN_VOLUME;
		} else if(volume < RemoteControl.MIN_VOLUME) {
			this.volume = RemoteControl.MAX_VOLUME;
		}else {
			++volume;
		}
		
	}// setVolume
	
}// end class

(4)인터페이스 사용

-추상 메소드 (실제 구현된 객체에서)
-디폴트 메소드
1)인터페이스만으로는 사용 불가(인스턴스메소드)
2)모든 구현 객체가 가지고 있는 기본 메소드로 사용
-정적 메소드
인터페이스로 바로 호출 가능 (인터페이스명.메소드명)

--------------------------인터페이스 구현 클래스 사용 ----------------------------
package ex_04_12.interfaceex;

public class RemoteControlExample {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		RemoteControl rc;

		rc = new Television(); //다형성 1
		System.out.println("1. rc: " + rc);
		
		rc.turnOn();  // 다형성 2 
		
		rc = new Audio(); // 다형성 1 
		System.out.println("1. rc: " + rc);
		
		rc.turnOn();

	} // main

} // end class

(5)익명 구현 객체

-명시적인 구현 클래스 작성 생략하고 바로 구현 객체를 얻는 방법
(이름 없는 구현 클래스 선언과 동시에 객체 생성)
(인터페이스의 추상 메소드들을 모두 재정의하는 실체 메소드가 있어야 한다)

------------------------------------익명 구현 객체 사용 ------------------------------
package ex_04_12.interfaceex.noname;

public class RemoteControlExample {

	public static void main(String[] args) {
		//익명 구현 rc에 저장
		RemoteControl rc = new RemoteControl() {  
			
			String name = "kkk";
			int age = 23; 
			
			
			public void myMethod() {
				System.out.println("Anonymous::myMethod() intvoked.");
			} 
			
			
			@Override
			public void turnOn() {
				System.out.println("Anonymous::turnOn() intvoked.");
				System.out.println("\t + name:" + name);
				
			}//turnOn

			@Override
			public void turnOff() {
				System.out.println("Anonymous::turnOff() intvoked.");
				System.out.println("\t + name:" + age);
			}//turnOff

			@Override
			public void setVolume(int volume) {
				
				System.out.println("Anonymous::setVolume() intvoked.");
			}//setVolume
			
		};
		
		System.out.println(rc);
		//다형성 -2 
		rc.turnOn();
		rc.setVolume(10);
		rc.turnOff();
		
		//인터페이스를 통한 모든 구현객체의 기능 확장 
		rc.setMute(true); //default 메소드 
		RemoteControl.changeBattery(); // static 메소드
	
		
		
		
//		----
//		System.out.println(rc.name); 익명객체에서 구현된 오버라이딩 외의 멤버는 밖에서 사용 불가능
//		System.out.println(rc.myMethod);
		
	}//main

} // end class

(6)다중 인터페이스 구현 클래스 /인터페이스간 상속

-다중 인터페이스 구현 클래스는 인터페이스의 실체 메소드 모두 구현
-하위 인터페이스 구현 클래스는 아래 추상 메소드를 모두 재정의해야

---------------------------------인터페이스와 상속 동시 예제 -----------------------
--------------------------------인터페이스 생성 -------------------------------
package ex_04_12.multi;

public interface Searchable {
	
	public abstract void search(String url);
}// end interface
-------------------------------클래스 생성--------------------------------
package ex_04_12.multi;

import ex_04_12.interfaceex.RemoteControl;

public class SmartTelevision {

	private int volume;
	
	public void turnOn() {
		System.out.println("Audio를 켭니다.");
	}; // t on
	
	public  void turnOff() {
		System.out.println("Audio를 끕니다.");
	};// t  off
	public  void setVolume(int volume) {
		if(volume > RemoteControl.MAX_VOLUME) {
			this.volume = RemoteControl.MIN_VOLUME;
		} else if(volume < RemoteControl.MIN_VOLUME) {
			this.volume = RemoteControl.MAX_VOLUME;
		}else {
			++volume;
		}
		
	}// setVolume

}//class
-----------인터페이스와 클래스 상속을 받는 클래스 생성----------------------
package ex_04_12.multi;

public class SmartTvEx extends SmartTelevision implements Searchable {

	public static void main(String[] args) {
		SmartTelevision tv = new SmartTvEx();
		
		tv.turnOn();
//		tv.search("naver.com")  SmartTelevision에 메소드 정의 안되어있어서 안됌 
		
		
		 Searchable Stv= (Searchable) tv;
		 Stv.search("naver.com");
//		 Stv.turnOn(); Searchable 에는 메소드 정의 안되어있어서 안됌 
		 
		 
		 SmartTvEx smart = (SmartTvEx) Stv;
		 smart.turnOn();
		 smart.turnOff();
		 smart.search("naver.com");
		 
	}//main

	@Override
	public void search(String url) {
		System.out.println(url);
	} // search

}//class

(7)디폴트 메소드와 인터페이스 확장

-디폴트 메소드와 확장 메소드 사용하기
-디폴트 메소드가 있는 인터페이스 상속
-부모 인터페이스의 디폴트 메소드를 자식 인터페이스에서 활용 방법
1)디폴트 메소드를 단순히 상속만 받음
2)디폴트 메소드를 재정의(Override)해서 실행 내용을 변경
3)디폴트 메소드를 추상 메소드로 재선언

-------------------------------------다중인터페이스와 인터페이스끼리의 상속 ----------------------------
------------------------부모 인터페이스 생성-------------------------
package ex_04_12.interface_extends;

public interface A {
	public abstract void methodA();
}
------------------------부모 인터페이스 생성-------------------------
package ex_04_12.interface_extends;

public interface B {
	public abstract void methodB();
	public default void methodBB() {
	}
}
----------------2명의 부모를 가진 자식 인터페이스 생성/ 디폴트 메소드 추상화--------------------
package ex_04_12.interface_extends;

public interface C extends A,B{ // 인터페이스의 상속은 여러개 가능 
	public abstract void methodC();
	
//	@Override
//	public abstract void methodBB(); //default 추상메서드로 재선언 
}
-------------------인터페이스들과 아무 관계 없는 인터페이스 ----------------
package ex_04_12.interface_extends;

public interface D {
	public abstract void methodD();
}
------------------------모두를 최종으로 다중 상속받는 클래스/디폴트 재선언----------------- 
package ex_04_12.interface_extends;

public class Cplaing implements C,D{

	@Override
	public void methodA() {
		System.out.println("A구현");
	}//A  주석처리하면 오류난다.

	@Override
	public void methodB() {
		System.out.println("B구현");
	}//B 주석처리하면 오류난다.  이유: C가 A,B를 상속했기 때문에 

	@Override
	public void methodC() {
		System.out.println("C구현");
	}//C
	@Override
	public void methodBB() {} // 상속받은 default 메소드 실행내용을 변경

	@Override
	public void methodD() {
		
	}
}
--------------------------최종 사용 예제 --------------------------------
package ex_04_12.interface_extends;

public class Example {
	public static void main(String ... args) {
		Cplaing ex = new Cplaing(); //구현 객체 생성.
		
		A a = ex ;			// 할아버지 인터페이스 
		a.methodA();
		
		B b = ex;			// 할머니 인터페이스 
		b.methodB();
		
		C c = ex;			// 부모 인터페이스 
		c.methodC();
		c.methodB();
		c.methodA();
		c.methodBB();
		//구현 객체만 생성하면 조상의 조상 인터페이스까지 참조타입으로 가능하다.
		
		
	}//main
}//end class

좋은 웹페이지 즐겨찾기