Java

제네릭

제네릭이란?

제네릭(Generic)은 클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법을 의미한다. 말이 어렵다. 아래 그림을 보자.

위의 그림은 아래의 코드를 간략화한 것이다.

package org.opentutorials.javatutorials.generic;

class Person<T>{
    public T info;
}

public class GenericDemo {

	public static void main(String[] args) {
		Person<String> p1 = new Person<String>();
		Person<StringBuilder> p2 = new Person<StringBuilder>();
	}

}

그림을 보자. p1.info와 p2.info의 데이터 타입은 결과적으로 아래와 같다.

  • p1.info : String
  • p2.info : StringBuilder

그것은 각각의 인스턴스를 생성할 때 사용한 <> 사이에 어떤 데이터 타입을 사용했느냐에 달려있다. 

클래스 선언부를 보자.

public T info;

클래스 Person의 필드 info의 데이터 타입은 T로 되어 있다. 그런데 T라는 데이터 타입은 존재하지 않는다. 이 값은 아래 코드의 T에서 정해진다.

class Person<T>{

위 코드의 T는 아래 코드의 <> 안에 지정된 데이터 타입에 의해서 결정된다. 

Person<String> p1 = new Person<String>();

위의 코드를 나눠보자. 아래 코드는 변수 p1의 데이터 타입을 정의하고 있다.

Person<String> p1

아래 코드는 인스턴스를 생성하고 있다. 

new Person<String>();

즉 클래스를 정의 할 때는 info의 데이터 타입을 확정하지 않고 인스턴스를 생성할 때 데이터 타입을 지정하는 기능이 제네릭이다. 

제네릭이 무엇인가를 알았으니까 이제 제네릭을 사용하는 이유를 알아보자. 

제네릭을 사용하는 이유

타입 안전성

아래 코드를 보자.

package org.opentutorials.javatutorials.generic;
class StudentInfo{
    public int grade;
	StudentInfo(int grade){ this.grade = grade; }
}
class StudentPerson{
	public StudentInfo info;
	StudentPerson(StudentInfo info){ this.info = info; }
}
class EmployeeInfo{
	public int rank;
	EmployeeInfo(int rank){	this.rank = rank; }
}
class EmployeePerson{
	public EmployeeInfo info;
	EmployeePerson(EmployeeInfo info){ this.info = info; }
}
public class GenericDemo {
	public static void main(String[] args) {
		StudentInfo si = new StudentInfo(2);
		StudentPerson sp = new StudentPerson(si);
		System.out.println(sp.info.grade); // 2
		EmployeeInfo ei = new EmployeeInfo(1);
		EmployeePerson ep = new EmployeePerson(ei);
		System.out.println(ep.info.rank); // 1
	}
}

그리고 아래 코드를 보자. 위의 코드는 StudentPerson과 EmployeePerson가 사실상 같은 구조를 가지고 있다. 중복이 발생하고 있는 것이다. 중복을 제거해보자.

package org.opentutorials.javatutorials.generic;
class StudentInfo{
    public int grade;
	StudentInfo(int grade){ this.grade = grade; }
}
class EmployeeInfo{
	public int rank;
	EmployeeInfo(int rank){	this.rank = rank; }
}
class Person{
	public Object info;
	Person(Object info){ this.info = info; }
}
public class GenericDemo {
	public static void main(String[] args) {
		Person p1 = new Person("부장");
		EmployeeInfo ei = (EmployeeInfo)p1.info;
		System.out.println(ei.rank);
	}
}

위의 코드는 성공적으로 컴파일된다. 하지만 실행을 하면 아래와 같은 오류가 발생한다.

Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to org.opentutorials.javatutorials.generic.EmployeeInfo
    at org.opentutorials.javatutorials.generic.GenericDemo.main(GenericDemo.java:17)

아래 코드를 보자.

Person p1 = new Person("부장");

클래스 Person의 생성자는 매개변수 info의 데이터 타입이 Object이다. 따라서 모든 객체가 될 수 있다. 그렇기 때문에 위와 EmployeeInfo의 객체가 아니라 String이 와도 컴파일 에러가 발생하지 않는다. 대신 런타임 에러가 발생한다. 컴파일 언어의 기본은 모든 에러는 컴파일이 발생할 수 있도록 유도해야 한다는 것이다. 런타임은 실제로 애플리케이션이 동작하고 있는 상황이기 때문에 런타임에 발생하는 에러는 항상 심각한 문제를 초래할 수 있기 때문이다. 

위와 같은 에러를 타입에 대해서 안전하지 않다고 한다. 즉 모든 타입이 올 수 있기 때문에 타입을 엄격하게 제한 할 수 없게 되는 것이다. 

제네릭화

이것을 제네릭으로 바꿔보자.

package org.opentutorials.javatutorials.generic;
class StudentInfo{
    public int grade;
	StudentInfo(int grade){ this.grade = grade; }
}
class EmployeeInfo{
	public int rank;
	EmployeeInfo(int rank){	this.rank = rank; }
}
class Person<T>{
	public T info;
	Person(T info){ this.info = info; }
}
public class GenericDemo {
	public static void main(String[] args) {
		Person<EmployeeInfo> p1 = new Person<EmployeeInfo>(new EmployeeInfo(1));
		EmployeeInfo ei1 = p1.info;
		System.out.println(ei1.rank); // 성공
		
		Person<String> p2 = new Person<String>("부장");
		String ei2 = p2.info;
		System.out.println(ei2.rank); // 컴파일 실패
	}
}

p1은 잘 동작할 것이다. 중요한 것은 p2다. p2는 컴파일 오류가 발생하는데 p2.info가 String이고 String은 rank 필드가 없는데 이것을 호출하고 있기 때문이다. 여기서 중요한 것은 아래와 같이 정리할 수 있다.

