본문 바로가기
Language/JAVA

JAVA 7일차 - 접근 제어자, 다형성

by 코젼 2022. 6. 28.
728x90
반응형

💌 참고하면 좋은 사이트

💬다형성

https://reakwon.tistory.com/48-

 

[JAVA] 자바 다형성(Polymorphism) 개념부터 응용 쉬운 설명

다형성(Polymorphism) 다형성이라는 개념은 OOP에서 아주 중요한 개념이므로 모르면 OOP에 대해서 제대로 안다고 할 수 없는 개념입니다. 각 요소들이 여러 가지 자료형으로 표현될 수 있다는 것을 말

reakwon.tistory.com


📂프로젝트 파일

7_oop4.zip
0.01MB


💡 생성자

생성자의 접근 제어자
- 일반적으로 생성자의 접근 제어자는 클래스의 접근 제어자와 일치한다.
- 생성자에 접근 제어자를 사용함으로써 인스턴스 생성을 제한할 수 있다.

 

싱글톤 패턴, 싱글톤 인스턴스
- 인스턴스를 하나만 생성한다.

💬 생성자에 private가 적혀있다.
ex) private MyTest() {}
💬 객체에 static
ex) static MyTest mt = null;
💬 객체를 하나 출력하게 한다.
ex) mt = new MyTest();

📃 싱글톤 예제 (1)

- MyTest 클래스

public class MyTest {
	// getInstance()에서 사용될 수 있도록 인스턴스가 미리 생성되어야 하므로 static이어야한다.
	static MyTest mt = null; // 주소 값을 저장할 참조 변수, 공유 메모리 공간에 만듬
	
	private MyTest() {
		System.out.println("MyTest 생성");
	}
	
	static MyTest getInstance() {
		
		if(mt == null) { // 처음 null일 때 객체 생성하고 출력
			mt = new MyTest();
		}
		
		return mt;
	}
}

- TestMain 클래스

public class TestFile {
	public static void main(String[] args) {
		MyTest m1 = MyTest.getInstance(); // 출력
		MyTest m2 = MyTest.getInstance(); // 출력 X
		MyTest m3 = MyTest.getInstance(); // 출력 X
	}
}

📃 싱글톤 예제 (2)

- MusicPlayer 클래스

// 다른 클래스에서 getInsatance를 여러 번 호출해도
// 인스턴스를 한 번만 생성하도록 코드를 수정하세요
public class MusicPlayer {
	
	private static MusicPlayer mp = null;
	
	private MusicPlayer() {
		System.out.println("뮤직플레이어 생성");
	}
	
	public static MusicPlayer getInstance() {
		if(mp == null) {
			mp = new MusicPlayer();
		}
		
		return mp;
	}

}

 - TestMain 클래스

public class TestFile2 {
	public static void main(String[] args) {
		MusicPlayer m1 = MusicPlayer.getInstance(); // 출력
		MusicPlayer m2 = MusicPlayer.getInstance(); // 출력 X
		MusicPlayer m3 = MusicPlayer.getInstance(); // 출력 X
	}
}

💡다형성

다형성(polymorphism) : 조상타입의 참조변수로 자손타입의 객체를 다룰 수 있는 것 (조타참 자타객)
- 하나의 참조변수로 여러 타입의 객체를 참조할 수 있는 것

💬 장점
- 조상 클래스가 자손 클래스의 메소드를 쓰면서 활용성이 높아진다.
- 메소드의 접근이 용이해진다.

⚡예제
Tv t = new Tv();
CaptionTv c = new CaptionTv();
다형성을 사용하게 되면 위처럼 따로따로 인스턴스를 정의하지 않아도 된다.

Tv ctv = new CaptionTv();
class Man extends People{
    @Override
    public void printInfo() {
        super.printInfo();
        System.out.println("그리고 나는 남자입니다.");
    }
     
    public void enlist() {
                System.out.println("내일 군대를 갑니다.");
        System.out.println("충성!");
    }
     
}
class Woman extends People{
    @Override
    public void printInfo() {
        super.printInfo();
        System.out.println("그리고 나는 여자입니다.");
    }
     
    public void makeUp() {
                System.out.println("예뻐질 거랍니다.");
        System.out.println("톡톡 촵촵!");
    }
}​
public class Test {
 
    public static void main(String[] args) {
        People people=new Man();
        people.printInfo();
        ((Man)people).enlist();
         
        System.out.println();
         
        people=new Woman();
        people.printInfo();
        ((Woman)people).makeUp();
         
    }
}

