Interview Questions 2
자바 관련 질문 리스트 정리
Java의 특징?
Java는 대표적인 OOP 기반의 프로그래밍 언어, 모든 요소를 객체 형태로 표현하며, 메소드 호출을 통해 객체에 대한 연산을 수행할 수 있다.
Java 특징으로 아래와 같은 점을 가진다.
-
Cross Platform: Java는 JVM위에서 동작하기 때문에 어떠한 운영체제 위에서도 동작한다.
-
Garbage Collector을 통해 메모리 해제가 자동으로 이루어진다.
Java 파일 실행 과정(컴파일 과정)
Java라는 언어 자체는 특이하게 Compiler 와 Interpreter의 성격을 동시에 가지는 하이브리드 언어입니다. Java 소스코드에 대해서 compiler에 의해 byte code로 변홛외어 Execute Engine(JVM)에서 이를 순차적으로 실행하게 됩니다. 이때, 단순 순차적으로 실행하게 되면 Interpreter 처럼 오래 걸린다는 문제가 있기 때문에 자주 사용하는 코드에 대해서는 JIT compiler가 compile을 하여 성능의 향상을 도모한다.
Java source파일은 Java compiler에 의해 바이트 코드 형태인 .class 파일로 변환된다.
이후, JVM을 통해 바이트 코드가 실행된다.
JVM
- Class Loader: 바이트코드에서 사용하는 클래스를 로드한다.
- Execute Engine: 실제 바이트코드를 실행하는 영역으로, 내부적으로 Garbage Collector가 동작한다.
- 인터프리터, JIT
- Run Data Access: OS에 의해 할당된 메모리 공간으로 JVM이 동작할 때 필요한 정보를 저장한다.
- Stack: 각각의 쓰레드에서 사용하는 지역변수, 파라미터 등을 저장하기 위한 공간
- Heap: 동적인 메모리인 객체, 배열, 등을 저장하기 위한 공간
- Method Area: 클래스 변수, 메소드 정보, 상수와 같은 정보를 포한한다.
- PC: 각각의 실행을 관리하기 위한 Program Counter 정보
GC의 과정
JVM의 execute engine에 있는 garbage collector은 더 이상 참조되지 않는 객체에 대한 메모리 해제 작업을 진행한다.
Garbage Collector은 Minor GC, Major GC로 동작하게 되는데, 우선 Minor GC의 과정을 살펴보면 객체가 생성되면 우선 eden 영역에 들어가게 된다. eden 영역이 가득차게 되면 참조가 남아 있는 메모리 영역은 marking하고, 이를 survivor로 넘겨준다. survivor 영역에 대해서도 가득차면 위와 동일 방식으로 다른 survivor로 복사를 수행한다.
이와 같은 과정을 반복해서 끝까지 survivor 영역에 남아있으면 이를 old 영역으로 이동한다. Major GC는 old 영역에서 이루어진다. 참조가 더이상 이루어지지 않는 객체를 marking하고 이를 삭제한다. 이후, compact 과정을 통해 메모리 영역을 한곳으로 모아주어 외부 단편화를 방지한다.
Collection Framework
Queue, Set, Map과 같은 자료구조를 효율적으로 구현해놓은 프레임워크로, Generic으로 구현되어 다양한 타입 기반의 컬렉션 구성을 지원한다.
제네릭
범용적인 타입 설계를 통해 자료형에 의존하지 않는 클래스 설계가 가능하여 번거로운 타입 변환 과정을 제거해주며, 컴파일 단위 타입 체크를 통해 타입 안정성을 제공해준다.
Annotation?
interface 기반의 문법으로 주석처럼 클래스, 메소드에 메타데이터를 추가하기 위해 사용되는 문법이다. annotation 표기를 통해 특별 의미를 부여하건, 기능을 주입할 수 있다. 대표적으로 @SuppressWarnings, @Override,등이 있고, Spring에서는 이러한 Annotation을 활용해서 AOP를 수행한다.
오버로딩과 오버라이딩의 차이
오버로딩은 메소드 이름이 같지만 매개변수의 종류, 수를 달리하여 행위를 여러 방식으로 다양화 한것을 의미하며, 오버라이딩은 상위 클래스에서 정의한 메소드를 하위클래스에서 새롭게 재정의하는 방식이다.
오버로딩은 컴파일 타임 다형성을 지원하며, 오버라이딩은 런타임 다형성을 지원한다.
인터페이스와 추상클래스
인터페이스와 추상클래스는 기능에 대한 추상화를 제공한다는 점에서 공통점을 가지지만,
용도의 차이가 존재한다. 인터페이스는 주어진 기능들을 구현한다는 초점에 맞춘 반면 추상 클래스는 상속을 통해 상위 클래스의 기능을 확장한다는 차이점이 있다.
인터페이스는 구현 객체에 대해 모두 동일한 기능을 제공해야한다는 강제성을 띄고, 추상클래스의 경우 상속 기반의 공통 개념을 묶고자 할떄 사용된다.
추상 클래스는 상태, 행위를 가지기 때문에 다중 상속이 안되지만, 기능만을 가지는 인터페이스는 다중상속이 가능하다.
클래스와 객체의 차이
클래스는 흔히 설계도로 객체를 생성하는 방식을 정의한 틀이다. 객체는 클래스 기반으로 생성되어 식별자, 상태를 가진다. 또한 객체가 생성되면 객체에 메모리가 할당되어 인스턴스가 된다.
static
클래스 멤버 변수로 설정된 static 변수는 클래스가 memory method으로 로딩될때, 같이 로딩된다. GC의 대상이 되지 않고 어플리케이션 실행 과정에서 끝까지 남기 때문에 성능에 문제가 발생할 수 있다.
어플리케이션 전반에 걸쳐 공유되는 정보 저장을 위해 활용된다.
Java의 원시타입 종류
|Type|Byte| |–|–| |boolean|1| |char|2| |byte|1| |short|2| |int |4| |long|8| |float|4| |double|8|
원시 타입과 참조 타입
자바에서 제공하는 원시 타입으로는 boolean, char, short, byte, int, long, float, double가 있으며 참조 타입은 클래스 기반의 객체 타입이다.
원시타입은 참조타입과 달리 항상 값을 가지고 있어야한다는 점이 있다.
접근 제어자의 종류
java는 특정 클래스, 메소드에 대한 접근 수준을 명시하기 위해, private, public, default, protected을 제공합니다. private는 오직 클래스 내부에서만 접근이 가능함을 명시한다 default는 같은 패키지 내부에서 접근이 가능하다. protected는 상속 받은 클래스 내부에서 접근이 가능하다 public은 모든 곳에 접근할 수 있다.
OOP
객체 지향은 모든 것을 객체 형태로 표현하고 메세지를 이용해서 이들간에 데이터를 주고 받는 프로그래밍 방식을 의미합니다.
OOP의 특징으로 추상화, 상속, 다형성, 캡슐화가 있습니다.
추상화는 객체의 공통적인 속성, 기능을 추출하여 정의하는 것을 말하는데, 추상화 방식으로 추상 클래스, 인터페이스가 존재한다.
캡슐화는 관련 정보를 내부에 결합해서 불필요한 정보의 노출을 최소화하기 위해 사용된다.
상속은 기존에 생성한 클래스를 재사용하여 상위 클래스가 가지는 기능을 활용할 수 있고, 이에 추가로 확장하여 사용하는 것이 가능하다. 상속을 통해 코드 중복을 최소화 하고 상위 클래스를 활용하여 같은 상태를 가지는 클래스를 묶을 수 있다.
다형성은 하나의 메소드에 대해 서로 다른 방식으로 동작하도록 지원한다. 오버라이딩과 오버로딩을 통해 다형성이 동작한다.
SOLID
좋은 객체 지향설계를 위해 지켜야하는 5가지 원칙을 SOLID라고 한다.
- SRP: 단일 책임의 원칙으로, 변경의 여지를 한곳으로 통일한다는 원칙이다.
- OCP: 개방 폐쇄의 원칙으로, 수정에는 닫혀있고, 확장에는 열려 있어야한다는 원칙이다.
- LSP: 리스코프 치환의 원칙으로, 하위 클래스는 상위 클래스와 동일한 방식으로 동작해야함을 의미한다.
- ISP: 인터페이스 분리의 원칙으로, 인터페이스는 최대한 단순한 구조로 설계해야하며, 구현되지 않는 기능은 제거해야한다.
- DIP: 의존성 역전의 원칙으로, 항상 추상화에 의존한 설계를 진행해야한다는 점이다.
동일성과 동등성
동일성은 인스턴스가 완전히 일치한다는 의미로 서로 같은 객체임을 의미한다. 동등성의 경우 같은 값을 객체간에 성립하는 내용이다. Object.equals()는 기본적으로 동일성의 원칙으로 동작하기 때문에 동등값 비교를 위해서는 개발자가 이를 오버라이딩 해야한다.
String, StringBuilder, StringBuffer
3가지 방식 모두 문자열을 만드는 것과 관련있는 객체라는 공통점을 가진다. String은 immutable 인스턴스를 만든다는 특징이 있습니다. StringBuilder는 가변적인 문자열이 구성이 가능하다는 특징이 있으며, StringBuffer은 MultiThread 환경에서 동시성 문제를 고려한 문자열 생성이 가능하다.
Checked Exception vs UncheckedException
자바에서 발생되는 에러는 크게 checked exception과 unchecked exception와 같이 크게 2가지로 분류되는데, checked exception의 경우 반드시 처리되어야하는 에러이다. checked exception을 처리(catch, throws)을 하지 않으면 컴파일 오류가 발생한다.
checkedexception은 exception 클래스와 그의 자식 클래스 타입(RuntimeException 제외)에서 발생하는 에러타입이다. 예외 처리 과정을 강제 하기 때문에 누락된 에러가 발생하지 않는다. 대표적으로, SQLException, IOException
uncheckedexception은 exception 클래스의 자식 클래스인 RuntimeException을 상속하는 클래스에 대해서 발생되는 에러타입이다. 대표적으로, NullPointerException, ClassCastException
try-with-resource
try-with-resource 방식을 통해 Auto-Closable를 구현하고 있는 자원에 대해 자동으로 try 구문 이후에 자원을 해제하기 위해 사용된다.
강한 결합 vs 약한 결합
객체 내부에서 다른 객체에 대해 직접 생성을 수행하게 되면, 특정 구현체에 의존하게 되는데, 이를 강한 결합이라고 한다. 약한 결합의 경우, 외부에서 구현 클래스를 주입해줘, 특정 구현 클래스에 의존적이지 않는 설계가 가능하다. 이러한 약한 결합을 기반으로 동작하는 것이 DI이다.
DIP와 관련된 내용이네..
직렬화?
자바에서 활용되는 객체를 외부 시스템에서도 사용할 수 있게 하기 위해 Byte 형태로 변화는 기술을 의미하며, 역직렬화 역의 과정을 의미한다.
자바의 동시성 문제
자바의 경우, 멀티 쓰레드 환경에서 Heap, Method Area를 서로 공유하면서 각자의 실행흐름을 가지기 때문에, 공유되는 변수에 대한 동시 접근 문제가 발생할 수 있다. 이를 처리하기 위해 synchronized 블록과 같이 critical section을 설정하여 해당 블록내에 하나의 thread만 동작하도록 지정할 수 있다.
Vector vs ArrayList
두 컬렉션 프레임워크 모두 List<E>
을 상속하는 클래스로, 서로 동일한 기능을 제공한다.
vector는 arraylist와 달리 내부적으로 동기화가 이루어져있어, Thread-safe한 특징을 가진다. 그렇지만 ArrayList의 경우 동기화가 이루어져지 않아 그 만큼 성능이 더 좋다.
그래서, Multi-Thread 기반이냐, 아니냐에 따라 둘의 사용여부가 결정된다.
댓글남기기