  • 컴파일 단계에서 오류가 검출된다.
  • 중복의 제거와 타입 안전성을 동시에 추구할 수 있게 되었다.

제네릭의 특성

복수의 제네릭

클래스 내에서 여러개의 제네릭을 필요로 하는 경우가 있을 것이다. 예제를 보자.

package org.opentutorials.javatutorials.generic;
class EmployeeInfo{
    public int rank;
	EmployeeInfo(int rank){	this.rank = rank; }
}
class Person<T, S>{
	public T info;
    public S id;
    Person(T info, S id){ 
        this.info = info; 
    	this.id = id;
    }
}
public class GenericDemo {
	public static void main(String[] args) {
		Person<EmployeeInfo, int> p1 = new Person<EmployeeInfo, int>(new EmployeeInfo(1), 1);
	}
}

위의 코드는 예외를 발생시키지만 문제는 다음 예제에서 처리하고 형식만 보자. 

즉, 복수의 제네릭을 사용할 때는 <T, S>와 같은 형식을 사용한다. 여기서 T와 S 대신 어떠한 문자를 사용해도 된다. 하지만 묵시적인 약속(convention)이 있기는 하다. 그럼 예제의 오류를 해결하자.

기본 데이터 타입과 제네릭

제네릭은 참조 데이터 타입에 대해서만 사용할 수 있다. 기본 데이터 타입에서는 사용할 수 없다. 따라서 아래와 같이 코드를 변경한다.

package org.opentutorials.javatutorials.generic;
class EmployeeInfo{
    public int rank;
	EmployeeInfo(int rank){	this.rank = rank; }
}
class Person<T, S>{
	public T info;
	public S id;
	Person(T info, S id){ 
		this.info = info;
		this.id = id;
	}
}
public class GenericDemo {
	public static void main(String[] args) {
		EmployeeInfo e = new EmployeeInfo(1);
		Integer i = new Integer(10);
		Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i);
		System.out.println(p1.id.intValue());
	}
}

