1. JVM 구조
- 윈도우 프로그램과 JVM 프로그램의 차이
2. GC(Garbage Collection)
3. String vs StringBuilder vs StringBuffer
- String 불변의 장점
4. 제네릭 + 왜 사용?
- 특징
- c++ template과의 차이
5. 컬렉션 프레임워크
study 준비
- 자바언어 특징과 장단점
- 추상클래스 & 인터페이스
- 자바의 컴파일 과정
- 클래스, 객체, 인스턴스
- 직렬화(Serialize)
- 직렬화 조건
- 역직렬화 조건
- serialVersionUID
- 인스턴스 멤버와 정적 멤버
- java의 main 메서드가 static인 이유?
- main이 실행되는 과정
- 접근 제어자의 종류와 각각의 접근 가능 범위
- serialVersionUID
- SOLID 원칙
- 오버라이딩, 오버로딩
- JAVA8의 가장 큰 변경사항
- stream
- lambda의 등장
- 함수형 프로그래밍/파라다임
- 객체지향 프로그래밍(OOP)
- 특징
- 5대 원칙 : SOLID 원칙
- 객체지향 프로그래밍과 절차지향 프로그래밍의 차이
- 객체 지향의 장점과 단점
- 불변 객체나 final
- 자바의 메모리 영역 & 할당되는 시점
- 컴파일 타임
- 런타임
- Error와 Exception의 차이
- checkedException vs unCheckedException
- synchronized에 대해
- 클래스, 함수, 변수에서 final keyword에 대한 차이점
- Collection의 대표적인 구현체
JVM 구조
자바 컴파일러에 의해 JAVA Source 파일을 JVM이 해석할 수 있는 JAVA Byte Code(.class 파일)로 변경합니다. 일반적인 윈도우 프로그램의 경우, Compile 이후 Assembly 언어로 구성된 파일이 생성됩니다. Class Loader가 JVM 내로 .class 파일들을 Load 합니다. Loading된 클래스들은 Runtime Data Area에 배치됩니다. 일반적인 프로그램의 경우, Load 과정은 OS가 주도합니다. 이렇게 Loading된 클래스들의 Byte code를 Execution Engine이 해석합니다. 이 과정에서 Byte Code가 Binary Code로 변경됩니다. 일반적인 윈도우 프로그램의 경우 Assembler가 Assembly언어로 쓰여진 코드 파일을 Binary code로 변경합니다. Runtime Data Area는 JVM이라는 프로그램이 OS로부터 할당받는 메모리 영역입니다.
이 내부에는 Method, Heap, Stack Area, PC Register, Native Method Stack이 있습니다. Method Area는 클래스 정보, 변수정보, Method 정보, static 변수정보, 상수정보 등이 저장되는 영역이며 모든 thread가 공유합니다. Heap Area는 new 명령어로 생성된 인스턴스와 객체가 저장되는 구역으로 Garbage Collection 이슈는 이영역에서 일어나고 모든 thread가 공유합니다. Stack Area는 Method 안에서 사용되는 값들(매개변수, 지역변수, 리턴값 등)이 저장되는 구역으로 메소드가 호출될 때 LIFO로 하나씩 생성되고, 메소드 실행이 완료되면 LIFO로 하나씩 지워집니다. 각 Thread별로 하나씩 생성됩니다. PC Register Area는 CPU Register과 역할이 비슷합니다. 현재 수행중인 JVM 명령의 주소값이 저장되며 각 Thread별로 하나씩 생성됩니다. 마지막으로 Native Method Stack은 다른 언어의 메소드 호출을 위해 할당되는 구역 언어에 맞게 스택이 형성되는 구역입니다.
+윈도우 프로그램과 JVM 프로그램의 차이
우선 Java Virtual Machine은 JAVA가 OS에 상관 없이 동작할 수 있도록 중계작 역할을 하며, GC(Garbage Collection)등의 기능을 제공합니다. 일반적인 프로그램은 compile, linking 과정을 거쳐 exe 파일을 생성합니다. 이후 로딩 과정을 거쳐 메모리에 프로그램을 적재합니다. 프로그램은 CPU를 동작시키는 명령으로 구성되어 있으므로 명령어들을 하나씩 CPU 레지스터에 넣는 fetch 작업을 수행합니다. CPU는 이러한 명령어를 각 필드 별로 분해하고 적절히 해것하여 어떤 연산을 할 것인지 decoding 작업을 수행합니다.
반면 JAVA의 경우 compile 후 해석과 link 없이 JVM에 적재된다는 점과 OS로부터 메모리를 할당받아 스스로 메모리를 관리한다는 점에 차이점이 있습니다. 즉, 프로그램 생성과정과 실행과정 일부에 JVM이 관여하게됩니다. JVM은 ByteCode를 구성하고 있는 OS에 맞추어 BinaryCode로 해석합니다. 따라서 JAVA는 OS에 독립적일 수 있습니다. 또한 ByteCode는 클래스단위로 생성되므로, 프로그램이 수정이 일어나더라도 전체 소스코드를 다시 컴파일 할 필요가 없으며 프로그램이 실행되는 도중에도 JVM은 OS로부터 메모리를 할당받아 스스로 관리합니다. 대표적으로 GC가 있습니다.
GC(Garbage Collection)
가비지 컬렉션이란?
자바가 실행되는 JVM에서 사용되는 객체, 즉 Heap 영역의 객체를 관리해주는 메모리 관리 기법 중 하나로 시스템에서 동적으로 할당됐던 메모리 영역 중에서 필요없어진 메모리 영역을 회수하여 메모리를 관리해주는 기법입니다. 이 과정에서 stop the world가 일어나게 되며, 이 일련 과정을 효율적으로 하기 위해서는 가비지 컬렉터 변경 또는 세부 값 조정이 필요합니다.
GC의 작업을 수행하기 위해 JVM이 어플리케이션의 실행을 잠시 멈추고, GC를 실행하는 쓰레드를 제외한 모든 쓰레드들의 작업을 중단 후(Stop the world 과정) 사용하지 않는 메모리를 제거(Mark and Sweep 과정)하고 작업이 재개됩니다.
Young 영역에 대한 Minor GC : Young 영역에(Eden, survivor) 있는 객체는 각 하위 영역이 가득 차면 Minor GC가 동작한다. 새로 생성된 대부분의 객체(Instance)객체는 Eden 영역에 위치한다. Eden영역에서 GC가 한번 발생한 후 살아남은 객체는 Survivor 영역 중 하나로 이동된다. 이 과정을 반복하다가 계속해서 살아남아 있는 객체는 일정시간 참조되고 있다는 뜻이므로 Old영역으로 이동시킨다. ‘일정 기간’의 기준은 객체마다 age bit라는 것을 가지고 있는데 이는 Minor GC에서 살아남은 횟수를 기록한다.
Old 영역에 대한 Major GC : Old 영역에 있는 객체는 영역이 가득차면 Major GC가 동작한다. Old영역에 있는 모든 객체들을 검사하여 참조되지 않은 객체들을 한꺼번에 삭제한다. 시간이 오래 걸리고 실행 중 프로세스가 정지된다. 이것을 ‘stop-the-world’라고 하는데 Major GC가 발생하면 GC를 실행하는 스레드를 제외한 나머지 스레드는 모두 작업을 멈춘다. GC 작업을 완료한 이후에야 중단했던 작업을 다시 시작한다.
String vs StringBuilder vs StringBuffer
공통점은 다 문자열을 저장하고 관리하느니 클래스들이라는 것입니다. String과 나머지 두개의 가장 큰 차이는 String은 불변(immutable)의 속성을 가지며, StringBuffer과 StringBuilder는 가변의 속성을 가진다는 것입니다. String 클래스에 저장되는 문자열은 private final char[]의 형태로 불변하기 때문에 문자열을 수정하는 시점에 새로운 String 인스턴스가 생성됩니다.(예 : String str=”hello”;에 str = str + “world”; 연산을 수행했을 때 str은 “hello world”라는 새로운 메모리 영역을 가리키게 변경되고 처음 선언했던 “hello”로 값이 할당 되어 있던 메모리 영역은 Garbage로 남아 있다가 GC에 의해 사라지게 된다.) 따라서 변하지 않는 문자열을 자주 읽어들일 경우 사용하면 좋은 성능을 발휘합니다. 그러나 문자열 추가, 수정, 삭제 등의 연산이 빈번하게 발생하는 경우에 String 클래스를 사용하면 힙 메모리에 많은 Garbage가 생성되어 힙 메모리 부족으로 성능에 치명적인 영향을 끼칩니다. 이를 해결하기 위해 가변(mutable)성을 가지는 StringBuffer와 StringBuilder 클래스를 도입합니다. 가변성을 가지기 때문에 .append(), .delete()등의 API를 아용하여 동일 객체 내에서 문자열을 변경하는 것이 가능합니다. 따라서 문자열의 추가, 수정, 삭제가 빈번하게 발생할 경우 이것들을 사용하는 것이 좋습니다. StringBuffer와 StringBuilder의 가장 큰 차이는 동기화의 유무로 StringBuffer는 동기화를 지원하여 멀티 쓰레드 환경에서 안전합니다. 참고로 String도 불변성을 가지고 있기 때문에 thread-safe한 특징을 가지고 있습니다. 반대로 StringBuilder는 동기화를 지원하지 않아 싱글 쓰레드 환경에서 주로 사용합니다.
+String 불변의 장점
캐싱 기능에 의한 메모리 절약과 속도 향상 : 자바에서 String 객체들은 Heap의 String Pool이라는 공간에 저장되는데, 참조하려는 문자열이 String Pool에 존재하는 경우 새로 생성하지 않고 Pool에 있는 객체를 사용하기 때문에 특정 문자열 값을 재사용하는 빈도가 높을 수록 상당한 성능 향상을 기대할 수 있습니다.
thread-safe : String 객체는 불변이기 때문에 여러 쓰레드에서 동시에 특정 String 객체를 참조하더라도 안전합니다.
보안기능 : 중요한 데이터를 문자열로 다루는 경우 강제로 해당 참조에 대한 문자열 값을 바꾸는 것이 불가능하기 때문에 보안에 유리합니다.
제네릭 + 왜 사용?
제네릭은 데이터의 타입을 하나로 지정하지 않고 사용할 때마다 범용적이고 포괄적으로 지정한다는 의미입니다. 제네릭 타입을 사용함으로써 잘못된 타입이 사용될 수 있는 문제를 컴파일 과정에서 체크하기 때문에 런타임에서 ClassCastException과 같은 UncheckedException을 보장받고 에러를 제거할 수 있어 에러를 사전에 방지할 수 있습니다. 또 제네릭 코드를 사용하면 타입을 국한하기 때문에 요소를 찾아올 때 타입변환을 할 필요가 없어 코드가 간결해지고 프로그램 성능이 향상됩니다.
+특징
모든 객체에 대해 동일하게 동작해야하는 static 멤버에 타입 변수 T를 사용할 수 없다. T는 인스턴스 변수로 간주되기 때문이다. static 멤버는 인스턴스변수를 참조할 수 없다. 제네릭 타입의 배열을 생성하는 것도 허용되지 않는다. 제네릭 배열 타입의 참조변수를 선언하는 것은 가능하지만, new T[10]과 같이 배열을 생성하는 것은 안된다. 이유는 new 연산자 때문이다. 이 연산자는 컴파일 시점에 타입 T가 무엇인지 명확히 알아야 하기 때문이다.
+c++ template과의 차이
템플릿은 하나의 클래스를 서로 다른 여러 타입에 재사용할 수 있도록 하는 방법이다. c++의 템플릿에는 int와 같은 기본 타입을 인자로 넘길 수 있지만, java는 Integer를 대신 사용해야 한다. c++의 template은 인자로 주어진 타입으로부터 객체를 만들어낼 수 있지만 java에서는 불가능하다. java에서 제네릭 클래스로 만든 모든 객체는 Generic 타입 인자가 무엇이냐에 관계 없이 전부 동등한 타입이다. c++에서는 다른 Template 타입 인자를 사용해 만든 객체는 서로 다른 타입의 객체이다. java의 경우 generic 타입 인자를 특정한 타입이 되도록 제한할 수 있다. java에서 generic 타입의 인자는 정적 메서드나 변수를 선언하는 데 사용될 수 없다. c++ template은 각 클래스를 다른 클래스로 처리하므로 template 타입 인자를 정적 메서든 변수를 선언하는 데 사용할 수 있다.
컬렉션 프레임워크
[간단하게]
다수의 데이터를 쉽고 효과적으로 관리할 수 있는 표준화된 방법을 제공하는 클래스의 집합을 의미합니다. 자바 컬렉션에는 List, Set, Map 인터페이스를 기준으로 여러 구현체가 존재하고, 이에 더해 Stack, Queue인 인터페이스도 존재합니다.
[구체적으로]
배열을 사용하다보면 여러가지 비효율적인 문제가 생깁니다. 가장 큰 문제점은 크기가 고정적이라는 것인데 저장할 때 크기를 넘어가면 더이상 저장 할 수 없고 삭제하면 해당 인덱스의 데이터가 비어있어 메모리 낭비가 발생합니다. 따라서 자바는 널리 알려져 있는 자료구조를 바탕으로 객체나 데이터들을 효율적으로 관리(추가, 삭제, 검색, 저장)할 수 있는 자료구조들을 만들어 놨고 이러한 라이브러리를 컬렉션 프레임워크라고 합니다. 컬렉션 프레임워크는 자바의 인터페이스를 사용하여 구현되며 대표적으로 List, Set, Map, Stack, Queue가 있습니다.
+List
List 컬렉션은 객체를 일렬로 늘어놓은 구조를 가지고있습니다. 객체를 인덱스로 관리하기 때문에 객체를 저장하면서 자동 인덱스가 부여되고 인덱스로 객체를 검색, 삭제할 수 있는 기능을 제공합니다. List컬렉션은 객체 자체를 저장하는 것이 아니라 위와 같이 객체의 번지를 참조합니다. 동일한 객체를 중복 저장할 수 있는데 이 경우 동일한 번지가 참조됩니다. null도 저장이 가능한데, 이 경우 해당 인덱스는 객체를 참조하지 않습니다. List 컬렉션을 구현하는 대표적인 클래스들은 ArrayList, LinkedList, Vector가 있습니다.
+Set
Set 컬렉션은 저장 순서가 유지되지 않습니다. 또한 객체를 중복해서 저장할 수 없고, 하나의 null만 저장할 수 있습니다. 그렇기에 Set컬렉션은 순서 자체가 없으므로 인덱스로 객체를 검색해서 가져오는 get(index) 메소드도 없습니다. 대신 전체 객체를 대상으로 한번씩 반복해서 가져오는 반복자(Iterator)를 제공합니다. Set 컬렉션을 구현하는 대표적인 클래스들은 HashSet과 TreeSet이 있고 순서를 보장하기 위해서는 LinkedHashSet을 사용합니다.
+Map
Map 컬렉션은 키와 값으로 구성된 객체를 저장하는 구조를 가지고 있습니다. 키는 중복 저장될 수 없짐나 값은 중복 저장될 수 있으며 중복된 key값이 들어온다면 기존의 값은 없어지고 새로운 값으로 대치됩니다. Map은 리스트나 배열처럼 순차적으로 해당 요소 값을 구하지 않고 key를 통해 value를 얻는게 큰 특징입니다. 따라서 Map 컬렉션은 키로 데이터를 관리합니다. 대표적인 클래스들은 HashMap, HashTable, LinkedHashMap(순서를 보장), TreeMap 등이 있습니다.
+Stack & Queue
Stack 객체는 직접 new 키워드로 사용 할 수 있고, Queue 인터페이스는 LinkedList에 new 키워드를 적용하여 사용할 ㅅ 있습니다.
study 준비
- 자바언어 특징과 장단점에 대해 설명해주세요
- Java는 객체지향 프로그래밍 언어입니다. 기본 자료형을 제외한 모든 요소들이 객체로 표현되고, 객체 지향 개념의 특징인 캡슐화, 상속, 다형성이 잘 적용된 언어입니다. JVM 위에서 동작하기 때문에 운영체제에 독립적이며 Garbage Collector를 통한 자동적인 메모리 관리가 가능합니다. 하지만 JVM 위에서 동작하기 때문에 실행 속도가 상대적으로 느립니다. 또한 다중 상속이나 타입에 엄격하며, 제약이 많습니다.
- 추상클래스와 인터페이스에 대해 설명하고, 차이점을 설명해주세요
-
- [간단하게] 추상 클래스는 클래스 내 추상 메소드가 하나 이상 포함되거나 abstract로 정의된 경우를 말하고 인터페이스는 모든 메소드가 추상 메소드로만 이루어져 있는 것을 말합니다. 둘 다 new 연산자로 인스턴스 생성이 불가능하며 사용하기 위해서는 하위 클래스에서 확장/구현해야합니다. 하지만 인터페이스는 그 인터페이스를 구현하는 모든 클래스에 대해 특정한 메소드가 반드시 존재하도록 강제함에 있고, 추상 클래스는 상속받는 클래스들의 공통적인 로직을 추상화 시키고, 기능 확장을 위해 사용합니다. 또한 추상클래스는 다중상속이 불가능하지만, 인터페이스는 다중상속이 가능합니다.
- [구체적으로]
- 추상클래스는 클래스 구현부 내부에 추상 메소드가 하나 이상 포함되거나 abstract로 정의된 경우를 말합니다. abstract class를 상속받은 클래스(하위 클래스)는 자기의 성질에 맞게 Overriding하여 사용합니다. 추상클래스는 new 연산자를 사용하여 객체를 생성할 수 없고 추상클래스와 일반 클래스, 자식 클래스는 상속의 과나계에 놓여 있습니다. 추상클래스는 새로운 일반 클래스를 위한 부모 클래스의 용도로만 사용되며 공통된 필드와 메소드를 통일하여 일반 클래스 작성 시 시간을 절약할 수 있습니다. 또한 단일 상속만 가능하며 일반 변수를 가질 수 있습니다. 추상클래스는 동일한 부모를 가지는 클래스를 묶는 개념으로 상속을 받아서 기능을 확장시키는 것이 목적입니다.
- 인터페이스는 모든 메소드가 추상 메소드인 경우를 말합니다. 인터페이스는 추상 클래스보다 한 단계 더 추상화된 클래스라고 볼 수 있습니다. 인터페이스에 적는 모든 메소드들은 추상 메소드로 간주되기 때문에 abstract를 적지 않습니다. 기존에는 인터페이스에 일반 메소드를 구현할 수 없었지만, 자바 8버전부터 default 예약어를 통해 일반 메소드도 구현이 가능합니다. 인터페이스는 static final 필드만 가질 수 있습니다. public static final을 사용하는 이유는 구현 객체의 같은 동작을 보장하기 위함이며 인터페이스의 변수는 스스로 초기화 될 권한이 없고 아무 인스턴스도 존재하지 않는 시점이기 때문입니다. 인터페이스도 추상 클래스와 마찬가지로 new 연산자를 사용하여 객체를 생성할 수 없습니다. 구현 객체가 같은 동작을 한다는 것을 보장하는 것이 목적이며 다중 상속이 가능합니다.
- 자바 컴파일 순서에 대해 설명해주세요
- [간단하게]개발자가 .java 파일을 생성하여 build합니다. java compiler의 javac 명령어를 통해 바이트코드(.class)를 생성합니다. Class Loader를 통해 JVM 메모리 내로 로드하고 실행엔진을 통해 컴퓨터가 읽을 수 있는 기계어로 해석됩니다.
- [구체적으로] JVM 구조
- 클래스, 객체, 인스턴스에 대해 설명해주세요
- 클래스는 객체를 찍어내기 위한 설계도 혹은 틀이라고 할 수 있고, 객체를 생성하는데 사용합니다. 객체는 설계도인 클래스를 바탕으로 생성되며, 자신의 고유 이름과 상태, 행동을 갖습니다. 여기서 상태는 필드, 행동은 메소드라고 표현합니다. 객체에 메모리가 할당되어 실제로 활용되는 실체를 ‘인스턴스’라ㅏ]고 부릅니다.
- 직렬화(Serialize)에 대해서 설명해주세요
- 각자 PC의 OS마다 서로 다른 가상 메모리 주소 공간을 갖기 때문에, reference type의 데이터들은 인스턴스를 전달할 수 없습니다. 따라서, 이런 문제를 해결하기 위해선 주소값이 앙닌 byte 형태로 직렬화된 객체 데이터를 전달해야합니다. 직렬화된 데이터들은 모두 primitive type(기본형)이 되고, 이는 파일 저장이나 네트워크 전송 시 파싱이 가능한 유의미한 데이터가 됩니다. 따라서 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데이터 변환하는 기술을 직렬화라고 말할 수 있습니다. 반대로 직렬화된 바이트 형태의 데이터를 다시 객체로 변환하는 과정을 ‘역직렬화’라고 합니다.
- 직렬화 조건 : primitive 타입의 경우 가능하고, primitive 타입이 아닌 reference 타입처럼 주소값을 지닌 객체들은 바이트로 변환하기 위해 java.io.Serializable 인터페이스 구현이 필요합니다.
- 역직렬화 조건 : 직렬화 대상이 된 객체의 클래스가 클래스 패스에 존재해야하며 import 되어 있어야합니다. 또한 자바 직렬화 대상 객체는 동일한 serialVersionUID를 가지고 있어야 합니다.
- 인스턴스 멤버와 정적 멤버에 대해 설명해주세요
- 인스턴스 멤버 즉 non-static 멤버는 객체마다 별도로 존재하며 객체 생성 시에 멤버가 생성되고 객체 생성 후 멤버 사용이 가능합니다. 또한 객체가 사라지면 멤버도 사라지게 됩니다. 멤버는 객체 내에 각각의 공간을 유지하기 때문에 공유되지 않는다는 특성을 가지고 있습니다.
- static 멤버는 클래스 멤버라고도 부르며 객체 내부가 아닌 별도의 공간에 클래스당 하나가 생성됩니다. 클래스 로딩 시에 멤버가 생성되어 객체가 생성되기도 전에 이미 생성됩니다. 따라서 객체를 생성하지 않고도 사용이 가능하며 객체가 사라져도 멤버는 사라지지 않습니다. 즉 멤버는 프로그램이 종료될 때 사라지게됩니다. 그리고 static 멤버는 동일한 클래스의 모든 객체들에 의해 공유된다는 특징이 있습니다.
- java의 main 메서드가 static인 이유? JVM은 인스턴스가 없는 클래스의 main()을 호출해야하기 때문에 static 이어야 합니다.
- main이 실행되는 과정 : 코드를 실행하면 컴파일러가 .java 코드를 .class(byte code)로 변환합니다. 클래스 로더가 .class 파일을 메모리 영역(Runtime Data Area)에 로드합니다. Runtime Data Area 중 Method Area(=Class Area =Static Area)라고 불리는 영역에 Class Variable이 저장되는데, static 변수 또한 여기에 포함됩니다. JVM은 Method Area에 로드된 main()을 실행합니다.
- 자바의 컴파일 과정에 대해 설명해주세요
- 자바의 메모리 구조에 대해 설명해주세요
- 추상클래스와 인터페이스에 대해 설명해주세요.
- 접근 제어자의 종류와 각각의 접근 가능 범위에 대해 설명해주세요
- 변수 또는 메소드의 접근 범위를 설정해주기 위해서 사용하는 java의 예약어를 의미하며 총 네가지 종류가 존재합니다.
- public : 어떤 클래스의 객체에서든 접근이 가능합니다.
- private : 이 클래스에서 생성된 객체들만 접근 가능합니다.
- protected : 이 클래스와 동일 패키지에 있거나 상속 관계에 있는 하위 클래스의 객체들만 접근 가능합니다.
- package(default) : 동일 패키지에 있는 클래스의 객체들만 접근 가능합니다.
- serialVersionUID란 무엇이고 왜 사용해야할까요?
- JVM은 직렬화와 역직렬화를 하는 시점의 클래스에 대한 버전 번호를 부여하는데, 만약 그 시점에 클래스의 정의가 바뀌어 있다면 새로운 버전 번호를 할당하게 됩니다. 그래서 직렬화 할 때의 버전 번호와 역직렬화를 할 때의 버전 번호가 다르면 역직렬화가 불가능하게 될 수 있기 때문에 이런 문제를 해결하기 위해 serialVersionUID 를 사용합니다. 만약 직렬화할 때 사용한 SerialVersionUID의 값과 역직렬화 하기 위해 사용했던 UID가 다르다면 InvalidClassException이 발생할 수 있습니다.
- SOLID 원칙에 대해서 설명해주세요
- Single Responsibility Principle : 단일 책임 원칙
- 모든 클래스는 하나의 책임만 가져야하며 수정할 이유는 단 한가지여야합니다. 즉, 클래스는 그 책임을 완전히 캡슐화해야 함을 말합니다.
- 예를 들어 결제 클래스가 있다면 이 클래스는 오직 결제 기능만 책임지고 만약 이 클래스를 수정해야한다면 결제에 관련된 문제 뿐이여야합니다.
- Open-closed Principle : 개방-패쇄 원칙
- 소프트웨어 구성요소인 컴포넌트, 클래스, 모듈, 함수는 확장에는 열려있어야하지만 변경에는 폐쇄적이어야함을 의미합니다. 즉 기존의 코드를 변경하지 않으면서, 기능을 추가할 수 있도록 설계가 되는 원칙을 말합니다. 이 원칙을 적용하기 위한 중요 매커니즘은 추상화와 다형성입니다.
- 예를 들어, 캐릭터마다 움직임이 다를 경우, 움직임 패턴 구현을 하위 클래스에 맡긴다면 클래스의 수정은 필요없어 closed 된것이고, 움직임 패턴만 재정의 하면 되므로 open된 상태인 것입니다.
- Liskov Substitution Principle : 리스코프 치환 원칙
- 상위 타입은 항상 하위 타입으로 대체할 수 있어야 합니다. 즉, 부모클래스가 들어갈 자리에 자식 클래스를 넣어도 역할을 하는데 문제가 없어야 한다는 의미입니다. 리스코프 치환 원칙은 다형성과 확장성을 극대화하며, 개방-폐쇄 원칙을 구성합니다.
- Interface Segregation Principle : 인터페이스 분리 원칙
- 인터페이스 분리 원칙은 각 역할에 맞게 인터페이스를 분리하여 클래스가 꼭 필요한 인터페이스만 구현하도록 해야한다는 의미입니다. 즉 최소한의 기능만 제공하면서 하나의 역할에 집중해야한다는 뜻입니다. SRP와 ISP는 같은 문제에 대한 두가지 다른 해결책이라고 볼 수 있습니다. 가능한 최소한의 인터페이스를 사용하도록 하여 단일 책임을 강조한다고 볼 수 있습니다.
- Dependency Inversion Principle : 의존관계 역전 원칙
- 의존 관계를 맺을 때 변화하기 쉬운 것 또는 자주 변화하는 것보다는 변화하기 어려운것, 거의 변화가 없는 것에 의존하라는 것입니다. 즉, 구체적인 클래스보다 상위 클래스, 인터페이스, 추상 클래스와 같이 변하지 않을 가능성이 높은 클래스와 관계를 맺어야하며 상위 모듈이 하위 모듈에 의존하면 안된다는 것입니다.
- Single Responsibility Principle : 단일 책임 원칙
- 오버라이딩, 오버로딩에 대해서 설명해주세요
- 객체지향의 특징에는 다형성이 있는데 이는 같은 코드라 하더라도 상황에 따라 다른 방식으로 동작하는 성질을 의미하며 JAVA에서 다형성을 구현할 수 있는 대표적인 방법은 overriding과 overloading이 있습니다.
- 오버로딩은 두 메서드가 같은 이름을 갖고 있으나 인자의 수나 자료형이 다른 메소드를 ㄴ구현합니다. 코드의 중복이 줄어들고 가독성이 늘어납니다.
- 오버라이딩은 임의의 클래스가 다른 클래스를 상속 받거나 인터페이스를 구현했을 때, 상위 클래스 또는 인터페이스에 정의되어 있는 메소드를 재정의 하여 사용하는 것입니다. 메소드 호출 시 재정의되어 있지 않다면 상위 클래스의 메소드가 호출됩니다.
- 클래스와 인스턴스의 차이를 설명해주세요
- 본인이 생각하는 JAVA8의 가장 큰 변경사항이 무엇인가요?
- 함수형 프로그래밍, 함수형 패러다임의 등장에 따라 스트림과 람다가 등장했습니다. 함수형 프로그래밍이란 자료처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임을 의미합니다.
- stream
- 컬렉션(배열 포함)의 저장 요소를 하나씩 참조해서 람다식으로 처리할 수 있도록 해주는 반복자입니다. Iterator와 비슷한 역할을 하지만 람다식으로 요소 처리 코드를 제공하여 코드가 좀 더 간결하게 할 수 있다는 점과 내부 반복자를 사용하므로 병렬처리가 쉽다는 점에서 차이가 있습니다.
- lambda의 등장
- 메소드를 하나의 식으로 표현하는 것으로 매개변수, 화살표, 몸통의 구조를 따릅니다. 기존에 익명함수로 작성하던 코드를 줄여 간단하게 작성이 가능하고 병렬 프로그래밍에 용이합니다. 남용하명 코드를 이해하는데 어려움이 생기고 디버깅이 까다롭다는 단점도 있습니다.
- stream
- 함수형 프로그래밍, 함수형 패러다임의 등장에 따라 스트림과 람다가 등장했습니다. 함수형 프로그래밍이란 자료처리를 수학적 함수의 계산으로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임을 의미합니다.
- 객체지향 프로그래밍(OOP)에 대해 설명해주세요
- 모든 데이터를 개체취급하며, 처리요청을 받은 객체는 객체 안의 기능을 사용해 요청을 처리합니다. 특징으로는 캡슐화, 상속, 다형성, 추상화 등이 있고, 모듈 재사용으로 확장 및 유지보수가 용이합니다. 절차지향에 비해 처리속도가 느리다는 단점을 가지고 있지만 하드웨어의 발전으로 어느정도 해소되었습니다.
- 특징
- 추상화(Abstraction) : 구체적인 사물들의 공통적인 특징을 파악해서 이를 하나의 개념(집합)으로 다루는 것을 말합니다.
- 캡슐화(Encapsulation) : 필요가 없는 정보는 외부에서 접근하지 못하도록 제한하는 정보은닉(information hiding) 특징을 가지고 이를 통해 높은 응집도, 낮은 결합도를 유지하여 유연함과 유지보수성이 증가합니다.
- 상속(Inheritance) : 여러 개체들이 가진 공통된 특성을 부각시켜 하나의 개념이나 법칙으로 성립시키는 것을 의미합니다.
- 다형성(Polymorphism) : 서로다른 클래스의 객체가 같은 메시지를 받았을 때 각자의 방식으로 동작하는 능력을 의미하며 오버라이딩과 오버로딩이 대표적입니다.
- 5대 원칙 : SOLID 원칙
- 객체지향 프로그래밍과 절차지향 프로그래밍의 차이 : 절차지향은 순차적으로 실행하는 것에 초점이 되어있고 객체지향은 개체간의 관계에 초점을 두고 있습니다. 대표적인 절차지향 언어로는 C언어가 있고 컴퓨터의 처리구조와 유사해 실행속도가 빠르다는 정점을 가집니다. 하지만 유지보수가 어렵고 실행 순서가 정해져 코드의 순서가 바뀌면 동일한 결과를 보장하기 어렵다는 단점이 있습니다. 어느정도 하드웨어의 기본적인 사양을 잡아먹어도 더이상 큰 단점이 되지 않아서 개발시간을 단축하기 위해 객체지향 프로그래밍이 탄생했습니다. 객체지향 프로그래밍은 개발하려는 것을 기능별로 묶어 모듈화를 함으로써 같은 기능을 중복으로 연산하지 않거나 모듈을 재활용하기 때문에 유지보수에 유리합니다. 따라서 코드의 재활용성이 높고 코딩이 절차지향보다 간편하며 디버깅이 쉽습니다. 하지만 처리 속도가 절차지향보다 느리고 설계에 시간을 들여야한다는 단점또한 존재합니다.
- 객체 지향의 장점과 단점 : 객체를 중심으로 프로그래밍하기 때문에 사람의 관점에서 프로그램을 이해하고 파악하기 쉽습니다. 강한 응집력과 약한 결합력을 가지고 재사용성, 확장성, 융통성이 높습니다. 이러한 장점 때문에 디버깅과 유지보수가 용이하고 설계와 분석이 비교적 쉽습니다. 반면 객체간의 정보 교환이 모두 메시지 교환을 통해 일어나므로 실행 시스템에 많은 overhead가 발생하게 됩니다. 하지만 이러한 단점은 하드웨어의 발전으로 어느정도 해소되었습니다. 또한 객체가 상태를 갖기 때문에 예상치 못한 부작용이 발생할 수 있습니다. 변수가 존재하고 이 변수를 통해 객체가 예측할 수 없는 상태를 갖게 되어 애플리케이션 내부에서 버그를 탄생시킬 수 있습니다.
- 불변 객체나 final을 굳이 사용해야 하는 이유는 무엇이 있을까요?
- 불변객체란? 불변객체는 객체 생성 이후 내부의 상태가 변하지 않는 객체를 말합니다.
- 불변 객체나 final 키워드를 사용해 얻는 이점은 다음과 같습니다. Thread-safe하여 병렬 프로그래밍에 유용하며, 동기화를 고려하지 않아도 됩니다. 공유 자원이 불변이기 때문에 항상 동일한 값을 반환하기 때문입니다. 두번째로 실패 원자적인 메쇄드를 만들 수 있습니다. 어떠한 예외가 발생되더라도 메소드 호출 전의 상태를 유지할 수 있어 예외 발생 전과 똑같은 상태로 다음 로직을 처리할 수 있게 해줍니다. 부수효과를 피해 오류를 최소화 할 수 있습니다. 부수효과란 변수의 값이 바뀌거나 객체의 필드 값을 설정하거나 예외나 오류가 발생하여 실행이 중단되는 현상을 말합니다. 네번째로 메소드 호출 시 파라미터 값이 변하지 않는다는 것을 보장할 수 있고 가비지 컬렉션 성능을 높일 수 있습니다. 이는 가비지 컬렉터가 스캔하는 객체의 수가 줄어들기 때문에 수행 시 지연시간도 줄어들기 때문입니다.
- 자바의 메모리 영역에 대해 설명해주시고, 각 메모리 영역이 할당되는 시점이 언제인지도 설명해주세요
- 자바 메모리 구조
- 자바 메모리 공간은 크게 Method 영역, Stack 영역, Heap 영역으로 구분되고, 데이터 타입에 따라 할당됩니다. 메소드 영역은 전역 변수와 static 변수를 저장하며 Method영역은 프로그램의 시작부터 종료까지 메모리에 남아있습니다. JVM이 동작해서 클래스가 로딩될 때 생성됩니다. 스택 영역은 지역변수와 매개변수 데이터 ㅠ값이 저장되는 공간이며, 메소드가 호출될 때 메모리에 할당되고 종료되면 메모리가 해제됩니다. LIFO 구조를 갖고 변수에 새로운 데이터가 할당되면 이전 데이터는 지워집니다. 스택영역은 런타임시 할당됩니다. 마지막으로 new 키워드로 생성되는 객체(인스턴스), 배열 등이 Heap 영역에 저장되며, 가비지 컬렉션에 의해 메모리가 관리되어집니다. 힙 영역은 컴파일 타임 시에 할당됩니다.
- 컴파일 타임 : 소스 코드가 기계어로 변환되어 실행가능한 프로그램이 되는 과정
- 런타임 : 컴파일 타임 이후 프로그램이 실행되는 때
- Error와 Exception의 차이를 설명해주세요
- Error는 실행 중 일어날 수 있는 치명적 오류를 말합니다. 컴파일 시점에 체크할 수 없고, 오류가 발생하면 프로그램은 비정상 종료되며 예측 불가능한 UncheckedException에 속합니다. 반면 Exception은 Error보다 비교적 경미한 오류이며, try-catch를 이용해 프로그램의 비정상 종료를 막을 수 있습니다.
- checkedException vs unCheckedException
- synchronized에 대해 아는 대로 말해주세요
- 여러개의 쓰레드가 한 개의 자원을 사용하고자 할 때, 현재 데이터를 사용하고 있는 쓰레드를 제외하고 나머지 쓰레드들은 데이터에 접근할 수 없게 막는 개념입니다. 데이터의 thread-safe를 보장하기 위해 자바에서 synchronized 키워드를 제공해 멀티 쓰레드 환경에서 쓰레드간 동기화를 시켜 데이터의 thread-safe를 보장합니다. synchronized는 변수와 메소드에 사용해서 동기화 할 수 있으며, synchronized 키워드를 남발하게 되면 오히려 프로그램의 성능저하를 일으킬 수 있습니다.
- JAVA의 컴파일 과정에 대해 설명해주세요
- 자바의 메모리 영역에 대해 설명해주세요
- 각 메모리 영역이 할당되는 시점은 언제인가요?
- 인터페이스란 무엇이고 왜 사용하나요?
- JVM과 GC에 대해 설명해주세요
- 클래스, 함수, 변수에서 final keyword에 대한 차이점을 알려주세요
- 오버라이딩과 오버로딩에 대해서 설명해주세요
- Collection의 대표적인 구현체 4개를 설명해주세요
- 컬렉션 프레임워크
- List 인터페이스는 순서가 있다는 특징과 데이터의 중복을 허용한다는 특징이 있습니다.
- ArrayList : 크기가 가변적으로 변하는 선형리스트입니다. 객체들이 추가되어 저장 용량을 초과한다면 자동으로 부족한 크기만큼 저장 용량이 늘어난다는 특징을 가지고 있습니다. index를 가지고 무작위 접근이 가능하기 때문에 해당 index의 값을 한번에 가져올 수 있습니다. 삽입과 삭제 시 최악의 경우 O(N)의 시간을 가지므로 삽입과 삭제가 많다면 ArrayList는 비효율적입니다.
- LinkedList : 각 노드가 데이터와 포인터를 가지고 한 줄로 연결되어 있는 방식의 자료구조 입니다. 데이터를 담고 있는 노드들이 연결되어 있고, 노드의 포인터가 이전 노드와 다음 노드와의 연결을 담당합니다. 순차적 접근으로 검색의 속도가 느리지만 데이터를 추가 삭제시 가리키고 있는 주소 값만 변경해주면 되기 때문에 ArrayList에 비해 상당히 효율적입니다.
- Set 인터페이스는 순서가 없는 데이터의 집합을 가지고 데이터의 중복을 허용하지 않는다는 특징이 있습니다.
- HashSet : TreeSet의 경우 자동정렬을 해주는데 HashSet의 경우는 정렬을 해주지 않는다는 차이점이 있습니다.
- Map 인터페이스는 키와 값이 한 쌍으로 이루어진 데이터의 집합으로 순서가 없습니다. 키는 중복을 허용하지 않고 값은 중복을 허용한다는 특징이 있습니다.
- HashMap : 해싱을 사용하기 때문에 많은 양의 데이터를 검색하는 데 있어 뛰어난 성능을 보입니다.
- 자바의 접근 범위 4가지에 대해서 설명해주세요