100일 챌린지/빅데이터기반 인공지능 융합 서비스 개발자
Day 11 - generic, 순서가 없는 자료구조(Enumeration),그리고 Map
ksyke
2024. 8. 5. 10:55
Generic
- JDK 1.5 버전부터 나온 문법
- 문법적으로 자료형을 제약, 개념적으로 확장한다.
- 캐스팅이 필요하지 않아 캐스팅 미스매치로 일어나는 Exception오류를 피할 수 있다.
// 캐스팅이 필요한 리스트
ArrayList list1 = new ArrayList();
list1.add("문자열");
System.out.println(list1.get(0));
String msg1 = (String) list1.get(0);
System.out.println(msg1);
// 캐스팅이 필요하지 않은 general 리스트
ArrayList<String> list2 = new ArrayList<String>();
list2.add("문자열");
System.out.println(list2.get(0));
String msg2 = list2.get(0);
System.out.println(msg2);
generic을 이용한 클래스와 상속 (개념적 확장) - class 에서의 generic
interface Pen{
void draw();
}
class Ballpen1 implements Pen{
String bold = "진한";
public void draw() {
System.out.println(bold + " 선을 긋습니다. ");
}
}
class Pencil implements Pen{
String bold = "희미한";
public void draw() {
System.out.println(bold + " 선을 긋습니다. ");
}
}
class Ball implements Pen{
// String bold = "희미한";
public void draw() {
System.out.println("공놀이한다.");
}
}
class Box1<T>{ // 클래스를 만들 단시 generic을 설정한다.
T pen;
public void setPen(T pen) {
this.pen = pen;
}
public T getPen() {
return this.pen;
}
}
public class Ex02_1 {
public static void main(String[] args) {
Box<Pencil> box = new Box<Pencil>();
box.setPen(new Pencil());
Pencil1 pen1 = box.getPen();
pen1.draw();
Box1<Ballpen> box2 = new Box<Ballpen>();
box2.setPen(new Ballpen());
Ballpen pen2 = box2.getPen();
pen2.draw();
Box1<Ball> box3 = new Box1<Ball>();
box3.setPen(new Ball());
Ball ball = box3.getPen();
ball.draw();
}
}
2개 이상의 generic
class Box2<T1, T2>{
T1 obj1;
T2 obj2;
public void setObj1(T1 obj1) {
this.obj1 = obj1;
}
public void setObj2(T2 obj2) {
this.obj2 = obj2;
}
public T1 getObj1() {
return obj1;
}
public T2 getObj2() {
return obj2;
}
}
public class Ex03 {
public static void main(String[] args) {
Box2<Pencil1, Ballpen1> box = new Box2<Pencil1, Ballpen1>();
box.setObj1(new Pencil1());
box.setObj2(new Ballpen1());
Pencil1 pen1 = box.getObj1();
pen1.draw();
Ballpen1 pen2 = box.getObj2();
pen2.draw();
}
}
매개변수를 사용한 generic 타입 - 메서드에서의 generic
class Box3{
public static <T>T func01(T pen) {
Box1<T> box = new Box1<T>();
box.setPen(pen);
return box.getPen();
}
}
public class Ex04 {
public static void main(String[] args) {
Pencil pen = Box3.<Pencil>func01(new Pencil());
pen.draw();
Ballpen pen1 = Box3.<Ballpen>func01(new Ballpen());
pen1.draw();
}
}
- => generic을 명시하지 않아도 매개변수의 유형을 통해 추론이 가능한다.
Pencil pen = Box3.func01(new Pencil());
pen.draw();
generic의 표현 방식
class Box05<T>{
T t;
public void setT(T t) {
this.t = t;
}
public T getT() {
return t;
}
}
public class Ex05 {
public static void main(String[] args) {
Ballpen1 pen1 = new Ballpen1();
Pencil1 pen2 = new Pencil1();
// generic의 추론 타입(jdk 1.7~)
// Box05<Ballpen1> box1 = new Box05(); // - generic이 붙지 않은 객체(Object)를 생성한다. - Ballpen만 사용할 수 있음
// Box05<> box1 = new Box05<Ballpen1>(); // - generic이 붙지 않은 효과와 같음 - 사용할때 캐스팅이 필요함
// Box05<Ballpen1> box1 = new Box05<>(); // 생성자의 generic을 생략 가능
// Box05<?> tmp = new Box05<>(); // Wild - generic을 붙이지만 타입의 결정을 미룬다.\
// Box05<Ballpen1> box1 = (Box05<Ballpen1>) tmp; // wild가 붙은 생성자의 generic을 결정함
Box05<Pen1> box1 = new Box05<>(); // 생성자의 generic을 생략 가능
box1.setT(pen1);
Pen1 pen3 = box1.getT();
pen1.draw();
box1.setT(pen2);
Pen1 pen4 = box1.getT();
pen4.draw();
}
}
generic의 제약 방식
class Box05<T extends Pen>{ // Pen을 상속받는 클래스만 붙일 수 있다.
public void func01(java.util.List<? super Number> list) { // Number 이상의 클래스만 붙일 수 있다.
java.util.List<Number> list = null; // 가능
java.util.List<Object> list = null; // 가능
java.util.List<Integer> list = null; // 불가능
box1.func01(list);
(이론적으로) 순서가 없는 자료구조
- 중복 불가
Enumeration
- 오직 열람을 위해 존재하고 안에 존재하는 element들을 수정할 수 없다.
// 순서가 있는 자료구조
Vector vec = new Vector();
vec.addElement("첫번째");
vec.addElement("두번째");
vec.addElement("세번째");
vec.addElement("네번째");
vec.addElement("다섯번째");
for(int i = 0; i < vec.size(); i++) {
System.out.println(vec.elementAt(i));
}
System.out.println("-----------------------------");
// 순서가 없는 자료구조
Enumeration eles = vec.elements();
// while(eles.hasMoreElements()) {
// System.out.println(eles.nextElement()); // 다음 엘리먼트를 가리킴
// }
System.out.println(eles.nextElement()); // 다음 엘리먼트를 가리킴
System.out.println(eles.nextElement()); // 다음 엘리먼트를 가리킴
System.out.println(eles.nextElement()); // 다음 엘리먼트를 가리킴
// Enumeration으로는 다시 처음으로 돌아가는 방법이 없다.
System.out.println("-----------------------------");
eles = vec.elements(); // 다시 엘리먼트를 받아내는 방법 밖에.
System.out.println(eles.nextElement());
Stack
// 후입선출 (LIFO)
Stack list = new Stack();
list.push("첫번째");
list.push("두번째");
list.push("세번째");
list.push("네번째");
//
// System.out.println(list.pop()); // 네번째
// System.out.println(list.peek()); // 세번째
// System.out.println(list.pop()); // 세번째
// System.out.println(list.peek()); // 두번째
// System.out.println(list.pop()); // 두번째
// System.out.println(list.peek()); // 첫번째
// System.out.println(list.pop()); // 첫번째
// System.out.println(list.empty());
System.out.println(list.search("두번째")); // 3
System.out.println("---------------------");
while(!list.empty()) {
System.out.println(list.pop());
}
Set
// 순서가 없는
java.util.Set<String> set = new java.util.HashSet<>();
set.add("첫번째");
set.add("두번째");
set.add("세번째");
set.add("네번째");
Iterator<String> ite = set.iterator(); // 열람을 하기 위한 별도의 객체
// System.out.println(ite.next());
// System.out.println(ite.next());
// System.out.println(ite.next());
// System.out.println(ite.next());
// System.out.println(ite.hasNext());
while(ite.hasNext()) {
String msg = ite.next();
System.out.println(msg);
}
Set을 이용한 자료의 중복 제거
List<Integer> list = new ArrayList<>();
list.add(1111);
list.add(2222);
list.add(2222);
list.add(1111);
Set<Integer> set = new HashSet<>(list);
terator<Integer> ite = set.iterator();
while(ite.hasNext()) {
System.out.println(ite.next());
}
Set<String> set = new HashSet<>();
set.add("첫번째");
set.add("첫번째");
set.add("두번째");
set.add("첫번째");
List<String> list = new ArrayList<>(set);
for(int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
중복값 검사를 위한 Set의 종류
// Set을 사용하는 건 중복값검사를 위해서이다.
Set<Integer> set;
// set = new HashSet<>();
// set = new LinkedHashSet<>();
set = new TreeSet<>(); // integer 사용 시 순서대로 나옴 - 이진트리구조를 이용한 자료의 정렬
set.add(3333);
set.add(1111);
set.add(4444);
set.add(2222);
Iterator<Integer> ite = set.iterator();
while(ite.hasNext()) {
System.out.println(ite.next());
}
TreeSet
- 이진트리구조를 이용한 자료의 정렬
- 이진트리 방식을 사용하면 검사를 수행해야 할 획수가 획기적으로 줄어든다.
class Car implements Comparable<Car>{
String color;
public Car(String color) {
this.color = color;
}
@Override
public String toString() {
return color + "색 차";
}
@Override
public int compareTo(Car o) { // TreeSet의 검사를 수행하기 위해 Comparable이 수반돼야 한다.
return this.color.compareTo(o.color);
}
}
public class Ex12 {
public static void main(String[] args) {
Set<Car> set;
set = new TreeSet<>(); // 이진트리구조를 이용해 중복을 검사
set.add(new Car("빨강"));
set.add(new Car("주황"));
set.add(new Car("노랑"));
set.add(new Car("노랑"));
set.add(new Car("초록"));
Iterator<Car> ite = set.iterator();
while(ite.hasNext()) {
System.out.println(ite.next());
}
}
HashSet
class Car implements Comparable{
String color;
public Car(String color) {
this.color = color;
}
@Override
public String toString() {
return color + "색 차";
}
public int hashCode() { // 해시 코드의 주소를 같게 만듬
if(color.contentEquals("빨강")) return 1111;
if(color.contentEquals("노랑")) return 2222;
return super.hashCode();
}
public boolean equals(Object obj) {
return true;
}
}
public class Ex12 {
public static void main(String[] args) {
Set<Car> set;
set = new HashSet<>(); // 해시코드(메모리의 주소)를 비교해 중복을 검사
set.add(new Car("빨강"));
set.add(new Car("빨강"));
set.add(new Car("주황"));
set.add(new Car("노랑"));
set.add(new Car("노랑"));
set.add(new Car("초록"));
Iterator<Car> ite = set.iterator();
while(ite.hasNext()) {
System.out.println(ite.next());
}
}
}
- List와 Set은 서로 복사가 가능하다.
Map
- 순서가 없는 자료구조
- 순서는 Key를 가지고 value를 뽑아낸다. - Entry set이라는 객ㅊ?로 가지고 있다.
- Map은 collection을 상속받고 있지 않지만 Set과 List의 기능을 가지고 있다.
- Map은 Map 끼리만 복사가 가능하다.
Map<String, String> map = new HashMap<>();
// key, value
// key : set (중복 불허)
// value : list (중복 허용)
map.put("key1", "val1");
map.put("key2", "val2");
map.put("key3", null);
map.put(null, "val3");
// map.put(null, null); // value는 중복이 가능하나 Key는 중복이 불가능하다.
System.out.println(map.get("key1"));
System.out.println(map.get("key2"));
System.out.println(map.get("key3"));
System.out.println(map.get(null));
System.out.println(map.get("key4")); // null
Map에서의 수정/삭제
map.replace("key2", "value222");
map.remove("key2", "value222"); // value가 같을 때만 삭제를 수행
map.remove("key2");
Map에서의 반복
Map<String, String> map = new HashMap<>();
map.put("key1", "val1");
map.put("key2", "val2");
map.put("key3", "val3");
map.put("key4", "val4");
Set<Entry<String, String>> set = map.entrySet();
Iterator<Entry<String, String>> ite = set.iterator();
while(ite.hasNext()) {
Entry<String, String> ent = ite.next();
System.out.println("key = " + ent.getKey() + ", val = " + ent.getValue());
}
System.out.println("-----------------------");
Set<String> keys = map.keySet();
Iterator<String> ite2 = keys.iterator();
while(ite2.hasNext()) {
String key = ite2.next();
System.out.println("key = " + key + ", value = " + map.get(key));
}