Java, 객체 지향 관련 질문 모음입니다.
자세한 내용은 추가로 검색을 해보셔서, 본인의 언어로 정리하시길 추천드립니다.
이 글 역시 제 생각과 언어에 맞게 정리하였고, 틀린 부분이 있을 수 있으니 댓글로 지적해 주시면 감사하겠습니다!
[ 객체 지향 ]
💡OOP(객체지향 프로그래밍)의 특징
객체 지향의 특징은 크게 4가지가 있습니다.
⬇️객체지향의 4가지 특징
캡슐화
객체가 역할을 수행하기 위한 정보와 기능을 하나로 묶어서 데이터를 외부로부터 보호하는 것을 말합니다.
- 클라이언트에게는 인터페이스만 제공을 해서 필요한 정보만 노출을 하고, 실제 구현 정보는 숨겨서 기능만 사용할 수 있게 합니다.
- 필드는 private으로 접근을 막고, 메서드를 public으로 열어서 캡슐화를 사용합니다.
추상화
객체지향에서 모델링 방법을 말합니다. 실제 현실 객체에서 필요 없는 부분은 빼고, 필요한 부분만을 추출하여 사용합니다.
즉, 객체의 공통적인 속성과 기능을 추출하여 정의하는 것을 의미합니다.
- 추상 클래스와 인터페이스로 추상화를 구현할 수 있습니다.
- 어떤 객체의 행위를 추상 클래스 또는 인터페이스로 규정해 두고, 실제 구현은 구현체에서 하도록 프로그래밍을 설계할 수 있습니다.
상속
상위(부모) 클래스의 특성을 하위(자식) 클래스가 물려받는 것을 말합니다.
상속을 받은 자식 클래스는 부모 클래스와 계층적 관계를 갖게 됩니다.
상위 클래스에서 하위 클래스로 내려갈수록 구체화되는 것이 중요합니다.
- 부모 클래스의 메서드 또는 필드를 자식클래스에서 접근하여 사용할 수 있습니다.
다형성
하나의 메서드를 여러 가지 형태로 변화시킬 수 있는 것을 말합니다.
overriding과 overloading을 통해 구현합니다.
💡다형성을 구현하는 두가지 방법
⬇️overriding과 overloading
overriding
메서드의 틀(반환값, 매개변수)은 유지하되, 내부 구현을 재정의 하는 것을 말합니다.
- 부모 클래스를 상속받은 자식 클래스에서 부모 클래스의 메서드를 재정의 할 수 있습니다.
- 인터페이스를 implement 받은 구현체에서 인터페이스의 메서드를 재정의 할 수 있습니다.
(구현체는 인터페이스의 모든 메서드를 필수로 구현해야 합니다.)
overloding
같은 메서드 명으로 매개변수의 개수나 타입이 다르면, 같은 이름의 메서드를 재정의 할 수 있습니다.
반환타입과는 관계가 없습니다.
- 메서드 오버로딩, 생성자 오버로딩이 있습니다.
📁[JAVA] 생성자 / 오버로딩(overloading)
💡객체 지향 설계 5원칙
⬇️SOLID
SRP(Single Responsibility Principal) : 단일 책임 원칙
하나의 클래스는 하나의 기능만을 가져야 하고, 하나의 클래스를 변경해야 하는 이유는 하나뿐이어야 한다는 원칙입니다.
단일 책임 원칙을 지키면 객체 간의 결합이 느슨해지고,
잘 지키지 못하면 여러 클래스가 복잡하게 결합되어 변경이 일어날 때 고쳐야 하는 부분이 많아지게 됩니다.
- 변경에 의한 연쇄 작용 감소
- 가독성, 유지보수성 향상
OCP(Open Closed Principal) : 개방 폐쇄 원칙
확장에는 열려있고, 변경에는 닫혀 있어야 한다는 원칙입니다.
요구사항이 추가되어 기능을 확장할 때, 기존 구성요소는 수정하지 않고 쉽게 기능을 추가할 수 있도록 설계해야 합니다.
- 객체지향의 추상화와 다형성을 활용하면 개방폐쇄 원칙을 잘 지킬 수 있습니다.
LSP(Liskov Substitution Principal) : 리스코프 치환 원칙
서브 클래스를 항상 상위 클래스로 교체할 수 있어야 한다는 원칙입니다.
자식 클래스는 항상 부모클래스에서 가능한 행위를 항상 수행할 수 있어야 한다는 의미입니다.
- 인터페이스의 구현체가 여러 개 있을 때, 구현체를 갈아 끼워도 구현체를 사용하는 곳에서는 똑같이 동작해야 합니다.
- 클래스나 인터페이스의 상속을 이용해 확장성을 얻을 수 있고, 이 때문에 인터페이스를 만들어 사용하는 게 좋습니다.
ISP(Interface Segregation Principal) : 인터페이스 분리 원칙
사용하지 않는 메서드를 가진 인터페이스는 필요한 기능만을 담은 인터페이스로 분리해서 사용하라는 원칙입니다.
클라이언트에게 꼭 필요한 기능만을 가진 인터페이스를 제공해야 합니다.
특정 인터페이스가 1, 2, 3, 4의 기능이 있는데,
클라이언트 A는 1, 2의 기능을 사용하고, 클라이언트 B는 2, 3, 4의 기능을 사용한다면
A에게는 1, 2의 기능만을 담은 인터페이스를 제공하고,
B에게는 2, 3, 4의 기능만을 담은 인터페이스를 만들어서 제공하는 게 좋습니다.
DIP(Dependency Inversion Principal) : 의존 역전 원칙
하위 모듈이 변경될 때, 상위 모듈은 변경되지 않도록 설계해야 한다는 원칙입니다.
추상화(인터페이스)에 의존해야하고, 구체화(클래스)에 의존하면 안된다.
Spring에서는 DI를 이용하여 DIP를 잘 지키도록 합니다.
상위 모듈인 Controller에서 하위 모듈인 Service 인터페이스를 의존할 때,
하위 모듈인 Service의 구현체를 변경해도 상위 모듈인 Controller는 변경되지 않도록 합니다.
⬇️💡DIP와 DI는 같은 걸까요?
다릅니다. DI를 이용해서 DIP를 잘 지키도록 하는 것입니다.
DI는 Dependency Injection으로 의존성 주입이고, DIP는 의존성 역전 원칙입니다.
Controller에서는 @Bean으로 등록된 Service 구현체를 주입받아서 사용합니다.
📁[CS] SOLID : 객체지향 설계 5 원칙
💡클래스 vs 객체 vs 인스턴스의 차이?
⬇️Answer
- 클래스 : 객체를 만들기 위한 코드, 틀, 명세 같은 느낌
- 객체 : 클래스에서 선언된 모양 그대로 생성하면 객체
- 인스턴스 : 객체가 생성되어 메모리에 할당되면 그것이 인스턴스
💡인터페이스와 추상 클래스의 차이
⬇️공통점
- new 연산자로 인스턴스를 생성할 수 없다.
- 사용하기 위해서는 하위 클래스에서 확장/구현해야 한다.
⬇️interface와 abstract class
인터페이스(interface)
- 구현체들이 같은 동작을 한다는 걸 보장하기 위해 사용한다. -> 하위 클래스가 반드시 모든 메서드를 구현해야 한다.
- 다중 상속이 가능하고, 구현체들 간에 연관관계가 없을 수 있다.
- 구현 내용 변경이 용이하게 하도록 하기 위해 인터페이스를 사용한다.
추상 클래스(abstract class)
- 객체들의 공통된 개념을 묶어서 추상화시키고, 기능 확장을 위해 사용한다.
- 추상 클래스를 상속받는 객체들 간에는 연관관계가 있다.
📁[JAVA] 인터페이스(interface)
📁[JAVA] 추상 클래스 (abstract class)
💡좋은 객체 지향 프로그래밍이란?
⬇️Answer
"역할과 구현을 분리"
인터페이스를 안정적으로 잘 설계하는 것이 중요하다.
- 실세계의 역할과 구현 이라는 편리한 컨셉을 다형성을 통해 객체 세상으로 가져올 수 있음
- 유연하고, 변경이 용이
- 확장 가능한 설계
- 클라이언트에 영향을 주지 않는 변경 가능
[ Java ]
💡Java의 특징
⬇️Answer
- 객체지향 프로그래밍 언어
- 기본 자료형(Primitive type : 원시 자료형)을 제외한 모든 것들이 객체로 표현되어 있다.
- JVM(Java Virtual Machine) 위에서 동작하기 때문에, OS에 독립적이다.
- GC(Garbage Collector)를 통한 자동 메모리 관리가 되어 메모리를 직접 해제하지 않아도 된다.
- JVM 위에서 동작하기 때문에 실행 속도가 상대적으로 느린 편이다.
- 다중 상속이나 type에 엄격하다.
💡JVM(Java Virtual Machine)이란?
⬇️Answer
- Java와 OS 사이에서 Java Byte Code를 운영체제에 맞게 해석해 주는 역할을 합니다.
- JVM 덕분에 Java가 OS에 구애받지 않고 똑같이 동작할 수 있게 됩니다.
- Java의 Garbage Collection을 수행하는 것도 JVM입니다.
📁[Java / CS] JVM과 Java의 메모리 구조
💡Java의 컴파일 과정
⬇️Answer
- 개발자가 Java 코드 작성 (.java 파일 )
- build
- Java Compiler가 javac의 명령어를 통해 Java Byte Code를 생성
- Java Byte Code가 Class Loader를 통해 JVM으로 로드됨
- JVM이 운영체제에 맞게 기계어로 해석
💡Compiler / Interpreter / Java는???
⬇️Compiler와 Interpreter
두 가지 모두 고레벨의 언어를 컴퓨터가 이해할 수 있는 기계어로 변환하는 것을 말합니다.
- Compiler : 전체 소스코드를 보고 명령어를 수집하여 재구성한다.
- Interpreter : 소스코드의 각 행을 연속적으로 분석한다.
⬇️💡Java는???
Java는 컴파일 언어와 인터프리터 언어를 혼합한 형태의 하이브리드 언어입니다.
- Java Compiler는 Java 코드를 JVM이 실행시킬 수 있는 Java Byte Code로 변환됩니다.
- 이렇게 변환된 Java Byte Code는 JVM의 Java Interpreter를 이용하여 한 줄씩 실행됩니다.
즉, Java code는 Java Compiler를 통해 Java Byte Code로 변환되고,
Java Byte Code는 Java Interpreter를 통해 한 줄씩 실행되어 기계어로 변환됩니다.
💡Java의 접근 제어자
⬇️Answer
- public : 어디서나 사용할 수 있도록 열어두는 것
- protected : 같은 패키지 내에서만 사용할 수 있게 하는 것
- default : 접근 제어자가 없으면 default (상속이 불가하다.)
- private : 같은 클래스 내에서만 사용할 수 있게 하는 것
📁[JAVA] 접근 제어 지시자( private, protected, default, public) / 정보은닉, 캡슐화
💡Java의 원시 타입 (Primitive Type)
⬇️Answer
- boolean(1), byte(1), char(2), short(2), int(4), long(8), float(4), double(8)
- (1)은 1byte를 의미한다.
이외의 모든 것은 Reference Type(참조 타입) 모두 객체로 취급한다.
💡static 키워드
⬇️Answer
static 키워드는 여러 인스턴스가 공유하는 기준 값이 필요한 경우에 사용합니다.
- 인스턴스가 생성될 때 만들어지는 변수가 아니고, 프로그램이 처음으로 메모리에 올라갈 때 메모리를 할당받고 바로 사용할 수 있습니다.
- 객체 생성(인스턴스) 없이 사용합니다.
- 모든 객체가 메모리를 공유하고 GC 관리 영역 밖에 있기 때문에, 프로그램이 종료될 때까지 메모리 값이 유지된 채로 존재하게 됩니다.
💡final 키워드
⬇️Answer
변하지 않는 상수가 필요한 경우에 사용합니다.
- 변수명은 전부 대문자로 사용하는게 관례
- static final을 이용하여 지역변수의 상수로 사용할 수 있습니다.
static final double PI = 3.141592;
📁[JAVA] static과 final
💡String vs StringBuilder vs StringBuffer 차이점
⬇️Answer
String은 한번 메모리가 할당되면 불변이라는 특징이 있습니다.
StringBuilder와 StringBuffer는 내부적으로 가변적인 char [] 배열을 가져서 크기가 가득 차면 크기를 늘리면서 유연하게 동작합니다.
⬇️💡StringBuilder와 StringBuffer의 차이
두 가지는 비슷하지만, StringBuffer는 내부적으로 synchronized 키워드를 통해 동시 접근을 제어하여, 동기화를 지원한다는 차이가 있습니다.
따라서 StringBuffer는 멀티스레드 환경에서 사용하며,
StringBuilder는 싱글스레드 환경에서 사용합니다.
📁[JAVA] 문자열 다루기 String, StringBuilder, StringBuffer
💡Thread Safe? / Synchronized? / 동기화?
⬇️동기화란?
동기화란 여러 개의 스레드가 한 개의 자원을 동시에 사용하고자 할 때,
하나의 자원에 하나의 스레드만 접근할 수 있도록 하는 개념입니다.
- Thread Safe : Synchronized, 동기화를 지원한다. ex) ConcurrentHashMap
- Thread Safe 하지 않음 : Unsynchronized, 동기화를 지원하지 않음 ex) HashMap
💡CheckedException vs UnCheckedException
⬇️Answer
CheckedException
컴파일 시점에서 예측할 수 있는 예외를 말하고, 필수적으로 예외처리를 해야 합니다.
ex) IOException, ClassNotFoundException 등
UnCheckedException
실행 중에 발생할 수 있는 예외를 말하고, 따로 예외처리를 하지 않아도 됩니다.
RuntimeException을 상속받은 예외들이 UnCheckedException입니다.
ex) NullPointerException, ArrayIndexOutOfBoundException 등
💡Error vs Exception
⬇️Answer
- Error는 실행 중에 일어날 수 있는 치명적인 오류를 말합니다.
Error가 발생하면 프로그램이 비정상 종료되고, UnCheckedException에 속합니다. - Exception은 Error보다 경미한 오류이며, try-catch를 이용해 예외를 잡을 수 있습니다.
💡Java 8 변경 사항
⬇️Answer
함수형 프로그래밍이 도입되었습니다.
Lambda / Stream API / Optional / 날짜, 시간 API 등이 추가되었습니다.
- Lambda : 함수형 프로그래밍을 지원하기 위한 기능
- Stream : 고차 함수를 지원
- Optional : NullPointerException을 방지하는 기능
📁[Java] Optional 클래스
📁[JAVA] 람다식과 스트림 Stream()
💡Java에서 Null-Safety 방법
⬇️Answer
Optional을 이용하여 null을 방지할 수 있습니다.
상황에 따라 isPresent(), isEmpty() 등을 통해 null 여부를 확인하는 로직을 작성할 때도 있고,
orElseThrow를 통해 RuntimeException을 상속받은 CustomException을 만들어서 예외를 터트리는 방식으로 처리할 때도 있습니다.
💡JDK와 JRE?
⬇️Answer
JDK(Java Development Kit)는 개발자가 Java로 개발하는 데 사용하는 도구로, JRE를 포함하고 있습니다.
JRE(Java Runtime Environment)는 자바로 만들어진 프로그램을 실행시키는데 필요한 도구의 역할을 합니다.
운영 서버에는 개발에 필요한 도구가 아닌 프로그램을 실행시키는 도구만 필요하기 때문에 JDK가 아닌 JRE만 설치해도 됩니다.
'기타 > Tech Interview' 카테고리의 다른 글
백엔드 개발자 기술 면접 정리 - 운영체제(CS) (0) | 2024.03.19 |
---|---|
백엔드 개발자 면접 질문 모음 (답변 없음) (0) | 2024.03.19 |
백엔드 개발자 기술 면접 정리 - 기타 기술 스택 (0) | 2024.02.12 |
백엔드 개발자 기술 면접 정리 - 네트워크(Web, HTTP, Network) (0) | 2024.02.12 |
백엔드 개발자 기술 면접 정리 - Spring, JPA (1) | 2024.02.10 |