*본 내용은 [Do it! 자바 프로그래밍 입문] 책과 강의를 보고 공부하면서 요점 정리한 내용입니다.
여러 자료형이 대체될 수 있도록 프로그래밍하는 방식
참조자료형에서만 사용
변수의 선언이나 메서드 매개변수를 하나의 참조 자료형이 아닌 여러 자료형을 변환될 수 있도록 프로그래밍하는 방식
실제 사용되는 참조 자료형으로의 변환은 컴파일러가 검증하므로 안정적인 프로그래밍 방식
컬렉션 프레임워크에서 많이 사용되고 있음
[Object 사용]
ThreeDPrinter.java
package generics;
public class ThreeDPrinter {
private Object material;
public Object getMaterial() {
return material;
}
public void setMaterial(Object material) {
this.material = material;
}
}
ThreeDPrinterTest.java
package generics;
public class ThreeDPrinterTest {
public static void main(String[] args) {
ThreeDPrinter printer = new ThreeDPrinter();
printer.setMaterial(new Powder());
Powder powder = (Powder)printer.getMaterial(); // 명시적 형 변환 필요
}
}
[제네릭 클래스 사용]
ThreeDPrinter.java
package generics;
public class ThreeDPrinter<T> {
private T material;
public T getMaterial() {
return material;
}
public void setMaterial(T material) {
this.material = material;
}
}
ThreeDPrinterTest.java
package generics;
public class ThreeDPrinterTest {
public static void main(String[] args) {
ThreeDPrinter<Powder> printer = new ThreeDPrinter<Powder>();
printer.setMaterial(new Powder());
Powder powder = printer.getMaterial(); // 명시적 형 변환 필요X
}
}
ArrayList<String>list = new ArrayList<>();
ArrayList<String> list = new ArrayList<String>();
↓
var list = new ArrayList<String>();
| 용어 | 설명 |
|---|---|
| GenericPrinter<Powder> | 제네릭 자료형(Generic type), 매개변수화된 자료형(parameterized type) |
| Powder | 대입된 자료형 |
Plastic.java
package generics;
public class Plastic extends Material{
public String toString() {
return "재료는 Plastic 입니다.";
}
@Override
public void doPrinting() {
System.out.println("Plastic 재료로 출력합니다.");
}
}
Powder.java
package generics;
public class Powder extends Material{
public String toString() {
return "재료는 Powder 입니다.";
}
@Override
public void doPrinting() {
System.out.println("Powder 재료로 출력합니다.");
}
}
Water.java
package generics;
public class Water {
public String toString() {
return "재료는 Water 입니다.";
}
}
Material.java
package generics;
public abstract class Material {
//제한 만들고 싶을 때 상위 클래스 만들어 상속 받기
public abstract void doPrinting();
}
ThreeDPrinter.java
package generics;
public class ThreeDPrinter<T extends Material> {
private T material;
public T getMaterial() {
return material;
}
public void setMaterial(T material) {
this.material = material;
}
@Override
public String toString() {
return material.toString();
}
public void printing() {
material.doPrinting();
}
}
ThreeDPrinterTest.java
package generics;
public class ThreeDPrinterTest {
public static void main(String[] args) {
ThreeDPrinter<Powder> printer = new ThreeDPrinter<Powder>();
printer.setMaterial(new Powder());
Powder powder = printer.getMaterial();
System.out.println(printer);
ThreeDPrinter<Plastic> printerPlastic = new ThreeDPrinter<Plastic>();
printerPlastic.setMaterial(new Plastic());
Plastic plastic = printerPlastic.getMaterial();
System.out.println(printerPlastic);
//Material을 상속 받으므로 Water 사용할 수 없어짐
// ThreeDPrinter<Water> printerWater = new ThreeDPrinter<Water>();
// printerWater.setMaterial(new Water());
// System.out.println(printerWater);
printer.printing();
printerPlastic.printing();
}
}
실행 결과
재료는 Powder 입니다.
재료는 Plastic 입니다.
Powder 재료로 출력합니다.
Plastic 재료로 출력합니다.
명시하지 않으면 Object로 간주
GenericPrinter<Powder>와 같이 사용할 자료형 (Powder)를 명시해야함
자료형을 명시하지 않고 사용할 수 있음 이런 경우 자료형을 명시하라는 경고표시가 나타남
반환형에 따라 강제 형변환을 해야함
ArrayList list = new ArrayList();
메서드의 매개변수를 자료형 매개변수로 사용하는 경우
[자료형 매개변수가 하나 이상인 경우]
제네릭 메서드의 일반 형식
public <자료형매개변수> 반환형 메서드이름 ( 자료형매개변수 ... ) {}
[자료형 매개변수가 두 개인 경우]
T, V 두 개의 자료형 매개변수 사용
-제네릭 메서드 구현하기
사각형의 너비를 구하는 메서드
두 점의 위치가 여러 자료형으로 사용되는 경우
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 + "입니다.");
}
}


