[220927] 다형성

최수정·2022년 9월 27일
0

멋쟁이사자처럼

목록 보기
3/14
post-thumbnail

다형성 (폴리몰피즘)

  • 객체들의 타입이 다르면 똑같은 메시지(함수)가 전달되더라도
    서로 다른 동작을 하는 것.

  • 조상 타입 참조변수로 자손 타입 객체를 다루는 것
Tv t = new SmartTv();

객체와 참조변수의 타입이 일치할 때와 일치하지 않을 때의 차이는 ❓
일치할 땐, 모든 멤버변수와 메서드에 접근 가능하지만 일치하지 않을때에는 객체가 가지고 있는 변수나 메서드를 다 사용할 수 없다. 조상 클래스가 가지고 있는 기능 만을 수행한다.
예시) TV리모컨으로 SmartTV를 동작하면 TV기능만을 사용할 수 있다. 유투브 되는데 리모컨엔 유투브가 없어

💡 주의점
1. 부모 = 자식
2. 오버라이딩은 자식꺼
3. 자식 = 부모 기본적으로 안됨.
“ 하위 객체를 상위 클래스형 변수에 대입 “

Shape shape = new Circle()

code

class Cake {
	public void yummy() {
		System.out.println("Yummy Cake");
	}
}

class CheeseCake extends Cake {
	public void yummy() {
		System.out.println("Yummy CheeseCake");
	}
    
    public void yummy2() {
        System.out.println("하위클래스에만 있는 메소드");
    }
}

public class Hello {

	public static void main(String[] args) {
		
		Cake c1 = new CheeseCake();
		CheeseCake c2 = new CheeseCake();
		
		c1.yummy();  // 출력값: "Yummy CheeseCake
		c2.yummy();  // 출력값: "Yummy CheeseCake

	   Cake c3 = new Cake();
	   c3.yummy2();  // 오류
	}

}

객체와 참조변수의 타입이 일치할 때와 일치하지 않을 때의 차이는 ❓
일치할 땐, 모든 멤버변수에 접근 가능하지만 일치하지 않을때에는 객체가 가지고 있는 변수나 메서드를 다 사용할 수 없다. 조상 클래스가 가지고 있는 기능 만을 수행한다.
예시) TV리모컨으로 SmartTV를 동작하면 TV기능만을 사용할 수 있다. 유투브 되는데 리모컨엔 유투브가 없어


(1) 참조변수의 형변환

💡 개념
-사용할 수 있는 멤버의 갯수를 조절한다.
-조상, 자손 관계의 참조변수만 서로 형변환 가능하다.

  • 업캐스팅

자동형변환, 부모 = 자식();, 자식 객체를 부모 객체로 형변환한다.

  • 다운캐스팅

"자신의 고유한 특성을 잃은 자식 클래스의 객체를 다시 복구 시켜주는 것"
즉, 업캐스팅된 것을 다시 원상태로 돌리는 것

🔽 형변환 code

// 업캐스팅, 다형성을 적용한 것
Shape s = new Circle();

// 다운캐스팅
Shape s = new Circle(); // Circle클래스에만 있는 함수 사용불가! -> Circle특성 잃어버림ㅠ
Circle c = (Circle) s; // Circle 클래스에만 있는 함수도 사용가능! -> Circle특성 복구완료~

Q1
데이터 타입은 heap 메모리에 접근할 수 있는 범위를 제한시킨다.

Parent p = new Child();
Child c = (Child)p;   

Child c = (Child)p 처럼 형변환을 하게 된다면 참조변수 c는 heap 메모리에 있는 Child 객체까지 접근할 수 있기 때문에 오류가 나지 않는다.

Q2
참조변수의 형변환은 왜 하는가?
-> 참조변수(리모콘)을 변경함으로써 사용할 수 있는 멤버의 갯수를 조절하기 위해서


(2) instanceof 연산자

개념
-참조변수를 형변환하기 전에 형변환 가능여부 확인에 사용. 가능하면 true 반환한다.
-참조형 객체에만 사용가능하다.

