Polymorphism
<1> 정의
다형성이란 하나의 객체가 많은 형(타입)을 가질 수 있는 성질이다. 다형성은, 상속관계에 있을 때 조상클래스의 타입으로 자식 클래스 객체를 레퍼런스 할 수 있다.
ex) 팥붕어빵 is a 붕어빵 | 슈크림붕어빵 is a 붕어빵 | 피자 붕어빵 is a 붕어빵
<2> 활용
- 다형성으로 다른 타입의 데이터를 하나의 배열로관리할 수 있다
public ArrayList(int initialCapacity){ if(initialCapcity>0){this.elementData = new Object [initialCapacity];} else if (initialCapacity ==0 ){this.elementData = EMPTY_ELEMENTDATA;} else{throw new IllegalArgumentException ("Illegal Capcity: " + initialCapacity);}}
- 대표적인 예로, 오브젝트 클래스를 볼 수 있다. 오브젝트 클래스는 모든 클래스의 조상인데, 오브젝트의 배열은 어떤 타입의 객체라도 다 저장할 수 있기 때문에 자바의 자료구조를 간단하게 처리할 수 있다.
- 매개변수의 다형성
public void println (Object x){ //Object 를 파싱하고 있어서 출력이 되고있던거임 String s = String.valueOf(x); synchronized(this){print(s); newLine();}}
- 메서드가 호출되기 위해서는 메서드 이름과 파라미터가 맞아야 하는데, println 에는 무엇을 넣어도 출력이 된다 → 왜그럴까? 아래는 println의 소스 코드이다
다형성과 참조형 객체의 형변환
메모리에 있더라도 참조하는 변수의 타입에 따라 접근할 수 있는 내용이 제한된다
Method Area: 클래스 로딩 시 생성 - 클래스 자체 정보만 올라간다 JVM Stacks : static 변수/ 메서드가 쌓인다 Heap : non-static 변수/ 메서드가 쌓인다. new keyword 가 쓰인 애들이 여기로 온다 → 독립적
https://junebee.tistory.com/6 참고
- 참조형 객체의 형 변환
- 묵시적 캐스팅 : child → super
자손 타입의 객체를 조상 타입으로 참조할 때에는 형변환 생략이 가능하다
🧸조상의 모든 내용이 자식에게 있기 때문에 걱정할 필요 없다 - 명시적 캐스팅 : super → child
조상 타입을 자손타입으로 참조할 때에는 형변환 생략이 불가능하다 조상을 무작정 자손으로 바꿀 수 없으니 주의하자 → instanceof 연산자를 이용하여 실제 메모리에 있는 객체가 특정 클래스 타입인지 boolean으로 리턴한 후 true 일때에만 캐스팅할 것
아래의 코드는 super → child 로의 형변환한 코드이다. 명시적 캐스팅 시, instanceof 를 사용하여 실제로 캐스팅이 가능한지 아닌지 확인을 하지 않느다면, 자바는 알려주지 않기 때문에 신중하게 써야한다.
- 묵시적 캐스팅 : child → super
Pokemon pikachu = new Pokemon ();
if (pikachu instanceof FairyType) { FairyType ft = (FairyType) pikachu; }
//위의 코드처럼 instance of 를 쓰지 않았을 경우에는,
Pokemon phantom = new Pokemon ();
FairyType ft2 = (FairyType) phantom;
phantom.angelicKiss();
//compile error 발생이 안됨. 자칫하면 오옷 되네 하다가 프로그램 부실수도 있다..
2. 참조 변수의 레벨에 따른 객체의 맴버 연결
1. 상속 관계에서 객체의 맴버 변수가 중복될 때, 참조변수의 타입에 따라 연결이 달라짐
(2) 상속관계에서 메서드가 중복될 때 (Method Overriding) : 무조건 자식 클래스의 메서드가 호출되며, 최대한 메모리에 생성된 실체 객체에 최적화 된 메서드가 동작한다 (즉, overriding 된 메서드가 있다면, 그 메서드를 출력하는 것)
아래의 코드는 둘다 같은 결과를 출력한다. 이는 println 의 toString() override 때문이다
System.out.println(Phantom.toString());
System.out.println(Phantom);
<3> Generics
Generics는 다양한 타입의 객체를 다루는 메서드, 컬렉션 클래스에서 컴파일 시에 타입을 체크한다 즉, 미리 형변환을 하지 않아도 사용할 수 있게 하는 것이다.
표현
- 클래스 또는 인터페이스 선언 시 <> 에 타입 파라미터를 표시
className : Raw Type
className<T> : Generic Type
public class ClassName<T> {}
public interface InterfaceName<T> {}
2. 타입 파라미터 임의의 참조형 타입을 뜻함
🤦🏻♀️ T : reference Type
E : Element
K : Key
V : Value
public class ArrayList<E> extends AbstractList<E> implements List<E>, RnadomAccess, Cloneable {...}
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Serializable{...}
3. 객체 생성 변수쪽과 생성 쪽의 타입은 반드시 같아야 한다
ClassName <String> generic1 = new ClassName<String>();
List<Integer> generic2 = new ArrayList<Integer>();
List<String> generic3 = new ArrayList<Character>(); //틀림
예시
public class GenericClass<T> {
private T something;
public T getSomething(){return something;}
public void setSome(T something){this.something = something;}}
public class Test{
private static void genericTest(){
//< > 안에 원하는 타입을 넣기
GenericClass <String> gStr = new GnericClass<>(); //String 이라고 정의하면..?
GenericClass <Integer> gInt = new GenericClass<> (); //Integer도 가능,,?!
//원하는 타입 집어 넣기
gStr.setsomething("String something이라고 정해져서 나와..!");}
gInt.setsomething("Integer something 이라고 suggest 되!");
//원하는 타입 끄집어 내기
String gStr2 = gStr.getSomething();
System.out.println(gStr2); //오 뺄때도 string 만 가능해졌어 !
}
} //컴파일 타입에 타입 파라미터들이 대입된 타입으로 대체됨!
사용
- Type Parameter 의 제한 필요에 따라 구체적인 타입 제한이 필요하다.
ex: 계산기 프로그램 구현 시 Number 이하의 타입 (byte, short, interger..) 로만 제한해야 한다
type parameter 선언 뒤 extends 와 함께 상위 타입을 명시하여 제한한다.
class Number< T extends Number>{} //T는 Number 를 상속 받아야 한다
2. 인터페이스로 제한할 경우도 extends 사용
3. 클래스와 함께 인터페이스 제약 조건을 이용할 경우 & 로 연결
class TypeRestrcit1 <T extends Cloneable> ();
class TypeRestrict2 <T extends Number & Cloneable & Comparable<String>>{}
'취준 > JAVA' 카테고리의 다른 글
QUEUE (0) | 2022.05.18 |
---|---|
캡슐화 (0) | 2022.05.17 |
상속 (0) | 2022.05.17 |
추상화 (0) | 2022.05.17 |
객체 지향 프로그래밍 (0) | 2022.05.17 |