Java 문법 정리

Kotlin을 배우다가, 결국 Java도 정리할 수밖에 없게 되었다.

기본 타입들, 구문

  • 모든 코드조각이 클래스 안에 포함되어야 한다.
  • 전역 변수는 없고, static은 쓸 수 있다.
  • 변수, 함수는 카멜 표기법, 클래스는 파스칼 표기법
  • primitive 타입들: Primitive는 그 자체로 값임
    • 정수: byte, char, short, int, long
    • 실수: float, double
    • 논리: boolean
  • Wrapper class를 제공해줌
    • 예를들어 Integer
    • 이 클래스들은 오브젝트이며, Reference로 지칭됨
    • Generic에 넣어줄때 이용됨 (Generic은 Primitive를 못받음)
  • String은 라이브러리로 제공
  • 연산자는 거의 C랑 똑같음
  • JVM은 Generation GC 함
  • 배열은 C++ vector에 가까움
    • Bound 체크를 해줌
    • 한번 만들면 append 불가능.
    • 이중일때 서로 다른 사이즈 할당이 가능 { {1} , {1,2} }
    • Vector 같은것이 필요할 때 ArrayList를 쓸 것.
  • 조건문, 반복문은 C++과 완전 같다.

클래스, 상속

  • 클래스 선언 및 프로퍼티 Visibility 제한자들은 C++과 동일
  • 최상위 클래스에는 public만 붙일 수 있음
  • 내부 클래스에는 3개 모두 가능
  • 멤버 메소드의 오버로딩 가능.
  • 연산자 오버로딩 안됨
  • 상속은 extends로 받음, 오버라이딩 가능
    • @Override를 붙여서 실수 방지
    • super()로 부모 클래스의 생성자 이용 가능
      • super가 가장 먼저 불려야함.
    • super로 사용하는 경우는 부모 객체의 Instance 접근 가능.
  • this, 생성자 사용 가능. C++과 거의 같음

익명 클래스

  • 일회성으로 선언해서 사용 가능한 익명 클래스(재사용 불가)
  • new ArrayList() { /* members */}의 형태로 사용
  • final 혹은 effective final을 만족하는 외부변수만 참조 가능.

인터페이스

  • interface로 인터페이스 선언
  • 추상 메서드 + 상수 + default 메서드 + static 메서드
  • implements로 클래스에서 사용
  • 하나의 클래스는 여러개의 인터페이스를 구현할 수 있음.
  • default 메서드로 구현을 집어넣을 수 있음
    • default에서는 상수, 다른 default메서드, static 메서드 사용 가능
    • 상속이 가능하며, 다중상속시 오버라이딩 필수
  • static 메서드도 구현을 집어넣을수 있으나 상속되지 않음

한정자, 제어자

  • final
    • final 변수: 상수 취급
    • final 메소드: 오버라이드 불가
    • final 클래스: 상속 불가
  • abstract로 추상클래스 선언
    • 추상 메서드만 포함 가능
  • 접근 제어자
    • public, private, protected

예외

  • try, catch, finally을 씀
  • Throwable을 상속받은 객체만 던질 수 있음.
  • 던지는 클래스에서는 throws로 던져지는 예외들을 명시해주어야함

제너릭

기초

  • 제너릭: Parameterized type
  • Generic으로 쓸 수 없는 타입들
    • Anonymous inner classes
    • Exception types
    • Enum types
  • 용법
    • Generic Class/Interface: 클래스 이름 뒤에 Generic을 선언
    • Generic Method: 함수 이름 앞에 Generic을 선언
  • 기본적으로 Syntactic Sugar임.
    • Generic을 지우고, 해당 위치를 Object로 바꿔도 아무 문제 없이 사용가능
      • 명시적 형변환은 필요할 수 있음
    • 런타입에는 제너릭 타입 정보를 지움
      • 모든 Generic instance는 static을 공유
    • 타입을 활용한 분기 불가능
      • 타입을 쓰고싶으면 class 오브젝트를 활용하거나 해야함

Generic 타입 선언/사용

  • Type 선언시 바운드 가능
    • Unbounded type parameter: <T>
    • Bounded type parameter: <T extends Numbers>
    • Recursive type bound <T extends List<T>>
  • 타입 사용시 wildcard type 사용 가능
    • Unbounded wildcard Pair<?,?> limit
    • Bounded wildcard
      • Iterable<? extends E> limit
      • Iterable<? super E> limit
  • 선언시 생략 가능 Box box<Integer> = new Box<>();
  • Generic 타입으로 캐스팅 할 경우 Raw 타입으로 캐스팅되어버림
    • 아래 예에서는 oArrayList<String>이 아닌 ArrayList로 캐스팅
      1
      2
      3
      4
      5
      ArrayList<Integer> a = new ArrayList<Integer>();
      a.add(1);
      Object o = a;
      ArrayList<String> b = (ArrayList<String>) o; // No error, unchecked
      System.out.println(b.get(0)); // Error! Hard to find. 
      
  • List<Object>List<String>의 서브타입이 아님
    • 제너릭들은 서브타입 관계를 가지지 않음.
    • void printAll(ArrayList<Object> c)ArrayList<String> 대입불가.
    • void printAll(ArrayList<? extends Object> c)에는 대입 가능
  • Array와 섞어서 쓰면 거진 다 Type Unsafe임.
    • 거의 섞어서 쓸일이 없음 그냥 Collections를 쓰자.

try-with-resources

  • try와 소괄호를 이용해 자원을 자동해제 할 수 있다. Python의 with처럼 쓸 수 있음.
    1
    2
    3
    4
    5
    6
    try (
      FileReader fr = new FileReader("data.txt");
      BufferedReader br = new BufferedReader()
    ) {
      return br.readLine();
    }