본문 바로가기
IT/자바

다형성과 인터페이스 그리고 instanceof 연산자

by 독서실총무J 2017. 5. 9.
반응형

새벽부터 쓰는건 처음인것 같다

아픈지 얼마나 지났다고

이상하게 목이 간질간질 거려서

하루종일 혼났다


오늘은 드디어 자바의 꽃이라 

불리는 (나는 그렇다) 

다형성과 인터페이스에 대해

알아보자


이 두놈은 정말정말 중요하다

또 그만큼 이해하기 힘들기 

때문에 잘보고 학습하길 바란다


물론 오늘 내 설명이 

전에 비해서 월등히 나아지거나

그렇진 않을것이다 


긴말 필요없이 코드 보자


interface IWearable {
	
}
class Clothes implements IWearable{
	public int price;
}
class Pants extends Clothes {
	public int length;
}
class Ex1 {

	public static boolean pantsOrNot(Clothes c) {
		if(c instanceof Pants) {
			System.out.println("바지가 맞아요~");
			return true;
		} else {
			System.out.println("바지가 아니에요~");
			return false;
		}
		
	}

	public static void main(String[] args) {
		// 다형성
		Pants p = new Pants();
		Clothes c = p;		// Clothes이 더 큰개념 : 작 -> 큰
		Object o = p;		
		IWearable w = p;
		// 상향 -> 하향 (ok)
		if(pantsOrNot(c)) {			
			Pants p2 = (Pants)c;
		}
		// 불가능
		Clothes c2 = new Clothes();
		if(pantsOrNot(c2)) {
			Pants p3 = (Pants)c2;
		}
	}
}


먼저 나와있는 interface는 그냥 쌩까도록 하자

다음다음 예제에서 제대로 언급할테니 말이다


먼저 다형성에 대한 개념부터 설명하자면

말그대로 많다(다) 형(형태) 라고 할수있다

형태가 많다는것이다


한가지 예시를 들어 말해보겠다

모든 동물들이 울음소리를 내면

우리는 그들이 '짖다'라고 표현한다


그러나 아시다시피 짖는 울음소리는 다 다르다

멍멍이는 멍멍 , 야옹이는 야옹 할것이란 말이다

멍멍이와 야옹이에게 짖어라고 명령하면

그들은 다른 소리로 짖게 될것인데,

멍야옹이 둘을 객체라고 생각하면 된다


그럼 이 다형성이 어떤 부분에서 유용할까?

그건 메시지를 받는 쪽이 어떤 타입인지 

알필요가 없다는것이다

객체를 상황에 따라 다양하게 형성할수 있다


다형성에서 형변환은 두가지로 나눈다

상향형변환과 하향형변환이 그것인데

이 둘은 다음 소스에서 살펴보자


위의 코드는 워밍업으로 쳐보길 바란다


class Parent {
	public void parentMethod() {
		System.out.println("parentMethod");
	}
}
class Child extends Parent {
	public void childMethod() {
		System.out.println("childMethod");
	}
}
class Ex3 {
	public static void main(String[] args) {
		Parent p = new Parent();
		Child c = new Child();
		Parent o = new Child();

		p.parentMethod();

		c.childMethod();
		c.parentMethod();

		o.parentMethod();
		Child temp = (Child)o;
		temp.childMethod();
	}
}


Parent o = new Child();

상향형변환 하였다

어찌보면 정말 당연한것이라 볼수 있다


상향형변환 한것을 원래 상태로 되돌리는 

방법이 하향형변환이라 보면된다

상향 한것만 하향할수 있다


Child temp = (Child)o;

하향형변환 시에는 반드시 명시적으로

형변환 연산자를 적어주어야 한다


가끔 우리는 잦은 형변환으로 인해 

참조변수가 어떤 객체를 참조하는지,

가르키는지 모를때가 있다 


그럴때에는 instanceof 연산자를 이용하여

현재 참조하는 객체를 알아낼수 있다


instanceof 연산자의 관련소스는 

당신이 방금까지 친 첫번째에 있다


내가 언급하지 않았어도 

직접 쳐보고 실행 해보았다면

어떤 기능을 하는 놈인지 

