반응형
6. 제네릭(Generic) 프로그래밍
제네릭 자료형 정의
- 클래스에서 사용하는 변수의 자료형이 여러개일 수 있고, 그 기능(메서드)은 클래스의 자료형을 특정하지 않고
추후 해당 클래스를 사용할 때 지정할 수 있도록 선언 - 실제 사용되는 자료형의 변환은 컴파일러에 의해 검증되므로 안정적인 프로그래밍 방식
- 컬렉션 프레임워크에서 많이 사용되고 있다.
제네릭 타입을 사용하지 않는 경우의 예
- 재료가 Powder인 경우
public class ThreeDPrinter1 {
private Powder material;
public Powder getMaterial() {
return material;
}
public void setMaterial(Powder material) {
this.material = material;
}
}
- 재료가 Plastic인 경우
public class ThreeDPrinter2 {
private Plastic material;
public Plastic getMaterial() {
return material;
}
public void setMaterial(Plastic material) {
this.material = material;
}
}
- 여러 타입을 대체하기위해 Object를 사용할 수 있음
public class ThreeDPrinter3 {
private Object material;
public Object getMaterial() {
return material;
}
public void setMaterial(Object material) {
this.material = material;
}
}
- Object를 사용하는 경우엔 형 변환을 해주어야 한다.


- 제네릭 클래스 정의
GenericPrinter.java
public class GenericPrinter<T> {
private T material; // T 자료형으로 선언한 변수
public T getMaterial() {
return material;
}
public void setMaterial(T material) { // T 자료형을 반환하는 제네릭 메서드
this.material = material;
}
public String toString() {
return material.toString();
}
}
- 자료형 매개변수 T ( type parameter ) : 이 클래스를 사용하는 시점에 실제 사용할 자료형을 지정,
static 변수는 사용할 수 없다 - GenericPrinter : 제네릭 자료형
- E : element, K : key, V : value 등 여러 알파벳을 의미에 따라 사용 가능
Powder.java
public class Powder {
public String toString() {
return "재료는 Powder 입니다";
}
}
Plastic.java
public class Plastic {
public String toString() {
return "재료는 Plastic 입니다";
}
}
GenericPrinterTest.java
public class GenericPrinterTest {
public static void main(String[] args) {
Powder powder = new Powder();
GenericPrinter<Powder> powderPrinter = new GenericPrinter<>();
powderPrinter.setMaterial(powder);
Powder p = powderPrinter.getMaterial();
System.out.println(p.toString());
Plastic plastic = new Plastic();
GenericPrinter<Plastic> plasticPrinter = new GenericPrinter<>();
plasticPrinter.setMaterial(plastic);
Plastic pl = plasticPrinter.getMaterial();
System.out.println(pl.toString());
System.out.println(powderPrinter.toString());
System.out.println(plasticPrinter.toString());
}
}

다이아몬드 연산자 <>
- <> 를 다이아몬드 연산자라고 한다
- ArrayList list = new ArrayList<>(); // 다이아몬드 연산자 내부에서 자료형은 생략이 가능함
- 제네릭에서 자료형 추론 ( 자바10 부터 )
ArrayList list = new ArrayList() >> var list = new ArrayList();
7. T extends 클래스
상위 클래스의 필요성
- T자료형의 범위를 제한할 수 있음
- 상위 클래스에서 선언하거나 정의하는 메서드를 활용할 수 있음
- 상속을 받지 않는 경우는 T는 Object클래스가 기본으로 제공하는 메서드만 사용가능
T extends를 사용한 프로그래밍
- GenericPrinter에 material 변수의 자료형을 상속받아 구현
- T에 무작위 클래스가 들어갈 수 없게 Material 클래스를 상속받은 클래스로 한정

Material.java

Powder.java, Plastic.java


GenericPinter.java

GenericPinterTest.java

8. Generic 메서드 활용
제네릭 메서드란?
- 자료형 매개변수를 메서드의 매개변수나 반환 값으로 가지는 메서드는 자료형 매개변수가 하나 이상인 경우도 있음
- 제네릭 클래스가 아니더라도 내부에 제네릭 메서드는 구현하여 사용할 수 있음
- public < 자료형 매개변수 > 반환형 메서드 이름 ( 자료형 매개변수 ) {}
제네릭 메서드의 활용 예
- 두 점 ( top, bottom )을 기준으로 사각형을 만들 때 사각형의 너비를 구하는 메서드를 만들어 보자
- 두 점은 정수인 경우도 있고, 실수인 경우도 있으므로 제네릭 타입을 사용하여 구현한다.
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 size = GenericMethod.<Integer, Double>makeRectangle(p1, p2);
System.out.println(size);
}
}

9. 컬렉션 프레임 워크
컬렉션 프레임 워크란 ?
- 프로그램 구현에 필요한 자료구조를 구현해 놓은 JDK 라이브러리
- java.util 패키지에 구현돼 있음
- 개발에 소요되는 시간을 절약하면서 최적화 된 알고리즘을 사용할 수 있음
- 여러 구현 클래스와 인터페이스의 활용에 대한 이해가 필요함

