edu day 23
🙂제네릭은 JDK 1.5 버전부터 사용하기 시작한 문법으로 컴파일 시점에서, 사용하는 데이터형을 체크하기 때문에 프로그램의 안정성을 향상시키거나 데이터 사용시 형변환 코드가 필요하지 않기 때문에 코드 사용도 간편하다는 장점이 있다.
제네릭은 앞으로 배울 컬렉션 API, 람다식 등에서 전반적으로 사용하기 때문에 매우👍 중요하다.
상속과 다형성을 사용하면 데이터 관리가 매우 쉬운 장점도 있으나, 잘못된 데이터가 저장되었다는 것을 인지하는 시점이 컴파일 시점이 아닌 매우 늦은 실행시점이거나 instanceof
연산자 또는 형변환을 사용하여 구현하는 것은 큰 불편함😭이 있다.
이러한 불편한 점을 개선한 것이 Generic
이고 클래스 또는 인터페이스, 메서드의 파라미터, 리턴타입에 사용될 수 있다.
클래스와 인터페이스에 제네릭이 적용된 타입을 '제네릭 타입' 이라고 부르고 적용하지 않은 타입을 '원시 타입(raw type)' 이라고 부른다.
제네릭 타입은 클래스와 인터페이스 이름 뒤에 <>
를 사용하여 표현한다.
public class Class_Name
<T>
{ }
public interface Interface_Name<T>
{ }
<T>
라고 쓰인 부분이 타입 파라미터 선언이다. 반드시 T라고 사용할 필요는 없지만 일반적으로 다음과 같이 사용하는 것이 관례이다.
타입 | 설명 |
---|---|
T | 참조 타입 ( Reference Type ) 지정시 |
E | 요소 ( Element ) 지정시 |
K | Map계열의 키( Key ) 지정시 |
V | Map계열의 값( Value ) 지정시 |
public class Class_Name<T>{ }
Class_Name<String> genericType = new Class_Name<String>();
Class_Name<String> genericType2 = new Class_Name<>();
Class_Name rawType = new Class_Name();
--> 마지막 코드는 Object 타입으로 지정하겠다는 것이다. 제네릭 타입의 클래스를 객체 생성할 때 제네릭 타입을 사용하지 않으면 제네릭 타입을 사용하도록 이클립스에서 경고로 알려준다.
🙂 예제
package com.one;
import java.util.Date;
class Box<T>{
T obj;
public T getValue() {
return obj;
}
public void setValue(T obj) {
this.obj = obj;
}
}
public class GenericTest1 {
public static void main(String[] args) {
// 제네릭스 타입(generics type)
Box<String> b = new Box<String>();
b.setValue("Hello");
b.setValue("100");
// b.setValue(new Date()); //error
String x = b.getValue(); //형변환을 해줄 필요가 없는 장점이 있다.
System.out.println(x.length());
System.out.println("================");
Box<Date> b2 = new Box<>(); // 오른쪽은 타입 생략 가능
b2.setValue(new Date());
// b2.setValue("aaa"); //error
Date d = b2.getValue(); //마찬가지로 형변환 없다.
System.out.println(d);
System.out.println("================");
Box<Integer> b3 = new Box<>();
b3.setValue(100);
// b3.setValue("100"); //error
int xxx = b3.getValue(); //오토 언박싱(Integer를 int로 바로 받는다)
System.out.println(xxx);
}
}
다음과 같은 와일드카드 문자를 사용한다.
표현 | 설명 |
---|---|
<?> | 타입 제한이 없다. <? extends Object> 와 동일 기능 |
<? extends T> | T와 T를 상속받은 하위 클래스만 사용 가능 |
<? super T> | T와 T의 부모 클래스만 사용 가능 |
데이터를 관리하는 여러 가지 저장 방식이 존재하며 이런 여러 가지 방식을 자바의 클래스로 구현한 것이 컬렉션이다.
지정 방식 | 설명 |
---|---|
변수 ( variable ) | - 데이터 개수만큼 변수 필요 - 저장되는 값에 따라서 기본형 변수와 참조형 변수로 구분됨 |
배열 ( array ) | - 대량의 데이터 관리에 변수보다 효율적 - 같은 데이터만 저장 가능 - 저장되는 값은 기본형 및 참조형 모두 가능. 배열 자체는 참조형 - Arrays API 활용하여 배열을 효율적으로 관리 가능 |
컬렉션 ( Collection ) | - 대량의 데이터 관리에 배열보다 매우 효율적 - 저장되는 데이터 종류 무관 - 자동으로 크기 변경 가능 - 저장되는 값은 참조형만 가능 - Collections API 활용하여 컬렉션을 효율적으로 관리 가능 |
Collection
인터페이스이다. add, remove, size 같은 데이터 저장 및 관리와 관련된 추상 메서드가 선언되어 있다.Set
인터페이스와 List
인터페이스가 제공된다.Set
계열의 특징은 데이터의 저장 순서가 없기 때문에 중복 저장이 불가능하다. (ex. HashSet, SortedSet)List
계열의 특징은 데이터의 저장 순서가 존재하기 때문에 중복 저장이 가능하다. (ex. ArrayList)Set
계열과 List
계열은 모두 실제 데이터만 저장하는 자료구조 형태인 반면에Map
계열은 key/value 쌍으로 저장하고 이후에 key를 이용해서 value를 얻는 방법으로 구현된 자료구조이다. key는 중복을 허용하지 않고 value는 중복을 허용하며 저장 순서가 없다.Map
도 인터페이스이기 때문에 실제 구현된 HashMap
, HashTable
클래스를 이용하고 HashTable
의 하위 클래스로 Properties
클래스가 제공된다. 검색 속도가 매우 빠른 특징을 갖는다.
- 배열과 다르게 하나의 컬렉션에 서로 다른 데이터형 저장이 가능하다.
- 참조 데이터 형만 저장 가능하다. 기본 데이터 형은 Wrapper 클래스를 이용하거나 오토 박싱(autoboxing)으로 저장할 수 있다.
- ArrayList, HashSet, HashMap, Properties과 같은 다양한 형식의 자료구조가 제공된다.
- 컬렉션의 크기는 size() 메서드를 사용하여 구한다.
- 객체인 데이터를 저장할 때마다 크기가 자동으로 늘어난다.
- 제네릭(Generic) 타입을 지원한다. 따라서 제네릭 타입을 사용하여 생성한다
메서드 | 설명 |
---|---|
boolean add(Object o) boolean addAll(Collection c) | 지정된 객체 또는 Collection의 객체들을 Collection에 추가 |
void clear() | Collection의 모든 객체를 삭제 |
boolean isEmpty() | Collection이 비어있는지 확인 |
int size() | Collection에 저장된 객체의 갯수 |
Object [] toArray() | Collection에 저장된 객체를 배열로 변환 |
boolean contains(Object o) | Collection에 o 요소를 포함하고 있는지 반환 |
Iterator <E> Iterator() | Collection에 저장된 데이터를 반복출력하기 위한 Iterator 인터페이스 반환 |
Set 계열의 특징은 ❗순서가 없고, ❗중복 저장이 불가능하다. 처리속도가 빠르다.
😁 예제
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
public class SetTest {
public static void main(String[] args) {
//배열 생성(순서x, 중복x)
Set set = new HashSet(); //Generic을 지정하지 않았기 때문에 object타입.
set.add("1");
set.add("2");
set.add(3); //Integer
set.add("4");
set.add(3.15); //Double
set.add(new Date());
// 값 출력
System.out.println("길이:" + set.size());
System.out.println("포함여부:" + set.contains(20));
System.out.println("empty냐:" + set.isEmpty());
System.out.println(set); // == set.toString()
Object [] xxx = set.toArray();
for (Object o : xxx) {
System.out.println(o);
}
set.clear();
System.out.println(set.size());
}
}
--> set을 그냥 출력하면 toString()형식으로 모든 값이 출력된다. Object 배열에 toArray()메서드를 통해 배열을 넣어서 값이 여러 타입을 가진 클래스 형태일 경우 원하는 타입의 값을 지정하여 get함수를 통해 출력할 수 있다.
import java.util.HashSet;
import java.util.Iterator;
public class SetTest2 {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
// Set<String> set2 = new HashSet<>(); // 같다
set.add("1");
set.add("2");
set.add("3");
set.add("4");
set.add("5");
set.add("6");
// set.add("10"); //잘못된 데이터 저장 감지를 컴파일때 인식 가능.
System.out.println(set);
//2. foreach
for (String x : set) {
System.out.println(x);
}
//3. 일관된 방법인 Iterator 이용
Iterator<String> ite = set.iterator();
while(ite.hasNext()){
String m = ite.next();
System.out.println(">>"+m);
}
Iterator<String> ite2 = set.iterator();
while(ite2.hasNext()) {
String m = ite2.next();
System.out.println(">>"+m);
}
}
}
🙂 Set 배열의 여러가지 출력 예제
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetTest3_2 {
public static void main(String[] args) {
Set<Person> set = new HashSet<>();
// Set set = new HashSet<>();
Person kkkk = new Person("유관순", 17, "서울");
set.add(new Person("홍길동", 20, "서울"));
set.add(new Person("이순신", 44, "전라"));
set.add(new Person("이순신", 44, "전라")); //위의 값이 같은 객체랑 다른 주소를 갖는다.
set.add(kkkk);
set.add(kkkk); //중복 저장 불가능
System.out.println(set);
//toArray()==> 순회 이름만 출력
// Object [] toArray
Object[] xx = set.toArray();
for (Object o : xx) {
Person p = (Person)o;
System.out.println(p.getName());
}
System.out.println("=====");
// foreach
for (Person p: set) {
System.out.println(p.getName());
}
System.out.println("=====");
// Iterator
Iterator<Person> ite = set.iterator();
while(ite.hasNext()) {
System.out.println(ite.next().getName());
}
}
}
import java.util.HashSet;
import java.util.Set;
public class SetTest4 {
public static void change(int num) { //call by value
num = 100;
}
public static void change2(int[] num) { //call by reference
num[0] = 0;
}
public static void change3(HashSet<String> set) { //call by reference
set.remove("홍길동");
}
public static void change4(Set<String> set) { //Set은 HashSet의 부모 클래스 이기때문에 가능하다.
set.remove("홍길동");
}
public static Set<String> getSet() {
Set<String> set = new HashSet<>();
set.add("1");
set.add("2");
return set;
}
public static void main(String[] args) {
int m = 10;
System.out.println("변경전: "+ m); // 10
change(m);
System.out.println("변경후: "+ m); // 10
/////////////////////////////////////
int [] m2 = {9,8,7};
System.out.println("변경전: "+ m2[0]); // 9, 8, 7
change2(m2);
System.out.println("변경후: "+ m2[0]); // 0, 8, 7
/////////////////////////////////////
System.out.println("변경전: "+ m2[0]); // 0
change(m2[0]);
System.out.println("변경후: "+ m2[0]); // 0
/////////////////////////////////////
HashSet<String> set = new HashSet<>();
set.add("홍길동");
set.add("이순신");
set.add("유관순");
System.out.println("변경전: "+ set); //[홍길동, 이순신, 유관순]
// change3(set);
change4(set);
System.out.println("변경후: "+ set); //[이순신, 유관순]
//////////////////
System.out.println(getSet());
}
}
HashSet<String> set = new HashSet<>();
set.add("홍길동");
set.add("이순신");
set.add("유관순");
🔴OracleMain.java
import java.util.HashSet;
import com.service.OracleService;
public class OracleMain {
public static void main(String[] args) {
OracleService ser = new OracleService();
HashSet<String> set = ser.service();
for (String s : set) {
System.out.println(s);
}
}
}
🟠OracleService.java
package com.service;
import java.util.HashSet;
import com.dao.OracleDAO;
public class OracleService {
private OracleDAO dao = new OracleDAO();
// 아래 service()함수에 OracleDAO 객체생성 코드를 넣으면
// serivce()가 호출될 때 마다 객체를 계속 생성하기 때문에
// 멤버변수 위치에 써준다.
// 기본생성자를 명시적으로 작성하여 내부에 객체를 생성해도 된다.
public HashSet<String> service() {
HashSet<String> set = dao.service();
return set;
// == return dao.service();
}
}
🟡OracleDAO.java
package com.dao;
import java.util.HashSet;
public class OracleDAO {
public HashSet<String> service() {
HashSet<String> set = new HashSet<>();
set.add("홍길동");
set.add("이순신");
set.add("유관순");
return set;
}
}
❗눈감고도 구현할 수 있어야 한다!!