2021. 04. 15(목)

eastgun_·2021년 4월 15일
0
post-thumbnail

Java

제네릭(Generic)

  • 소스 레벨에서 데이터 타입이 결정되지 않고, 별칭(타입파라미터)만 지정한다.

    • 데이터 타입은 필드의 타입, 매개변수 타입, 리턴타입 등이다.
  • 객체 생성싯점, 구현클래스 구현싯점, 메소드 실행싯점에 별칭을 대신할 데이터 타입을 외부에서 지정하는 것이다.

  • 제네릭은 <> 다이아몬드 표기법으로 타입파라미터(별칭)를 지정한다.

    • 타입파라미터는 보통 영어 대문자를 사용한다
    • 타입파라미터는 1개 이상 지정할 수 있다
    • 객체 생성 시타입파라미터의 위치에 실제로 사용할 타입을 지정하면 생성된 객체는 해당 타입으로 변경되어 있다.
    • 객체 생성싯점, 구현클래스 구현싯점, 메소드 실행싯점에 데이터타입을 지정한다.
    • 데이터타입은 클래스 혹은 인터페이스 타입만 가능하다.
    • 기본 자료형은 제네릭의 데이터 타입으로 지정할 수 없다.
  • 배열처럼 다양한 타입의 객체를 다루는 클래스를 설계할 때 사용한다.

  • 자바에서는 객체를 여러개 저장하는 콜렉션 클래스들이 대표적인 예다.

    • ArrayList<E>, HashSet<E>, TreeSet<E>, Stack<E>, Vector<E>, LinkedList<E>
  • 사용 목적

    • 타입파라미터로 지정한 타입의 객체만 저장된다.(타입안정성)
    • 어떤 타입의 객체를 저장할 목적으로 생성했는지 바로 파악이 가능하다.(코드 가독성 증가)
    • 프로그램 실행 전, 컴파일 과정에서 타입오류가 체크된다.
    • 형변환의 번거로움이 사라진다.
  • 사용 예

  ArrayList<Product> products = new ArrayList<Product>();
  ArrayList<Order> orders = new ArrayList<Order>();
  ArrayList<Book> books = new ArrayList<Book>();
  HashSet<Team> teams = new HashSet<Team>();
package generic;

public class BoxApp {

	public static void main(String[] args) {
		// 문자열을 저장하는 NormalBox와 GenericBox 만들기
		
		// 박스 객체 생성하기
		// NormalBox객체에는 어떤 객체가 저장될 예정인지 정보가 전혀 없음
		// GenerixBox객체에는 어떤 객체가 저장될것인지 미리 알 수 있음
		NormalBox box1 = new NormalBox();
		GenericBox<String> box2 = new GenericBox<String>();
		
		box1.setItem("홍길동님 안녕하세요, 오래간만입니다.");
//		box1.setItem(new BoxApp());		// 오류 확인 안됨, 원래의 의도와는 다른 객체를 저장해도 에러가 발생되지 않음
//		box1.setItem(100);				// 오류 확인 안됨, 원래의 의도와는 다른 객체를 저장해도 에러가 발생되지 않음
		String text1 = (String) box1.getItem();
		System.out.println("### 첫번째 박스의 내용 출력");
		System.out.println("메세지 : " + text1);
		System.out.println("글자수 : " + text1.length() + " 글자");
		
		box2.setItem("김유신님 잘 지내고 계신가요? 서울로 한번 오세요.");
//		box2.setItem(new BoxApp());		// 오류 발생, String객체 외의 다른 객체는 절대로 저장되지 않음
//		box2.setItem(100);				// 오류 발생, String객체 외의 다른 객체는 절대로 저장되지 않음
		String text = box2.getItem();
		System.out.println("### 두번째 박스의 내용 출력");
		System.out.println("메세지 : " + text);
		System.out.println("글자수 : " + text.length() + " 글자");
	}
}
package generic;

public class GenericBox<T> {
	private T item;

	public T getItem() {
		return item;
	}

	public void setItem(T item) {
		this.item = item;
	}
	
	
}
package generic;

/*
 * 제네릭이 적용되어 있지 않는 박스 설계도
 * 		1. 타입안전성이 좋지 않다.
 * 		2. 저장된 객체가 Object로 형변환 되어서 저장 된다.
 * 		   (실제로 저장된 객체를 참조하는 것이 아니라, 저장된 객체의 Object객체를 참조한다.)
 * 		3. 저장된 객체를 꺼낼때 마다 실제 저장된 타입으로 형변환해야 한다.
 */
