기본 콘텐츠로 건너뛰기

Chapter13 제네릭

 

제네릭<>

제네릭 타입(class<T>, interface<T>)

    public class 클래스명<T> {...}
    public interface 인터페이스명<T> {...}

제네릭의 장점 - 컴파일시 강한 타입 체크로 실행 시 에러를 사전에 방지. 타입변환(casting)을 제거

public class Box {
	private Object object;
	public void set(Object object) {
		this.object = object;
	}
	public Object get() {
		return object;
	}
}
public class BoxExample {

	public static void main(String[] args) {
		Box box = new Box();
		box.set("홍길동");
		String name = (String) box.get();
		System.out.println(name);
		box.set(555);
		int number = (int) box.get();
		System.out.println(number);
	}
}

타입 변환을 사용해야함

public class Box<T> {
	private T t;
	public void set(T t) {
		this.t = t;
	}
	public T get() {
		return t;
	}
}
public class BoxExample {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Box<String> box1 = new Box<String>();
		box1.set("홍길동");
		String name = box1.get();
		System.out.println(name);
		Box<Integer> box2 = new Box<Integer>();
		box2.set(555);
		int number = box2.get();
		System.out.println(number);
	}
}

타입 변환 없이 사용

멀티 타입 파라미터(class<K, V, ....>, interface<K, V, ....>)

public class Product<T, M> {
	private T kind;
	private M model;
	
	public T getKind() {
		return kind;
	}
	public void setKind(T kind) {
		this.kind = kind;
	}
	public M getModel() {
		return model;
	}
	public void setModel(M model) {
		this.model = model;
	}
}
public class ProductExample {
	public static void main(String[] args) {
		Product<Tv, String> product1 = new Product<Tv, String>();
		//자바 7부터
		Product<Tv, String> product2 = new Product<>();
		product1.setKind(new Tv());
		product1.setModel("스마트Tv");
		Tv tv = product1.getKind();
		String tvModel = product1.getModel();
	}
}

자바 7부터는 축약 사용 가능

제네릭 메소드(<T,R> R method(T t)) - 매개 변수 타입과 리턴 타입으로 타입 파라미터를 갖는 메소드, 리턴 타입 앞에 <> 기호를 추가하고 타입 파라미터를 기술한 다음, 리턴 타입과 매개 타입으로 타입 파라미터를 사용

public <타입파라미터, ...> 리턴타입 메소드명(매개변수, ...){ ...}
public <T> Box<T> boxing(T t) {...}

제네릭 메소드 호출 방법

리턴타입 변수 = <구체적타입> 메소드명(매개값);     //명시적으로 구체적 타입을 지정
리턴타입 변수 = 메소드명(매개값);               //매개값을 보고 구체적 타입을 추정
Box<Integer> box = <Integer>boxing(100);//타입 파라미터를 명시적으로 Integer로 지정
Box<Integer> box = boxing(100);         //타입 파라미터를 Integer로 추정


public class Util2 {
	public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
		boolean keyCompare = p1.getKey().equals(p2.getKey());
		boolean valueCompare = p1.getValue().equals(p2.getValue());
		return keyCompare && valueCompare;
	}
}
public class Pair<K, V> {
	private K key;
	private V value;
	
	public Pair(K key, V value) {
		this.key = key;
		this.value = value;
	}
	
	public void setKey(K key) {
		this.key = key;
	}
	public void setValue(V value) {
		this.value = value;
	}
	
	public K getKey() {
		return key;
	}
	public V getValue() {
		return value;
	}
}
public class CompareMethodExample {

	public static void main(String[] args) {
		Pair<Integer, String> p1 = new Pair<Integer, String>(1, "사과");
		Pair<Integer, String> p2 = new Pair<Integer, String>(1, "사과");
		//구체적인 타입을 명시적으로 지
		boolean result1 = Util2.<Integer, String>compare(p1, p2);
		if(result1) {
			System.out.println("논리적으로 동등한 객체입니다.");
		}else {
			System.out.println("논리적으로 동등하지 않는 객체입니다.");
		}
		
		Pair<String, String> p3 = new Pair<>("user1", "홍길동");
		Pair<String, String> p4 = new Pair<>("user2", "홍길동");
		//구체적인 타입을 추정
		boolean result2 = Util2.compare(p3, p4);
		if(result2) {
			System.out.println("논리적으로 동등한 객체입니다.");
		}else {
			System.out.println("논리적으로 동등하지 않는 객체입니다.");
		}
	}
}