🔽 순서
1. instanseof 연산자를 통해 형변환이 되는지 확인
2. 형변환 사용

🔽 코드

	void doWork (Car c)  {
			if (c instanceof FireEngine) { //1. 형변환 가능한지 확인
				FireEngine fe = (FireEngine) c; // 2. 형변환
				fe.water();			
			}
		}

(3) 다형성의장점

  1. 다형적 매개변수
  2. 하나의 배열로 여러종류 객체 다루기

매개변수의 다형성
참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다.

여러 종류의 객체를 배열로 다루기
조상타입의 배열에 자손들의 객체를 담을 수 있다.

🔽 code

class Buyer { //물건 사는 사람
	int money = 1000; // 소유금액
	int bonusPoint = 0; // 보너스점수 
	
	Product[] cart = new Product[10]; // 장점2)구입한 물건(객체)를 담을 배열
	
	int i = 0;
	
	void buy (Product p) { // 장점1)매개변수의 다형성, 메서드의 매개변수가 참조형 변수이다. 
		if (money < p.price) {
			System.out.println("잔액부족");
			return;
		}
		
		money -= p.price;
		bonusPoint += p.bonusPoint;
		cart[i++] = p;
	}
}

추상클래스와 인터페이스

둘의 차이점은 ❓
추상클래스는 일반 클래슨데 추상메서드를 가지고 있는것이고, 인터페이스는 완전히 아무것도 없는 추상메서드의 집합이다 ( 인터페이스는 iv를 가질 수 없으므로 ).

(1) 추상클래스 abstract

추상클래스는 왜 쓰는 걸까 ❓
-> 상속관계 관리하기 쉽다. 추상 메소드로 정의되면 자식클래스에서 반드시 오버라이드 해야하므로 자식클래스가 무조건 써야할 함수를 지정하기도 좋다. 또한 부모 클래스에서 메소드를 초기화하지 않아도 된다.

추상클래스화
1. 생성한 함수의 바디 부분을 없앤다.
2. 메소드와 클래스 앞에 abstract 넣어준다.
( 즉, 미완성이란 말은 함수 바디를 구현하지 않겠다는 것이다.)
3. 추상클래스를 상속받으면 추상메소드를 '구현'하여야한다.
4. 추상클래스는 일반메서드도 포함할 수 있다.

abstract class Animal {
	public abstract void move(); 	
}

class Lion extends Animal {

	@Override
	public void move() {
		System.out.println("사자의 move 메소드입니다.");
	}
	
}

public class Hello2 {

	public static void main(String[] args) {
		// 추상클래스는 기본적으로 객체생성이 되지 않는다. 
		// Animal animal = new Animal(); 
		Lion lion = new Lion();
		lion.move();
		

	}

}

주의점
추상클래스는 기본적으로 객체 생성이 안된다. 따라서 추상클래스 안의 추상메소드를 사용하려면 추상클래스를 상속받아 추상메소드를 구현하여야한다.


(2) 인터페이스

✍️개념
인터페이스 = 약속 = 강제 = 표준
-추상메서드의 집합 + 상수
-구현된 것이 전혀 없는 설계도 (모든 멤버가 public)
-다중 상속이 가능하다. (추상메서드는 충돌해도 문제 없음)
-인터페이스의 최고조상은 object가 아닌 인터페이스

✍️문법
1. 인터페이스 정의는 예전 클래스 자리에 오는 자리다.
2. 메소드에 몸체가 없다. ( 무조건 추상함수만 가진다 )
3. 객체생성 불가~~~ 참조변수 선언가능
4. 추상메소드를 자식클래스에서 구현해야한다. 일부만 구현하는 경우, 자식클래스 앞에 abstract를 붙여야 한다.

🔽 다중상속효과, 문법 예시

interface Drivable {
	void drive();
}

interface Flyable {
	void fly();
}
class FlyingCar implements Drivable,Flyable {
	// 이와 같이 두 인터페이스 모두 implement할 수 있다. 
    @Override
	public void fly() {
		System.out.println("날수 있습니다.");	
	}

