instanceof 연산자

- 참조변수의 형변환 가능여부 확인에 사용. 가능하면 true 반환

- 형변환 전에 반드시 instanceof로 확인해야 함

 

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

 

- 조상 클래스를 대상으로 하면 true가 나오기 때문에 조심해야 한다.

FireEngine fe = new FireEngine();
System.out.println(fe instanceof Object);		// true
System.out.println(fe instanceof Car);		// true
System.out.println(fe instanceof FireEngine);	// true

 

- Q & A

Q. 참조변수의 형변환은 왜 하나요?

A. 참조변수(리모콘)을 변경함으로써 사용할 수 있는 멤버의 개수를 조절하기 위해

 

Q. instanceof연산자는 언제 사용하나요?

A. 참조변수를 형변환하기 전에 형변환 가능여부를 확인할 때

 

매개변수의 다형성

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

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

ex)

class Product {
	int price;		// 제품의 가격
	int bonusPoint; // 제품구매 시 제공하는 보너스점수
	
	Product(int price) {
		this.price = price;
		bonusPoint = (int)(price/10.0);	// 보너스점수는 제품가격의 10%
	}
}

class Tv1 extends Product {
	Tv1() {
		// 조상클래스의 생성자 Product(int price)를 호출한다.
		super(100);		// Tv의 가격을 100만원으로 한다.
	}
	
	// Object클래스의 toString()을 오버라이딩 한다.
	public String toString() {
		return "Tv";
	}
}

class Computer extends Product {
	Computer() {
		super(200);
	}
	
	public String toString() {
		return "Computer";
	}
}

class Buyer {	// 고객, 물건을 사는 사람
	int money = 1000;	// 소유금액
	int bonusPoint = 0; // 보너스 점수
	
	void buy(Product p) {
		if(money < p.price) {
			System.out.println("잔액이 부족하여 물건을 살 수 없습니다.");
			return;
		}
		
		money -= p.price;
		bonusPoint += p.bonusPoint;
		System.out.println(p + "을/를 구입하셨습니다.");
		
	}
}
public class Ex7_8 {

	public static void main(String[] args) {
		Buyer b = new Buyer();
		
//		Product p = new Tv1();
//		b.buy(p);					
		b.buy(new Tv1());		// 위의 두 줄을 한 줄로 표현
		b.buy(new Computer());
		
		System.out.println("현재 남은 돈은 " + b.money + "만원입니다.");
		System.out.println("현재 보너스점수는 " + b.bonusPoint + "점입니다.");

	}

}

 

여러 종류의 객체를 배열로 다루기

- 조상타입의 배열에 자손들의 객체를 담을 수 있다.

Product p[] = new Product[3];
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();

-> Product를 상속하는 Tv, Computer, Audio 객체를 담을 수 있다.

 

ex) cartitemList를 추가한 물품구매

class Product2 {
	int price;			// 제품의 가격
	int bonusPoint;		// 제품구매시 제공하는 보너스점수
	
	Product2(int price) {
		this.price = price;
		bonusPoint = (int)(price/10.0);
	}
	
	Product2() {} // 기본 생성자
	
}

class Tv2 extends Product2 {
	Tv2() {
		super(100);
	}
	
	public String toString() { 
		return "Tv";
	}
}

class Computer2 extends Product2 {
	Computer2() {
		super(200);
	}
	
	public String toString() { 
		return "Computer";
	}
}

class Audio2 extends Product2 {
	Audio2() {
		super(50);
	}
	
	public String toString() { 
		return "Audio";
	}
}

class Buyer2 {			// 고객, 물건을 사는 사람
	int money = 1000;	// 소유금액
	int bonusPoint = 0; // 보너스점수
	Product2[] cart = new Product2[10];	// 구입한 제품을 저장하기 위한 배열
	int i = 0;		// Product배열에 사용될 카운터
	
	void buy(Product2 p) {
		if (money < p.price) {
			System.out.println("잔액이 부족하여 물건을 살 수 없습니다.");
			return;
		}
		
		money -= p.price;			// 가진 돈에서 구입한 제품의 가격을 뺀다.
		bonusPoint += p.bonusPoint; // 제품의 보너스 점수를 추가한다.
		cart[i++] = p;				// 제품을 Product[] cart에 저장한다.
		System.out.println(p + "을/를 구입하셨습니다.");
	}
	