제한된 타입 파라미터(<T extends 최상위타입>) - 구체적인 타입을 제한할 때 ex) 숫자 연산 메소드는 매개값으로 Number 또는 하위 클래스 타입(Byte, Short, Integer, Long, Double)의 인스턴스만 가져야 할때 extends 키워드를 붙이고 상위 타입을 명시하고 인터페이스도 가능한데 implements를 안쓰고 extends를 사용

public <T extends 상위타입> 리턴타입 메소드(매개변수, ...) { ...}

메소드의 중괄호 {} 안에서 타입 파라미터 변수로 사용한 것은 상위 타입의 멤버(필드, 메소드)로 제한

public class Util3 {
	public static <T extends Number> int compare(T t1, T t2) {
		double v1 = t1.doubleValue();	//Number의 doubleValue() 메소드 사
		double v2 = t2.doubleValue();
		return Double.compare(v1, v2);
	}
}
public class BoundedTypeParameterExample {
	public static void main(String[] args) {
		//String str = Util3.compare("a", "b");Number 타입이 아님
		//int -> Integer
		int result1 = Util3.compare(10, 20);
		System.out.println("result1 : " + result1);
		//double -> Double
		int result2 = Util3.compare(4.5, 3);
		System.out.println("result2 : " + result2);
	}
}

와일드카드 타입(<?>, <? extends ...>, <? super ...>)  

            - 제네릭타입<?> : 타입 파라미터를 대치하는 구체적인 타입으로 모든 클래스나 인터페이스 타입이 올 수 있음(제한 없음)

            - 제네릭타입<? extends 상위타입> : 타입 파라미터를 대치하는 구체적인 타입으로 상위타입이나 하위 타입만 올 수 있음(상위 클래스 제한)

            - 제네릭타입<? super 하위타입> : 타입 파라미터를 대치하는 구체적인 타입으로 하위 타입이나 상위 타입이 옴(하위 클래스 제한)



public class Course<T> {
	
	private String name;
	private T[] students;
	
	public Course(String name, int capacity) {
		this.name = name;
		students = (T[]) (new Object[capacity]);
		System.out.println(Arrays.toString(students)+"끄억"+capacity);
	}
	
	public String getName() {
		return name;
	}
	public T[] getStudents() {
		return students;
	}
	//배열에 비어있는 부분을 찾아서 수강생을 추가
	public void add(T t) {
		for(int i=0; i<students.length; i++) {
			students[i] = t;
			break;
 		}
	}
}
public class WildCardExample {
	public static void main(String[] args) {
		Course<Person> personCourse = new Course<Person>("일반인과정", 5);
		personCourse.add(new Person("일반인"));
		personCourse.add(new Worker("직장인"));
		personCourse.add(new Student("학생"));
		personCourse.add(new HighStudent("고등학생"));
		
		Course<Worker> workerCourse = new Course<Worker>("직장인과정", 5);
		workerCourse.add(new Worker("직장인"));
		Course<Student> studentCourse = new Course<Student>("학생과정", 5);
		studentCourse.add(new Student("학생"));
		studentCourse.add(new HighStudent("고등학생"));
		Course<HighStudent> highStudentCourse = new Course<HighStudent>("고등학생과정", 5);
		highStudentCourse.add(new HighStudent("고등학생"));
		//모든 과정 등록 가
		registerCourse(personCourse);
		registerCourse(workerCourse);
		registerCourse(studentCourse);
		registerCourse(highStudentCourse);
		
		//registerCourseStudent(personCourse); 학생이 아니므로
		//registerCourseStudent(workerCourse);
		registerCourseStudent(studentCourse);
		registerCourseStudent(highStudentCourse);
		
		registerCourseWorker(personCourse);
		registerCourseWorker(workerCourse);
		//registerCourseWorker(studentCourse; 학생 이므로
		//registerCourseWorker(highStudentCourse);
		
		
	}
	//모든 과정
	public static void registerCourse(Course<?> course) {
		System.out.println(course.getName() + "수강생 : " + Arrays.toString(course.getStudents()));
	}
	//학생 과정
	public static void registerCourseStudent(Course<? extends Student> course) {
		System.out.println(course.getName() + "수강생 : " + Arrays.toString(course.getStudents()));
	}
	//직장인과 일반인 과정
	public static void registerCourseWorker(Course<? super Worker> course) {
		System.out.println(course.getName() + "수강생 : " + Arrays.toString(course.getStudents()));
	}
}