Collection 인터페이스
- 하나의 객체를 관리하기위한 메서드가 선언된 인터페이스의 하위에 Set과 List인터페이스가 있다.
List 인터페이스
- 객체를 순서에 따라 저장하고 관리하는데 필요한 메서드가 선언된 인터페이스
- 자료구조 리스트 (배열, 연결리스트)의 구현을 위한 인터페이스
- 중복을 허용함
- ArrayList, Vector, LinkedList, Stack, Queue등
Set 인터페이스
- 순서와 관계없이 중복을 허용하지 않고, 유일한 값을 관리하는데 필요한 메서드가 선언됨
- 아이디, 주민번호, 사번 등을 관리하는데 유용
- 저장된 순서와 출력되는 순서는 다를 수 있음
- HashSet, TreeSet 등
Map 인터페이스
- 쌍( pair )으로 이루어진 객체를 관리하는데 사용하는 메서드들이 선언된 인터페이스
- 객체는 key-value의 쌍으로 이루어짐
- key는 중복을 허용하지 않음
- HashTable, HashMap, Properties, TreeMap등이 Map인터페이스를 구현함
10. List 인터페이스
멤버십 관리하기
- Member 클래스를 만들고, 아이디와 이름을 멤버 변수로 선언
- Member 클래스로 생성된 인스턴스들을 관리하는 클래스를 컬렉션 프레임워크 클래스들을 활용하여 구현한다.
ArrayList 활용하기
- 멤버를 순차적으로 관리
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() {
return memberName + " 회원님의 아이디는 " + memberId + " 입니다";
}
}
MemberArrayList.java
import java.util.ArrayList;
public class MemberArrayList {
private ArrayList<Member> arrayList;
public MemberArrayList() {
arrayList = new ArrayList<>();
}
public MemberArrayList(int size) {
arrayList = new ArrayList<>(size);
}
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(tempId == memberId) {
arrayList.remove(i);
return true;
}
}
System.out.println(memberId + "가 존재하지 않습니다.");
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(memberKim.getMemberId());
memberArrayList.showAllMember();
}
}
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(memberKim.getMemberId());
memberArrayList.showAllMember();
}
}

11. Collection 요소를 순회하는 Iterator
요소의 순회란?
- 컬렉션 프레임워크에 저장된 요소들을 하나씩 차례로 참조하는 것
- 순서가 있는 List인터페이스의 경우는 Iterator를 사용하지 않고 get(i)메서드를 활용할 수 있음
- Set 인터페이시의 경우 get(i)메서드가 제공되지 않으므로 Iterator를 활용하여 객체를 순회함
Iterator 사용하기
- boolean hasNext() : 이후에 요소가 더 있는지를 체크하는 메서드, 요소가 있다면 true를 반환
- E next() : 다음에 있는 요소를 반환
MemberArrayList.java와 removeMember() 메서드를 Iterator를 활용하여 구현

for 문을 사용한것과 같은 동작을 한다
12. 중복되지 않게 자료를 관리하는 Set 인터페이스를 구현한 클래스 활용
HashSet 클래스
- Set 인터페이스를 구현한 클래스와 멤버 중복 여부를 체크하기 위해 인스턴스의 동일성을 확인해야 함
- 동일성 구현을 위해 필요에 따라 equals()와 hashCode() 메서드를 재정의 함
Member.java

- 아이디가 동일한 경우 같은 멤버이므로 중복되지 않도록 Member 클래스의 equals()와 hashCode()메서드를 재정의
MemberHashSet.java
import java.util.HashSet;
import java.util.Iterator;
public class MemberHashSet {
private HashSet<Member> hashSet;
public MemberHashSet() {
hashSet = new HashSet<>();
}
public MemberHashSet(int size) {
hashSet = new HashSet<>(size);
}
public void addMember(Member member) {
hashSet.add(member);
}
public boolean removeMember(int memberId) {
Iterator<Member> ir = hashSet.iterator();
while(ir.hasNext()) {
Member member = ir.next();
int tempId = member.getMemberId();
if(tempId == memberId) {
hashSet.remove(member);
return true;
}
}
System.out.println(memberId + "가 존재하지 않습니다.");
return false;
}
public void showAllMember() {
for( Member member : hashSet ) {
System.out.println(member);
}
System.out.println();
}
}
MemberHashSetTest.java
public class MemberHashSetTest {
public static void main(String[] args) {
MemberHashSet memberHashSet = new MemberHashSet();
Member memberLee = new Member(1001, "이순신");
Member memberKim = new Member(1002, "김유신");
Member memberKang = new Member(1003, "강감찬");
memberHashSet.addMember(memberLee);
memberHashSet.addMember(memberKim);
memberHashSet.addMember(memberKang);
memberHashSet.showAllMember();
Member memberHong = new Member(1003, "홍길동"); // Id값이 같은값 추가
memberHashSet.addMember(memberHong);
memberHashSet.showAllMember();
}
}