- 객체를 매개변수로 받으면 그것을 상속하는 모든 클래스를 받아낼 수 있다.
  --> Object 객체로 모든 객체를 받을 수 있는 것은 다형성의 속성 때문이다.
public static void func(People people) {
	people.printInfo();
}

public static void main(String[] args) {
	Man man = new Man();
    Woman woman = new Woman();
    func(man);
    
    System.out.println();
    func(woman);
}​

- 추가적으로 필요에 의해서는 instanceof 연산자를 사용해서 캐스팅 할 수 있다.

public static void func(People people) {
	people.printInfo();
    
    /*------- 추가 ------*/
    if(people instanceof Man)
    	((Man)people).enlist();
    if(people instanceof Woman)
    	((Woman)people).makeUp();
	/*-------------*/        
}

public static void main(String[] args) {
	Man man = new Man();
    Woman woman = new Woman();
    func(man);
    
    System.out.println();
    func(woman);
}​

 

📃 다형성 예제 (1)

- Tv, CaptionTv 클래스

// 다형성 예제
class CaptionTv extends Tv {
	String text;
	void caption() {
		System.out.println("캡션 기능");
	}
}
public class Tv {
	int channel;
	boolean power;
	
	void power() {power = !power;}
	void channelUp() {channel++;}
	void channelDown() {channel--;}
}

- TestMain 클래스

Tv t = new Tv();
CaptionTv c = new CaptionTv();

== Tv t = new CaptionTv();  // 동일

public class TestMain {
	public static void main(String[] args) {
		CaptionTv ctv = new CaptionTv();
		ctv.caption();
		ctv.channelDown();


		
		// 조상 타입의 참조 변수로, 자손 타입의 객체에 접근(조타참 자타객)
		Tv t = new CaptionTv(); 
		t.channelUp();
		((CaptionTv)t).caption(); // 조상 클래스가 자식 클래스의 메소드를 사용하려면 자식 클래스로 형변환 해야한다.
		// t.caption(); // 에러
		
	}
}

📃 ⭐다형성 예제 (2)

[ 조건 ]
//클래스명 Product
//멤버변수 : int-price-제품가격
//생성자 : 매개변수가 하나인 생성자, 제품가격을 전달받아 초기화

//클래스명 : Tv
//생성자 : 기본생성자, 조상클래스의 생성자를 활용해 가격을 100원으로 초기화

//클래스명 : Computer
//생성자 : 기본생성자, 조상클래스의 생성자를 활용해 가격을 200원으로 초기화

//클래스명 : Audio
//생성자 : 기본생성자, 조상클래스의 생성자를 활용해 가격을 50원으로 초기화

- Product, Tv, Computer, Audio, Buyer 클래스

package Test1;

public class Product {
	int price; // 제품 가격

	// 매개변수가 하나인 생성자, 제품 가격을 전달받아 초기화
	Product(int price) {
		this.price = price;
	}
}

class Tv extends Product {
	// 기본 생성자, 조상클래스의 생성자를 활용해 가격을 100원으로 초기화
	Tv() {
		super(100);
	}

	public String toString() {
		return "Tv";
	}
}

class Computer extends Product {
	// 기본 생성자, 조상클래스의 생성자를 활용해 가격을 200원으로 초기화
	Computer() {
		super(200);
	}

	public String toString() {
		return "Computer";
	}
}

class Audio extends Product {
	// 기본 생성자, 조상클래스의 생성자를 활용해 가격을 50원으로 초기화
	Audio() {
		super(50);
	}

	public String toString() {
		return "Audio";
	}
}

class Buyer {
	int money = 1000;
	
	void buy(Product p) {
		if (money < 0) { return; }
        
		money = money - p.price;
		System.out.println("현재 잔액은 " + money);
	}
}

- TestMain 클래스

package Test1;

public class TestMain {
	public static void main(String[] args) {
//		Tv p1 = new Tv();
//		Computer p2 = new Computer();
//		Audio p3 = new Audio();
		
		Product p1 = new Tv();
		Product p2 = new Computer();
		Product p3 = new Audio();
		
		Buyer buyer = new Buyer();
		buyer.buy(p1); // 현재 잔액은 900
		buyer.buy(p2); // 현재 잔액은 700
		buyer.buy(p3); // 현재 잔액은 650
	}
}

💡 참조변수의 형변환

참조변수의 형변환
- 서로 상속관계에 있는 타입간의 형변환만 가능하다.
- 같은 자식 클래스끼리는 형변환이 불가능하다.
- 자손 타입에서 조상 타입으로 형변환하는 경우는 형변환을 생략할 수 있다.



참조형 변수?
- 형태(Type)

 


💡 instanceof 연산자

