김영한의 Java 초급편 강의를 듣고 정리한 내용

java 메모

java에서 클래스를 접근해서 수정할 때 .을 통해 접근하는데 java는 js처럼 immutable, mutable 관련 문제가 없나?

java는 new로 클래스 만듦. 사용자가 타입과 객체 구조 설계도를 만드는 게 클래스
클래스(설계도)를 기반으로 실제 객체를 만들면 -> 인스턴스. 객체 생성 시 메모리에 공간도 확보된다.

new Student가 반환하는 건 참조.
배열에 넣어주는 값이 없으면 널로 초기화

자바의 대입은 언제나 변수에 들어 있는 값을 복사해서 전달. 이건 참조값에대해서도 마찬가지다. 참조 복사.
-> 변수에는 인스턴스 자체가 아니라 인스턴스에 대한 참조가 들어있고 이게 복사된다. 대입(=)을 헷갈리지 말기

인텔리제이 단축어 : iter -> 대충 for문 같은 거 나옴
psvm: 기본적인 클래스랑 main 나옴

기본형 변수는 null 할당 불가. 참조형은 null 가능

인스턴스 멤버 변수는 자동으로 기본값으로 초기화됨, 상식적인 선에서 0, null, false등으로 초기화

아무도 참조하지 않는 객체의 경우 gc가 제거
null에 . 으로 접근 시 널 포인터 에러

절차지향은 데이터와 데이터 처리 방식이 분리
객체지향에서는 데이터와 데이터에 대한 행동(메서드) 가 객체 안에 함께 있다
데이터와 데이터를 다루는 기능은 밀접하게 연관되어 있기 때문에 같이 묶어서 관리 포인트를 줄인다.

만약 데이터/기능이 분리되어 있으면 데이터 관리 변경 시 기능 쪽이 있는 다른 포인트로 가서 변경해야 한다!

클래스 내부에 속성(data) 기능(method)를 같이 넣자.

객체지향에서도 절차지향에서 중요했던 실행 순서는 중요하다.
다만 객체의 설계와 관계를 좀 더 중시함으로써 프로그래밍을 “무엇을” 하는지를 중심으로 풀어 나가는 것. 객체간의 상호 작용으로 시스템을 모델링한다.
이 방식은 객체가 데이터 + 메서드를 함께 가지도록 함으로써 객체가 온전한 책임을 지도록 하는 것

섹션 5 생성자
객체를 생성했을 때 init() 같은 함수를 사용해서 객체를 초기화해줄 수 있다.
하지만 객체지향에서는 속성과 기능을 한 곳에 두는 게 더 낫다. 따라서 객체가 자기 자신의 데이터를 변경하거나 초기화하는 기능(메서드)을 제공하는 게 좋다.

인스턴스 자신을 가리킬 때 메서드 내부에서 this를 쓸 수 있다. 초기화 함수 / 생성자 등에서 파라미터와 클래스 멤버 변수의 이름이 겹칠 때 쓸 수 있다. 인수명이랑 멤버변수명이 겹칠 때 그냥 변수명만 쓰면 스코프 상에서 함수 인수가 더 우선해서 접근되기 때문이다. 물론 이름을 겹치지 않게 설정하면 this를 생략할 수 있다.

예전에는 this를 무조건 붙여 주는 코딩 스타일도 있었다. 멤버변수 / 지역변수(인수)를 구분하기 위해서였다. 하지만 요즘은 IDE에서 대부분 이를 색깔로 구분해준다.. 따라서 영한이는 권장 안 한다고 함. 꼭 필요할 때(이름 겹칠 때)는 쓰자

객체 생성 후 초기값을 할당할 수 있도록 생성자를 제공하는 언어가 많다. java에서는 클래스명과 같은 메서드를 선언하면 생성자가 된다. 생성자를 호출하면 java에서 자동으로 인스턴스 생성 후 생성자를 호출하여 초기화한다.

만약 생성자 선언 안 되면 java에서 매개변수가 없는 기본 생성자를 제공한다. 단 생성자를 하나라도 선언 시 기본 생성자를 제공해 주지 않기에 주의.