	@Override
	public void drive() {
		System.out.println("드라이브가 가능합니다.");	
	}
}

public class DriverTest {
	public static void main(String[] args) {
		
		FlyingCar flyingCar = new FlyingCar();
		flyingCar.drive();
		flyingCar.fly();        		
	}

}

출력값:
드라이브가 가능합니다.
날수 있습니다.

🔽 code

// 인터페이스 선언, class자리에 대체해서 들어간다 생각.
// 인터페이스는 기본적으로 상수와 추상함수만 들어간다. 
interface Printable {
	public abstract void print(String doc);
}
// implements: 인터페이스를 상속받는다란 느낌. 구현한다. 
class SprinterDriver implements Printable {

	@Override
	public void print(String doc) {
		System.out.println("삼성 프린터 입니다.");
		System.out.println(doc);
	}
}

class LPrintDriver implements Printable {

	@Override
	public void print(String doc) {
		System.out.println("엘쥐 프린터 입니다.");
		System.out.println(doc);
	}
	
}

public class DriverTest {
	public static void main(String[] args) {
		// 인터페이스도 다형성 활용가능한다. 변수선언 가능한다. 
		// 3. 객체생성 불가~~~ 참조변수 선언가능 
		// Printable prn = new Printable(); >> 불가! 
		Printable prn = new SprinterDriver();
		prn.print("출력해주세요.");
		
		prn = new LPrintDriver();
		prn.print("출력해주세요.");
	}

}

이런 인터페이스는 왜 쓰는걸까
-> " MS: 제조사 회사님들아~ 인터페이스 뿌려줄테니까~ 우리 os를 사용하고 싶으면 우리꺼 implement해서 함수가 작동하게끔 만들어 ^^~!! "

인터페이스를 이용한 다형성

  • 메서드의 매개변수로 인터페이스 참조변수를 쓸 수 있다. 주의할 점은 매개변수로 인터페이스 참조변수를 쓰는경우, 해당 인터페이스를 구현한 클래스의 인스턴스만 사용할 수 있다.
    🔽 code
interface Fightable {
	void move(int x, int y);
	void attack(Fightable f);
}
  • 인터페이스를 메서드의 리턴타입으로 지정할 수 있다.

default 메서드

사실 인터페이스는 기능에 대한 구현보다는, 기능에 대한 '선언'에 초점을 맞추어서 사용 하는데, default 메서드는 왜 등장했을까?

"하위 호환성"때문이다. 예를 들어 설명하자면, 여러분들이 만약 오픈 소스코드를 만들었다고 가정하자. 그 오픈소스가 엄청 유명해져서 전 세계 사람들이 다 사용하고 있는데, 인터페이스에 새로운 메서드를 만들어야 하는 상황이 발생했다. 자칫 잘못하면 내가 만든 오픈소스를 사용한 사람들은 전부 오류가 발생하고 수정을 해야 하는 일이 발생할 수도 있다. 이럴 때 사용하는 것이 바로 default 메소드다.

기존에 존재하던 인터페이스를 이용하여서 구현된 클래스를 만들고 사용하고 있는데 인터페이스를 보완하는 과정에서 추가적으로 구현해야 할 혹은 필수적으로 존재해야 할 메서드가 있다면, 이미 이 인터페이스를 구현한 클래스와의 호환성이 떨어 지게 된다. 이러한 경우 default 메서드를 추가하게 된다면 하위 호환성은 유지되고 인터페이스의 보완을 진행 할 수 있습니다.


질문사항 🔽

(1) 변수의 종류
1. 인스턴스 변수 : 클래스 내의 변수
2. static 변수 :
3. 지역변수 : 함수안에 있는 변수

(2) null
null은 참조형 변수에만 대입할 수 있다.
1. 가리키는 값이 없다.
2. 가비지콜렉터로 하여금 해당 메모리를 회수 해도 좋다는 의미

0개의 댓글