- Product, Tv, Computer, Audio, Buyer 클래스

// 위의 다형성 예제(2) 참고

instanceof 연산자
- 참조변수가 참조하는 인스턴스의 실제 타입을 체크하는데 사용
- 이항연산자이며 연산결과는 true/false
- 연산결과가 true이면 해당 타입으로 형변환이 가능하다.
- Buyer 클래스의 buy 메소드에서 instanceof 연산자 사용하기
// buy메소드 안에서 instanceof를 이용하여 전달받은 인자의 상품 유형 출력
// ex. Product p가 Tv, Computer, Audio 중 무엇인지 확인

📃 ⭐다형성 예제 (3)

package Test1;

public class Product {
	int price; // 제품 가격

	// 매개변수가 하나인 생성자, 제품 가격을 전달받아 초기화
	Product(int price) {
		this.price = price;
	}
}

class Tv extends Product {
	// 기본 생성자, 조상클래스의 생성자를 활용해 가격을 100원으로 초기화
	Tv() {
		super(100);
	}

	public String toString() {
		return "Tv";
	}
}

class Computer extends Product {
	// 기본 생성자, 조상클래스의 생성자를 활용해 가격을 200원으로 초기화
	Computer() {
		super(200);
	}

	public String toString() {
		return "Computer";
	}
}

class Audio extends Product {
	// 기본 생성자, 조상클래스의 생성자를 활용해 가격을 50원으로 초기화
	Audio() {
		super(50);
	}

	public String toString() {
		return "Audio";
	}
}

class Buyer {
	int money = 1000;
	
	void buy(Product p) {
		if (money < 0) { return; }
		
		// buy메소드 안에서 instanceof를 이용하여 전달받은 인자의 상품 유형 출력
		// ex. Product p가 Tv, Computer, Audio 중 무엇인지 확인
		if(p instanceof Tv) {
			System.out.print("Tv 구매 후, ");
		}
		else if(p instanceof Computer) {
			System.out.print("Computer 구매 후, ");
		}
		else if(p instanceof Audio) {
			System.out.print("Audio 구매 후, ");
		}
		
		money = money - p.price;
		System.out.println("현재 잔액은 " + money);
	}
}

- TestMain 클래스

package Test1;

public class TestMain {
	public static void main(String[] args) {
		Tv p1 = new Tv();
		Computer p2 = new Computer();
		Audio p3 = new Audio();
		
		Buyer buyer = new Buyer();
		buyer.buy(p1); // 현재 잔액은 900
		buyer.buy(p2); // 현재 잔액은 700
		buyer.buy(p3); // 현재 잔액은 650
	}
}

📃 ⭐다형성 예제 (4)

⚡ 자손간의 형변환은 불가능하다.
FireEngine f;
Ambulance a; 

a = (Ambulance)f;
f = (FireEngine)a;
⚡ 객체만 생성해두고 다형성으로 채울 수 있다.
FireEngine fe = new FireEngine();
fe.water();

Car car = null; // 생성
FireEngine fe2 = null;
car = fe; // == car = (Car)fe; [조상 <- 자손] -- 다형성
fe2 = (FireEngine)car; // [자손 <- 조상] (형변환 필요) -- 다형성
// car.water(); // 에러
fe2.water();
⚡형변환시 자손 클래스의 메소드를 사용할 수 있다.
Car c = null;
FireEngine f;
Ambulance a = new Ambulance();
c = a; // 다형성

// car.siren(); //에러

((Ambulance)c).siren(); // 형변환
package TypeTransfer;

public class Car {
	public static void main(String[] args) {
		Car c1 = new FireEngine();
		Car c2 = new Ambulance();
		
		if(c1 instanceof FireEngine) {
			System.out.println("This is a FireEngine instance");
		}
		else if(c1 instanceof Car) {
			System.out.println("This is a Car instance");
		}
		else if(c1 instanceof Object) {
			System.out.println("This is an Object instance");
		}
		
		((FireEngine)c1).water();
		((Ambulance)c2).siren();
		
		c1.drive();
		c1.stop();
		
		c2.drive();
		c2.stop();
	}
	
	String color;
	int door;
	
	void drive() { // 운전 기능
		System.out.println("drive, Brrrr~");
	}
	
	void stop() { // 멈추는 기능
		System.out.println("stop!!!");
	}
}

class FireEngine extends Car { // 소방차
	void water() { // 물 뿌리는 기능
		System.out.println("water!!!");
	}
}

class Ambulance extends Car { // 구급차
	void siren() { // 사이렌을 울리는 기능
		System.out.println("siren~~~");
	}
}
728x90
반응형

댓글