object
로 할 수 있으나, 런타임에 instanceof
로 객체를 체크해야 함.p staticMethod(P p) 는 가능하다.
//일반 클래스
class Foo{
}
// 제네릭 클래스
// 클래스를 선언할 때에는 설정되지 않은 타입이 있으며, 이것을 타입 파라미터로 표현한다.
class GenericFoo<T> { // T: 타입 파라미터
String name;
T memberVar; // T를 자료형으로 사용.
public GenericFoo(String name, T memberVar) {
//생성자 생성 어떤 타입의 자료형이 들어오는지 모르는데 구현 가능.
this.name = name;
this.memberVar = memberVar;
}
}
//제네릭 인터페이스
interface GenericInterface<T>{ //인터페이스도 제네릭이 가능
}
class HashMap<k,w>{ // 여러 개의 타입 파라미터로 쓸 수 있다.
}
GenericFoo<String> foo = new GenericFoo<String>("name","var");
//**생성할 때 자료형을 정해주게 되어 있음.**
// <>안에 스트링으로 넣어줬기 때문에 T도 스트링으로 된다.
GenericFoo<String> foo1 = new GenericFoo<>("name","var");//뒤에 <>생략가능
class GenericBar<T>{
// 제네릭은 객체를 생성할때 자료형을 입력받기 때문에
// 스태틱은 객체 생성 전에 자료형이 결정되어야 하기때문에
// 클래스에 속하기 때문에 T를 사용하면 자료형 알 수 없음.
// static은 클래스에 속하기 때문에 애초에 T가 쓸수 없음 문법적 문제
static T classVar;
// 안된다.. 클래스의 스테틱변수는 객체와 관계없이 클래스에 속해있기 때문에
// 스태틱 변수가 생겨야하는 생성시점에는 T 자료형이 없기 때문에
static void method(T var){} //이것도 마찬가지로 불가능.
instanceof
의 피연산자로 사용할 수 없다.new
키워드를 사용하여 객체 생성을 할 수 없다. // T memberVar = new T(); t는 new 키워드를 쓸 수 없음. 안정성 문제 때문에 불가능하다.
// T라는 자료형이 결정되지 않기때문에 생성자가 어떻게 정의될지 모르기 때문에 불가능 자바에서 막혀있음.
// 타입파라미터의 객체를 생성하는 것은 불가능 하다.
{
Object obj = new Object();
if(obj instanceof T){
// 어떤 객체가 있을 때 T에 속하는지 확인하기 불가능. 안정성 문제 때문에 그냥 막혀있음.
}
}
부모 클래스 또는 인터페이스에 선언한 타입 파라미터는 반드시 자식에서도 선언해야 된다.
자식 클래스에서 추가적인 타입 파라미터를 선언할 수 있다.
부모 클래스와 인터페이스의 타입 파라미터가 같을 경우 상속받는 클래스에서 다르게 넣어주면 된다.
class Product<T,M> {
private T kind;
private M model;
public T getKind() {
return kind;
}
public void setKind(T kind) {
this.kind = kind;
}
public M getModel() {
return model;
}
public void setModel(M model) {
this.model = model;
}
}
class Tv{
}
class ChildProduct<K,V,C> extends Product<K,V>{
private C company;
public C getCompany() {
return company;
}
public void setCompany(C company) {
this.company = company;
}
}
public class ChildProductAndStorageExam {
public static void main(String[] args) {
ChildProduct<Tv,String,String> childProduct = new ChildProduct<Tv, String, String>();
childProduct.setKind(new Tv());
childProduct.setModel("스마트티비");
childProduct.setCompany("삼성");
}
}
//타입 제한을 하지 않으면 extends object와 동일하다.
class GenericNoTypeLimit<T extends Object>{
}
//extends를 이용해서 부모클래스를 제한 할 수 있음, 추상클래스를 상속하면서 인터페이스를 추가로 구현할 수 있음
// 추상클래스+인터페이스를 구현해야한다
class GenericTypeLimitation<T extends Number & Cloneable>{
}
class GenericMethod{
public <T> T method(T x){
// 여기서 <T> 는 제네릭 타입으로 선언을 하겠다라는 의미이다.
return x;
}
}
class GenericMethod<T> {
public static void method(T t) { // Error
...
}
public static <P> P method (P p) { // Possible
...
}
}
class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
class Util {
public static <T> Box<T> boxing(T t){
Box<T> box = new Box<T>();
box.set(t);
return box;
}
}
public class BoxingMethodExam {
public static void main(String[] args) {
Box<Integer> box = Util.<Integer>boxing(123);
Box<String> box2 = Util.boxing("홍길동");
System.out.println(box.get());
System.out.println(box2.get());
}
}
이미 선언되어 있는 제네릭 타입을 매개변수나 리턴타입으로 사용할 때 타입 파라미터를 제한할 목적
와일드카드 ?는 메소드의 입력 타입에 제네릭이 쓰일 경우, 제네릭의 타입 변수를 제한할 수 있다.
<?>
=> <? extends Object>
와 동일
<? extends T>
=> 와일드카드의 상한을 제한
<? super T>
=> 와일드카드의 하한을 제한
// 와일드카드
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return name;
}
}
class Worker extends Person {
public Worker(String name) {
super(name);
}
}
class Student extends Person{
public Student(String name) {
super(name);
}
}
class HighStudent extends Student{
public HighStudent(String name) {
super(name);
}
}
public class Course<T> {
private String name;
private T[] students;
public Course(String name, int capacity) {
this.name = name;
students = (T[])new Object[capacity];
// T타입으로 new 로 생성을 못하니깐 오브젝트로 만든다음
// 타입 변환을 해야 한다.
}
public String getName() {
return name;
}
public T[] getStudents() {
return students;
}
public void add(T t) {
for(int i=0; i<students.length; i++) {
if (students[i] == null) {
students[i] = t;
break;
}
}
}
}
package sec02.exam06_generic_wildCard;
import java.util.Arrays;
public class WildCardExam {
public static void registerCourse(Course<?> course) {
System.out.println(course.getName()+"수강생 : "+Arrays.toString(course.getStudents()));
}
// Student, HightStudent 클래스 타입만 가능, 상한을 제한한다
public static void registerCourseStudent(Course<? extends Student> course) {
System.out.println(course.getName()+"수강생 : "+Arrays.toString(course.getStudents()));
}
// Person, Worker 클래스 타입만 가능, 하한을 제한한다.
public static void registerCourseWorker(Course<? super Worker> course) {
System.out.println(course.getName()+"수강생 : "+Arrays.toString(course.getStudents()));
}
public static void main(String[] args) {
Course<Person> personCourse = new Course<Person>("일반인 과정",5);
personCourse.add(new Person("일반인"));
personCourse.add(new Person("직장인"));
personCourse.add(new Person("학생"));
personCourse.add(new Person("고등학생"));
Course<Worker> workerCourse = new Course<Worker>("직장인 과정",5);
workerCourse.add(new Worker("직장인"));
Course<Student> studentCourse = new Course<Student>("학생 과정",5);
studentCourse.add(new Student("학생"));
studentCourse.add(new HighStudent("고등학생"));
Course<HighStudent> highStudentCourse = new Course<HighStudent>("고등학생 과정",5);
// highStudentCourse.add(new Student("일반인")); //error
highStudentCourse.add(new HighStudent("직장인"));
registerCourse(personCourse); // 일반인 과정수강생 : [일반인, 직장인, 학생, 고등학생, null]
registerCourse(workerCourse); // 직장인 과정수강생 : [직장인, null, null, null, null]
registerCourse(studentCourse); // 학생 과정수강생 : [학생, 고등학생, null, null, null]
registerCourse(highStudentCourse); // 고등학생 과정수강생 : [직장인, null, null, null, null]
//registerCourseStudent(personCourse); error
//registerCourseStudent(workerCourse); error
registerCourseStudent(studentCourse); // 학생 과정수강생 : [학생, 고등학생, null, null, null]
registerCourseStudent(highStudentCourse); // 고등학생 과정수강생 : [직장인, null, null, null, null]
registerCourseWorker(personCourse); // 일반인 과정수강생 : [일반인, 직장인, 학생, 고등학생, null]
registerCourseWorker(workerCourse); // 직장인 과정수강생 : [직장인, null, null, null, null]
//registerCourseWorker(studentCourse); error
//registerCourseWorker(highStudentCourse); error
}
}