-
제네릭 변수의 참조와 상속의 관계JAVA/Generic 2020. 10. 18. 22:12
아래와 같은 프로그램이 있다고 하자.
위의 OhMethod함수의 인자로 전달될 수 있는 참조 값의 자료형은 두 가지이다.
1. FruitBox<Fruit>의 인스턴스 참조 값
2. FruitBox<Fruit>를 상속하는 인스턴스의 참조 값
위의 클래스 Fruit와 Apple 클래스의 상속 구조에서
FruitBox<Apple> 클래스는 OhMethod의 인자가 될 수 없다.
반드시 키워드 extends를 이용해서 상속이 명시된 대상만 인자로 전달 될 수 있다.
... extends FruitBox<Fruit>
다음과 같은 구조이다. 일단 보고 넘기자. 아래에 이 내용이 나온다.
와일드 카드와 제네릭 변수의 선언
와일드 카드란, 이름 또는 문자열에 제한을 가하지 않음을 명시하는 용도로 사용하는 특별한 기호이다.
위의 <? extends Fruit>가 의미하는 바는 "Fruit를 상속하는 모든 클래스"이다.
FruitBox<Fruit> 인스턴스의 참조 값도, FruitBox<Apple> 인스턴스의 참조 값도
인자와 전달받을 수 있는 매개변수의 선언에는 와일드카드 문자?가 사용된다.
아래의 문장이 의미하는 것은 자료형에 상관 없이 FruitBox<T>의 인스턴스를 참조해 사용되는
참조변수로 다음의 선언과 동일하다.
즉,아래의 두 문장은 서로 같다.
예제
소스 코드
더보기class Fruit { public void ShowYou() { System.out.println("I am Fruit."); } } class Apple extends Fruit { @Override public void ShowYou() { System.out.println("I red Fruit."); } } class FruitBox<T> { T item; public void Store(T item) {this.item = item;} public T PullOut() {return this.item;} } public class Exam1 { public static void main(String[] args) { FruitBox<Fruit> box1 = new FruitBox<Fruit>(); box1.Store(new Fruit()); FruitBox<Apple> box2 = new FruitBox<Apple>(); box2.Store(new Apple()); } public static void OpenAndShowFruitBox(FruitBox<? extends Fruit> box) { Fruit fruit = box.PullOut(); // Fruit클래스를 상속받은 객체들이 저장된다. fruit.ShowYou(); } }
하위 클래스를 제한하는 용도의 와일드 카드
위는 ~을 상속하는 클래스라면 무엇이든지라는 의미를 갖는다.
즉, Apple을 상속하는 클래스의 인스턴스라면 무엇이든지 참조 가능한 참조변수 선언이다.
위는 ~이 상속하는 클래스라면 무엇이든지라는 의미를 갖는다.
Apple이 상속하는 클래스의 인스턴스라면 무엇이든지 참조 가능한 참조변수 선언이다.
제네릭 클래스의 다양한 상속 방법1
위와 같이 제네릭 클래스도 상속이 가능하다. 그리고 이 경우 다음과 같이 인스턴스를 생성하게 된다.
아래를 보자.
위와 같은 경우는 T는 각 각 String과 Integer로 대체되어 인스턴스가 생성된다.
제네릭 클래스의 다양한 상속 방법2
아래와 같이 제네릭 클래스의 자료형을 결정해서 상속하는 것도 가능하다.
이 경우, BBB클래스는 제네릭과 관련 없는 클래스가 되어, 일반적인 방법으로 인스턴스를 생성하면 된다.
아래의 예제를 보자.
프로그램 실행결과
소스 코드
더보기class AAA<T> { T itemAAA; // 생성자 public AAA(T itemAAA) { this.itemAAA = itemAAA; } public void Print() { System.out.println("AAA : " +this.itemAAA); } } class BBB extends AAA<String> { int itemBBB; // 생성자 public BBB(String item) { super(item); // 부모 클래스 AAA<String>를 호출 } } public class Exam1 { public static void main(String[] args) { BBB bbb = new BBB("MyString"); bbb.Print(); } }
제네릭 인터페이스의 구현 방법
아래와 같이 인터페이스가 있다고 하자.
위의 인터페이스를 상속하는 두 클래스를 정의해보자.
1. 클래스
위의 클래스를 보면 알겠지만, 일반적인 인터페이스의 상속과 차이가 없다.
2. 클래스
위의 클래스를 보면 제네릭 인터페이스의 자료형을 지정해서 구현하는 것도 가능함을 알 수 있다.
소스 코드
더보기interface MyInterface<T> { public T MyFunc(T item); // 러턴형이 T인 추상 메소드 } class MyImplement<T> implements MyInterface<T> { @Override public T MyFunc(T item) { return item; } } class MyImplementString implements MyInterface<String> { @Override public String MyFunc(String item) { return item; } } public class Exam1 { public static void main(String[] args) { } }
'JAVA > Generic' 카테고리의 다른 글
제네릭 메소드와 배열 (0) 2020.10.18 매개변수의 자료형 제한 (0) 2020.10.18 제네릭 메소드 (0) 2020.10.18 제네릭 클래스의 이해와 설계 (0) 2020.10.18