velog에서 이전한 글 입니다.

23.5.2 ~ 23.5.19 사전 캠프 기간의 TIL 기록이다.
TIL: Today I Learned

멤버 변수 초기화

class InitTest{
    int x;
    int y = x; // 멤버변수는 초기화 하지않아도 기본값으로 초기화

    private void method1(){
        int i;
        int j = i; //지역변수는 사용전 초기화 안하면 에러
    }
}
  • 기본값
    • boolean : false
    • char : '\u0000'
    • 참조형 : null
  • 변수 초기화
    • 클래스 변수(cv) 초기화 -> 인스턴스 변수(iv) 초기화
    • 자동 초기화 -> 명시적 초기화 -> 초기화 블럭, 생성자
class Main{
    static {
        System.out.println("클래스 초기화 블럭");
    }

    {
        System.out.println("인스턴스 초기화 블럭");
    }

    private Main(){
        System.out.println("인스턴스 생성자");
    }

    public static void main(String[] args){
        System.out.println("Start Main");
        Main t = new Main();
        Main t2 = new Main();
    }
}

결과
클래스 초기화 블럭
Start Main
인스턴스 초기화 블럭
인스턴스 생성자
인스턴스 초기화 블럭
인스턴스 생성자

클래스 초기화 블럭이 가장 먼저 한 번 동작하고 인스턴스 초기화 블럭이 생성자보다 먼저 수행된다.

멤버변수 변경은 getter setter 메서드 만들어하자.


제어자

접근 제어자

  • 클래스 : public, (default)
  • 메서드/멤버변수/생성자 : public, protected, (default), private
  • 지역변수 : X

기타 제어자

  • final
    • class : 변경 불가, 확장 불가
    • method : 오버라이딩 불가
    • 멤버변수/지역변수 : 상수로 동작
  • abstract
    • 클래스 : 클래스 내에 추상 메서드가 있음을 의미.
    • 메서드 : 선언만 했고 구현부 작성안한 추상 메서드임을 알림.

다형성, 참조변수

  • 다형성 : 부모 타입의 참조변수로 자식의 인스턴스를 참조할 수 있도록 한 것으로부터 나오는 여러 형태
    • 매개변수의 다형성 : 매개변수를 부모 타입으로 받아 공통으로 처리할 수 있다.

참초변수의 형변환

public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        FireCar firecar = new FireCar();

        Car re_firecar = (Car) firecar;
        FireCar re2_firecar = (FireCar) re_firecar;
        re2_firecar.fire();

//        FireCar re_car = (FireCar) car; // 여기부터 에러
//        re_car.fire();
        System.out.println( car instanceof  FireCar); //false
    }
}

class Car{
    void say(){
        System.out.println("Car");
    }
}

class FireCar extends Car {
    void fire(){
        System.out.println("fire!");
    }
}

자식이 부모로 형변환은 문제없으나 부모가 자식으로 형변환은 명시적이어야 한다. 사실 자식 -> 부모 -> 자식 가는게 아니면 못하는 듯 하다.
형변환 가능 여부는 instanceof 로 확인할 수 있다.

  • toString()은 Object 클래스의 메서드
  • 참조변수 + 문자열 = 참조변수.toString() + 문자열

모듈/패키지

모듈 : 여러 패키지 및 자원을 모아 놓은 컨테이너
module > package
module-info.java, package-info.java 같은 파일을 통해 여러 옵션으로 관리할 수 있어 보인다.

interface

인터페이스의

  • 모든 멤버변수는 public static final 이어야 한다.
  • 모든 메서드는 public abstract 이어야 한다.
    둘 다 생략 가능하며 컴파일 시에 자동으로 추가해준다.
  • 상속과 구현 동시가능
class A extends B implements C{
    public void c(){
        System.out.println("a가 구현한 c");
    }
}

interface C{
    /** 구현해야할 c 설명 */ 
    void c(); //public abstract 생략
}
  • 인터페이스 타입의 매개변수 : 메서드 호출 시 해당 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 제공해야 함을 의미한다.
  • 리턴타입이 인터페이스 : 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 것을 의미한다.

인터페이스를 이용한 다형성

Fightable f = (Fightable)new Fighter();
또는
Fightable f = new Fighter();

구현한 클래스의 인스턴스를 인터페이스 타입의 참조변수로 참조하는 것이 가능하다.

default/static method

원래는 둘 다 안됐으나
static 메서드는 인스턴스와 관계없는 독립적인 메서드로 추가 못할 이유가 없었다.
default는 인터페이스를 변경되지 않는게 최고이지만 언젠가 변경은 발생하기 마련이었고 그에 따른 대책이다. ( 추상 메서드를 추가하면 구현한 기존의 모든 클래스들이 새로 추가된 메서드를 구현해야하므로 )

interface Test{
    static void saystack(){
        System.out.println("say stack");
    }

    default void say() {
        System.out.println("hello");
    }
}

마찬가지로 public은 생략가능하다.

충돌 해결 규칙

  • 여러 인터페이스의 디폴트 메서드 간의 충돌 -> 구현한 클래스에서 오버라이딩 해야한다.
  • 디폴트 메서드와 부모 클래스의 메서드 간의 충돌 -> 부모 메서드가 상속되고 디폴트는 무시된다.

익명 클래스

class Animal {
    public String bark() {
        return "동물이 웁니다";
    }
}

public class Main {
    public static void main(String[] args) {
        Animal dog = new Animal() {
            // @Override 메소드
            public String bark() {
                return "개가 짖습니다";
            }

            // 새로 정의한 메소드
            public String run() {
                return "달리기 ㄱㄱ싱";
            }
        };

        dog.bark();
        dog.run(); // ! Error - 외부에서 호출 불가능
    }
}

출처
위 코드 처럼 클래스 정의와 동시에 객체를 생성할 수 있으며 일회성 오버라이딩 용으로 사용한다.
오버라이딩 한 메소드 사용만 가능하고, 새로 정의한 메소드는 외부에서 사용이 불가능 하다는 점을 주의하자. 새로 메서드를 정의해도 Animal에는 없는 메소드이므로 Err (다형성의 법칙)