-> 이는 장점도 있는데 직접 정의한 생성자가 있다면 직접 정의한 생성자를 반드시 호출해야 하기 때문. 생성자 호출(즉 초기화)이 필수가 된다는 것 -> 필수값 입력 보장!

기본 생성자가 있는 이유는, 생성자가 필요 없는 클래스의 경우도 많은데 이런 클래스에도 생성자를 정의해야 하면 귀찮으니까 기본 생성자를 java에서 편의 기능처럼 제공해 주는 것

생성자도 오버로딩 가능. 오버로딩한 생성자 중 하나만 호출하면 알아서 java가 구분해서 해줌

이때 만약 생성자들 간에 연관 관계가 있다면 this() 로 생성자 내부에서 자신의 다른 생성자를 호출 가능. 가령 생성자 1에서 생성자2를 호출. 이를 통해 생성자 내부의 중복 로직 제거 가능
-> 이때 this()는 생성자 코드의 첫 문장에만 작성할 수 있다는 규칙이 있다.

정리: 생성자는 객체 생성 직후 객체 초기화를 위한 특별한 메서드

섹션 6 패키지

프로그램이 작아서 클래스가 몇개 없다면 괜찮지만 프로그램이 커지면? 기능별로 분류해서 관리하고 싶을 것이다. 컴퓨터에서 파일을 분류하기 위해 폴더를 쓰듯이 java에서도 패키지라는 걸 둔다.

패키지를 사용하는 경우 항상 코드 첫 줄에 package 패키지명 적어줘야 한다.

다른 패키지에서 클래스 생성자를 호출하려면 public을 넣어줘야 함
그리고 현재 파일 경로와 다른 파일 경로에 있는 클래스 생성자를 호출하려면 pack.a.User 처럼 패키지 전체 경로를 포함한 클래스를 적어 주면 됨

이렇게 풀네임 적어 주는 게 귀찮으면 import 사용
코드 첫줄엔 패키지, 다음 줄엔 import를 사용 가능
만약 특정 패키지 안의 클래스를 전부 가져오고 싶으면 패키지명.* 쓸 수 있다

근데 만약 다른 패키지에 있는 같은 이름 클래스를 둘 다 쓰고 싶다면? 어쩔 수 없이 둘 중 하나는 풀네임을 적어 줘야 한다..보통 여러 번 사용하는 클래스를 import 후 덜 사용되는 걸 import 없이 풀네임(패키지.클래스명)을 쓴다.

패키지 규칙

실제로는 각 패키지에서 클래스를 만들고 서비스에서 import해서 로직을 구성하는 그런 식. 기능별로 패키지를 만들고 관련된 클래스들을 모아 놓는 역할(가령 사용자 관련된 클래스들)

-> 기능별로 묶어 놓는 게 핵심
다른 패키지의 클래스 가져오기

섹션 7. 접근 제어자
private 등으로 클래스 멤버의 접근을 막을 수 있다. 이 규칙을 안 지키고 접근 시도시 아예 컴파일 에러가 뜸

private; 모든 외부 호출 막음. 클래스 안으로 속성/기능을 숨김
default 같은 패키지 안에서는 호출 가능(기본, package-private이라 한다)
패키지 단위로 속성/기능을 숨김
protected 같은 패키지 안의 호출 허용, 패키지 달라도 상속 관계 호출은 허용
상속 관계로 속성/기능을 숨김
public 모든 외부 호출 허용

지역 변수에는 접근 제어자를 쓸 수 없고 클래스 멤버에 쓰는 거임

클래스 레벨의 접근 제어자 규칙 -> public, default만 쓸 수 있음
public 클래스는 반드시 파일명과 이름이 같아야 함
하나의 파일에 여러 클래스를 만들수 있지만 public 클래스는 파일명과 같은 이름의 단 하나만 있어야 한다. 나머지는 그냥 선언하는 default 클래스(같은 패키지 내부에서만 접근 가능)

캡슐화
데이터와 해당 데이터를 처리하는 메서드를 하나로 묶어서 외부에서의 접근 제한
즉 속성 + 기능을 하나로 묶고 외부에는 필요한 기능만 노출하기
이를 안전하게 완성할 수 있도록 해주는 게 접근 제어자

  1. 데이터를 숨기기 -> 객체 데이터는 객체가 제공하는 기능인 메서드를 통해서 접근(getter, setter도 같은 개념) 대부분의 data는 private이다
    우리가 자동차의 엑셀을 밟는 거지 속도계를 직접 조작하지 않는 거랑 같은 이치
  2. 기능 숨기기 -> 외부에 노출할 필요가 없는 기능은 전부 숨기기

