BlueHarmel
BlueHarmel Devlog
BlueHarmel
전체 방문자
오늘
어제

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • 분류 전체보기 (330)
    • Book (11)
    • Dev (29)
      • ArtCon (0)
      • ESTsoft 오르미 (29)
    • Study (290)
      • Web (18)
      • AWS (2)
      • 알고리즘 (1)
      • GameDev (1)
      • 정보처리기사 (201)
      • English (1)
      • Mathematics (24)
      • 머신러닝 (7)
      • 딥러닝 (10)
      • 네트워크 보안 (5)
      • R (4)
      • 컴퓨터 네트워크 (6)
      • 데이터베이스 (8)
      • 데이터 통신 (0)
      • 운영체제 (2)
      • TIL (0)
    • Project (0)
      • 개인 (0)
      • 단체 (0)

인기 글

hELLO · Designed By 정상우.
BlueHarmel

BlueHarmel Devlog

제네릭
Dev/ESTsoft 오르미

제네릭

2024. 2. 23. 10:59

1. 제네릭 사용하는 이유

  • 설명 보기
    • 제네릭 : 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법
      • Wrapper 타입이나 사용자가 생성한 클래스가 들어갈 수 있다.
      • 제네릭이 생략되는 경우 최상위 객체인<Object>가 들어간것으로 생각한다.
      • 이 때문에 다양한 타입의 데이터들이 들어갈 수 있어 컴파일 오류가 날 가능성이 있다.
      • 장점
        1. 컴파일 시 미리 타입이 정해져, 타입 검사나 변환 같은 번거로운 작업을 생략가능 (casting을 제거)
          List list = new ArrayList();
          list.add("Hello");
          String str = (String) list.get(0);
          
          List<String> list = new ArrayList<String>();
          list.add("Hello");
          String str = list.get(0);
        1. 클래스나 메소드 내부에서 사용하는 타입 안정성을 높일 수 있다. (강한 타입 체크)
      • 사용 이유
        • 해당 타입을 이용함으로써 잘못된 타입이 사용될 수 있는 가능성을 컴파일 과정에서 제거 가능
        List<Youtube> youtubeList = new ArrayList<Youtube>();
        
        youtubeList.add(new Youtube());   
        youtubeList.add(new DisneyPlus());   // 컴파일 에러 발생. Youtube 외에 다른 타입 저장불가
        • 클래스, 인터페이스, 메소드를 정의할때 타입을 파라미터로 사용할 수 있도록 한다.

2. 제네릭 타입(class <T>, Interface<T>)

  • 설명 보기
    • 클래스 / 인터페이스 뒤에 <> 부호가 붙고 사이에 타입 파라미터를 적는다
    • 실제 클래스가 사용될 때 구체적인 타입을 지정해 타입 변환을 최소화 시킨다.
      public class 클래스명<T> { ... }
      public interface 인터페이스명<T> { ... }
      public class Box {
      	private Object object;
      
      	public void set(Object object) {
      		this.object = object;
      	}
      
      	public Object get() {
      		return object;
      	}
      }
      public class Box<T> {
      	private T t;
      	
      	public T get() {
      		return t;
      	}
      	
      	public void set(T t) {
      		this.t = t;
      	}
      }
      
      //Box<String> box = new Box<String>();
      //이런식으로 간단하게 String 타입으로 설정이 가능하다

3. 제네릭 메소드

  • 설명 보기
    • 제네릭 메소드 : 매개 타입과 리턴타입으로 타입 파라미터를 갖는 메소드
      public <T> Box<T> boxing(T t) {
      }
      Box<Integer> box = boxing(100);
      public class Util {
      	public static <T> Box<T> boxing(T t) {
      		Box<T> box = new Box<T>();
      		box.set(t);
      		return box;
      	}
      }
      public class GenericMethodExample {
          public static void main(String[] args) {
              Box<Integer> box1 = Util.boxing(100);
              int intValue = box1.get();
      
              Box<String> box2 = Util.boxing("홍길동");
              String strValue = box2.get();
          }
      }

4. 제한된 타입 파라미터 (<T extends 최상위타입>)

  • 설명 보기
    • 타입 파라미터에 구체적인 타입을 제한하는 기능
    • 타입 파라미터에 지정되는 구체적인 타입 : 상위타입 or 상위 타입의 하위 또는 구현 클래스
    public <T extends Number> int compare(T t1, T t2) {
    	double v1 = t1.doubleValue();
    	double v2 = t2.doubleValue();
    	return Double.compare(v1, v2);
    }
    public class BoundedTypeParameterExample {
    	public static void main(String[] args) {
    		// String value = Util.compare("a", "b");   // String은 Number 타입이 아니므로 컴파일 오류 발생
    
    		int result1 = Util.compare(1, 2);            // int -> Integer (자동 Boxing)
    		System.out.println(result1);
    
    		int result2 = Util.compare(4.5, 3);            // double -> Double (자동 Boxing)
    		System.out.println(result2);
    	}
    }

