이 글은 남궁성의 정석코딩 [자바의정석-기초편]을 수강하며 정리한 글입니다.
🟣 기본 환경: IDE: Eclipse, Language: Java
지네릭스(Generics): 컴파일 시 타입을 체크해 주는 기능
: runtimeException을 compileException으로 변환
ArrayList<Tv> tvList = new ArrayList<Tv>;
<>를 통해서 ArrayList에 들어올 수 있는 객체 제한
ArrayList<>(참조변수)와 new ArrayList<>(생성자)가 일치해야 함
tvList.add(new Tv());
tvList.add(new Audio()); - compile error(ClassCastException 형변환 오류)
객체 타입의 안정성을 높이고 형변환의 번거로움을 줄여줌
Box<T> Generic class, T의 Box or T Box라고 읽음
T(타입 문자): 타입변수 또는 타입 매개변수
Box: 원시타입(raw type)
지네릭 클래스 선언
class Box<T> = class 원시타입<타입변수>
지네릭 클래스에서 객체 생성
Box<String> b = new Box<String>();
참조변수 생성자
<대입된 타입(parameterized type)>
다형성 원리와 달리 대입된 타입의 경우, 조상-자손관계일 때도 타입이 일치해야 함
ArrayList<Product> list = new ArrayList<Tv>(); // Error
단, 타입이 아닌 arraylist 등에서는 다형성 성립(지네릭 클래스간 다형성 성립)
List<Tv> list = new ArrayList<Tv()>; // ArrayList가 List 구현, OK
매개변수의 다형성 성립
ArrayList<Product> list = newArrayList<Product>();
list.add(new Product());
list.add(new Tv()); // OK
list.add(new Audio()); // OK
Product p = list.get(0); // 형변환 불요
Tv tv = (Tv) list.get(1); // 형변환 필요
Hash<K, V>
여러개의 타입 변수가 필요한 경우, ‘,’ 사용
extends로 대입할 수 있는 타입을 제한
class FruitBox<T extends Fruit> { // Fruit 자손만 타입으로 지정 가능
Interface인 경우에도 extends를 사용
interface Eatable{}
class FruitBox<T extends Fruit & Etable>
→ 인터페이스 여러개 상속 & 만 사용 가능
타입 변수에 대입은 인스턴스 별로 다르게 지정 가능
Box<Apple> appleBox = new Box<Apple>();
Box<Grape> grapeBox = new Box<Grape>();
static member(모든 인스턴스에서 공통이므로)에 타입변수 사용 불가
** static variable에 generic 사용 불가(static T nameX)
** static method에 generic 사용 불가
** generic method에 static 사용 가능
타입변수 배열 선언은 가능
T[] itemArr();
배열, 객체 생성 시 타입 변수 사용불가(= new T (X))
T[] toArray() {T[] tmpArr = new T[itemArr.length]} // Error
- 와일드 카드<?>
하나의 참조 변수로 대입된 타입이 다른 객체를 참조 가능
→ 하나의 참조변수로 서로 다른 타입이 대입된 여러 지네릭 객체를 다루기 위한 것
cf. 지네릭 메서드: 메서드를 호출할 때마다 다른 지네릭 타입을 대입할 수 있게 한 것
<? extends T> 와일드 카드의 상한 제한, T와 그 자손들만 가능 - 주로 사용
<? super T> 와일드 카드의 하한 제한, T와 그 조상들만 가능
<?> 제한 없음, 모든 타입 가능(=<? extends Object>)
메서드의 매개변수에 와일드 카드 사용 가능
static Juice makeJuice(FruitBox<? extends Fruit>) {}
→ Fruit, Apple 가능
Generic Method
지네릭 타입이 선언된 메서드(타입 변수는 메서드 내에서만 유효)
클래스 타입 매개변수<T>와 메서드의 타입 변수<T>는 별개
매서드를 호출할 때마다 타입을 대입해야 함(대부분 생략 가능)
FruitBox<Fruit> fruitBox = new FruitBox<Fruit>();
FruitBox<Apple> appleBox = new FruitBox<Apple>();
println(Jucier.<Fruit>makeJuice(fruitBox));
println(Jucier.<Apple>makeJuice(appleBox));
→ Fruitbox에서 매개변수 타입<T>이 선언되었으므로 매서드 호출에서 사용되는 매개변수<T>는 대부분 생략 가능
메서드를 호출할때 타입을 생략하지 않을 때는 클래스 이름 생략 불가(같은 클래스 내 일지라도)
println(<Fruit>makeJuice(fruitBox)); // Error
println(this.<Fruit>makeJuice(fruitBox)); // OK
println(Jucier.<Fruit>makeJuice(fruitBox)); // OK
지네릭 타입과 원시 타입 간의 형변환은 바람직하지 않음
Box b = null;
Box<String> bStr = null;
b = (Box)bStr; // B<>→B 가능은 하지만 경고
bStr = (Box<String>)b; // B→B<> 가능은 하지만 경고
지네릭 타입의 제거
컴파일러는 지네릭 타입을 제거하고, 필요한 곳에 형변환을 넣는다.
Object→<T>를 다시 Object로 돌림
단, T type이 제한된 경우는 제한된 타입으로 변경
Box<T extends Fruits>→Fruits
→ 지네릭 타입 제거 후에 타입이 불일치하면 형변환을 추가한다.
get(int i) {return list.get(i);}
→ fruit get(int i) {return fruit.list.get(i)}
list.get(i)가 object이므로 fruit으로 형변환 필요
→ 와일드 카드가 포함된 경우, 적절한 타입으로 형변환 추가
열거형(enum): 관련된 상수들을 같은 묶어놓은 것
enum Kind = {CLOVER, HEART, DIAMOND, SPADE}
enum Value = {TWO, THREE, FOUR}
-> enum으로 정의하면, CLOVER에 0부터 부여
타입의 안전한 열거형 제공(값, 타입 모두 확인)
C언어: Kind enum의 CLOVER와 Value enum의 TWO는 모두 0으로 만일 Card.CLOVER==Card.TWO, 하면 같다고 반환(의미는 Kind와 Value가 다르므로 같다고 나오면 안됨)
Java_enum: Card.kind.CLOVER == Card.Value.TWO 를 적으면 타입이 달라서 비교가 불가능하다는 컴파일 에러가 발생
열거형 정의
enum Direction {E, S, W, N}
열거형 타입의 변수 선언 및 사용법
class Unit {
unit x, y;
Direction dir; // 열거형 iv 선언(enum Direction {E, S, W, N}만 대입 가능)
void init()
dir = Direction.E; 초기화
}
열거형 상수의 비교에 ==와 compareTo() 사용 가능
if(dir==Direction.E) {
x++;
} else if(dir>Direction.E) { // Error - 열거형 상수=객체이므로 비교 연산자 사용 불가(equal, compareTo써야하지만, ==도 예외적으로 가능)
} else if(dir.compareTo(Direction.SOUTH)) { // CompareTo는 사용 가능
→ CompareTo: 왼:+1, 동:0, 오 +1(크기도 반환 가능)
}
java.lang.Enum
- String name(): 열거형 상수의 이름을 문자열로 반환
- int oridinal(): 열거형 상수가 정의된 순서를 반환(0부터 시작)
(단, 상수들이 실제로는 다른 값을 갖을 수 있기때문에 상수값과 순서값이 다를 수 있음)
- T valueOf(Class<T> enum Type, String name): 지정된 열거형에서 name과 일치하는 열거형 상수를 반환
컴파일러 자동 추가(values(),valueOf())
static E[] values()
Direction[] dArr = Direction.values(); // Direction의 상수를 배열로 반환
for(Direction d: dArr)
System.out.printf("%s=%d%n", d.name(), d.ordinal()); // 이름과 순서 반환
static E valueOf(String name)
Direction d = Direction.valueOf("W");
valueOf(열거형 상수 이름) -> 열거형 상수 반환
(Direction.W와 동일)
불연속적인 열거형 상수의 경우, 원하는 값을 괄호안에 적는다.
enum Direction {E(1), S(4), W(-1), N(7)}
* 여러개도 가능
enum Direction {east(1, “>”) south(5, “v”) west(-2, “<”) north(-8, “^”)}
→ 이러한 괄호를 사용하려면 인스턴스 변수와 생성자를 새로 추가해 줘야 한다.
enum Direction {
east(1, “>”) south(5, “v”) west(-2, “<”) north(-8, “^”)
private final int value; // 정수를 저장할 필드(인스턴스 변수 선언)를 추가
private final String symbol;
// esat(1, ">") -> east 객체의 1, ">" 생성자 호출 이므로
Direction(int value, String symbol) { // 생성자 추가
this.value = value
this symbol = symbol
}
cf. 생성자는 항상 private이므로 생략 가능→따로 표시가 없더라도 외부에서 객체 생성 불가
(Direction d = new Direction(1); // 열거형 생성자 private: 외부 호출 불가 -> Error)
public int getValue() {return value;}
public String getSymbol() {return symbol;}
}
애너테이션: 주석처럼 프로그래밍 언어에 영향을 미치지 않으며, 유용한 정보를 제공
/** ~ */ java.doc 주석(소스코드에 대한 설명)
@annotation
표준 애너테이션: 자바에서 제공하는 애너테이션
* @Override: 오버라이딩을 올바르게 했는지 컴파일러가 체크
class Parent {void parentMethod(){}}
class Child extends Parent {
@Override
void parentMethod() {}
}
* @Dreprecated: 앞으로 사용하지 않을 것을 권장하는 필드나 메서드
cmd 창에서 javac JavaFileName.java;
deprecated 경고 발생(eclipse는 자동 컴파일되므로 확인할 수 X)
javac -Xlint JavaFileName.java
상세한 경고 내용 확인 가능
* @Functionallterface
함수형 인터페이스에 붙이면 컴파일러가 올바르게 작성했는지 확인
함수형 인터페이스는 하나의 추상 메서드({}구현부가 없)는 메서드만 가져야 한다는 제약이 있어 그것을 확인해줌
일반 인터페이스는 여러 추상 메서드 보유 가능
interface testable {
void test();
void check();
}
일반 인터페이스 취급, 여러 추상 메서드 보유 가능
@FunctionnalInterface
interface testable {
void test();
void check();
}
1개 이상의 추상 메서드 구현으로 오류
* @SuppressWarnings
컴파일러의 경고메세지가 나타나지 않게 억제(해당 경고의 원인이 된 곳에 기재)
괄호()안에 억제하고자하는 경고의 종류를 문자열로 지정
@SuppressWarnings({”rawtypes”, ”deprecation”, ””})
→ 해당 경고를 내가 확인했다는 의미
→ 경고가 쌓이면서 놓치는 경우가 있을 수 있으므로 확인 한 경고는 SurpressWarnings에 기재해서 경고 삭제
*xlint옵션으로 cmd에서 컴파일하면 경고메시지 확인 가능
javac -Xlint AnnotionTest.java
-> [] 안의 경고가 SurpressWarnings에 들어가는 경고 이름
메타 애너테이션: 애너테이션을 만들 때 사용
- @Target
애너테이션을 정의할 때, 적용대상 지정에 사용
@Target({FIELD, TYPE, TYPE_USE}): 적용대상
ANNOTATION_TYPE: 애너테이션
field: 멤버 변수(IV, CV), ENUM 상수
type: class, interface, enum
type_use: 타입이 사용되는 모든 곳
애너테이션 만들기
@Target({FIELD, TYPE, TYPE_USE})
public @interface MyAnnotation {} // annottion 앞에 @interface 기재
@MyAnnotation // 적용대상: TYPE_USE
class MyClass {
@MyAnnotation // 적용대상: FIELD
int i;
@MyAnnotation // 적용대상: TYPE_USE
MyClass mc;
}
- @Retention: 애너테이션이 유지되는 기간을 지정하는데 사용
* 1. SOURCE: 소스파일에만 존재, 클래스 파일에는 X // @Override
2. RUNTIME: 클래스 파일에 존재, 실행 시 사용 가능 // @FuntionalInterface
3. CLASS: 클래스 파일에 존재, 실행 시 사용 불가 (기본값)
@Retention(RetentionPolicy.SOURCE)
public @interface Override
@Retention(RetentionPolicy.RUNTIME)
public @interface FunctionalInterface {}
- @Documented
javadoc으로 작성한 문서에 애너테이션 포함시키려고 할 때
- @Inherited
애너테이션을 자손 클래스에 상속하고자 할 때
@Inherited // SuperAnno가 자손까지 영향을 미치게
@interface SuperAnno{}
@SuperAnno
class Parent{}
class Child extends Parent {} // child에 @SuperAnno 애너테이션이 붙은 것으로 인식
- @Repeatable
반복해서 붙일 수 있는 애너테이션을 정의할 때 사용
@Repeatable(ToDos.class)
@interface Todo{String value();}
@ToDo()
@ToDo()
class MyClass
하나의 대상에 애너테이션을 반복해서 붙일 수 있음
@Repeatable인 @ToDo를 하나로 묶을 컨테이너 애너테이션도 정의해야 함
@interface ToDos{ // 여러개의 애너테이션을 담을 컨테이너 애너테이션 생성
ToDo[] value(); // todo 애너테이션 배열타입의 요소를 선언, 이름이 반드시 value여야 함
}
애너테이션 타입 정의하기
@interface 애너테이션 이름{
타입 요소이름();
}
애너테이션 메서드는 추상 매서드(구현 필요 X)이며, 애너테이션을 적용할 때 모든 요소를 다 적어줘야 하며, 순서는 상관X
(단, null제외 기본값 지정 가능→기본값 지정시 애너테이션 구성요소 작성 생략 가능)
@interface TestInfo{
int count() default 1;
}
@TestInfo(
count =3
)
enum 사용 가능
enum TestType {F, S}
TestType testType();
자신이 아닌 다른 애너테이션 포함 가능
@interface DateTime{}
DateTime testDate();
요소가 하나이고, 이름이 value면 요소이름 생략 가능
@interface TestInfo{
String value();
}
@TestInfo(”Passed”) // @TestInfo(value=”Passed”)와 동일
class NewClass{}
요소 타입이 배열인 경우 괄호를 사용해야 함
@interface TestInfo{
String[] testTools();
}
@Test(testTools={”JUnit”, “AutoTester”})
@Test(testTools=”JUnit”) - 1개일 때는 생략 가능
@Test(testTools={}) - 값이 없을 때는 괄호{}가 반드시 필요
모든 애너테이션의 조상은 interface
→ extends를 사용해서 상속하는 표현 쓰지X, 자동 상속
→ 모든 annotation의 조상인 interface Annotation의 추상매서드들을 모두 구현하지 않고도 사용 가능(컴파일러가 자동 구현)
마커 애너테이션(Marker Annotation)
요소가 하나도 정의되지 않은 애너테이션
@Test, @Deprecated, @Override
애너테이션 요소 규칙
애너테이션 요소를 선언할 때, 아래의 규칙을 반드시 지켜야 함
1. 요소의 타입은 기본형, String, enum, Annotation, Class만 허용
2. 추상 메서드 괄호()안에 매개변수를 선언 할 수 X
3. 예외를 선언할 수X
4. 요소를 타입 매개변수<T>로 정의할 수 없음
@interface AnnoTest {
(static final) int id = 100; - 상수O, default method*는 안됨
String major(int i, int j); - 2
String minor() throws Exception; - 3
ArrayList<T> list(); - 4
}
* default method
인터페이스에 메서드를 추가할 경우, 해당 인터페이스를 구현하고 있던 모든 class에 오류 발생
이 때, 인터페이스 내부에 메서드 추가시 default를 앞에 붙이면 필요적으로 구현하지 않아도 됨
interface A {
default void b() {}; - 추상 메서드와 달리 빈 선언부가 있음
void c() {};
}
class D impletmens A {
void c() {}; - 필요적 구현
void b() {}; - 선택적 구현
}
소스 코드
참고 자료
'Java > Java' 카테고리의 다른 글
[자바의 정석_기초편] Chapter11. 컬렉션 프레임워크(Collections framework)_3 (0) | 2023.06.11 |
---|---|
[자바의 정석_기초편] Chapter11. 컬렉션 프레임워크 (Collections framework)_2 (0) | 2023.06.03 |
[자바의 정석_기초편] Chapter11. 컬렉션 프레임워크 (Collections framework)_1 (1) | 2023.05.25 |
[자바의 정석_기초편] Chapter10. 날짜와 시간 & 형식화 (0) | 2023.05.20 |
[자바의 정석_기초편] Chapter09. java.lang package / Useful class_2 (0) | 2023.05.17 |