열어 둬서 사용하도록 허용하는 기능만 public으로 해야 한다. 즉 필요한 기능만 노출하고 나머지는 숨기는 게 캡슐화. 그래야 데이터도 보호하고 다른 개발자 입장에서 클래스를 보는 복잡도도 낮출 수 있다.

실무에선 클래스가 수십수백개라 이런 게 중요함

섹션 8. 자바 메모리 구조와 static
자바 메모리 -> 메서드 영역(클래스 정보를 보관. static 영역을 말하는 듯), 스택 영역(실제로 메서드가 실행되면서 지역 변수들이 들어감), 힙 영역(객체 생성되면 올라오는 영역)

메서드 영역
클래스 정보, static 변수들, 런타임 상수들(문자열 리터럴 등등). 메서드들은 인스턴스별로 저장되는 게 아니라 메서드 영역에 저장됨

스택 영역
자바 실행 시 실행 스택이 생성되고 각 스택 프레임은 해당 메서드 호출에 대한 정보를 담음
더 정확히는 스레드별로 하나의 실행 스택 생성. 즉 스레드 수만큼 스택 영역 생성됨

힙 영역
객체와 배열이 생성되는 영역. new로 객체 인스턴스 생성시 여기 들어가며 gc가 여기서 동작

인스턴스 메서드 호출 시 메서드 영역에 저장된 메서드 코드를 호출함 그리고 메서드 호출에 필요한 정보(매개변수 등)는 스택 프레임에 담기고 종료 시 메서드 관련 정보 다 사라짐.

참조가 사라지면 gc가 동작
이때 힙 영역 외부가 아니라 힙 영역 안에서 인스턴스끼리 참조하는 경우(순환 참조 등)도 gc 대상이 됨

static 키워드를 이용하면 클래스 전체에서 공용으로 사용하는 (정적) 변수를 만들 수 있다. static 변수는 클래스 자체에 속해 있으므로 클래스명.어쩌구 처럼 접근해서 함. 저장도 힙 영역이 아니라 메서드(static) 영역에서 관리

변수 생명 주기
지역 변수는 스택 영역에서 생존
인스턴스 변수는 힙 영역에서 gc까지 생존
클래스 변수는 static 영역에 생성되고 클래스가 JVM에 로딩될 때 생성된다. 그리고 JVM 종료까지 유지됨.

신기한 점 : 이때 static 변수는 인스턴스를 통해서 접근도 가능(물론 실제로는 static 변수에 접근을하는 건 똑같음) 하지만 인스턴스를 통해 접근하는 건 권장되지 않는다.
왜냐? 코드를 읽을 때 인스턴스 변수에 접근하는 것처럼 오해가 있을 수 있기 때문에 클래스를 통해 접근함으로써 명확하게 클래스 소속임을 드러내 주는 것

static 메서드
그냥 static을 붙이면 클래스 소속인 정적 메서드가 됨. 객체 생성 없이도 호출 가능

정적 메서드 사용법: 정적 메서드에서는 static 변수/메서드만 사용 가능. 당연하지만 인스턴스 변수/메서드 사용불가. 이는 정적 메서드가 사용되는 시점에 인스턴스가 생성되지 않아서 메모리에 없고 따라서 참조값을 알 수 없기 때문이다.
물론 당연히 인스턴스 생성 후 정적 메서드 매개변수로 전달하는 등의 방법으로는 정적 메서드에서도 인스턴스 사용 가능. 매개변수를 통해 넘어온 참조값을 알 수 있으니까. 다만 이건 외부에서 매개변수로 인스턴스를 넘겨주는 거고, 메서드 선언 시 사용은 불가.

물론 인스턴스 메서드에서는 static 메서드, 변수 등 전부 사용 가능. 어차피 클래스 소속이니까

이런 정적 메서드는 보통 메서드 호출만으로 연산 등을 수행하는 유틸리티 메서드에 사용