new Integer는 기본 데이터 타입인 int를 참조 데이터 타입으로 변환해주는 역할을 한다. 이러한 클래스를 래퍼(wrapper) 클래스라고 한다. 덕분에 기본 데이터 타입을 사용할 수 없는 제네릭에서 int를 사용할 수 있다.

제네릭의 생략

제네릭은 생략 가능하다. 아래 두 개의 코드가 있다. 이 코드들은 정확히 동일하게 동작한다. e와 i의 데이터 타입을 알고 있기 때문이다.

EmployeeInfo e = new EmployeeInfo(1);
Integer i = new Integer(10);
Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i);
Person p2 = new Person(e, i);

메소드에 적용

제네릭은 메소드에 적용할 수도 있다. 

package org.opentutorials.javatutorials.generic;
class EmployeeInfo{
    public int rank;
    EmployeeInfo(int rank){	this.rank = rank; }
}
class Person<T, S>{
	public T info;
	public S id;
	Person(T info, S id){ 
		this.info = info;
		this.id = id;
	}
	public <U> void printInfo(U info){
		System.out.println(info);
	}
}
public class GenericDemo {
	public static void main(String[] args) {
		EmployeeInfo e = new EmployeeInfo(1);
		Integer i = new Integer(10);
		Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i);
		p1.<EmployeeInfo>printInfo(e);
		p1.printInfo(e);
	}
}

제네릭의 제한

extends

제네릭으로 올 수 있는 데이터 타입을 특정 클래스의 자식으로 제한할 수 있다.

package org.opentutorials.javatutorials.generic;
abstract class Info{
    public abstract int getLevel();
}
class EmployeeInfo extends Info{
	public int rank;
	EmployeeInfo(int rank){	this.rank = rank; }
	public int getLevel(){
		return this.rank;
	}
}
class Person<T extends Info>{
	public T info;
	Person(T info){ this.info = info; }
}
public class GenericDemo {
	public static void main(String[] args) {
		Person p1 = new Person(new EmployeeInfo(1));
		Person<String> p2 = new Person<String>("부장");
	}
}

위의 코드에서 중요한 부분은 다음과 같다.

class Person<T extends Info>{

즉 Person의 T는 Info 클래스나 그 자식 외에는 올 수 없다.

extends는 상속(extends)뿐 아니라 구현(implements)의 관계에서도 사용할 수 있다.

package org.opentutorials.javatutorials.generic;
interface Info{
    int getLevel();
}
class EmployeeInfo implements Info{
	public int rank;
	EmployeeInfo(int rank){	this.rank = rank; }
	public int getLevel(){
		return this.rank;
	}
}
class Person<T extends Info>{
	public T info;
	Person(T info){ this.info = info; }
}
public class GenericDemo {
	public static void main(String[] args) {
		Person p1 = new Person(new EmployeeInfo(1));
		Person<String> p2 = new Person<String>("부장");
	}
}

이상으로 제네릭의 기본적인 사용법을 알아봤다. 

댓글

댓글 본문
작성자
비밀번호
  1. 궁금이
    아래코드에 왜 에러가 발생하는지 잘 모르겠어요... 생략을 하면 왜 오류가 나는거죠?

    https://ideone.com/cpUGe7