| 분류 | 설명 |
|---|---|
| List 인터페이스 | 순서가 있는 자료 관리, 중복 허용. 이 인터페이스를 구현한 클래스는 ArrayList, Vector, LinkedList, Stack, Queue 등이 있음 |
| Set 인터페이스 | 순서가 정해져 있지 않음. 중복을 허용하지 않음. 이 인터페이스를 구현한 클래스는 HashSet, TreeSet등이 있음 |
| 메서드 | 설명 |
|---|---|
| boolean add(E e) | Collection에 객체를 추가합니다. |
| void clear() | Collection의 모든 객체를 제거합니다. |
| Iterator<E> iterator | Collection을 순환할 반복자(Iterator)를 반환합니다. |
| boolean remove(Object o) | Collection에 매개변수에 해당하는 인스턴스가 존재하면 제거합니다. |
| int size | Collection에 있는 요소의 개수를 반환합니다. |
※ 이클립스에서 F1을 눌러 자세한 설명을 볼 수 있다.
Collections.synchronizedList(new ArrayList<String>());



Member.java
package collection;
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;
}
public String toString() {
return memberName + "회원님의 아이디는 " + memberId + "입니다.";
}
}
MemberArrayList.java
package collection.arraylist;
import java.util.ArrayList;
import collection.Member;
public class MemberArrayList {
private ArrayList<Member> arrayList;
public MemberArrayList() {
arrayList = new ArrayList<Member>();
}
public void addMember(Member member) {
arrayList.add(member);
}
public boolean removeMember(int memberId) {
for(int i = 0; i < arrayList.size(); i++) {
Member member = arrayList.get(i);
int tempId = member.getMemberId();
if(memberId == tempId) {
arrayList.remove(i);
return true;
}
}
System.out.println(memberId + "가 존재하지 않습니다.");
return false;
}
public void showAll() {
for(Member member : arrayList) {
System.out.println(member);
}
System.out.println();
// System.out.println(arrayList);
}
}
MemberArrayListTest.java
package collection.arraylist;
import collection.Member;
public class MemberArrayListTest {
public static void main(String[] args) {
MemberArrayList memberArrayList = new MemberArrayList();
Member memberLee = new Member(101, "이순신");
Member memberKim = new Member(102, "김유신");
Member memberShin = new Member(103, "신사임당");
memberArrayList.addMember(memberLee);
memberArrayList.addMember(memberKim);
memberArrayList.addMember(memberShin);
memberArrayList.showAll();
memberArrayList.removeMember(memberKim.getMemberId());
memberArrayList.showAll();
}
}
실행 결과
이순신회원님의 아이디는 101입니다.
김유신회원님의 아이디는 102입니다.
신사임당회원님의 아이디는 103입니다.
이순신회원님의 아이디는 101입니다.
신사임당회원님의 아이디는 103입니다.
Stack과 Queue의 기능은 구현된 클래스가 있지만 ArrayList나 LinkedList를 활용하여서 사용할 수도 있음
Stack: Last In First Out (LIFO)
맨 마지막에 추가된 요소가 먼저 꺼내지는 자료구조
게임의 무르기 기능, 최근 자료 추출 등에서 사용

Queue: First In First Out (FIFO)
먼저 저장된 자료가 먼저 꺼내지는 선착순, 대기열 구조

