컬렉션을 사용할 때 타입 안정성의 문제가 발생할 수 있습니다. 제네릭(Generic)은 이러한 문제를 해결하기 위한 기법으로, 컴파일 시점에 타입을 지정하여 타입 안정성을 높이고 형변환을 줄여줍니다.
제네릭은 컬렉션 프레임워크와 함께 사용되어, 컬렉션이 다루는 데이터의 타입을 명시적으로 지정할 수 있습니다. 제네릭을 사용하지 않으면, 모든 데이터가 Object
로 처리되기 때문에, 데이터를 꺼낼 때마다 형변환이 필요합니다. 그러나 제네릭을 사용하면 컴파일 시점에 데이터 타입이 결정되므로 형변환이 필요 없고, 더 안전한 코드를 작성할 수 있습니다.
ArrayList<String>
은 String
타입을 저장하는 ArrayList
입니다. <T>
, <E>
, <K, V>
등과 같은 타입 파라미터를 사용할 수 있습니다.수업코드
package com.util1;
import java.util.ArrayList;
public class ArrayListEx03 {
public static void main(String[] args) {
// 제네릭을 사용하지 않은 ArrayList (다양한 타입이 들어갈 수 있음)
ArrayList al = new ArrayList();
// 1. ArrayList에 다양한 타입의 데이터 추가
al.add("A"); // 문자열
al.add("B"); // 문자열
al.add(10); // 정수형 (int)
al.add(20); // 정수형 (int)
al.add('a'); // 문자형 (char)
al.add('b'); // 문자형 (char)
// 2. ArrayList의 요소 출력 (정상적으로 출력)
System.out.println(al); // 출력: [A, B, 10, 20, a, b]
// 3. ArrayList의 데이터 타입 불일치로 인한 문제 발생
// 이 코드는 컴파일 시에는 문제가 없지만, 실행 시 ClassCastException 오류 발생
for (int i = 0; i < al.size(); i++) {
// ArrayList에서 데이터를 가져올 때, Object로 반환되기 때문에
// 문자열로 형변환을 시도하지만, 정수나 문자형이 들어가 있으면 오류 발생
String data = (String) al.get(i); // 실행 중 ClassCastException 발생
System.out.println(data);
}
// 4. 제네릭을 사용한 ArrayList
// 제네릭을 사용하여 String 타입으로만 데이터를 받도록 제한
ArrayList<String> al2 = new ArrayList<>();
// 5. ArrayList에 문자열만 추가
al2.add("aa");
al2.add("bb");
al2.add("cc");
// 6. 제네릭을 사용한 ArrayList에서 데이터를 가져올 때는 형변환이 필요 없음
// 타입 안정성이 보장되므로 String 타입으로 바로 가져올 수 있음
for (int i = 0; i < al2.size(); i++) {
String data = al2.get(i); // 형변환 필요 없음
System.out.println(data);
}
// 7. 향상된 for문을 사용하여 ArrayList의 요소 출력 (더 간결하게 표현 가능)
for (String data : al2) {
System.out.println(data); // 형변환 없이 바로 출력
}
}
}
수업코드 : ArrayListEx04
package com.util1;
import java.util.Objects;
public class Student {
private String hakbun;
private String name;
public Student(String hakbun, String name) {
this.hakbun = hakbun;
this.name = name;
}
public String getHakbun() {
return hakbun;
}
public void setHakbun(String hakbun) {
this.hakbun = hakbun;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"hakbun='" + hakbun + '\'' +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(hakbun, student.hakbun) && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(hakbun, name);
}
}
package com.util1;
import java.util.ArrayList;
public class ArrayListEx04 {
public static void main(String[] args) {
// 3명의 Student 객체 생성
Student s1 = new Student("1001", "홍길동");
Student s2 = new Student("1002", "박문수");
Student s3 = new Student("1003", "임꺽정");
// Student 타입만 저장 가능한 ArrayList 생성
ArrayList<Student> al = new ArrayList<>();
// ArrayList에 Student 객체 추가
al.add(s1);
al.add(s2);
al.add(s3);
// ArrayList 출력 (내부적으로 toString 호출되어 각 객체의 정보가 출력됨)
System.out.println(al);
// for문을 통한 접근
for (int i = 0; i < al.size(); i++) {
Student s = al.get(i);
System.out.println(s.getHakbun());
System.out.println(s.getName());
}
// 향상된 for문
for (Student s : al) {
System.out.println(s.getHakbun());
System.out.println(s.getName());
}
}
}