관리 메뉴

KorSA

[남궁성 '자바의 정석'] 132~155강 본문

Study Memos/Java

[남궁성 '자바의 정석'] 132~155강

Praiv. 2021. 11. 17. 16:12
320x100

※ 이 글은 남궁성 저자의 '자바의 정석' 132~155강을 수강한 후 정리한 내용입니다.

 

1. HashTable은 old 버전, HashMap은 new 버전
    HashTable은 동기화가 처리되어 있고, HashMap은 동기화가 되어있지 않다.

2. TreeMap은 TreeSet과 비슷한 특성을 가졌다.
    이진탐색트리로 구성되어 있다.
    TreeSet이 내부적으로는 TreeMap으로 구현되어 있다.

3. 순서를 유지할 필요가 있을 땐 LinkedHashMap을 쓴다.

4. HashMap은 데이터가 많아도 검색이 빠르다.
    해싱기법으로 데이터를 저장하기 때문.
    키가 중복되어 들어갈 경우 최근 값으로 덮어써진다.

4. 해싱(Hashing)
    해시 함수로 해시 테이블에 데이터를 저장 & 검색
    해시 테이블은 배열과 링크드 리스트가 조합된 형태

5. Collections 패키지는 여러 static 메소드를 제공해준다.

synchronizedXXX(); // 동기화 되지 않은 컬렉션 -> 동기화된 컬렉션
unmodifiableXXX(); // 변경 가능한 컬렉션 -> 변경불가능한 컬렉션
singletonXXX(); // 객체 1개만 저장
checkedXXX(); // 한 종류이 객체만 저장

List syncList = Collections.synchronizedList(new ArrayList(...)); // 동기화 되지 않은 List -> 동기화된 List
unmodifiableList = Collections.unmodifiableList(new ArrayList(...)); // 변경 가능한 List -> 변경불가능한 List


6. Collections 패키지 Hierarchy
    추후 추가 예정

7. 제네릭
    Runtime 에러를 컴파일 에러 수준에서 catch하려는 노력.
    제네릭을 쓰면 타입 체크가 강화됨
    객체의 타입 안정성을 높이고 형 변환의 번거로움을 줄여줌.
    형변환 잘못할 시 ClassCastException()이 발생하는 데 이 예외를 컴파일 단계에서 차단할 수 있음.

ArrayList list = new ArrayList(); // JDK 1.5 이전, 제네릭 도입 이전
ArrayList<Object> list = new ArrayList<Object>(); // JDK 1.5 이후


8. Runtime 에러를 줄이기 위한 초기화 노력

String str = null; // X
String str = ""; // O

Object[] objArr = null; // X
Object[] objArr = new Object[0]; // O
Object[] objArr = { }; // O


9. 제한된 제네릭 클래스
    extends 키워드로 대입할 수 있는 타입을 제한

class FruitBox<T extends fruit & Eatable>{
	ArrayList<T> list = new ArrayList<T>();
}

FruitBox<Apple> appleBox = new FruitBox<Apple>(); // OK
FruitBox<Toy> toyBox = new FruitBox<Toy>(); // Error. Toy는 Fruit의 자손이 아님


10. 타입 변수에 대입은 인스턴스 별로 다르게 가능하다.

Box<Apple> appleBox = new Box<Apple>();
Box<Grape> grapeBox = new Box<Grape>();


    그래서 static 멤버에 타입 변수 사용은 불가하다. (인스턴스마다 다를 수 있으니까)

class Box<T> {
	static T item; // Error
	static int compare(T t1, T t2) { ... } // Error
}


    배열 생성할 때 타입 변수 사용불가. 타입 변수로 배열 선언은 가능

class Box<T> {
	T[] itemArr;

	T[] toArray(){
		T[] tmpArr = new T[itemArr.length]; // Error
	}
}


11. 와일드 카드 <?>
    하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능

    <? extends T> 와일드 카드의 상한 제한. T와 그 자손들만 가능
    <? super T> 와일드 카드의 하한 제한. T와 그 조상들만 가능
    <?> 제한 없음. 모든 타입이 가능. <? extends Object>와 동일

    보통 <? extends T>를 많이 씀.

