장점
단점
우리가 실생활에서 쓰는 모든 것을 객체라고 하는데, 객체 지향 프로그래밍은 프로그램 구현에 필요한 객체를 파악하고 상태와 행위를 가진 객체를 만들고 각각의 객체들의 역할이 무엇인지 정의하여 객체들 간의 상호작용을 통해 프로그램을 만드는 것을 말한다.
특징 - 캡슐화, 상속, 다형성, 추상화 등이 있으며 모듈 재사용으로 확장 및 유지보수가 용이하다.
연관있는 변수와 함수를 클래스로 묶는 작업이며 외부로부터 중요한 데이터를 보존, 보호하는 것 (은닉)
//가짜 캡슐화
public class Movie {
private Money fee;
public Money getFee() {
return this.fee;
}
public void setFee(Money fee) {
this.fee = fee;
}
}
// 진짜 캡슐화 참고
// https://steady-coding.tistory.com/449
객체의 관련 속성만 표시하고 불필요한 세부 정보는 숨기는 것
자료의 추상화 : 객체 지향 관점에서 클래스를 정의하는 것
추상 클래스 : 여러 클래스 간 비슷한 필드와 메소드를 공통적으로 추출해 만들어진 클래스
인터페이스 : 동일한 목적하에 동일한 기능을 수행하게끔 강제하는 것
부모 클래스의 변수, 메소드를 자식 클래스에서도 그대로 사용하는 것
상속은 언제 쓰나? 확장이 아닌 정제할 때 사용
public class Boy extends Student {
public Boy(String name) {
super(name);
}
public void run() {
System.out.println("[" + name + "] 뛰고 있습니다.");
}
}
public class Girl extends Student {
public Girl(String name) {
super(name);
}
public void walk() {
System.out.println("[" + name + "] 걷고 있습니다.");
}
}
부모-자식 상속 관계에 있는 클래스에서 상위 클래스가 동일한 메세지로 하위 클래스들을 서로 다르게 동작 시키는 것
다형성 구현 방법으로는 오버로딩, 오버라이딩, 함수형 인터페이스
오버로딩 : 요구사항이 변경되었을 때 모든 메소드 수정이 필요하므로 적절히 고려해 사용해야 한다.
오버라이딩 : 중복을 줄이기 위해
함수형 인터페이스 : 람다식과 관련, enum과 함께 사용하면 좋다.
public interface Movable {
void move();
}
public class Car implements Movable {
@Override
public void move() {
System.out.println("도로로 달립니다.");
}
}
public class Airplane implements Movable {
@Override
public void move() {
System.out.println("하늘을 납니다.");
}
}
public class Train implements Movable {
@Override
public void move() {
System.out.println("선로로 주행합니다.");
}
}
public class Main {
public static void main(String[] args) {
final List<Movable> movables = Arrays.asList(new Car(), new Train(), new Airplane());
for (final Movable movable : movables) {
movable.move();
}
}
}
SRP (단일 책임 원칙) : 한 클래스는 하나의 책임만 가져야 한다.
OCP (개방-폐쇄 원칙) : 확장에는 열려있고, 수정에는 닫혀있어야 한다.
LSP (리스코프 치환 원칙) : 상위 타입은 항상 하위 타입으로 대체할 수 있어야 한다.
ISP (인터페이스 분리 법칙) : 최소한의 기능만 제공하면서 하나의 역할에 집중하라는 의미, 단일 책임을 강조
DIP (의존관계 역전 원칙) : 구체적인 클래스보다 인터페이스, 추상클래스와 같이 변하지 않을 가능성이 높은 클래스와 관계를 맺어야 한다. DIP원칙을 따르는 가장 인기 있는 방법은 의존성 주입(DI)이다.
JVM은 스택 기반으로 동작하며, JAVA byte code를 OS에 맞게 해석해주는 역할을 하고 GC를 통해 자동적인 메모리 관리를 해준다.
method 영역
전역변수, static 변수 정보가 저장되는 공간이다. 프로그램의 시작부터 종료까지 메모리에 남아있다.
모든 스레드에서 정보가 공유된다.
Heap
new 연산자로 생성된 객체, 배열 등이 저장되는 공간이다. heap에 저장된 데이터는 GC가 처리하지 않는 한 소멸되지 않는다.
모든 스레드에서 정보가 공유된다.
Stack
지역변수, 메소드의 매개변수와 같이 잠시 사용되고 필요가 없어지는 데이터가 저장되는 공간이다. LIFO구조이며 변수에 새로운 데이터가 할당되면 이전 데이터는 지워진다.
스레드마다 하나씩 존재한다.
PC register
스레드가 생성되면서 생기는 공간으로 스레드가 어느 명령어를 처리하고 있는지 그 주소를 등록한다. JVM이 실행하고 있는 현재 위치를 저장하는 역할
Native method stack
java가 아닌 다른 언어 (c언어 등)로 구성된 메소드를 실행이 필요할 때 사용하는 공간
Method 영역 : JVM이 동작해서 클래스가 로딩될 때 생성
Stack 영역 : 컴파일 타임 시 할당
Heap 영역 : 런타임 시 할당
컴파일 타입 : 소스코드가 기계어로 변환되어 실행가능한 프로그램이 되는 과정
런타임 : 컴파일 타임 이후 프로그램이 실행되는 때
컴파일 결과로 만들어진 바이트 코드 파일을 읽어 메모리에 배치하는 역할
클래스 로더는 새로운 클래스를 로드해야 할 때, 다음과 같은 방식으로 로드를 수행한다.
1. JVM의 메소드 영역에 클래스가 로드되어 있는지 확인한다. 만약 로드외어 있는 경우 해당 클래스를 사용한다.
2. 메소드 영역에 클래스가 로드되어 있지 않을 경우, 시스템 클래스 로더에 클래스 로드를 요청한다.
3. 시스템 클래스 로더는 확장 클래스 로더에 요청을 위임한다.
4. 확장 클래스 로더는 부트스트랩 클래스 로더에 요청을 위임한다.
5. 부트스트랩 클래스 로더는 부트스트랩에 해당 클래스가 있는지 확인한다.
6. 확장 클래스 로더는 확장에 해당 클래스가 있는지 확인한다.
클래스가 존재하지 않을 경우 시스템 클래스 로더에게 요청을 넘긴다.
7. 시스템 클래스 로더는 시스템 Classpath에 해당 클래스가 있는지 확인한다. 클래스가 존재하지 않는 경우 ClassNotFoundException을 발생시킨다.
정수형 byte(1), short(2), int(4), long(8) 실수형 float(4), double(8), 문자형 char(2), 논리형 boolean(1)
오버라이딩(overriding) : 상위 클래스에 있는 메소드를 하위 클래스에서도 재정의하는 것
오버로딩(overloading) : 매개변수의 개수나 타입을 다르게 하여 같은 이름의 메소드를 여러 개 정의하는 것
객체 생성 이후 내부의 상태가 변하지 않는 객체를 말한다.
예로 final이 있으며
불변객체나 final을 사용하는 이유?
--> 메소드 호출 시 파라미터 값이 변하지 않는 보장이 있으며 GC가 스캔하는 객체의 수가 줄기 때문에 GC의 성능을 높일 수 있다.
JVM의 메모리 관리 기법 중 하나로 시스템에서 동적으로 할당됐던 메모리 영역 중에서 필요없어진 메모리 영역을 회수하여 메모리를 관리해주는 기법
JVM이 어플리케이션의 실행을 잠시 멈추고 GC를 실행하는 쓰레드를 제외한 모든 쓰레드들의 작업을 중단 후 사용하지 않는 메모리를 제거하고 작업이 재개
GC의 작업은 young영역에 대한 minor GC, major GC로 구분된다.
추상클래스는 클래스 내 추상 메소드가 하나 이상 포함되거나 abstract로 정의된 경우를 말하고, 인터페이스는 모든 메소드가 추상 메소드로만 이루어져 있는 것을 말한다.
공통점
차이점