    class EmployeeInfo4{
    public int rank;
    EmployeeInfo4(int rank){ this.rank = rank; }
    }
    class Person4<T, S>{ //generic으로 원시 기본 data type 을 사용할 수 없다. 사용하고 싶다면 wrapper class 을 사용해야한다. 원시 기본 data type을 객체화 시키는것
    public T info;
    public S id;
    Person4(T info, S id){
    this.info = info;
    this.id = id;
    }
    public <U> void printInfo (U info) {
    System.out.println(info);
    }
    }
    public class GenericDemo4 {
    public static void main(String[] args) { //Integer => int 에 대한 wrapping class

    System.out.println("");
    System.out.println("Multiple Generic Demo\n");

    EmployeeInfo4 e = new EmployeeInfo4(1);
    Integer i = new Integer(10);
    Person4<EmployeeInfo4, /*int*/Integer> p1 = new Person4<EmployeeInfo4, /*int*/Integer>(e, i);
    Person4 p2 = new Person4(e, i);
    //Person4 p1 = new Person4(new EmployeeInfo4(1), new Integer(10));

    //p1
    System.out.println(p1.info.rank);
    System.out.println(p1.id);
    System.out.println(p1.id.intValue());
    System.out.println("end\n");

    p1.<Integer>printInfo(e.rank);
    p1.printInfo(e.rank);
    p1.<Integer>printInfo(i);
    p1.printInfo(i);
    p1.<Integer>printInfo(i.intValue());
    p1.printInfo(i.intValue());
    System.out.println("end\n");

    //p2
    System.out.println(p2.info.rank); //=>오류 why?
    System.out.println(p2.id);
    System.out.println(p2.id.intValue()); //=>오류 why?
    System.out.println("end\n");

    p2.<Integer>printInfo(e.rank);
    p2.printInfo(e.rank);
    p2.<Integer>printInfo(i);
    p2.printInfo(i);
    p2.<Integer>printInfo(i.intValue());
    p2.printInfo(i.intValue());
    System.out.println("end\n");

    }
    }
  2. 오징돌
    temp를 Integer로 수정하고 data의 타입을 오브젝트말고 T 로 바꿔보세요
    대화보기
    • 오징돌
      person<String> A = person<>은
      person클래스한테 스트링의객채만 전달할수있다고 제한하는 것입니다 그러니까 A는 person클래스의 객채인거죠
      대화보기
      • 감자돌이
        궁금한게 있습니다.

        Person A = new person();
        이렇게 인스턴스를 생성하면 A의 데이터타입은 기본적으로 Person이 되잖아요

        그런데 제네릭을 사용해서
        Person <string>A = new Person<string>();
        하게되면 A의 데이터타입을 string으로 정하는게 맞나요?

        그럼 Person은 더이상 A의 데이터타입 기능을 하지 못하는 건가요??

        컬랙션즈 프레임워크 강의를 듣다가, Collection<integer>A = new Hashset<Integer>(); 를 보며 hashset이 컬렉션 인터페이스를 구현하므로 좌항의 데이터타입을 컬렉션으로 해도 된다고 말씀하시는 부분에서 혼동이 와서 질문합니다.
      • 정동휘
        다들 '제네릭의 제한' 실습 되시나요??? 전 위의 코드로 잘 안되는 것 같습니다.
      • 파이팅
        한번들으니 멍하네요 . 지식이 쪼개지면서 받아들여짐 ㅜㅡㅜ
      • 엔터군
        질문이 있습니다.
        제네릭의 생략 동영상 강좌를 보면서 코드를 따라가는데요..

        Person<EmployeeInfo, Integer> p1 = new Person<EmployeeInfo, Integer>(e, i); 이코드를
        Person p1 = new Person(e,i); 로 바꿨는데 컴파일 과정에서..

        Note: GenericDemo.java uses unchecked or unsafe operations.
        Note: Recompile with -Xlint:unchecked for details.

        이러한 에러메세지가 떴는데요....혹시 다른분들은 안뜨시나요??

        -메세지 발생 원인-
        구글링 해보니 버전의 차이에서 발생되는 메세지라는 것을 찾았네요...
        클래스파일도 생성되고 실행도 되더군요...;;;;
        혹시나 다른이유가 더 있을지몰라서 질문글은 남겨둡니다
      • Jeon Dong Ho
        휴.. 막바지 들어서 어렵지만.. 좀더 살펴보면서 다시 내용을 정리하고 연습해 보겠습니다.
        좋은 강의 늘 감사합니다^^
      • 광대승천
        T가 가질수 있는 타입은 Info 혹은 Info의 자식 클래스가 됩니다.
        Person의 변수에 T타입의 info가 있죠
        Info 클래스는 getLevel() 메소드를 가지고 있기 때문에
        Info 타입 혹은 Info의 자식 타입의 Person 클래스의 변수 info 타입이 결정되면
        info.getLevel()을 사용할 수 있는 것으로 보이네요.
        혹시 틀린것 있으면 지적 부탁드립니다.
        대화보기
        • 광대승천
          맞아요 좀 이상하다고 생각했는데 이게 맞는것 같습니다.
          대화보기
          • 버미
            그리고 아래 코드를 보자. 위의 코드는 StudentPerson과 EmployeeInfo가 사실상 같은 구조를 가지고 있다. 중복이 발생하고 있는 것이다. 중복을 제거해보자.