같은 정적 메서드를 여러 번 호출 시 import static을 쓰는 것도 고려(정적 변수도 static import 가능)

main도 정적 메서드임. 따라서 main에서 호출하는, 같은 클래스의 다른 메서드도 정적 메서드로 선언해서 사용했음

유틸리티 메서드를 정적으로 선언한 유틸리티 클래스의 인스턴스 생성을 막기 위하여 -> 생성자를 private로 선언

섹션 9. final

final은 끝이라서 더는 값을 변경할 수 없다는 뜻. const 같은 것
메서드 인자에도 final int 같은 타입을 줄 수 있는데 그러면 메서드 내부에서 매개변수 값을 변경할 수 없다. 메서드 호출 시점부터 종료시까지 같은 값이 사용됨

final 인스턴스 변수의 경우에는 생성자에서 1번만 초기화 가능(물론 멤버 변수 선언 시 초기값을 넣어 준 경우 생성자에서 초기화 불가). 이렇게 생성자를 통해서 final 필드 초기화 시 생성자를 통해 각 인스턴스마다 다른 final 필드 값을 할당 가능.
가령 유저 객체를 만든다면 id를 처음에 한번만 초기화하고 이후에는 변경 불가능하게 한다든지 하는 게 가능. 만약 유저 id를 변경하려고 할 때면 컴파일 오류가 날것

암튼 중요한 건 딱 한번만 초기화 가능하다는 것

static final 변수는 상수이므로 대문자로 쓰는 관례(CONST_VALUE 처럼)가 있다. 그리고 이런 상수는 직접 필드에 접근해서 사용한다.
이렇게 상수를 쓰면 MAX_USER 등 프로그램에서 쓰이는 여러 숫자들을 중앙화해서 관리하며 의미를 부여할 수 있다.

근데 이렇게 final로 선언시 변수 값이 변경이 안된다. 이때 원시형은 10, 20같이 값을 변경할 수 없다. 참조형의 경우 참조를 변경할 수 없다. js의 const 객체의 속성 변경은 가능한 걸 생각하면 될 듯

객체가 할당된 final 변수에 아예 새로운 뭔가를 할당하는 건 실패. 해당 객체의 내용을 바꾸는 건 가능. 참조값을 바꾸는 게 아니고 참조하고 있는 대상의 내용이 바뀌는 거니까!

섹션 10. 상속

extends로 상속 가능
자바는 단일 상속만 가능. 이는 다중 상속에서 발생하는 다이아몬드 문제 때문(A,B를 상속받았는데 A, B 모두 같은 이름의 메서드가 있을 때 어떤 걸 사용하는지의 문제)
대신 이후 인터페이스의 다중 구현을 통해 이런 부분을 극복

클래스 객체 생성 시 슈퍼클래스까지 포함해서 인스턴스를 생성한다. 상속 관계 사용 시 부모 클래스도 함께 생성됨. 내부에서는 부모 + 자식이 모두 생성되고 공간도 구분됨

그럼 메서드를 호출하면? Car를 상속한 ElectricCar의 메서드를 호출 시 어디서 메서드를 찾는가? 이는 호출하는 변수의 타입을 기준으로 선택한다. 따라서 Car 타입으로 ElectricCar 인스턴스를 생성 시 ElectricCar에만 있는 메서드는 사용하지 못함.

단 오버라이딩된 메서드는 상위 클래스 타입으로 선언된 하위 클래스 인스턴스라도 하위 클래스에서 오버라이딩된 메서드가 쓰인다.

만약 타입에 해당 메서드가 없으면 부모 클래스를 거슬러 올라가면서 메서드를 찾는다.

상속을 통해 공통되는 부분의 중복 코드를 줄이고 부모의 기능을 확장한 다른 새로운 클래스도 쉽게 만들기 가능. 좀 더 공통된 개념을 부모 클래스로 삼는다

@Override를 붙이면 이 메서드가 상위 메서드를 오버라이딩했다는 걸 컴파일러가 인식하고, 해당 메서드가 부모 클래스에 실제로 있는지를 검사하고 없을 시 컴파일 에러를 발생시켜준다.

