Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
중첩 클래스(nested class)는 다른 클래스 안에 정의된 클래스를 말한다.
중첩 클래스는 자신을 감싼 바깥 클래스에서만 사용되어야 하며, 그 외의 쓰임새가 있다면 톱레벨 클래스로 만들어야 한다.
중첩 클래스는 크게 네 가지로 나뉜다: 정적 멤버 클래스, 비정적 멤버 클래스, 익명 클래스, 지역 클래스.
이 중 첫 번째를 제외한 나머지는 내부 클래스(inner class)에 해당한다.

1. **정적 멤버 클래스 (static member class)**:
- 다른 클래스 안에 선언되며 바깥 클래스의 private 멤버에도 접근할 수 있다.
- 바깥 클래스와 독립적으로 존재할 수 있으며, 주로 바깥 클래스와 함께 사용할 때 유용한 public 도우미 클래스로 쓰인다.

2. **비정적 멤버 클래스 (non-static member class)**:
- 바깥 클래스의 인스턴스와 암묵적으로 연결된다.
- 인스턴스 메서드에서 바깥 인스턴스의 메서드나 참조를 사용할 수 있다.
- 보통 바깥 클래스의 인스턴스 메서드에서 생성된다.
- 주로 어댑터를 정의할 때 사용된다.

3. **익명 클래스 (anonymous class)**:
- 이름이 없고, 선언과 동시에 인스턴스가 만들어진다.
- 선언된 지점에서만 인스턴스를 생성할 수 있으며, 여러 인터페이스를 구현하거나 다른 클래스를 상속할 수 없다.
- 람다가 도입된 후에는 람다로 대체되는 경우가 많다.

4. **지역 클래스 (local class)**:
- 지역변수를 선언할 수 있는 곳이면 어디든 선언할 수 있다.
- 이름이 있어 반복 사용할 수 있으며, 비정적 문맥에서만 바깥 인스턴스를 참조할 수 있다.

중첩 클래스에서 바깥 인스턴스에 접근할 필요가 없다면 static으로 선언하는 것이 좋다.
static을 생략하면 바깥 인스턴스로의 숨은 참조가 생기고, 메모리와 시간이 소비된다.
공개된 클래스의 멤버 클래스는 정적이냐 비정적이냐에 따라 하위 호환성에 영향을 미친다.

## 핵심정리
중첩 클래스에는 네가지가 있으며, 각각의 쓰임이 다르다. 메스드 밖에서도 사용해야 하거나 메서드 안에 정의하기엔 너무 길다면 멤버 클래스로 만든다.
멤버 클래스의 인스턴스 각각이 바깥 인스턴스를 참조한다면 비정상적으로, 그렇지 않으면 정적으로 만들자.
중첩 클래스가 한 메서드 안에서만 쓰이면서 그 인스턴스를 생성하는 지점이 단 한 곳이라고 해당 타입으로 쓰기에 적합한 클래스나 인터페이스가 이미 있다면 익명 클래스로 만들고, 그렇지 않으면 지역 클래스로 만들자.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
소스 파일 하나에 여러 개의 톱레벨 클래스를 선언하는 것은 자바 컴파일러가 허용하지만, 이는 득이 없고 심각한 위험을 초래할 수 있다. 이런 방식은 한 클래스를 여러 가지로 정의할 수 있으며, 컴파일 순서에 따라 다른 클래스를 사용할 수 있기 때문이다.

예를 들어, `Main` 클래스가 두 개의 톱레벨 클래스 `Utensil`과 `Dessert`를 참조한다고 하자. 이 두 클래스가 `Utensil.java` 파일에 정의되어 있다면, `Main`을 실행하면 "pancake"를 출력할 것이다. 그런데 `Dessert.java` 파일에 같은 이름의 두 클래스를 정의하면, 컴파일 순서에 따라 출력이 달라질 수 있다.

- `javac Main.java Dessert.java` 명령으로 컴파일하면 컴파일 오류가 발생하고, 중복 정의가 있다고 알려준다.
- `javac Main.java` 또는 `javac Main.java Utensil.java` 명령으로 컴파일하면 "pancake"를 출력한다.
- `javac Dessert.java Main.java` 명령으로 컴파일하면 "potpie"를 출력한다.