            EmployeeInfo -> EmployeePerson
          • 라떼
            어렵지만 더 공부를 해야겠네요 .. 감사합니다!
          • 헛둘헛둘
            진짜 너무 좋네요 ㅠㅠ 동영상까지 올려주시고 감사합니다.
          • 자바바
            갑자기 너무 어렵다;;
          • Weaver
            강의 감사합니다~
          • SK Kim
            Generic 계념은 이해가 되는데, 설명 예제들의 구조가 오히려 햇갈리네요.
            클래스 내부에 클래스가 있고 하니..
            초보가 사용하기에는 고급 내용인듯하니 다음 강의로 넘어갑니다.
          • JustStudy
            고맙습니다
          • 감사합니당ㅇ
          • 김트라슈
            감사합니다~
          • 보람차게
            IDE 인텔리제이 쓰고 있는데 제네릭 생략하면 Person(T,S)의 요청이 확인되지 않는다는 경고문구가 뜨네요. 그리고 p2.info.rank가 해결되지 않는다고 에러가 발생하는데 왜 이런걸까요?
            p2.info
            p2.id
            는 잘 되는데 말이죠...
          • 보람차게
            Java5 이상부턴 new Integer(1)로 박싱 안 하고 그냥 1로 보내도 된다는군요
          • 오빠는다르다
            감사합니다!!!!!!
          • ㅇㅇ
            작년에 처음들었을때는 도저히 이해가 안갔었는데
            이번에 두번째로 들으니깐 보이긴 보이네요
            막상 나중에 쓸려고 하면 또 어려울듯 ㅋㅋ
          • 박첩구드
            제네릭은 정말 유용할 것 같아요~!!
          • flys0m@naver.com
            자바 넘나 어려운것
          • eagles70
            좀 어려워 지네요^^;;
          • scs87
            안녕하세요 이고잉 강사님 !

            두 번째 강의에서 StudentPerson 과 EmployeePerson 로직의 형태가 중복되고 있는데요~.

            EmployeePerson 대신 EmployeeInfo로 잘못 메모 되어 있는 것 같아서요

            수정해주시면 더 좋은 강의가 될 것 같아서요 !

            무튼 감사합니다. 아 그리고 지금까지 강의 전부 만족하는데요 ^^

            enum강의만 꼭 좀 보완 해주시면 감사해요

            노트에는 나와있는데 설명을 안해주시는 부분도 있더라구요

            그럼 수고하세요 파이팅 ^^
          • 방문자
            String Integer 둘이 다르기 때문이 아닐까여
            대화보기
            • dkiekkf@gmail.com
              클래스에서는 T S 를 사용하셨고 메서드에서는 U를 사용하셨는데 각각의 T S U가 용도가 틀린가요 아니면 전부다 generic을 의미하는 대문자 같은건가요?
            • cocohodu
              좋은강의 감사합니다
            • 나무늘보
              유튜브 오른쪽 하단에
              HD라고 뜬 톱니바퀴모양
              속도 <<<<<<<<<<
              대화보기
              • 배속
                배속으로 보는법좀요
                대화보기
                • case 어쩌구가 아니라
                  ClassCastException인듯 하네요
                  다운캐스팅이 불가할때 발생하는 예외입니다
                  대화보기
                  • GunLoc
                    처음으로 질문 남깁니다.,
                    class Person<T extends Info>{
                    public T info;
                    Person(T info){ this.info = info; }
                    }
                    이 클래스 안에다가
                    info..getLevel();이 가능 한 이유를 알고 싶습니다.
                    여기서 info는 EmployeeInfo이므로 Info의 자식이기때문에
                    Info의 기능을 쓸수있다는건 알겠는데.
                    여기서 "info."는 참조변수로 봐야하는건가요? (즉, 가리킨다고 봐야하나요?)
                    접근을 "info."로 하는 이유가 궁금해서요 ㅎ
                  • 이리지기
                    감사합니다 잘보고 갑니다.
                    하나 궁금한게 있는데요.