5. 와일드카드 타입 <?>, <? extends …>,<? super ..>

  • 설명 보기
    • 와일드카드(?) : 제네릭 타입을 매개값이나 리턴타입으로 사용할 때 사용
      1. 제네릭타입<?> : Unbounded Wildcards (제한 없음)
        1. 타입 파라미터를 대치하는 구체적인 타입으로 모든 클래스나 인터페이스 타입이 올 수 있다.
      1. 제네릭 타입<? extends 상위타입> : Upper Bounded Wildcards (상위 클래스 제한)
        1. 타입 파라미터를 대치하는 구체적인 타입으로 본인이나 하위 타입만 올 수 있다.
      1. 제네릭 타입<? super 하위타입> : Lower Bounded Wildcards (하위 클래스 제한)
        1. 타입 파라미터를 대치하는 구체적인 타입으로 본인이나 상위 타입이 올 수 있다.
    public class Course<T> {
    	private String name;
    	private T[] students;
    
    	public Course(String name, int capacity) {
    		this.name = name;
    		students = (T[]) (new Object[capacity]); //타입 파라미터로 배열을 생성하려면 new T[n] 형태로 배열을 생성할 수 없고 (T[]) (new Object[n])으로 생성해야한다.
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public T[] getStudents() {
    		return students;
    	}
    	
    	public void add(T t) {
    // 배열에 비어있는 부분을 찾아서 수강생을 추가하는 메소드 
    		for (int i = 0; i < students.length; i++) {
    			if (students[i] == null) {
    				students[i] = t;
    				break;
    			}
    		}
    	}
    }
    • Course<?> : 수강생은 모든 타입(Person, Worker, Student, HighStudent)이 될 수 있다.
    • Course<? extends Student> : 수강생은 Student와 HighStudent만 될 수 있다.
    • Course<? super Worker> : 수강생은 Worker와 Person만 될 수 있다.
    public class WildCardExample {
    
    	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()));
    	}
    
    	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<>("학생과정", 5);
    		studentCourse.add(new Student("학생"));
    		studentCourse.add(new HighStudent("고등학생"));
    
    		Course<HighStudent> highStudentCourse = new Course<>("고등학생과정", 5);
    		highStudentCourse.add(new HighStudent("고등학생"));
    		
    		
    		registerCourse(personCourse);
    		registerCourse(workerCourse);
    		registerCourse(studentCourse);
    		registerCourse(highStudentCourse);				// 모든 과정 등록 가능
    		System.out.println();
    		
    		// registerCourseStudent(personCourse);  (X)
    		// registerCourseStudent(workerCourse);	 (X)	
    		registerCourseStudent(studentCourse);
    		registerCourseStudent(highStudentCourse);		// 학생 과정만 등록 가능
    		System.out.println();
    		
    		registerCourseWorker(personCourse);				
    		registerCourseWorker(workerCourse);				// 직장인과 일반인 과정만 등록 가능
    		// registerCourseWorker(studentCourse); 	(X)
    		// registerCourseWorker(highStudentCourse); (X)
    		
    	}
    }

6. 제네릭 타입의 상속과 구현

  • 설명 보기
    • 제네릭 타입도 상속이 가능하다
      • 자식 제네릭 타입은 추가적으로 타입 파라미터를 가질 수 있다
      public class ChildProduct<T, M, C> extends Product<T, M> {
      }

7. 기타

  • static import : https://hardlearner.tistory.com/284
    • https://offbyone.tistory.com/283
  • generic T와 와일드카드 ? 의 차이
    • 제네릭 T는 클래스를 설계할 때 쓰이고 ?는 설계된 클래스를 사용할 때 (주로 함수의 매개변수)로 사용한다.
    • T는 하나의 타입으로 고정, ? 는 하나의 타입으로 고정되지 않는다. (범위지정)

8. Daily Quiz

Daily Quiz 02/14

'Dev > ESTsoft 오르미' 카테고리의 다른 글

컬렉션  (0) 2024.02.23
리스트  (0) 2024.02.23
예외처리  (0) 2024.02.23
JVM 조사 : ClassLoader  (1) 2024.02.23
인터페이스  (0) 2024.02.23
    BlueHarmel
    BlueHarmel
    Interested in Mathematics, Foreign Language, and "Programming"

    티스토리툴바