오버라이딩의 조건들.. 물론 이걸 다 외울 건 없고 @Override를 붙이면 알아서 검사하고 해줄거다
메서드 이름이 같아야 하고 파라미터 타입,순서,개수,반환타입 같아야
상위 클래스 메서드보다 더 강한 접근 제어자 쓰면 안됨
static, final, private는 재정의 불가

protected 접근 제어자 : 같은 패키지에서 접근 가능. 패키지가 달라도 상속 관계에서는 접근 허용

스스로의 타입이 없으면 부모 클래스에서 메서드를 찾는데 이때 접근 제어자가 영향을 준다. 객체 내부에서는 자식, 부모가 구분되어 있기 때문에, 부모 클래스 입장에서는 자식 클래스(즉, 외부)에서 부모 클래스 메서드를 호출한 것과 같다.

this는 자기 자신의 참조, super는 부모 클래스에 대한 참조.

상속 관계 사용 시 자식 클래스 생성자 첫 줄에 부모 클래스 생성자를 반드시 호출해야 한다는 규칙(안 하면 컴파일 에러). super() 하면 됨

이때 부모의 기본 생성자 super()는 생략할 수 있다. java가 자동으로 해줌. 기본 생성자를 많이 쓰기 때문에 이런 편의기능이 있는 것

만약 부모에 기본 생성자가 없을 경우(따로 생성자를 정의해서) super(인자)를 명시적으로 호출해 줘야 한다.
생성자 실행 순서는 자식 생성자마다 있는 super()를 통해, 최상위 부모의 생성자부터 실행된다. 부모 -> 자식 -> 그 자식.. 왜냐? 자식 생성자에서는 매번 부모의 생성자를 super()를 이용해서 호출하기 때문.

섹션 11. 다형성

다형성은 oop의 꽃
한 객체가 여러 타입 객체로 취급될 수 있는 능력

다형적 참조
-> 상위 타입 클래스로 하위 타입 클래스 인스턴스 선언 가능(부모 타입은 자식 타입 인스턴스 담기 가능)

단 하위 타입에만 있는 메서드는 사용 불가(상위 타입은 이 메서드를 모르니까..) 하위 타입 메서드 사용하려면 타입 캐스팅을 해야 한다 -> 다운 캐스팅. 호출하는 타입을 (Child) inst처럼 자식 타입으로 변경한다. 기본적으로는 하위타입은 상위타입을 담을 수 없으므로

일시적 다운캐스팅. 메서드 호출 순간만 다운캐스팅
((Child) inst).childMethod();

업캐스팅: 부모 타입으로 변경. 하지만 원래 자식은 부모타입에 담길 수 있으니 생략가능

근데 다운캐스팅을 잘못하면 Parent 인스턴스를 Child로 캐스팅하고 Child에만 있는 메서드를 불러버려서 런타임 에러가 날 수 있다. 호환되지 않는 클래스로 객체 형변환 시도 시에도 ClassCastException 런타임 에러 발생

런타임 오류는 프로그램 실행중 터져서 별로 안좋음.

그럼 이 인스턴스가 어떤 클래스에서 만들어진건지 확인하고 캐스팅을 하거나 로직을 짜거나 하고 싶으면?
-> instanceof. 참조하고 있는 실제 인스턴스 타입 확인
Parent로 주어진 매개변수를 instanceof로 Child 인스턴스인지 확인한 후 Child로 다운캐스팅하는 등이 가능하다.

이때 instanceof는 대입 가능성을 판별하므로 (Child 인스턴스) instanceof (Parent)도 true다. Child는 Parent에 담을 수 있으니까. 상속 관계도 고려해야 한다!

정리하자면 A instanceof B -> 상속까지 고려하여 A 인스턴스를 B 클래스에 담을 수 있으면 true 아니면 false

java 16: Pattern Matching in instanceof
parent instance of Child child -> parent를 Child로 다운캐스팅한 변수 child까지 선언해주기

암튼 instanceof를 사용해 안전한 다운캐스팅 가능

단 변수는 오버라이딩이 안 됨.
Parent c = new Child()를 하면?
이때 c.prop에 접근시 c에는 부모 인스턴스와 자식 인스턴스 둘 다 있음
Child 인스턴스지만 타입은 Parent 타입이니까 Parent 인스턴스에 접근해서 Parent의 prop 값 읽음

