클래스에서 사용하는 변수의 자료형이 여러개일 수 있고, 그 기능은 (메서드) 동일한 경우 클래스의 자료형을 특정하지 않고 이후에 해당 클래스를 사용할 때 지정할 수 있도록 한다.
실제 사용되는 자료형의 변환은 컴파일러에 의해 검증되므로 안정적인 프로그래밍 방식이다. 컬렉션 프레임워크에서 많이 사용된다.
재료가 Powder인 경우
public class ThreeDPrinter1{
private Powder material;
public void setMaterial(Powder material) {
this.material = material;
}
public Powder getMaterial() {
return material;
}
}
재료가 Plastic인 경우
public class ThreeDPrinter2{
private Plastic material;
public void setMaterial(Plastic material) {
this.material = material;
}
public Plastic getMaterial() {
return material;
}
}
public class ThreeDPrinter{
private Object material;
public void setMaterial(Object material) {
this.material = material;
}
public Object getMaterial() {
return material;
}
}
대신 Object를 사용하는 경우는 형 변환을 해줘야한다.
ThreeDPrinter printer = new ThreeDPrinter();
Powder powder = new Powder();
printer.setMaterial(powder);
Powder p = (Powder)printer.getMaterial();
GenericPrinter.java
public class GenericPrinter<T> {
private T material;
public void setMaterial(T material) {
this.material = material;
}
public T getMaterial() {
return material;
}
public String toString(){
return material.toString();
}
}
T(type parameter) : 이 클래스를 사용하는 시점에 실제 사용할 자료형을 지정, static 변수는 사용할 수 없음Powder.java
public class Powder {
public String toString() {
return "재료는 Powder 입니다";
}
}
Plastic.java
public class Plastic {
public String toString() {
return "재료는 Plastic 입니다";
}
}
GenericPrinter.java
public class GenericPrinter<T> {
private T material; //T 자료형으로 선언한 변수
public void setMaterial(T material) {
this.material = material;
}
public T getMaterial() { //T 자료형을 반환하는 제네릭 메서드
return material;
}
public String toString(){
return material.toString();
}
}
GenericPrinterTest.java
public class GeneriPrinterTest {
public static void main(String[] args) {
GenericPrinter<Powder> powderPrinter = new GenericPrinter<Powder>();
powderPrinter.setMaterial(new Powder());
System.out.println(powderPrinter);
GenericPrinter<Plastic> plasticPrinter = new GenericPrinter<Plastic>();
plasticPrinter.setMaterial(new Plastic());
System.out.println(plasticPrinter);
}
}
<>상위클래스를 상속받음으로써 T 자료형의 범위를 제한할 수 있다. 또한 상위 클래스에서 선언하거나 정의하는 메서드를 활용할 수 있게 된다.
상속을 받지 않는 경우에는 T는 Object로 변환되어 Object 클래스가 기본으로 제공하는 메서드만 사용할 수 있다.

