제네릭이 무엇인지 직접적으로 알려준다면 다음과 같은 질문을 드릴 수 없습니다.
정수형, 부동소수점형, 문자열형 등 다양한 형태의 데이터를 저장할 수 있는 좌표점 클래스를 정의합니다.
처음에는 변수 유형이 불확실하므로 모든 유형의 상위 클래스, 즉 Object 클래스를 대신 사용한다고 생각하기 쉽습니다.
더 이상 말도 안되는 소리는 하지 마세요. 코드를 사용하여 반영하세요.
예 1: 객체를 사용하여 불확실한 데이터 유형 입력 구현
//불확실한 유형을 나타내기 위해 Object를 사용합니다.
공개 포인트(객체 x, 객체 y) {
this.setX(x);
this.setY(y);
}
공공 무효 setX(객체 x) {
this.x = x;
}
공공 객체 getX() {
x를 반환;
}
공공 무효 setY(객체 y) {
this.y = y;
}
공공 객체 getY() {
y를 반환;
}
}
//테스트 클래스
공개 수업 데모 {
공개 정적 무효 메인(String[] args) {
System.out.println("좌표를 나타내기 위해 부동 소수점 숫자를 사용합니다: ");
포인트 p = new Point(12.23,23.21);
//여기서 Object 클래스가 Double 클래스로 변환된 후 자동으로 unboxing됩니다. 다음 두 가지는 동일합니다.
System.out.println("X 좌표" + (Double)p.getX());
System.out.println("Y 좌표" + (Double)p.getY());
System.out.println();
System.out.println("정수를 사용하여 좌표를 나타냅니다: ");
포인트 p2 = 새로운 포인트(12, 23);
System.out.println("X 좌표" + (정수)p2.getX());
System.out.println("Y 좌표" + (Integer)p2.getY());
System.out.println();
System.out.println("좌표를 문자열로 표현: ");
Point p3 = new Point("북위 29도", "동경 113도");
System.out.println("X 좌표" + (String)p3.getX());
System.out.println("Y 좌표" + (String)p3.getY());
}
}
전달하려는 유형을 명확하게 이해한 다음 사용하기 전에 다운캐스트해야 합니다.
이는 요구 사항을 충족하지만 안전하지 않은 요소도 암시하는 이유는 무엇입니까?
예를 들어 new Point(12.23, "북위 29도")를 사용하여 Point 객체를 구성합니다.
그런 다음 (Double)을 사용하여 아래쪽으로 변환하면 결과가 어떻게 될까요?
예, 컴파일은 통과하지만 일단 실행되면 유형 변환 예외가 발생합니다.
클래스 변환 예외를 방지하는 것도 매우 간단합니다. Object 선언을 고정 유형 선언(예: String x, String y)으로 바꾸면 컴파일 중에 오류가 보고됩니다.
그러면 실수를 발견하고 수정할 수 있습니다.
하지만 그러면 우리는 그 수요를 충족시킬 수 없을 것입니다.
보안 위험을 방지하고 다양한 데이터 유형을 대체하기 위해 이러한 재능 있는 사람들이 JDK1.5에서 제네릭 개념을 도입했습니다.
제네릭을 사용하여 위 코드를 다시 작성하는 방법을 살펴보겠습니다.
예제 2: 일반 클래스
공개 수업 데모 {
공개 정적 무효 메인(String[] args) {
System.out.println("좌표를 나타내기 위해 부동 소수점 숫자를 사용합니다: ");
//제네릭으로 다시 작성한 후에는 사용된 데이터에 대해 하향 변환을 수행할 필요가 없습니다.
Point<Double> p = new Point<Double>(12.23,23.21);
System.out.println("X 좌표" + p.getX());
System.out.println("Y 좌표" + p.getY());
System.out.println();
System.out.println("정수를 사용하여 좌표를 나타냅니다: ");
Point<Integer> p2 = new Point<Integer>(12, 23);
System.out.println("X 좌표" + p2.getX());
System.out.println("Y 좌표" + p2.getY());
System.out.println();
System.out.println("좌표를 문자열로 표현: ");
Point<String> p3 = new Point<String>("북위 29도", "동경 113도");
System.out.println("X 좌표" + p3.getX());
System.out.println("Y 좌표" + p3.getY());
}
}
이때 의도적으로 다른 데이터 유형을 전달하는 경우:
Point<Double> p = new Point<Double>("북위 29도",12.22);
그러면 컴파일 중에 오류가 보고됩니다.
제네릭이 정의되어 있더라도 생성자에서 제네릭 메커니즘을 사용하지 않으면 데이터가 객체로 처리됩니다.
이것의 목적은 주로 다음과 같은 JDK1.4 이전의 이전 코드와 호환되는 것입니다.
포인트 p = new Point(22.11,23.21);
최종 실행 결과는 동일하지만 컴파일 중에 경고 메시지가 표시됩니다.
예시 3: 일반 메서드
위의 예에서 볼 수 있듯이 생성자에 객체 유형이 지정되면 전체 클래스에서 동일한 유형이 사용됩니다.
가장 일반적인 예는 다음과 같이 컬렉션 프레임워크에서 사용됩니다. ArrayList<Integer> al = new ArrayList<Integer>();
이때, al에서 동작하는 모든 객체 타입은 Integer이다.
그러나 때로는 연산의 대상을 고정하고 싶지 않고, 범용적인 기술을 좀 더 유연하게 사용하고 싶을 때도 있습니다.
이때 일반적인 방법을 시도해 볼 수 있습니다.
공개 <E> 무효 쇼(E e) {
System.out.println(e);
}
}
공개 수업 데모 {
공개 정적 무효 메인(String[] args) {
인쇄 p = new Print();
p.print(12);
p.print("안녕하세요");
p.show(new Integer(33));
p.show(23);
}
}
사실 이런 방식은 메소드에서 Object 객체를 사용하는 것과 큰 차이가 없습니다.
게다가 JDK1.5 이후에는 자동 언박싱 기능이 추가되어 하향 변환이 필요하지 않게 되었습니다.
예시 4: 일반 인터페이스
//구현 방법 1:
InterDemo1 클래스는 Inter<String> {을 구현합니다.
공공 무효 인쇄(문자열 t) {
System.out.println("인쇄: " + t);
}
}
//구현 방법 2:
InterDemo2<T> 클래스는 Inter<T> {를 구현합니다.
공공 무효 인쇄(T t) {
System.out.println("인쇄: " + t);
}
}
클래스 데모 {
공개 정적 무효 메인(String[] args) {
InterDemo1 id1 = 새로운 InterDemo1();
id1.print("안녕하세요");
InterDemo2<Integer> id2 = new InterDemo2<Integer>();
id2.print(new Integer(23));
}
}
제네릭 인터페이스를 구현하는 방법에는 두 가지가 있습니다. 하나는 구현 시 제네릭 형식을 지정하는 것입니다.
다른 하나는 여전히 제네릭을 사용하고 생성 중에 제네릭 유형을 결정하는 것입니다.