제네릭 타입의 상속과 인터페이스 구현도 가능하다 

댓글

이 블로그의 인기 게시물

mac 맥 맥북 Brew 완전 삭제

맥북에서 Brew 초기화 Brew를 써서 h2를 쓰려고 하는데 brew install h2가 안되서 이리 저리 알아보다가 완전 삭제 후 다시 설치 하니까 되서 그 방법을 남겨놈 1. 터미널에 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/uninstall.sh)" 입력후 y랑 뭐 비번.. 2. /usr/local 폴더에서 Homebrew 폴더 삭제 rm -rf Homebrew/ 권한설정으로 잘.....삭제하고 3. 다시 설치 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" 좀 오래걸리니까 기다려야한다는걸 배움... 출처.... https://discourse.brew.sh/t/error-no-formulae-found-in-taps/8331/9

메이븐으로 라이브러리 인식

 간혹 퍼블릭 jar가 아닌 파일이 있는데 그럴때 쓰면 될듯 <dependency> <groupId> SimpleCryptLib </groupId> <artifactId> SimpleCryptLib </artifactId> <version> 1.1.0 </version> <scope> system </scope> <systemPath> ${basedir}/src/main/webapp/WEB-INF/lib/SimpleCryptLib-1.1.0.jar </systemPath> </dependency> version, scope, systemPath는 꼭 작성해야 한다 groupId, artifactId, version은 암거나 해도 되는거 같음 최근(2021.05.04)스프링 부트    < dependency > < groupId > NiceID </ groupId > < artifactId > NiceID </ artifactId > < version > 1.0 </ version > < scope > system </ scope > < systemPath > ${basedir}/src/main/resources/lib/NiceID.jar </ systemPath > </ dependency > 이걸 추가해주는것도 필요할지도..?? < build > < plugins > < plugin > < groupId > org.springframework.boot </ groupId > < artifactId > spring-bo...

ORA-28000 계정이 잠금되었습니다 계정 잠길때

오라클 계정이 잠길때 해제방법 증상 t he account is locked 오류 발생 원인 Oracle 에서 t he account is locked  에러가 나는 원인은 ● 잘못된 패스워드로 설정횟수만큼 접속 시도시 Lock. ●  30일동안(Default) 해당 계정으로 로그인을 하지 않았을 경우 Lock. 등이 있다. 해결방법 command창에서 * 로컬일경우, sqlplus "/as sysdba"  또는  sqlplus /nolog  conn /as sysdba  * 로컬이 아닐 경우, sqlplus /nolog conn sys/password@<sid> 이름/패스워드@sid로 입력 로 접속 후 SELECT username, account_status, lock_date FROM dba_users; 으로 Lock이 된 사용자를 확인한 후 LOCKED<TIMED> 라고 되있으면, 패스워드 설정횟수 입력 오류로, 아래의 Unlock 명령만, EXPIRED & LOCKED 라고 되있으면, 패스워드 기간만료로, Unlock 후 비밀번호를 지정해줘야 한다. ALTER USER 사용자명 ACCOUNT UNLOCK; 로 Lock된 사용자를 Unl ock 시킨다 방금 말했다시피, 다시 Lock된 사용자 확인했는데,  Open되지 않고 EXPIRED되어 있다면, alter user 사용자명 identified by 바꿀패스워드;  로 패스워드를 변경하거나 또는 SQL*PLUS 를 재시작하여 Lock를 해제한 계정(사용자명/패스워드)로 로그인 하면 패스워드 변경 창이 뜬다. 추가로 패스워드 Lock 횟수 확인하는 방법은 SELECT U....