StackTest.java
package collection.arraylist;
import java.util.ArrayList;
class MyStack{
private ArrayList<String> arrayStack = new ArrayList<String>();
public void push(String data) {
arrayStack.add(data);
}
public String pop() {
int len = arrayStack.size();
if(len == 0) {
System.out.println("스택이 비었습니다.");
return null;
}
return arrayStack.remove(arrayStack.size() - 1);
}
public String peek() {
int len = arrayStack.size();
if(len == 0) {
System.out.println("스택이 비었습니다.");
return null;
}
return arrayStack.get(arrayStack.size() - 1);
}
}
public class StackTest {
public static void main(String[] args) {
MyStack stack = new MyStack();
stack.push("a");
stack.push("b");
stack.push("c");
System.out.println(stack.peek());
System.out.println(stack.peek());
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
}
}
실행 결과
c
c
c
b
a
스택이 비었습니다.
null
QueueTest.java
package collection.arraylist;
import java.util.ArrayList;
class MyQueue {
private ArrayList<String> arrayQueue = new ArrayList<String>();
public void enQueue(String data) {
arrayQueue.add(data);
}
public String deQueue() {
int len = arrayQueue.size();
if(len == 0) {
System.out.println("큐가 비었습니다.");
return null;
}
return arrayQueue.remove(0);
}
}
public class QueueTest {
public static void main(String[] args) {
}
}
Iterator ir = memberArrayList.iterator();
| 메서드 | 설명 |
|---|---|
| boolean hashNext() | 이후에 요소가 더 있는지를 체크하는 메서드이며, 요소가 있다면 true를 반환합니다. |
| E next() | 다음에 있는 요소를 반환합니다. |
[Iterator로 ArrayList의 removeMember() 다시 작성해보기]
public boolean removeMember(int memberId) {
// for(int i = 0; i < arrayList.size(); i++) {
// Member member = arrayList.get(i);
// int tempId = member.getMemberId();
// if(memberId == tempId) {
// arrayList.remove(i);
// return true;
// }
// }
Iterator<Member> iterator = arrayList.iterator();
while(iterator.hasNext()) {
Member member = iterator.next();
int tempId = member.getMemberId();
if(memberId == tempId) {
arrayList.remove(member);
return true;
}
}
System.out.println(memberId + "가 존재하지 않습니다.");
return false;
}
HashSetTest.java
package collection.hashset;
import java.util.HashSet;
public class HashSetTest {
public static void main(String[] args) {
HashSet<String> set = new HashSet<String>();
boolean b1 = set.add("aaa");
System.out.println(b1);
set.add("bbb");
set.add("ccc");
System.out.println(set); // 들어가는 순서 저장되는 순서 동일하지 않다.
boolean b = set.add("aaa");
System.out.println(b); // 같은 값이라 안들어감 --> false
System.out.println(set);
}
}
실행 결과
true
[aaa, ccc, bbb]
false
[aaa, ccc, bbb]
MemberHashSet.java
package collection.hashset;
import java.util.HashSet;
import java.util.Iterator;
import collection.Member;
public class MemberHashSet {
private HashSet<Member> hashSet;
public MemberHashSet() {
hashSet = new HashSet<Member>();
}
public void addMember(Member member) {
hashSet.add(member);
}
public boolean removeMember(int memberId) {
Iterator<Member> iterator = hashSet.iterator();
while(iterator.hasNext()) {
Member member = iterator.next();
int tempId = member.getMemberId();
if(memberId == tempId) {
hashSet.remove(member);
return true;
}
}
System.out.println(memberId + "가 존재하지 않습니다.");
return false;
}
public void showAll() {
for(Member member : hashSet) {
System.out.println(member);
}
System.out.println();
// System.out.println(arrayList);
}
}
MemberHashSetTest.java
package collection.hashset;
import collection.Member;
public class MemberHashSetTest {
public static void main(String[] args) {
MemberHashSet memberHashSet = new MemberHashSet();
Member memberLee = new Member(101, "이순신");
Member memberKim = new Member(102, "김유신");
Member memberShin = new Member(103, "신사임당");
memberHashSet.addMember(memberLee);
memberHashSet.addMember(memberKim);
memberHashSet.addMember(memberShin);
memberHashSet.showAll();
Member memberLee2 = new Member(101, "이몽룡");
memberHashSet.addMember(memberLee2);
memberHashSet.showAll();
// 같은 아이디에 add 되면 안됨. But 왜 작동했을까?
// Member클래스에 equals(), hashCode()를 구현해야 HashSet에서 add할 때 기존 멤버 같은지 여부 체크할 수 있음.
}
}
실행 결과
김유신회원님의 아이디는 102입니다.
신사임당회원님의 아이디는 103입니다.
이순신회원님의 아이디는 101입니다.
김유신회원님의 아이디는 102입니다.
이몽룡회원님의 아이디는 101입니다.
신사임당회원님의 아이디는 103입니다.
이순신회원님의 아이디는 101입니다.
[Member클래스의 hashCode(), equals() 오버라이딩하기]
Member.java
package collection;
public class Member {
...
@Override
public int hashCode() {
return memberId;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Member) {
Member member = (Member) obj;
if(this.memberId == member.memberId) {
return true;
}
else return false;
}
return false;
}
}
MemberHashSetTest.java 실행 결과
이순신회원님의 아이디는 101입니다.
김유신회원님의 아이디는 102입니다.
신사임당회원님의 아이디는 103입니다.
이순신회원님의 아이디는 101입니다.
김유신회원님의 아이디는 102입니다.
신사임당회원님의 아이디는 103입니다.
TreeSet<Member> treeSet = new TreeSet<Member>(new Member());
MemberTreeSet.java
package collection.treeset;
import java.util.Iterator;
import java.util.TreeSet;
import collection.Member;
public class MemberTreeSet {
private TreeSet<Member> treeSet;
public MemberTreeSet() {
treeSet = new TreeSet<Member>();
//treeSet = new TreeSet<Member>(new Member());
//compare 사용할 땐 생성자에 default constructor 불러줘야함
}
public void addMember(Member member) {
treeSet.add(member);
}
public boolean removeMember(int memberId) {
Iterator<Member> iterator = treeSet.iterator();
while(iterator.hasNext()) {
Member member = iterator.next();
int tempId = member.getMemberId();
if(memberId == tempId) {
treeSet.remove(member);
return true;
}
}
System.out.println(memberId + "가 존재하지 않습니다.");
return false;
}
public void showAll() {
for(Member member : treeSet) {
System.out.println(member);
}
System.out.println();
}
}
MemberTreeSetTest.java
package collection.treeset;
import collection.Member;
public class MemberTreeSetTest{
public static void main(String[] args) {
MemberTreeSet memberHashSet = new MemberTreeSet();
Member memberLee = new Member(102, "이순신");
Member memberKim = new Member(101, "김유신");
Member memberShin = new Member(103, "신사임당");
memberHashSet.addMember(memberLee);
memberHashSet.addMember(memberKim);
memberHashSet.addMember(memberShin);
memberHashSet.showAll();
// 어떻게 비교해서 트리 구성할지 정해지지 않아 오류 발생-->Member클래스 오버라이딩하기
}
}
Member.java
package collection;
import java.util.Comparator;
public class Member implements Comparable<Member>, Comparator<Member> {
private int memberId;
private String memberName;
public Member() {}
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;
}
public String toString() {
return memberName + "회원님의 아이디는 " + memberId + "입니다.";
}
@Override
public int hashCode() {
return memberId;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Member) {
Member member = (Member) obj;
if(this.memberId == member.memberId) {
return true;
}
else return false;
}
return false;
}
/*** Comparable, Comparator 구현 ***/
@Override
public int compareTo(Member member) {
// id 기준으로
// 더 큰 경우에 양수 반환 됨 --> 오름차순 정렬됨(음수 --> 내림차순)
// return (this.memberId - member.memberId);
// name 기준으로(오름차순) (-1 곱하면 내림차순)
return (this.memberName.compareTo(member.memberName));
}
@Override
public int compare(Member member1, Member member2) {
return member1.memberId - member2.memberId;
}
}
실행 결과
김유신회원님의 아이디는 101입니다.
신사임당회원님의 아이디는 103입니다.
이순신회원님의 아이디는 102입니다.
ComparatorTest.java
package collection.treeset;
import java.util.Comparator;
import java.util.TreeSet;
class MyCompare implements Comparator<String>{
@Override
public int compare(String str1, String str2) {
// 내림차순
return str1.compareTo(str2) * (-1);
}
}
public class ComparatorTest {
public static void main(String[] args) {
TreeSet<String> tree = new TreeSet<String>(new MyCompare());
tree.add("aaa");
tree.add("ccc");
tree.add("bbb");
System.out.println(tree);
}
}
실행 결과
[ccc, bbb, aaa]

