인터뷰 스터디
1. StringBuffer와 StringBuilder의 차이 (1/22)
- StringBuffer와 StringBuilder는 mutation(가변성)이 존재하여 인스턴스 생성 후에도 문자열의 내용을 변경할 수 있습니다. 또한 append() 등의 함수를 이용할 수 있습니다.
- 하지만 StringBuilder는 동기화를 지원하지않아 멀티스레드 환경에서는 안전하지 않지만, 단일 스레드 환경에서는 이러한 동기화가 필요없기때문에 StringBuffer보다 빠릅니다.
- StringBuffers는 내부적으로 동기화를 지원하여 멀티스레드 환경에서 안전하게 사용될 수 있지만, 동기화로 인해 StringBuilder보다 성능이 떨어질 수 있습니다.
결국 StringBuffer는 스레드에 안전한 프로그램이 필요할때나, 개발중인 시스템의 부분이 스레드에 안전한지 모를 경우에 사용하면 좋습니다. StringBuilder는 스레드에 안전한지 여부가 전혀 관계없는 프로그램을 개발할 때 사용하면 좋습니다.
2. Java의 메모리 영역 (1/24)
JVM = Java Virtual Machine(자바 가상 머신)의 Runtime data area(런타임 데이터 영역) 메모리 영역은 메서드, 힙, 스택, pc 레지스터, 네이티브 영역으로 구분됩니다.
메서드(클래스, Static) : 클래스가 로딩될 때 생성되며, 클래스, 생성자, 메서드 정보, static 변수(클래스 변수), Constant Pool을 저장합니다. 프로그램이 종료되기 전까지 메모리 상에 존재한다.
힙 : 런타임시 할당되며, 주로 new 키워드로 할당되는 객체가 저장됩니다. GC(가비지 컬렉터)를 통해 정리됩니다.
스택: 컴파일 시 할당되며, 메서드 호출시 개별적으로 스택이 생성되며, 종료시 해제됩니다. 기본 자료형, 지역 변수, 매개변수가 저장됩니다. heap 영역에 생성되는 객체의 주소값을 가집니다. 스레드 별로 자신만의 stack을 가집니다.
pc 레지스터 : 스레드가 생성될 때마다 생성되는 영역으로 다음 명령어의 주소를 알고 있습니다.
네이티브 : 자바 외 언어로 작성된 코드를 위한 영역입니다.
- 힙과 스택은 같은 메모리 공간을 동적으로 공유하며, 과도하게 사용하는 경우 OOM(메모리 부족)이 발생할 수 있습니다.
- new 키워드로 인스턴스를 생성할 때, heap 영역에는 생성된 객체가 저장, stack 영역에서는 생성된 객체의 주소값이 저장됩니다.
3. 오버로딩과 오버라이딩 차이 (1/26)
- 오버로딩 : 새로운 메서드 추가
- 반환타입 관계없이, 메서드 명은 같지만 매개 변수는 달라야합니다. (접근제어자도 상관X) 생성자가 여러개 필요한 경우 유용합니다.
- 오버라이딩 : 상속받은 메서드 재정의
- 반환타입, 메서드명, 매개 변수가 모두 같아야합니다. 부모 클래스로부터 상속받은 메서드를 재정의합니다.
- 결합도를 낮출 수 있는 interface 사용시 오버라이딩이 적극적으로 사용됩니다.
- 오버라이딩 주의사항
- 자식 클래스에서 오버라이딩하는 메서드의 접근제어자는 부모 클래스보다 더 좁게 설정할 수 없습니다.
- 자식 클래스에서 예외는 부모 클래스보다 더 큰 범위의 예외를 던질 수 없습니다.
- 부모 클래스의 static 메서드를 인스턴스로, 또는 그 반대 모두 불가능합니다.
4. 추상 클래스와 인터페이스 차이 (1/29)
공통점 1) new를 이용한 인스턴스 생성이 불가능합니다. 2) 메소드에 대한 상세 구현이 필요합니다.
추상클래스 1) 추상클래스는 하위 클래스들의 공통점을 모아 추상화한것이며, 클래스간의 연간 관계를 구축하는것에 중점을 둡니다 2) 추상클래스는 extends 키워드를 사용하며 다중 상속이 불가능합니다. 3) 또한 하나 이상의 abstract 메소드가 존재해야합니다. 4) 자식 클래스에서 abstract 메소드에 대한 구현이 필수 입니다.
인터페이스 1) 인터페이스는 구현 객체가 같은 동작을 한다는것을 보장하기 위해 사용하는 것에 초점을 둡니다 2) 인터페이스는 implements 키워드를 사용하며 다중 상속이 불가능합니다 3) 변수를 가질수 없고, static final과 같은 상수만 가능합니다. 4) 모든 메소드는 선언부만 존재합니다 5) 구현 클래스는 인터페이스에 선언된 모든 메소드에 대한 overriding이 필수 입니다.
5. 제네릭이란 (1/31)
Generic = 데이터 타입을 일반화한다.
- 제네릭이란 클래스(내부)에서 사용할 타입을 클래스 외부에서 설정하도록 만드는 것이다. (컴파일 시에 미리 지정한다.)
- 제네릭으로 선언한 클래스는 내가 원하는 타입으로 만들어 사용할 수 있다.
- <>안에는 참조자료형(클래스, 인터페이스, 배열)만 가능하다. 기본 자료형을 이용하기 위해서는 wrapper 클래스를 활용해야한다.
- 비슷한 기능을 지원하는 경우 코드의 재사용성이 높아진다.
- Generic Type의 암묵적인 규칙이 있다.
- <T> : Type
- <E> : Element
- <K> : Key
- <V>: Value
- <N> : Number
6. 접근제어자란 (2/2)
객체지향에서는 정보 은닉이라 하여 사용자가 굳이 알 필요가 없는 정보는 사용자로부터 숨겨야한다는 개념이 있습니다. 이러한 정보 은닉을 위해 접근 제어자를 아래와 같이 제공합니다.
A패키지와 B패키지가 있다고 가정하겠습니다.
- 1) private : A패키지 내의 한 클래스 내부끼리만 접근 가능합니다.
- 2) default : 기본제한자이며, A 패키지 내의 모든 클래스들이라면 접근 가능합니다
- 3) protected : B 패키지에 있는 클래스지만. A 패키지에 있는 클래스로부터의 자식이라면, 해당 자식은 A 패키지의 부모한테는 접근 가능합니다.
- 4) public : A 패키지와 B 패키지 내의 클래스들 끼리 접근이 모두 허용됩니다.
7. Java 컴파일 과정 (2/5)
자바 컴파일 과정은 크게 컴파일 -> 클래스로더 -> 실행엔진에서의 작동으로 나뉩니다.
먼저, “.java” 파일을 자바컴파일러가 읽어서 “.class”라는 바이트코드로 변환 합니다.
컴파일된 바이트 코드는 JVM의 클래스로더에게 전달되고, 클래스로더는 동적로딩 통해 필요한 클래스들을 링킹 및 로드하여, JVM의 메모리(Runtime Data Area)에 올립니다.
JVM의 실행엔진은 JVM의 메모리에 있는 바이트코드들을 인터프리터나 JIT 컴파일러 등을 사용하여 실행합니다.