12. 클래스의 타입 매개변수<T>와 메서드의 타입 매개변수 <T>는 별개이다.
    범위에 따른 Instance Variable과 Local Variable의 차이와 유사

13. 제네릭 메서드는 호출할 때마다 타입을 대입해야하지만 대부분 생략 가능하다.

14. 제네릭 메서드와 와일드 카드는 비슷한 일을 하지만 다른 용도로 사용된다.
    제네릭 메서드: 메서드를 호출할 때마다 다른 제네릭 타입을 대입할 수 있게 한 것 
    와일드 카드: 하나의 참조 변수로 서로 다른 타입이 대입된 여러 제네릭 객체를 다루기 위한 것

15. 원시 타입과 제네릭 타입 간의 형변환은 바람직하지 않다.
    JDK 1.5 이후로는 원시 타입 자체보단 제네릭 타입으로 쓰는 게 애초에 좋음.

Box<Object> objBox = null;
Box box = (Box) objBox; // 경고
Box<Object> objBox = (Box)box ; // 경고


16. 열거형 상수의 비교에는 ==와 compareTo()만 사용가능
    비교연산자('>', '<' 등)는 사용할 수 없음

17. 쓰레드의 구현과 실행
    1) Thread 클래스를 상속
    2) Runnable 인터페이스를 구현

18. JAVA는 쓰레드의 우선순위를 1~10으로 구분한다
    JVM에서 정한 게 1~10
    실제 OS인 Windows는 32 단계
    JVM에서 정한 우선 순위는 희망 사항이어서 반드시 이 순위가 지켜지진 않음.
    JVM이 OS는 아니기 때문에.

19. 데몬 쓰레드(daemon thread)
    일반 쓰레드의 작업을 돕는 보조적인 역할을 수행
    일반 쓰레드가 모두 종료되면 자동적으로 종료된다.
    반대로 말하면 일반 쓰레드는 자동적으로 종료되지 않음.
    ex) 가비지 컬렉터(GC), 자동저장, 화면 자동갱신 등

20. 데몬 쓰레드는 보통 무한루프로 구현
    프로그램이 언제 종료될지 모르니까.

21. 쓰레드 sleep()
    예외 처리를 해야 한다. (InterruptedException이 발생하면 깨어남)
    보통 함수로 try-catch를 한 번 wrapping해서 사용

void delay(long millis){
  try{
	  Thread.sleep(millis);
  } catch(InerruptedException e){ }
}


    특정 쓰레드를 지정해서 멈추게 하는 것은 불가능하다

th1.sleep(2000); // th1을 sleep() 시키는 게 아니다. 이렇게 쓰지마라. 실제론 내가 sleep 한다. 이렇게 하면 오해의 소지가 다분하다.

Thread.sleep(2000); // 내가 sleep 한다.


22. 쓰레드 interrupt()

void interrupt(); // 쓰레드의 interrupted 상태를 false에서 true로 변경
boolean isInterrupted(); // 쓰레드의 interrupted 상태를 반환
static boolean interrupted(); // 현재 쓰레드의 interrupted 상태를 알려주고 , false로 초기화


    파일 다운로드 중 취소하고 싶을 때 등에 사용

23. 쓰레드 suspend(), resume(), stop()

void suspend(); // 쓰레드를 일시정지 시킨다.
void resume(); // suspend()에 의해 일시정지된 쓰레드를 실행대기상태로 만든다.
void stop(); // 쓰레드를 즉시 종료시킨다.


    얘네들은 사용을 권장하지 않는다. dead-lock의 여지가 있기 때문에 deprecated 됨.


24. volatile 키워드
    자주 바뀌는 변수임을 나타내는 키워드
    CPU가 cache할 때 복사본으로 cache하지 말고 직접 원본에 접근해서 사용하라는 의미

25. 쓰레드 yield()
    남은 시간을 다음 쓰레드에게 양보하고, 자신(현재 쓰레드)은 실행 대기한다.

26. 쓰레드에서 yield()와 interrupt()를 적절히 사용하면 응답성과 효율을 높일 수 있다.

728x90
728x90
Comments