이 문제는 간단히 톱레벨 클래스를 각기 다른 소스 파일로 분리하여 해결할 수 있다. 부차적인 클래스라면 정적 멤버 클래스로 만드는 것이 좋다. 이는 코드의 가독성을 높이고 접근 범위를 최소화할 수 있다.

다음은 정적 멤버 클래스로 바꾼 예시이다:

```java
public class Test {
public static void main(String[] args) {
System.out.println(Utensil.NAME + Dessert.NAME);
}

private static class Utensil {
static final String NAME = "pan";
}

private static class Dessert {
static final String NAME = "cake";
}
}
```

이와 같이 정적 멤버 클래스를 사용하면 코드가 더 명확하고 관리하기 쉬워진다.

## 핵심정리
소스 파일 하나에는 반드시 톱레벨 클래스를 하나만 담자. 이 규칙만 따른다면 컴파일러가 한 클래스에 대한 정의를 여러 개 만들어 내는 일은 사라진다.
소스 파일을 어떤 순서로 컴파일하든 바이너리 파일이나 프로그램의 동작이 달라지는 일은 결코 일어나지 않을 것이다.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
## 제네릭
제네릭(generic)은 자바 5부터 사용할 수 있으며, 제네릭을 사용하면 컬렉션이 담을 수 있는 타입을 컴파일러에 알려줘 형변환 오류를 방지하고, 더 안전하고 명확한 프로그램을 만들 수 있다. 제네릭 타입을 사용하면 컴파일러가 형변환 코드를 자동으로 추가해준다.

## 주요 개념
1. 제네릭 클래스와 인터페이스
타입 매개변수를 사용하는 클래스와 인터페이스를 말한다.
예: List<E>는 원소의 타입을 나타내는 타입 매개변수 E를 받는다.

2. 매개변수화 타입:

제네릭 타입에 실제 타입 매개변수를 지정한 것을 말한다.
예: List<String>은 원소의 타입이 String인 리스트를 의미한다.

3. raw type:
제네릭 타입에서 타입 매개변수를 전혀 사용하지 않은 것.
예: List는 List<E>의 로 타입이다.
로 타입을 사용하면 타입 안전성과 표현력을 잃게 된다.

## 제네릭의 사용 예시
1. 로 타입 사용 예 (사용하지 말 것):
```java
private final Collection stamps = ...;
stamps.add(new Coin(...)); // "unchecked call" 경고 발생
for (Iterator i = stamps.iterator(); i.hasNext();) {
Stamp stamp = (Stamp) i.next(); // ClassCastException 발생 가능
stamp.cancel();
}

```

2. 매개변수화된 컬렉션 타입 사용 예:
```java
private final Collection<Stamp> stamps = ...;
```

3. 비한정적 와일드카드 타입 사용 예:
```java
static int numElementsInCommon(Set<?> s1, Set<?> s2) {
int result = 0;
for (Object o1 : s1) {
if (s2.contains(o1)) result++;
}
return result;
}

```

## 로 타입 사용을 피해야 하는 이유
로 타입을 사용하면 타입 안전성을 잃게 되어 런타임 오류가 발생할 수 있다.
대신, 비한정적 와일드카드 타입을 사용하면 더 안전하게 코드를 작성할 수 있다.

## 예외 사항
1. class 리터럴:
- 제네릭 타입의 class 리터럴은 사용할 수 없다.
- 예: List.class, String[].class, int.class는 허용되지만 List<String>.class, List<?>.class는 허용되지 않는다.

2. instanceof 연산자:
- 런타임에 제네릭 타입 정보가 지워지므로, instanceof 연산자는 비한정적 와일드카드 타입 이외의 매개변수화 타입에는 적용할 수 없다.
예:
```java
if (o instanceof Set) { // 로 타입
Set<?> s = (Set<?>) o; // 와일드카드 타입
}
```

## 핵심 정리
raw type을 사용하면 런타입외 예외가 일어날 수 있으니 사용하면 안됟나. raw type은 제네릭이 도입되기 이전 코드와의 호환성을 위해 제공될 뿐이다.