index = hash(key) // index는 저장 위치
| 메서드 | 설명 |
|---|---|
| V put(K key, V value | key에 해당하는 value 값을 map에 넣습니다. |
| V get(K key) | key에 해당하는 value 값을 반환합니다. |
| boolean isEmpty() | Map이 비었는지 여부를 반환합니다. |
| boolean containsKey(Object key) | Map에 해당 key가 있는지 여부를 반환합니다. |
| boolean containsValue(Object value) | Map에 해당 value가 있는지 여부를 반환합니다. |
| Set keyset() | key 집합을 Set로 반환합니다. (중복 안 되므로 Set) |
| Collection values() | value를 Collection으로 반환합니다. (중복 무관) |
| V remove(key) | key가 있는 경우 삭제합니다. |
| boolean remove(Object key, Object value) | key가 있는 경우 key에 해당하는 value가 매개변수와 일치할 때 삭제합니다. |
[HashMap 클래스 사용 예]
MemberHashMap.java
package collection.hashmap;
import java.util.HashMap;
import java.util.Iterator;
import collection.Member;
public class MemberHashMap {
private HashMap<Integer, Member> hashMap;
public MemberHashMap() {
hashMap = new HashMap<Integer, Member>();
}
public void addMember(Member member) {
hashMap.put(member.getMemberId(), member);
}
public boolean removeMember(int memberId) {
if(hashMap.containsKey(memberId)) {
hashMap.remove(memberId);
return true;
}
System.out.println(memberId + "가 존재하지 않습니다.");
return false;
}
public void showAllMember() {
Iterator<Integer> ir = hashMap.keySet().iterator();
while(ir.hasNext()) {
int key = ir.next();
Member member = hashMap.get(key);
System.out.println(member);
}
}
}
MemberHashMapTest.java
package collection.hashmap;
import collection.Member;
import collection.treeset.MemberTreeSet;
public class MemberHashMapTest {
public static void main(String[] args) {
MemberHashMap memberHashMap = new MemberHashMap();
Member memberLee = new Member(102, "이순신");
Member memberKim = new Member(101, "김유신");
Member memberShin = new Member(103, "신사임당");
memberHashMap.addMember(memberLee);
memberHashMap.addMember(memberKim);
memberHashMap.addMember(memberShin);
memberHashMap.showAllMember();
System.out.println();
memberHashMap.removeMember(102);
memberHashMap.showAllMember();
}
}
실행 결과
김유신회원님의 아이디는 101입니다.
이순신회원님의 아이디는 102입니다.
신사임당회원님의 아이디는 103입니다.
김유신회원님의 아이디는 101입니다.
신사임당회원님의 아이디는 103입니다.
MemberTreeMap.java
package collection.treemap;
import java.util.Iterator;
import java.util.TreeMap;
import collection.Member;
public class MemberTreeMap {
private TreeMap<Integer, Member> treeMap;
public MemberTreeMap() {
treeMap = new TreeMap<Integer, Member>();
}
public void addMember(Member member) {
treeMap.put(member.getMemberId(), member);
}
public boolean removeMember(int memberId) {
if(treeMap.containsKey(memberId)) {
treeMap.remove(memberId);
return true;
}
System.out.println(memberId + "가 존재하지 않습니다.");
return false;
}
public void showAllMember() {
Iterator<Integer> ir = treeMap.keySet().iterator();
while(ir.hasNext()) {
int key = ir.next();
Member member = treeMap.get(key);
System.out.println(member);
}
}
}
MemberTreeMapTest.java
package collection.treemap;
import collection.Member;
import collection.treeset.MemberTreeSet;
public class MemberTreeMapTest {
public static void main(String[] args) {
MemberTreeMap memberTreeMap = new MemberTreeMap();
Member memberLee = new Member(102, "이순신");
Member memberKim = new Member(101, "김유신");
Member memberShin = new Member(103, "신사임당");
memberTreeMap.addMember(memberLee);
memberTreeMap.addMember(memberKim);
memberTreeMap.addMember(memberShin);
memberTreeMap.showAllMember(); // 정렬되어 출력 됨
System.out.println();
memberTreeMap.removeMember(102);
memberTreeMap.showAllMember();
}
}
실행 결과`
김유신회원님의 아이디는 101입니다.
이순신회원님의 아이디는 102입니다.
신사임당회원님의 아이디는 103입니다.
김유신회원님의 아이디는 101입니다.
신사임당회원님의 아이디는 103입니다.