인터뷰 질문 대비
Updated:
인터뷰
1. 접근제어자
- public
- 어떤 클래스에서라도 접근이 가능하다.
- protected
- 클래스가 정의되어 있는 해당 패키지 내 그리고 해당 클래스를 상속받은 외부 패키지의 클래스에서 접근이 가능하다.
- default
- 클래스가 정의되어 있는 해당 패키지 내에서만 접근이 가능하도록 접근 범위를 제한한다.
- private
- 정의된 해당 클래스에서만 접근이 가능하도록 접근 범위를 제한한다.
2. 오버로딩 vs 오버라이딩
- 오버로딩
- 상위 클래스의 메서드와 이름, return 값은 동일하지만, 매개변수만 다른 메서드를 만드는 것을 의미.
- 오버라이딩
- 상속받은 상위클래스의 메서드를 필요에 맞게 재정의하는 것을 의미
3. 인터페이스와 추상 클래스의 차이
- 공통
- 선언만 있고 구현 내용이 없는 클래스
- 새로운 인스턴스(객체)를 생성할 수 없다.
- 차이
- 키워드는 목적
- 추상 클래스는 추상 메서드를 자식 클래스가 구체화하여 그 기능을 확장하는데 목적이 있다.
-
인터페이스는 서로 관련이 없는 클래스에서 공통적으로 사용하는 기능을 구현할 필요가 있는 경우
- 추상 클래스는 클래스이지만 인터페이스는 클래스가 아니다.
- 추상 클래스는 단일 상속이지만 인터페이스는 다중 상속이 가능하다.
- 예를 들어서 포유류는 젖을 먹이는 동물이라고 한다.
- 이때 사자, 사람, 기린은 젖을 먹이는 포유류일때 포유류라는 클래스를 만들면 추상클래스이다.
- 그러나 젖을 먹인다라는 행위(동작)을 추상메서드로 만들어 해당 객체들이 각자 구현할 수 있게 한다.
- 인터페이스라 함은 추상 메서드를 정의하고 인터페이스를 구현하는 클래스에서 추상 메서드를 구현하는 것이었다.
- 인터페이스를 사용하는 것은 확장성, 다형성을 위해서 사용
4. 데이터 타입
-
기본 타입 : 정수, 실수, 논리, 문자
- 크기가 작고 고정적이라 stack 영역
-
참조 타입 : class, array, interface, String
- 크기가 유동적이라 heap
- String은 참조타입이다.
- 선언 위치에 따른 분류
- 멤버변수와 지역변수로 분류
- 멤버변수는 클래스 영역에 선언. 여기서 다시 인스턴스변수와 클래스 변수로 분류
- 인스턴스 변수 : 클래스 영역에 선언. 각 변수마다 다른 값을 가짐.
- 클래스 변수 : 인스턴스 변수 앞에 static을 붙이기만 하면 됨. 인스턴스와 반대로 값을 공유.
-
지역변수는 메소드 내에 선언
- 메소드가 종료되면 사라짐. 반대로 멤버변수는 사라지지 않음.
- 매개변수 : 흔히 파라미터라고 불림. 메소드에서 입력값을 받을 때 사용하는 변수. 메소드 내에서 선언되므로 지역변수라고 간주.
5. OOP 4가지 특징
- 객체지향
- 관심사가 같은 기능과 데이터를 모아서 재사용이 가능한 객체로 캡슐화 하는 것을 의미함.
- 추상화
- 구체적인 사물들의 공통적인 특징을 파악해서 이를 하나의 개념으로 다루는 것
- 캡슐화
- 정보은닉 : 외부에서 접근하지 못하도록 제한
- 높은 응집도와 낮은 결합도를 유지.
- 상속
- 부모 클래스의 속성이나 기능을 재사용하고 확장
- 외부세계에 자식 클래스 자체를 캡슐화하는 것으로 확장
- 다형성
- 서로 다른 클래스의 객체가 같은 메시지를 받았을 때 각자의 방식으로 동작하는 능력
- 상속이랑 연계되어 동작
- 오버로딩, 오버라이딩을 말함
6. OOP의 5대 원칙
“SOLID” 원칙
-
S : 단일 책임 원칙(SRP, Single Responsibility Principle)
- 객체는 단 하나의 책임만 가져야 한다.
-
O : 개방-폐쇄 원칙(OCP, Open Closed Principle)
- 기존의 코드를 변경하지 않으면서 기능을 추가할 수 있도록 설계가 되어야 한다.
-
L : 리스코프 치환 원칙(LSP, Liskov Substitution Principle)
- 자식 클래스는 최소한 자신의 부모 클래스에서 가능한 행위는 수행할 수 있어야 한다.
-
I : 인터페이스 분리 원칙(ISP, Interface Segregation Principle)
- 인터페이스를 클라이언트에 특화되도록 분리시키라는 설계 원칙이다.
-
D : 의존 역전 원칙(DIP, Dependency Inversion Principle)
- 의존 관계를 맺을 때 변화하기 어려운 것, 거의 변화가 없는 것에 의존하라는 것이다.
7. main 메서드가 static인 이유
- 클래스 로딩 시 JVM에게 할당된 런타임 데이터 영역의 메서드 영역에 static 맴버를 저장
static
멤버는 인스턴스를 생성하지 않아도 호출이 가능하다- JVM은 인스턴스 필요가 없는 클래스의
main()
을 호출해야하기 때문에static
이어야 한다.
8. JDK, JRE, JVM
- Java를 실행시키기 위해선 JVM, JRE, JDK 세 가지가 모두 필요하다.
-
JDK > JRE > JVM
- JDK
- 개발도구
- JRE와 개발용 라이브러리를 포함
-
일반적으로 JDK를 설치하면 다 포함.
- JRE
- JVM용 운영체제(소프트웨어 역할)
- JVM이 자바 프로그램을 실행하기 위해 필요한 라이브러리와 파일을 가지고 있다.
- JRE만 있어도 프로그램을 구동시킬수는 있다.
- JVM
- 자바 가상 머신(하드웨어 역할)
- 파일명.java 들을 컴파일한 파일명.class 들을 실행
- 플랫폼에 의존적(window, mac, linux etc)
9. JVM 동작 방식
- 프로그램 실행되면 컴파일러가 .java 파일을 class 파일로 변환시킨다.
- 클래스 로더가
.class
파일을 메모리 영역(Runtime Data Area)에 로드한다.
9.1 구성
- 런타임 데이터 area
- 런타임 데이터 영역은 JVM이 실행될 때 할당 받는 메모리 영역
-
Method Area (메소드, 클래스, 스태틱 영역)
-
JVM이 읽어드린 클래스, 인터페이스에 대한 런타임 constant pool. static 메소드, 변수 저장
-
상수풀은 클래스와 같은 Heap의 Permanent area(고정 영역)에 생성되어 Java 프로세스의 종료까지 그 생을 함께 합니다.
String을 new로 생성하지 않고 “” 리터럴을 사용하여 생성할경우, 내부적으로 new String() 메소드 호출 이후에String.intern()이라는 메소드가 호출되어 고유의 인스턴스를 공유하도록 interned됩니다. 이것은 생성한 String을 Constant pool에 등록하는(만약 이전에 같은 char sequence의 문자열이 이미 상수풀에 있다면 문자열을 힙에서 해제하고 그 상수풀의 레퍼런스를 반환) 작업을 수행하지요. 즉, 같은 패키지의 같은 클래스 내에서는 정수(literal) 스트링들은 동일한 String 객체를 참조한다.
-
-
Heap area
- 인스턴스 객체 저장 공간
- stack area
- 스레드가 시작될때마다 생성
- 메소드 정보, 지역변수, 매개변수, 연산 중 발생하는 임시 데이터 저장
-
program counter registers (PC 레지스터)
- 현재 수행 중인 JVM 명령 주소를 갖는다.
-
native 메서드 stack
- 자바 외 언어로 작성된 네이티브 메서드 정보를 저장
-
샐행 엔진 : 런타임 데이터 영역에 할당 된 바이트 코드를 실행
- 인터프리터
- 바이트 코드 해석, 하나의 메소드가 여러번 호출되면 매번 새로 해석하여 느리게 실행
- JIT
- 인터프리터 단점을 해소. 전체 바이트 코드를 컴파일하고 원시코드로 변경
- 가비지 컬렉터
- 애플리케이션이 생성한 객체의 생존 여부를 판단하여 더 이상 사용되지 않는 객체를 해제하는 방식으로 메모리를 자동 관리한다.
- Heap Area 영역의 메모리 관리
- 인터프리터
-
Java Native interface
- 자바코드가 다른 언어들로 작성된 라이브러리들을 호출하거나 반대로 호출되는 것을 가능하게 하는 프레임워크
-
Native 메서드 라이브러리
- 실행 엔진에 필요한 원시 라이브러리
10. final
- 변수나 메서드 또는 클래스가 ‘변경 불가능’하도록 만든다.
- 원시(Primitive) 변수에 적용 시
- 변수 값 변경 불가능
- 참조(Reference) 변수에 적용 시
- heap 내 다른 객체를 가리키도록 변경할 수 없다.
- 메서드에 적용 시
- 해당 메서드를 오버라이드할 수 없다.
- 클래스에 적용 시
- 해당 클래스의 하위 클래스를 정의할 수 없다.
- finally, finalize는 다른 것
- finalize : 메소드이다. GC에 의해 호출되는 함수.
11. 자바 직렬화와 역직렬화
- 자바 직렬화(Serialization)란
- 자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트형태로 데이터 변환
- 시스템적으로 이야기하자면 JVM의 메모리에 상주(힙 또는 스택)되어 있는 객체 데이터를 바이트 형태로 변환하는 기술
- 역직렬화
- 바이트를 객체로 변환 (직렬화 반대)
12. 클래스, 객체, 인스턴스
- 클래스
- 구현할 대상을 만들기 위한 설계도
- 연관되어 있는 변수와 메서드의 집합
- 객체
- 구현할 대상
- 인스턴스
- 구현된 실체
- 객체는 현실세계에 가깝고 인스턴스는 소프트웨어 세계에 가깝다.
- 사람이라는 객체는 실제 없으나 소프트웨어로는 구현 가능
13. Java Collections Framework
-
Collection
- Set : 순서의 의미가 없다. 중복 없음
- SortedSet : TreeSet : 요소들의 정렬 방법을 직접 지정할 수 있다.
- LinkedHashSet : 요소가 추가된 순서대로 접근할 수 있다.
- HashSet : 빠른 접근 속도를 가지고 있으나 순서를 예측할 수 없다. 해시 알고리즘
- List : 순서가 있는 Collection. 중복 있음
- LinkedList: 순서가 변경되는 경우 노드 링크만 변경하면 되므로 삽입, 삭제가 빈번할 때 빠르다.
- arraylist : 상대적으로 빠르고 요소에 대해 순차적으로 접근할 수 있다
- Set : 순서의 의미가 없다. 중복 없음
-
Map : 검색할 수 있는 인터페이스. Key와 Value의 형태
-
HashTable : HashMap 보다는 느리지만 동기화를 지원하며 null 값을 허용하지 않는다.
- LinkedHashMap : HashMap과 기본적으로 동일. 입력한 순서대로 접근이 가능하다.
- HashMap : 중복을 허용하지 않고 순서를 보장하지 않으며 null 값을 허용한다.
- SortedMap
- TreeMap : 정렬된 순서대로 Key와 Value를 저장하므로 빠른 검색이 가능하지만 요소를 추가할 때 정렬로 인해 오래걸린다. 레드-블랙 트리(Red-Black tree)로 구현
-
14. String StringBuilder StringBuffer
- String
- 새로운 값을 할당할 때마다 새로 클래스에 대한 객체가 생성된다.
- String + String ..
- 각각의 String 주소값이 Stack에 쌓이고, Garbage Collector가 호출되기 전까지 생성된 String 객체들은 Heap에 쌓이기 때문에 메모리 관리에 치명적이다.
- StringBuilder, StringBuffer
- memory에 append하는 방식으로, 클래스에 대한 객체를 직접 생성하지 않는다.
- 변경 가능한 문자열
- StringBuilder
- 비동기 처리
- StringBuffer
- 동기 처리
- multiple thread 환경에서 안전한 클래스(thread safe)
- 그니까 JVM에서 heap영역, 메소드 영역 같이 스레드들이 공유하여 발생하는 문제를 방지한다는 이야기
- JDK 1.5 버전 이후에는 컴파일 단계에서 String 객체를 StringBuilder로 컴파일 되도록 변경됨
- 그래서 JDK 1.5 이후 버전에서는 String 클래스를 사용해도 StringBuilder와 성능 차이가 없어짐
- 하지만 반복 루프를 사용해서 문자열을 더할 때에는 객체를 계속 새로운 메모리에 할당함
- String 클래스를 사용하는 것 보다는 스레드와 관련이 있으면 StringBuffer, 스레드 안전 여부와 상관이 없으면 StringBuilder를 사용하는 것을 권장
15. String에서 == , eqauls
- == 연산자 : 참조 비교. 메모리 주소를 비교
- equals 메서드: 객체 비교. 안에 내용을 비교
16. java의 리플렉션 이란
- 리플렉션(Reflection) 이란?
- 구제적인 클래스 타입을 몰라도 그 클래스를 동적으로 로딩하여 생성자, 멤버 필드, 멤버 메서드 등을 사용할 수 있는 기법
- 컴파일 시간(Compile Time)이 아니라 실행 시간(Run Time)에 동적으로 특정 클래스의 정보를 객체화를 통해 분석 및 추출해낼 수 있는 프로그래밍 기법이다.
- 사용 방법
Class.forName("클래스이름")
- 클래스의 이름으로부터 인스턴스를 생성할 수 있고, 이를 이용하여 클래스의 정보를 가져올 수 있다.
- 왜 사용할까?
- 실행 시간에 다른 클래스를 동적으로 로딩하여 접근할 때
- 클래스와 멤버 필드 그리고 메서드 등에 관한 정보를 얻어야할 때
- 리플렉션 없이도 완성도 높은 코드를 구현할 수 있지만 사용한다면 조금 더 유연한 코드를 만들 수 있다.
- 주의할 점
- 외부에 공개되지 않는 private 멤버도
Field.setAccessible()
메서드를 true로 지정하면 접근과 조작이 가능하기 때문에 주의해야 한다.
- 외부에 공개되지 않는 private 멤버도
17. Generic
-
데이터 타입을 일반화하기 위해서 사용
-
클래스나 메서드에서 사용할 때 데이터 타입 컴파일 시 미리 지정하는 방법
18. Wrapper class
- 기본 타입의 데이터를 객체로 취급해야 하는 경우 사용
- Primitive data type 인 경우에는
==
로 바로 비교해줄 수 있다. - 래퍼 클래스는 객체이므로 == 비교하면 주소값을 비교한다.
- 값을 비교할 때는 equals를 사용해야 한다.
- JDK 1.5 부터는
AutoBoxing
과AutoUnBoxing
을 제공한다.
19. Multi-Thread 환경에서의 개발
19.1 필드 맴버
필드(field)
란 클래스에 변수를 정의하는 공간을 의미한다.- 메서드끼리 변수를 주고 받는데 있어서 참조하기 쉬움
- 하지만 객체가 여러 스레드가 접근하는 싱글톤 객체라면 field 에서 상태값을 갖고 있으면 안된다.
- 모든 변수를 parameter 로 넘겨받고 return 하는 방식으로 코드를 구성해야 한다.
19.2 동기화
- 필드에서 불가피하게 컬렉션을 사용할 때 싱크로나이즈 사용하여 스레드간 race 컨디션을 통제
- 싱크로나이즈 기반으로 구현된 컬렉션들이 존재 ex. vectoer, hashtable
- 그러나 api가 적고 성능이 좋지 않음
- 컬렉션스라는 유틸 클래스에서 제공하는 스태틱 메소드들이 있음
- jdk 1.7부터는 concurrent 패키지의 concurrenthashmap을 사용.
- 싱크로나이즈 키워즈 적용 범위가 좁아 더 좋은 성능을 냄
19.3 스레드 로컬
- 스레드 사이에 간섭이 없어야 하는 데이터에 사용한다.
- 클래스 필드에 변수를 추가할수 없으니 매개변수로 넘겨 받아야한다.
- 즉, 싱글톤 패턴에 사용.
- 주로 인증, 세션정보, 트랜잭션 컨텍스트에 사용
- 스레드 풀 환경에서는 스레드로컬을 사용하는 경우 스레드 로컬 변수에 보관된 데이터의 사용이 끝나면 반드시 삭제해야 함
20. 패턴
20.1 디자인 패턴
- 소프트웨어를 설계할 때 자주 발생하는 문제들이 또 발생했을 때 재사용할 수 있는 해결책
- 생성 패턴
- 구조 패턴
- 행위 패턴
20.2 싱글톤 패턴
- 싱글톤 패턴이란 애플리케이션에서 인스턴스를 하나만 만들어 사용하기 위한 패턴
- 스레드풀, 커넥션 풀등 여러 개의 인스턴스를 사용하면 자원을 낭비하거나 버그를 발생시키므로 하나의 인스턴스로 자원을 관리할 때 사용
- 너무 많은 자원을 처리하거나 데이터를 공유할 경우 다른 클래스의 인스턴스들 간에 결합도가 높아져 개방 폐쇄 원칙을 위배
20.3 strategy 패턴
- 행위를 클래스로 캡슐화해 객체의 행위를 동적으로 바꾸고 싶은 경우 직접 행위를 수정하지 않고 전략을 바꿔주기만 함으로써 행위를 유연하게 확장하는 방법
- 예를 들어 게임의 캐릭터가 공격과 방어 방식을 바꿀 때 사용하는 패턴
20.4 탬플릿 메서드 패턴
- 상속을 통해 기능을 확장해서 사용한다.
- 변하지 않는 부분은 슈퍼클래스에 두고 사용하고 변하는 부분은 추상 메서드로 정의하여 서브클래스에서 오버라이드하여 새롭게 정의해 사용하도록 하는 것
21. Stream API
- 스트림 API는 데이터를 추상화하여 다루므로, 다양한 방식으로 저장된 데이터를 읽고 쓰기 위한 공통된 방법을 제공
- 따라서 스트림 API를 이용하면 배열이나 컬렉션뿐만 아니라 파일에 저장된 데이터도 모두 같은 방법으로 다룰 수 있게 된다.
21.1 특징
- 컬렉션은 외부 반복, 스트림은 내부 반복
- 스트림은 재사용이 가능한 컬렉션과는 달리 한 번만 사용할 수 있다.
- 스트림은 원본 데이터를 변경하지 않는다.
- 스트림의 연산은 필터-맵 기반의 API를 사용하며 지연 연산을 통해 성능을 최적화 한다.
- parallelStream 메서드를 통한 손쉬운 병렬 처리를 지원한다.
22. Exception, RuntimeException의 개념과 사용 용도
- 컴파일이 성공적으로 수행되어도 실행 도중에 발생할 수 있는 잠재적인 오류를 대비하기 위해 예외처리를 사용한다.
- Excetipion
- ClassNotFound (여기부터 IO까지 체크 예외)
- CloneNotSupported
- Instantiation
- IO
- RunTimeException (여기는 언체크 예외)
- Arithmetic (0으로 나누기)
- IllegalArgument
- IndexOutOfBounds (배열)
22.1 throws(예외 회피하기), throw (예외 강제 발생)
-
자바에서 throw를 통해 발생시킬 수 있는 예외는 세 가지다.
1) Error
- 시스템에 뭔가 비정상적인 상황이 발생했을 경우에 사용
- 주로 자바 VM에서 발생시키는 것이고 애플리케이션 코드에서 잡으려고 하면 안된다.
- 메모리 아웃이나 스레드Death 같은 에러이므로 try~catch로 안된다.
- 이러한 에러 처리 신경은 쓰지 않아도 된다.
2) Exception과 체크 예외
- 에러가 아닌 Exception 클래스는 체크 예외와 언체크 예외로 구분
- 체크 예외 : Exception 클래스의 서브 클래스이면서 RuntimeException 클래스를 상속하지 않은 것
- 언체크예외 : RuntimeException 클래스를 상속한 클래스
- 체크 예외가 발생할 수 있는 메서드를 사용할 경우 반드시 예외를 처리하는 코드를 함께 작성해야 한다.
- 사용할 메서드가 체크 예외를 던진다면 이를 catch문으로 잡든지, 아니면 throws를 정의해서 메서드 밖으로 던져야 한다.
- 그렇지 않으면 컴파일 에러가 발생
3) RuntimeException과 언체크/런타임 예외
- 명시적인 예외처리를 강제하지 않기 때문에 언체크 예외라고 불린다.
- 에러와 마찬가지로 굳이 try나 throws로 선언하지 않아도 된다.
- 런타임 예외는 주로 프로그램의 오류가 있을 때 발생하도록 의도된 것들이다.
- 이런 예외는 코드에서 미리 조건을 체크하도록 주의 깊게 만든다면 피할 수 있다.
- 피할 수 있지만 개발자의 부주의로 발생할 수 있는 경우 발생하도록 만든 것이 런타임 예외다.
- 체크 예외, 언체크 예외의 차이점은 컴파일 시 예외 처리 체크를 하느냐 안하느냐 차이다.
- 즉, 컴파일러는 런타임예외를 제외한 모든 예외 클래스들을 컴파일시 예외처리를 했는지 반드시 확인 한다.
- 하지만 런타임예외 클래스 부류가 발생했을 때는 try를 사용하지 않더라도 컴파일까지 가능하다.