	void summary() {		// 구매한 물품에 대한 정보를 요약해서 보여준다.
		int sum = 0;		// 구입한 물품의 가격 합계
		String itemList = "";	// 구입한 물품목록
		
		// 반복문을 이용해서 구입한 물품의 총 가격과 목록을 만든다.
		for (int i=0; i<cart.length; i++) {
			if(cart[i]==null) {
				break;
			}
			sum += cart[i].price;
			itemList += cart[i] + ", ";
		}
		System.out.println("구입하신 물품의 총 금액은 " + sum + "만원입니다.");
		System.out.println("구입하신 제품은 " + itemList + "입니다.");
	}
}
public class Ex7_9 {

	public static void main(String[] args) {
		Buyer2 b = new Buyer2();
		
		b.buy(new Tv2());
		b.buy(new Computer2());
		b.buy(new Audio2());
		b.summary();
		
		
	}

}

 

추상 클래스 (abstract class)

- 미완성 설계도. 미완성 메소드를 갖고 있는 클래스.

(일반클래스가 추상메소드를 갖고 있으면 추상클래스)

 
abstract class Player {
	abstract void play(int pos);	// 추상메소드 (몸통 {}이 없는 미완성 메소드)
	abstract void stop();		// 추상메소드
}

 

- 다른 클래스 작성에 도움을 주기 위한 것. 인스턴스 생성 불가.

Player p = new Player(); // 에러, 추상 클래스의 인스턴스 생성 불가

 

- 상속을 통해 추상 메소드를 완성해야 인스턴스 생성가능

class AudioPlayer extends Player {
	void play(int pos) { /* 내용 생략 */ }	// 추상메소드를 구현
	void stop() { /* 내용 생략 */ }		// 추상메소드를 구현
}
AudioPlayer ap = new AudioPlayer();	// OK. 인스턴스 생성 가능
Player ap2 = new AudioPlayer();		// OK.

 

추상 메소드(abstract method)

- 미완성 메소드. 구현부(몸통, {})가 없는 메소드

 

/* 주석을 통해 어떤 기능을 수행할 목적으로 작성하였는지 설명한다. */

abstract 리턴타입 메소드이름();

 

꼭 필요하지만 자손마다 다르게 구현될 것으로 예상되는 경우에 추상메소드 사용.

 
abstract class Player {
	abstract void play(int pos);	// 추상메소드 
	abstract void stop();		// 추상메소드
}

class AudioPlayer extends Player {
	void play(int pos) { /* 내용 생략 */ }	// 추상메소드를 구현
	void stop() { /* 내용 생략 */ }		// 추상메소드를 구현
}
abstract class AbstractPlayer extends Player { // 일부만 구현해도 된다.
	void play(int pos) { /* 내용 생략 */ } // 추상메소드를 구현
}

 

- 추상 메소드 호출 가능(호출할 때는 선언부만 필요)

 
abstract class Player {
	boolean pause;		// 일시정지 상태를 저장하기 위한 변수
	int currentPos;		// 현재 Play되고 있는 위치를 저장하기 위한 변수

	Player() {
		pause = false;
		currentPos = 0;
	}

	abstract void play(int pos);	// 추상메소드
	
	abstract void stop();		// 추상메소드

	void play() {
		play(currentPos);	// 추상메소드를 사용할 수 있다. 메소드는 선언부만 알면 호출가능하므로 추상메소드도 호출 가능하다.
	}
    
    }

 

ex)

abstract class Player { 		// 추상 클래스(미완성 클래스, 미완성 설계도)
	abstract void play(int pos); // 추상 메소드(미완성 메소드)
	abstract void stop(); // 추상 메소드(선언부만 있고 구현부{}가 없는 메소드
}

// 추상 클래스는 상속을 통해 완성해야 객체 생성가능
class AudioPlayer extends Player {
	void play(int pos) {
		System.out.println(pos+"위치 부터 play합니다.");
	}
	void stop() {
		System.out.println("재생을 멈춥니다.");
	}
}

public class PlayerTest {

	public static void main(String[] args) {
//		Player p = new Player();	// 추상클래스의 객체를 생성
//		AudioPlayer ap = new AudioPlayer();
		Player ap = new AudioPlayer();	// 다형성
		ap.play(100);
		ap.stop();
		
	}

}

 

 

추상클래스의 작성

- 여러 클래스에 공통적으로 사용될 수 있는 추상클래스를 바로 작성하거나 기존클래스의 공통 부분을 뽑아서 추상클래스를 만든다.

 

 