메서드도 마찬가지로 Parent.method를 읽으려고 한다. 오버라이딩된 메서드가 항상 우선권을 가짐 그래서 만약 이 메서드가 오버라이딩되어 있을 경우 Child.method(오버라이딩되어 있다면)가 실행됨

다형성의 구성

섹션 12. 다형성

여러 동물 클래스가 sound() 메서드를 가지고 있다고 하면 어떻게 이 클래스 인스턴스들의 sound를 한번에 호출할까? 울도록 하는 메서드를 만들기도, for문을 돌리려고 해도 타입이 다르니까 어렵다.
-> 공통의 타입을 사용할 수 있는 방법이 있을까?
다형적 참조와 메서드 오버라이딩 활용

부모 클래스를 만들고 sound를 만든 후 자식에서 오버라이딩
그리고 배열 같은 경우 Animal[] 타입으로 선언하면 된다. 동물들이 범용적으로 들어갈 수 있는 함수라면 Animal 타입을 인수로 받도록 선언
-> 부모 타입에는 자식을 담을 수 있으니까(다형적 참조). 그리고 메서드는 오버라이딩된 게 항상 우선권을 가지니까(메서드 오버라이딩) 이렇게 각각의 동물 인스턴스의 메서드를 잘 쓰기 가능

코드가 변하는 부분(main 등)이랑 변하지 않는 부분(Animal.sound를 다형적으로 호출하는 것)이 있는데 변경사항이 있을 때 변경 범위가 최소화되는 게 일반적으로 좋은 코드이다.

그런데 아직 문제가 있다.

추상 메서드를 오버라이딩하지 않은 자식 클래스는 역시 추상 클래스가 되어야.

-> 다형성 사용시 발생할 수 있는 문제를 방지하기 위해 추상 클래스/메서드가 적절한 제약을 제공

순수 추상 클래스: 모든 메서드가 추상 메서드인 추상 클래스
이는 실행 로직이 전혀 없고 다형성을 위한 껍데기 역할만 한다.

인터페이스 멤버로 상수는 가질 수 있다. 즉 무조건 public static final이다. 이 제한자는 삭제 가능.

인터페이스는 다중 상속 가능. 왜나면 모두 추상 메서드로 이루어져 있어서 자식 인터페이스에서 오버라이딩하니까 어떤 메서드 기능을 호출할지 모호한 부분이 없다.
클래스는 다중 상속이 안된다. 죽음의 다이아몬드 문제같이 어떤 메서드를 호출해야 할지 모호해지는 부분이 있기 때문

인터페이스를 구현하는 클래스는 extends 대신 implements 사용. 부모의 기능을 물려받는 게 아니라 클래스에서 모든 메서드를 오버라이딩해서 다 구현해야 하기 때문. 설계도를 구현하는 거나 다름없으니 “구현”이라 한다. 다만 자바 입장에서 실제 메모리구조, 접근 등에서는 상속이나 구현이나 똑같다. 사람 입장에서 느낌이 다른 거지..

추상 클래스 vs 인터페이스
물론 순수 추상 클래스로도 인터페이스와 같은 기능을 할 수 있다. 하지만 이후 코드를 고치면서 추상 클래스에 구체적인 메서드를 끼워넣게 될 수도 있고 그런 가능성으로 인해 순수 추상 클래스가 깨질 수 있다. 인터페이스는 이런 걸 제약해준다. 모든 클래스가 추상 메서드가 강제됨.

그리고 단일 상속만 가능한 클래스와 달리 인터페이스는 다중 구현 가능
즉 인터페이스는 다형성을 위한 “순수 추상 클래스”를 위한 제약을 제공한다.

물론 java 8,9에서는 메서드를 구현할 수 있는 기능이 들어오고 그랬지만 이런 건 아주 특수한 경우에 사용하는 것이고 인터페이스에는 원래 메서드를 구현하는 게 아니다. 따라서 이런 부분은 지금 생각 안해도 됨.

인터페이스 타입에 클래스 인스턴스 타입 담기 -> 메서드 호출시 인터페이스 타입 가서 메서드 찾음. 하지만 당연히 오버라이딩된 게 있음. 따라서 오버라이딩된 메서드 호출!