                    public <T> T back(Object data){
                    return (T) data;
                    }
                    위의 형태로 메서드를 작성했을 때

                    int temp = a.<Integer>back("12");
                    위와같이 호출을 하면, 반환값에서 왜 case Exception이 나는건가요?
                  • ps.won
                    감사합니다 잘보고 갑니다~~
                  • 안졸려고노력하는이
                    졸릴땐 1.5배속 혹은 2배속으로 보세요.
                    대화보기
                    • 지나가는이
                      와 고맙습니다. 머리에 쏙쏙 들어오는데요
                    • 개발원교육센터
                      <너><무><어><렵><네><요>
                    • 경영기술
                      <졸><립><네><요>
                    • 지나가는 인
                      뒷부분은 많이 복잡하게 느껴지네요.
                      하나짜리는 좀 봐서 쓸만한데 다수를 동시에 하면 복자도가 올라가고 어려울 것 같네요.

                      그래도 덕분에 좋은 리뷰가 되었네요.
                      감사합니다.
                    • coolperson<>
                      강의는 너무 고마운데, 말투가 너무 너무 졸리워요..
                    • jeyul
                      제가 아는 범위내에서 두 가지 경우로 나눠서 적어 볼께요.

                      1) 제네릭을 생략하지 않은 경우에는 그냥 변수의 값을 출력하시면 됩니다.
                      p1.info는 EmployeeInfo 타입입니다.
                      p1.info.rank는 int 타입입니다.
                      p1.id는 Integer 타입입니다.
                      p1.id.intValue()의 리턴값은 int 타입입니다.

                      2) 제네릭을 생략한 경우에는 형변환이 필요합니다. 마우스 포인터를 변수 p2.info와 p2.id 위에
                      올려놓아보면 Object 타입임을 확인할 수 있습니다. 맴버 필드의 값을 참조하기위해 Object 타입을
                      해당 클래스 타입으로 형변환해줘야 합니다.
                      p2.info는 Object 타입입니다.
                      ((EmployeeInfo)p2.info).rank는 int 타입입니다.
                      p2.id는 Object 타입입니다.
                      ((Integer)p2.id).intValue()의 리턴값은 int 타입입니다.

                      제네릭 생략시 Person 클래스의 맴버 필드 info와 id가 Object 클래스 타입으로 인식되는 것만
                      주의하시고 변수들의 타입을 잘 확인하고 콘솔에 값을 출력해보시면 됩니다.
                      질문1답) intValue()메소드를 호출해도 되고 안 해도 됩니다. 결과는 똑 같이 출력됩니다.
                      질문2답) 멤버 필드의 접근 지시자가 public이므로 당연히 접근이 가능합니다.
                      대화보기
                      • Haewon Lee
                        제네릭을 생략화 시키니까 3번째 강의에서 구현했던
                        System.out.println(p1.id.intValue()); 이 부분에서 오류가 나네요??
                        제네릭 생략화를 했을 때 위 구문을 실행시키려면 어떻게 바꿔줘야하나요??
                        -> 아 System.out.println(p1.id); 로 바꿔주면 되는군요. 그런데 제네릭 생략화 하기전에
                        System.out.println(p1.id); 이렇게 실행해도 아무 오류가 없네요...
                        질문1. 흠.... 그렇다면 id의 상수값을 호출하기 위해서 꼭 .intValue()를 꼭 붙여줘야하나요?? (단순히 화면 출력할 떄는 .intValue가 구지 필요한건 아닌건가요..?)

                        제네릭 생략화가 되어있는 상태에서
                        System.out.println(p1.info.rank); 이 구문을 제가 시험삼아 적어봤는데,
                        오류가 나네요. 이건 어떻게 바꿔줘야하나요?(물론, 제네릭 생략화를 안했을때는 정상 실행이 됬습니다.)
                        -> 아 class Person<T,S>를 class Person<T extends EmployeeInfo, S> 이렇게 바꿔주니 실행이 되네요. 불특정한 Object의 변수 중에는 rank라는 변수가 없어서 오류가 났다고 이해했습니다.

                        질문2. 그렇다면 class Person<T,S>로 선언되어 있고 제네릭을 생략화 시키지 않았을때 메인 메소드에서 System.out.println(p1.info.rank); 는 왜 실행이 되는거죠?
                      • egoing
                        알겠습니다. 제네릭 부분 수업 다시 만드는 것도 고려해볼께요. 지금 밀려있는 일들 정리 되는데로요..
                        대화보기
                        • Lewis6
                          Hyug Yoon 님이 말씀하신 대로 '제네릭화' 부분의 예제 설명이 빠진 듯 합니다.
                          제네릭화 하여 p1은 성공, p2는 컴파일 실패를 확인해 보는 예제 부분이요 ^^

                          그래서 인지 .. 갑자기 '복수의 제네릭' 사용법이 나와 이해가 좀 어려웠네요 ;;
                          대화보기
                          • 도로시
                            사소한 오타가 있네요. 아마 보시는 분들에게 큰 문제는 없었을 테지만..

                            타입 안전성의 첫 예제 아래에 있는 텍스트에서
                            "위의 코드는 StudentPerson과 EmployeeInfo가 사실상 같은 구조를 가지고 있다"
                            --> "위의 코드는 StudentPerson과 EmployeePerson이 사실상 같은 구조를 가지고 있다"
                            이렇게 바뀌는 게 맞을 것 같아요 ^^
                          • Hyug Yoon
                            동영상을 다시 다 보았는데, 제 생각에는
                            2/5 영상과 3/5 영상 사이에서 예제 소스를 '제네릭화' 하는 내용이 빠진 것 같네요.
                            3/5 영상이 시작되면 "자바라는 언어에 새로운 기능이 추가도입되면서 벌어지는 상황"에 대해 잠시 얘기해주신 뒤에,
                            바로 '복수의 제네릭' 사용법에 대해서 강의해 주고 계시거든요.

                            시간 되실 때 2/5 영상 끝과, 3/5 영상 앞부분을 체크해보시면 좋을 것 같습니다.
                            지금 보니까 페이지 내에서 예제 소스 블록에 대해서 [예제 1], [예제 2], 이런식으로 붙어 있으면
                            더 소통하기 좋지 않을까 하는 생각도 드네요.

                            좋은 강의 감사드립니다.
                            대화보기
                            • egoing
                              음 제가 동영상을 전부 다시 리뷰해보지는 못했는데요. 아마 제네릭을 사용하는 방법 자체는 첫번째 동영상에서 설명한 것이 아닐까 싶습니다. 혹시 제가 빠뜨린게 있으면 알려주세요. 감사합니다.
                              대화보기
                              • Hyug Yoon
                                훈훈한 목소리의 egoing님 강의 잘 보고 있습니다. :D
                                2/5 영상 끝부분에서 '타입안정성'에 대해서 설명해주신 후에,
                                "'제네릭화' 시키는 부분은 다음 동영상에서 살펴본다"고 하셨는데,
                                3/5 영상을 보면 바로 '제네릭의 특성 > 복수의 제네릭' 내용 부터 시작하는 것 같네요.
                                혹시 중간에 누락된 게 아닌지요?
                              버전 관리
                              egoing
                              현재 버전
                              선택 버전
                              graphittie 자세히 보기