HashSet을 사용하기 전에는 같은 ID 값인 1003 홍길동이 출력되지만
HashSet추가 후에는 중복값이므로 출력되지 않는다. ( 집합 개념 )
13. 정렬을 위해 Comparable과 Comparator 인터페이스 구현
TreeSet 클래스 활용
- 객체의 정렬에 사용하는 클래스
- Set 인터페이스를 구현하여 중복을 허용하지 않고, 오름차순이나 내림차순으로 객체를 정렬할 수 있음
- 내부적으로 이진검색트리(binary search tree)로 구현됨
- 이진검색트리에 저장하기 위해 각 객체를 비교해야 함
- 비교 대상이 되는 객체에 Comparable이나 Comparator 인터페이스를 구현해야 TreeSet에 추가 될 수 있음
- String, Integer등 JDK의 많은 클래스들이 이미 Comparable을 구현했음
Member.java
public class Member implements Comparable<Member>{
......
@Override
public int compareTo(Member member) {
//return (this.memberId - member.memberId); //오름차순
return (this.memberId - member.memberId) * (-1); //내림 차순
}
}


class MyCompare implements Comparator<String>{
@Override
public int compare(String s1, String s2) {
return (s1.compareTo(s2)) *-1 ;
}
}
public class ComparatorTest {
public static void main(String[] args) {
Set<String> set = new TreeSet<String>(new MyCompare());
set.add("aaa");
set.add("ccc");
set.add("bbb");
System.out.println(set);
}
}
- Comparator의 활용 : 이미 Comparable이 구현된 경우 Comparator로 비교하는 방식을 다시 구현할 수 있음
14. 쌍 ( pair )으로 자료를 관리하는 Map 인터페이스를 구현한 클래스와 활용
HashMap 클래스 활용
- Map 인터페이스를 구현한 클래스와 가장 많이 사용되는 Map 인터페이스 기반 클래스
- key - value 를 쌍으로 관리하는 메서드 구현
- 검색을 위한 자료구조
- key를 이용하여 값을 지정하고 key를 이용하여 값을 꺼내오는 방식 - hash 알고리즘으로 구현
- key가 되는 객체는 중복될 수 없고 객체의 유일성 비교를 위한 equals()와 hashCode() 메서드를 구현해야 함
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 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;
}
@Override
public String toString() {
return memberName + " 회원님의 아이디는 " + memberId + " 입니다";
}
}
MemberHashMap.java
import java.util.HashMap;
import java.util.Iterator;
public class MemberHashMap {
private HashMap<Integer, Member> hashMap;
public MemberHashMap() {
hashMap = new HashMap<>();
}
public void addMember(Member member) {
hashMap.put(member.getMemberId(), member);
}
public boolean removeMember(int memberId) {
if ( hashMap.containsKey(memberId)) {
hashMap.remove(memberId);
}
System.out.println("no element");
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
import java.util.HashMap;
public class MemberHashMapTest {
public static void main(String[] args) {
MemberHashMap memberHashMap= new MemberHashMap();
Member memberHong = new Member(1004, "홍길동");
Member memberLee = new Member(1001, "이순신");
Member memberKim = new Member(1002, "김유신");
Member memberKang = new Member(1003, "강감찬");
memberHashMap.addMember(memberHong);
memberHashMap.addMember(memberLee);
memberHashMap.addMember(memberKim);
memberHashMap.addMember(memberKang);
memberHashMap.showAllMember();
HashMap<Integer, String> hashMap = new HashMap<Integer, String>();
hashMap.put(1001, "Kim");
hashMap.put(1002, "Lee");
hashMap.put(1003, "Park");
hashMap.put(1004, "Hong");
System.out.println(hashMap.toString());
}
}

TreeMap 클래스
- Map 인터페이스를 구현한 클래스이고, key에 대한 정렬을 구현할 수 있음
- key가 되는 클래스에 Comparable이나 Comparator 인터페이스를 구현함으로써 key-value쌍의 자료를
key값 기준으로 정렬하여 관리가 가능
반응형
'Java' 카테고리의 다른 글
| 자바의 다양한 기능 / 스트림, 예외처리 (0) | 2022.12.07 |
|---|---|
| 자바의 다양한 기능 / 내부 클래스 정의, 람다식 (0) | 2022.12.02 |
| 자바와 자료구조 / 배열, 스택, 큐 (0) | 2022.11.29 |
| 자바의 유용한 클래스 / Object, String, StringBuilder, StringBuffer, textblock, Class 클래스 (0) | 2022.11.22 |
| Java 객체지향 핵심 / 다운 캐스팅, 추상클래스, 추상클래스 응용, 인터페이스, DAO, 인터페이스 상속 (1) | 2022.11.18 |