충분히 알수 있을것이다


abstract class MobilePhone {
}
class Iphone extends MobilePhone {
}
class V20 extends MobilePhone {
}
class Note7 extends MobilePhone {
}
class Ex4 {
	public static void todo(Object o) {
		// o?
	}
	public static void printPhoneName(MobilePhone phone) {
		if(phone instanceof Iphone) {
			System.out.println("Iphone");
		} else if(phone instanceof V20) {
			System.out.println("V20");
		} else if(phone instanceof Note7) {
			System.out.println("Note7");
		} else if(phone instanceof MobilePhone) {
			System.out.println("MobilePone");
		} 
	}

	public static void main(String[] args) {
		printPhoneName(new V20());
		printPhoneName(new Note7());
		printPhoneName(new Iphone());
	}
}


그래도 잘 이해하지 못한 사람이 분명 있을것이므로

( 내가 제일 처음에 배울때 그랬기 떄문에 )

instanceof 연산자에 대해 더 자세히 살펴보자


위의 스마트폰 기종을 파라미터로 던져주면

당연히 해당 기종을 참조하는 상황이 된다

그러므로 각각의 실행문에 있는

자기소개를 하게 되는 것이다


이 예제에서는 단순하게 instanceof의 기능을 보여준다

그전에 이해되지 않은 사람도 정확히 알수 있을것이다


interface IWalking {
	void walk();	
}
class Dead implements IWalking{
	@Override
	public void walk() {
		System.out.println("좀비좀비~");
	}
}
class Human implements IWalking {
	@Override
	public void walk() {
		System.out.println("뚜벅뚜벅"); 
	}
}
class RunningMachine {
	public void play(IWalking some) {
		some.walk();
	}
}
public class Ex6 {	
	public static void main(String[] args) {
		RunningMachine rm = new RunningMachine();
		rm.play(new Human());
		rm.play(new Dead());

	}
}


이제부터는 인터페이스에 대해서 알아보자

인터페이스는 추상클래스의 극단적인 경우이다


안에 구성은 추상메소드 와 상수이다

인터페이스는 기능적인 역할만 하므로

그외에는 별다르게 필요없기 때문이다


위의 예제에서는 RunningMachine을 주목하자

IWalking some 파라미터를 유심히 보자


Dead와 Human형 객체들이 

IWaking을 상속 받으면서

파라미터로 쓰일수 있다


아리까리하니 다음 예제를 보자



interface IMachine {
	void turnOn();
	void turnOff();
}

class Tv implements IMachine {
	@Override
	public void turnOn() {
		System.out.println("TV켭니다~");
	}
	@Override
	public void turnOff() {
		System.out.println("TV끕니다.");
	}
}

class NetworkServer {
	public void performTurnOn(IMachine m) {
		m.turnOn();
	}
	public void performTurnOff(IMachine m) {
		m.turnOff();
	}
}

class Ex7 {
	public static void main(String[] args) {
		Tv tv = new Tv();
		NetworkServer server = new NetworkServer();

		server.performTurnOn(tv);
		server.performTurnOff(tv);
	}
}


NetworkServer 클래스를 보자

단순히 기능만 있는 IMachine 인터페이스를

이용하여 켜고 끄는 행동을 담은 클래스이다


직접 쳐보고 실행해보길 바란다

우리 생활에서 자주 볼수 있는 내용으로

구성되어서 그리 어렵지 않게 이해할수 있을거다


그리고, 전에 말했듯이 상속은 다중으로 받을수 없다

그러나 인터페이스의 경우는 가능하니 

이를 이용해 어떤 구성으로 짜냐에 따라서

코드가 아주 간결해질수도 있을것이고

아주 너저분해질수도 있을것이다



내가 적으면서도 느끼지만 

너무 설명이 부실한것 같다

확실히 머리로 알고 있는것과

설명하는것은 꽤 큰 차이가 있나보다


자바를 가르치는 모든 강사분들에게

존경을 표하며 오늘의 복습을 끝낸다


내일은 대통령 선거이다

귀찮다고 투표 안하지 말고 

국민의 한사람으로서

제발 제발 투표하도록 하자!

반응형

댓글