클래스 상속과 인터페이스 구현 함께 사용도 가능
이때 상속은 하나만 할 수 있고 implements는 여러개 할 수 있으므로 둘이 함께 쓸땐 extends가 먼저 나와야 한다.

섹션 13 다형성과 설계

좋은 객체 지향 프로그래밍이란?
추상화, 캡슐화, 상속, 다형성
->프로그램을 명령어의 목록이 아니라 서로 메시지를 주고받으며 데이터를 처리하는 객체들의 모임으로 보는 게 oop
프로그램을 유연하고 변경 쉽게 만듬. 이 핵심이 다형성

세상과 객체가 완전 대응되는 건 아니지만 역할과 구현으로 생각해 볼 수 있음
예를 들어 운전자 - 자동차 관계가 있고 자동차의 구현은 여러 가지 있음(아반떼, 소나타..etc.)
자동차라는 인터페이스가 있다. 새로운 자동차가 나와도 이 인터페이스만 따른다면 운전자에게는 전혀 영향을 주지 않음
즉 세상의 상호 작용을 역할, 구현으로 나눠서 구현을 매번 갈아끼울 수 있게 하기. 클라이언트는 역할만 잘 하면 됨

클라이언트는 대상의 역할만 알면 되고 내부 구조는 몰라도 되고 내부 구조나 구체적인 구현이 변경되어도 상관 없다.

객체 설계시 역할(인터페이스)부여. 그 역할을 수행하는 구현 객체 만들기.

자바의 다형성
다형성으로 인터페이스를 구현한 객체를 런타임에 유연하게 사용 가능. 인터페이스 “역할” 만 맞추면 된다

객체의 협력 시, 클라이언트(요청하는 입장)의 코드를 변경하지 않고 서버(응답)의 기능 구현을 유연하게 변경할 수 있다

그러니 인터페이스를 안정적으로 잘 설계해야 한다..역할인 인터페이스가 변하면 모든 게 변해야 하므로.
다형성이 가장 중요하다. 제어의 역전과 di도 결국 다형성

다형성은 역할만 고정하면 구현을 다양하게 활용할 수 있는 것이다.

클라이언트는 서버의 구현은 모르도록 설계.. 다형성을 이용하면 java가 알아서 해준다.
인터페이스 타입에 접근 -> 어? 자식에 오버라이딩된 메서드가 있네? 오버라이딩된 게 우선권 있으니 그걸 사용

인터페이스를 사용해서 같은 역할을 하는 새로운 구현을 자유롭게 추가 가능. 그리고 클라이언트도 새롭게 추가된 차량(인터페이스를 준수)을 코드 변경 없이 사용 가능.

즉 OCP에서 코드 수정에 닫혀 있다는 건, 아예 수정이 없다기보다는 인터페이스를 사용하는 클라이언트(운전자-자동차라면 Driver)의 코드는 변경하지 않고 차의 기능을 추가할 수 있다는 것.

이런 걸 구현한 디자인 패턴이 전략 패턴(strategy) 구체적인 구현만 갈아낄 수 있도록 한거.

중요한 건 pay service 변화 없이 새로운 결제 수단을 추가할 수 있게 하는 거

다형성: 인터페이스의 구현을 실행 시점에 유연하게 변경 가능(strategy pattern)
스프링도 다 다형성을 기반으로 쌓아올리는 것이다. 다형성을 통해 편하게 개발할 수 있게 해준다.

-> 역할과 구현을 분리시켜서 클라이언트가 역할(인터페이스)에만 의존하도록 하라. 그래야 코드 확장해도 변경되는 코드 최소화됨

이후

언어 배우는 3단계

그럼 스프링이란?
백엔드에서 대부분 스프링 사용. 스프링은 객체지향 개념을 편리하게 사용하게 도와줌 + 알파(수많은 라이브러리, 베스트 프랙티스, 공통 기능 등)

스프링 학습 전에
자바 초중고급-> DB? -> 스프링

만약 급하다면 자바 예외처리, 자바 컬렉션(자바 중급편에 있음)을 보고 넘어가면 된다.
DB는 스프링 진행중에 필요하면 하면 된다..이런건 백엔드 놈들에게 물어보면 됨.

김영한에 대해서는 EO(간략한 인터뷰), 개발바닥 인터뷰 참고