ex)

abstract class Unit {
	int x, y;
	abstract void move(int x, int y);
	void stop() {
		/* 현재 위치에 정치 */
	}
}

class Marine extends Unit {		// 해병
	void move(int x, int y) {
		/* 지정된 위치로 이동 */
		System.out.println("Marine[x=" + x + ", y=" + y + "]");
	}
	void stimPack() {
		/* 스팀팩을 사용한다. */
	}
}

class Tank extends Unit {	// 탱크
	void move(int x, int y) {
		/* 지정된 위치로 이동 */
		System.out.println("Tank[x=" + x + ", y=" + y + "]");
	}
	void changeMode() {
		/* 공격모드를 변환한다. */
	}
}

class Dropship extends Unit {	// 수송선
	void move(int x, int y) {
		/* 지정된 위치로 이동 */
		System.out.println("Dropship[x=" + x + ", y=" + y + "]");
	}
	void load() {
		/* 선택된 대상을 태운다. */
	}
	void unload() {
		/* 선택된 대상을 내린다. */
	}
}

public class Ex7_10 {
	
	public static void main(String[] args) {
		Unit[] group = { new Marine(), new Tank(), new Dropship() };
		
		for(int i=0; i<group.length; i++) {
			group[i].move(100, 200);
			// group의 타입은 Unit[], group[0], group[1], group[2]의 타입은 Unit이다.
		}
		
	}

}

- 추상화 <-> 구체화

추상화된 코드는 구체화된 코드보다 유연하다. 변경에 유리

 

GregorianCalendar cal = new GregorianCalendar(); // 구체적

Calendar cal = Calendar.getInstance(); // 추상적

cal에 넣을 객체를 유연하게 변경할 수 있다

 

 

인터페이스(interface)

- 추상 메소드의 집합

- 구현된 것이 전혀 없는 설계도. 껍데기(모든 멤버가 public)

interface 인터페이스이름 {
	public static final 타입 상수이름 = 값;	// 변수는 존재할 수 없음
	public abstract 메소드이름(매개변수목록);	// 추상메소드
}
interface PlayingCard {
	public static final int SPADE = 4;
	final int DIAMOND = 3;		// public static final int DIAMOND = 3;
	static int HEART = 2;		// public static final int HEART = 2;
	int CLOVER = 1;		// public static final int CLOVER = 1;

	public abstract String getCardNumber();
	String getCardKind();	// public abstract String getCardKind();
    
    }

(멤버에 public, abstract, final, static 등등 생략이 가능하다)

 

- 인터페이스의 조상은 인터페이스만 가능(Object가 최고 조상 아님)

- 다중 상속(조상이 여러개)이 가능(추상메소드는 충돌해도 문제 없음)

interface Fightable extends Movable, Attackable { }

interface Movable {
	void move(int x, int y);
}

interface Attackable {
	void attack(Unit u);
}

 

인터페이스의 구현

- 인터페이스에 정의된 추상 메소드를 완성하는 것

 

class 클래스이름 implements 인터페이스이름 {

// 인터페이스에 정의된 추상메소드를 모두 구현해야 한다.

}

 
interface Fightable {
	void move(int x, int y);		// public abstract가 앞에 생략되어 있음
	void attack(Unit u);
}

class Fighter implements Fightable {
	public void move(int x, int y) { /* 내용 생략 */ }
	public void attack(Unit u)     { /* 내용 생략 */ }
}

 

- 일부만 구현하는 경우, 클래스 앞에 abstract를 붙여야 함.

abstract class Fighter implements Fightable {
	public void move(int x, int y) { /* 내용 생략 */ }
	// public abstract void attack(Unit u);  가 생략되어 있음
}

Q & A

Q. 인터페이스란?

A. 추상 메소드의 집합

 

Q. 인터페이스의 구현이란?

A. 인터페이스의 추상메소드 몸통{} 만들기(미완성 설계도 완성하기)

 

Q. 추상 클래스와 인터페이스의 공통점은?

A. 추상 메소드를 가지고 있다(미완성 설계도)

 

Q. 추상 클래스와 인터페이스의 차이점은?

A. 인터페이스는 iv를 가질 수 없다. 생성자, 인스턴스 메소드 다 가질 수 없음.


출처 : 유튜브 남궁성의 정석코딩 [자바의 정석-기초편]

+ Recent posts