public class NormalBox {
	private Object item;

	public Object getItem() {
		return item;
	}

	public void setItem(Object item) {
		this.item = item;
	}
	
	
}

Collection Framework

  • 자바가 자료구조를 구현해 놓은 것
    • 자료구조 - 객체의 저장/삭제/조회 등의 기능을 제공하는 것
  • 자바의 모든 자료구조 구현 클래스는 Collection 인터페이스를 구현한 클래스다.
    • Collection 인터페이스에 정의된 모든 기능을 구현하고 있다.
  • 자바의 자료구조 특징
    • 객체만 저장할 수 있다.
    • 크기가 가변적이다.
    • 다양한 메소드를 지원한다.

Collection<E>

  • 모든 자료구조 클래스의 최상위 인터페이스다.
  • 주요 메소드
    • boolean add(E e)
      • 자료구조에 새로운 요소를 추가한다.
    • boolean addAll(Collection<? extends E> c)
      • 자료구조에 다른 자료구조의 모든 요소를 추가한다.
    • void clear()
      • 자료구조의 모든 요소를 삭제한다.
    • boolean contains(Object e)
      • 자료구조에 지정된 객체가 존재하는지 조회한다.
    • boolean isEmpty()
      • 자료구조가 비었는지 조회한다.
    • Iterator<E> iterator()
      • 자료구조의 각 요소를 반복해서 추출해주는 반복자객체를 반환한다.
    • boolean remove(Object e)
      • 자료구조에서 지정된 객체를 삭제한다.
    • int size()
      • 자료구조에 저장된 요소의 갯수를 반환한다.
    • Object[] toArray()
      • 자료구조에 저장된 요소를 배열로 반환한다.