Material.java
public abstract class Material {
public abstract void doPrinting();
}
Powder.java
public class Powder extends Material {
public void doPrinting() {
System.out.println("Powder 재료로 출력합니다");
}
public String toString() {
return "재료는 Powder";
}
}
Plastic.java
public class Plastic extends Material{
public void doPrinting() {
System.out.println("Plastic 재료로 출력합니다");
}
public String toString() {
return "재료는 Plastic 입니다";
}
}
GenericPrinter.java
public class GenericPrinter<T extends Material> {
private T material;
public void setMaterial(T material) {
this.material = material;
}
public T getMaterial() {
return material;
}
public String toString(){
return material.toString();
}
public void printing() {
material.doPrinting();
}
}
GenericPrinterTest.java
public class GenericPrinterTest {
public static void main(String[] args) {
GenericPrinter<Powder> powderPrinter = new GenericPrinter<Powder>();
powderPrinter.setMaterial(new Powder());
Powder powder = powderPrinter.getMaterial(); // 형변환 하지 않음
System.out.println(powderPrinter);
GenericPrinter<Plastic> plasticPrinter = new GenericPrinter<Plastic>();
plasticPrinter.setMaterial(new Plastic());
Plastic plastic = plasticPrinter.getMaterial(); // 형변환 하지 않음
System.out.println(plasticPrinter);
/* GenericPrinter powderPrinter2 = new GenericPrinter();
powderPrinter2.setMaterial(new Powder());
Powder powder = (Powder)powderPrinter.getMaterial();
System.out.println(powderPrinter);
*/
//GenericPrinter<Water> printer = new GenericPrinter<Water>();
}
}
자료형 매개변수를 메서드의 매개변수나 반환값으로 가지는 메서드는 자료형 매개 변수가 하나 이상인 경우가 있다. 제네릭 클래스가 아니더라도 내부에 제네릭 메서드를 구현하여 사용이 가능하다.
public <자료형 매개변수> 반환형 메서드이름 (자료형 매개변수 ... ) { ... }
Point.java
public class Point<T, V> {
T x;
V y;
Point(T x, V y){
this.x = x;
this.y = y;
}
public T getX() {
return x;
}
public V getY() {
return y;
}
}
GenericMethod.java
public class GenericMethod {
public static <T, V> double makeRectangle(Point<T, V> p1, Point<T, V> p2) {
double left = ((Number)p1.getX()).doubleValue();
double right =((Number)p2.getX()).doubleValue();
double top = ((Number)p1.getY()).doubleValue();
double bottom = ((Number)p2.getY()).doubleValue();
double width = right - left;
double height = bottom - top;
return width * height;
}
public static void main(String[] args) {
Point<Integer, Double> p1 = new Point<Integer, Double>(0, 0.0);
Point<Integer, Double> p2 = new Point<>(10, 10.0);
double rect = GenericMethod.<Integer, Double>makeRectangle(p1, p2);
System.out.println("두 점으로 만들어진 사각형의 넓이는 " + rect + "입니다.");
}
}
Member.java
public class Member {
private int memberId; //회원 아이디
private String memberName; //회원 이름
public Member(int memberId, String memberName){ //생성자
this.memberId = memberId;
this.memberName = memberName;
}
public int getMemberId() { //
return memberId;
}
public void setMemberId(int memberId) {
this.memberId = memberId;
}
public String getMemberName() {
return memberName;
}
public void setMemberName(String memberName) {
this.memberName = memberName;
}
@Override
public String toString(){ //toString 메소드 오버로딩
return memberName + " 회원님의 아이디는 " + memberId + "입니다";
}
}
MemberArrayList.java
public class MemberArrayList {
private ArrayList<Member> arrayList; // ArrayList 선언
public MemberArrayList(){
arrayList = new ArrayList<Member>(); //멤버로 선언한 ArrayList 생성
}
public void addMember(Member member){ //ArrayList 에 멤버 추가
arrayList.add(member);
}
public boolean removeMember(int memberId){ // 멤버 아이디를 매개변수로, 삭제 여부를 반환
for(int i =0; i<arrayList.size(); i++){ // 해당 아이디를 가진 멤버를 ArrayList에서 찾음
Member member = arrayList.get(i);
int tempId = member.getMemberId();
if(tempId == memberId){ // 멤버아이디가 매개변수와 일치하면
arrayList.remove(i); // 해당 멤버를 삭제
return true; // true 반환
}
}
System.out.println(memberId + "가 존재하지 않습니다"); //for 가 끝날때 까지 return 이 안된경우
return false;
}
public void showAllMember(){
for(Member member : arrayList){
System.out.println(member);
}
System.out.println();
}
}
MemberArrayListTest.java
public class MemberArrayListTest {
public static void main(String[] args) {
MemberArrayList memberArrayList = new MemberArrayList();
Member memberLee = new Member(1001, "이순신");
Member memberKim = new Member(1002, "김유신");
Member memberKang = new Member(1003, "강감찬");
Member memberHong = new Member(1004, "홍길동");
memberArrayList.addMember(memberLee);
memberArrayList.addMember(memberKim);
memberArrayList.addMember(memberKang);
memberArrayList.addMember(memberHong);
memberArrayList.showAllMember();
memberArrayList.removeMember(memberHong.getMemberId());
memberArrayList.showAllMember();
}
}
MemberArrayList.java 의 removeMember() 메서드를 Iterator를 활용하여 구현
public boolean removeMember(int memberId){ // 멤버 아이디를 매개변수로, 삭제 여부를 반환
Iterator<Member> ir = arrayList.iterator();
while(ir.hasNext()) {
Member member = ir.next();
int tempId = member.getMemberId();
if(tempId == memberId){ // 멤버아이디가 매개변수와 일치하면
arrayList.remove(member); // 해당 멤버를 삭제
return true; // true 반환
}
}
System.out.println(memberId + "가 존재하지 않습니다"); //for 가 끝날때 까지 return 이 안된경우
return false;
}