Collection의 주요 하위 인터페이스

  • Set<E>
    • 중복을 허용하지 않는다.(동일한 객체를 2개 저장할 수 없다.
    • 주요 구현 클래스
      • HashSet<E> : 가장 많이 사용하는 Set구현 클래스
      • TreeSet<E> : 저장되는 요소가 오름차순으로 정렬되어서 저장된다
    • Set의 구현객체 생성하기
        // String 객체를 여러 개 저장하는 HashSet객체 생성하기
        Set<String> set1 = new HashSet<String>();
        // 정수를 여러 개 저장하는 HashSet객체 생성하기
        Set<Integer> set2 = new HashSet<Integer>();
      
        // Book객체를 여러 개 저장하는 HashSet객체 생성하기
        Set<Book> set3 = new HashSet<Book>();
        // Account객체를 여러 개 저장하는 HashSet객체 생성하기
        Set<Account> set4 = new HashSet<Account>();
    • HashSet<E> 활용하기
        public static void main(String[] args) {
          // String객체를 여러 개 저장하는 HashSet객체 생성하기
          Set<String> set = new HashSet<String>();
      
          // HashSet에 객체 저장하기
          set.add("홍길동");
          set.add("김유신");
          set.add("이순신");
          set.add("강감찬");
          set.add("류관순");
          set.add("강감찬");	// 동일한 객체가 저장되어 있기 때문에 저장되지 않음
      
          // HashSet에 저장된 객체의 갯수 조회하기
          int count = set.size();
          System.out.println("저장된 객체의 갯수: " + count);	// 5가 출력됨
      
          // HashSet이 지정된 객체를 포함하고 있는지 조회하기
          boolean hasElement = set.contains("김유신");
          System.out.println("김유신을 포함하고 있는가?" + hasElement); // true가 출력됨
      
          // HashSet에서 지정된 객체를 삭제하기
          set.remove("홍길동");
      
          // HashSet이 비어있는지 조회하기
          boolean empty = set.isEmpty);
          System.out.println("비어있는가?" + empty);		// false가 출력됨
      
          // HashSet에 저장된 객체를 향상된 for문을 사용해서 순회하기
          for (String name : set) {
            System.out.println("저장된 이름: " + name);
          }
          // HashSet에 저장된 모든 객체 삭제하기		
          set.clear();
        }
  • List<E>
    • 순서가 유지된다.(저장된 순서대로 다시 꺼낼 수 있다.)
    • 요소가 저장될 때 마다 index(순번)이 자동으로 부여된다.
    • 특정위치에 요소 저장하기, 특정위치의 요소 삭제하기, 특정위치의 요소 꺼내기
    • List<E>가 지원하는 추가 메소드
      • void add(int index, E e)
        • 지정된 위치에 요소를 저장한다.
      • E get(int index)
        • 지정된 위치의 요소를 꺼낸다
      • E remove(int index)
        • 지정된 위치의 요소를 삭제한다.
      • E set(int index, E e)
        • 지정된 위치의 요소를 새 요소로 교체한다.
    • 주요 구현 클래스
      • ArrayList<E> : 가장 많이 사용하는 List구현 클래스(전체 자료구조 클래스 중에서 가장 많이 사용)
      • LinkedList<E> : 더블링크로 List를 구현한 클래스(요소의 추가/삭제 성능이 우수하다.)
      • Vector<E> : ArrayList와 유사하는 List구현 클래스(멀티스레드 환경에 안전하다.)
      • Stack<E> : LIFO(Last-In-First-Out)으로 구현된 List구현 클래스
    • List<E>의 구현객체 생성하기
        // String객체를 여러 개 저장하는 ArrayList객체 생성하기
        List<String> list1 = new ArrayList<String>();
        // 실수를 여러 개 저장하는 ArrayList객체 생성하기
        List<Double> list2 = new ArrayList<Double>();
        
        // Person객체를 여러 개 저장하는 ArrayList객체 생성하기
        List<Person> list3 = new ArrayList<Person>();
    • ArrayList<E> 활용하기
        public class Person {
          private int no;
          private String name;
          public Person() {}
          public Person(int no, String) {
            this.no = no;
            this.name = name;
          }
          public int getNo() {
            return no;
          }
          public String name() {
            return name;
          }
        }
        public static void main(String[] args) {
          // Person객체를 여러 개 저장할 수 있는 ArrayList객체 생
          List<Person> personList = new ArrayList<Person>();
          
          // ArrayList객체에 Person객체생성하기
          personList.add(new Person(100, "김유신"));
          personList.add(new Person(200, "강감찬"));
          personList.add(new Person(300, "이순신"));
          personList.add(new Person(400, "류관순"));
          
          // ArrayList객체에 저장된 Person객체의 갯수를 조회하기
          int count = personList.size();
          System.out.println("저장된 갯수: " + count); // 4가 출력됨
          
          // 향상된 for문을 사용해서 ArrayList객체에 저장된 Person객체를 순회하기
          for (Person person : personList) {
            int no = person.getNo();
            String name = person.getName();
            System.out.println("번호:" + no + ", 이름:" + name);
          }
          
          // ArrayList객체에서 0번에 저장된 Person객체 조회하기
          Person person0 = personList.get(0);
          
          // ArrayList객체에서 2번에 칸에 저장된 Person객체 삭제하기
          personList.remove(2)
          
          // ArrayList객체에서 1번에 저장된 객체를 새로운 Person객체로 변경하기
          personList.set(1, new Person(500, "안중근"));
          
          // ArrayList객체에 저장된 모든 객체 삭제하기
          personList.clear()
        }
    • Stack<E> 객체 사용하기
        public static void main(String[] args) {
          Stack<String> stack = new Stack<String>();
          
            // Stack객체에 문자열 저장하기
            stack.push("김유신");
            stack.push("강감찬");
            stack.push("이순신");
      
            // Stack객체에서 맨 위에 있는 객체를 조회한다.
            String value1 = stack.peek();	// 이순신
            String value2 = stack.peek();	// 이순신
            String value3 = stack.peek();	// 이순신
          
          // Stack객체에서 맨 위에 있는 객체를 꺼낸다.(Stack에서 해당 객체는 삭제된다.)
          String value1 = stack.pop();	// 이순신
            String value2 = stack.pop();	// 강감찬
            String value3 = stack.pop();	// 김유신
          
          // Stack객체가 비어있는지 확인하기
          boolean result = stack.isEmpty(); // true가 반환된다.
        }

배열과 콜렉션의 비교

| 구분 | 배열 | 콜렉션 |
| --- | --- | --- |
| 데이터 | 기본자료형, 객체 | 객체 |
| 길이 | 불변 | 가변적 |
| 저장 | 인덱스필요 | 맨 마지막요소의 끝에 자동으로 저장 |
| 삭제 | 인덱스필요 | 삭제 후 다음요소로 해당 위치가 |
| 삭제 | 해당부분 데이터가 비어있음 | 자동으로 채워짐 |
| Enhanced-for | 배열의 끝까지 반복 | 요소가 있는 부분까지만 반복 |

profile
게으르고 싶은 예비 개발자입니다.

0개의 댓글