질문모음

더보기
  1. 객체지향(OOP)이란?
  2. 객체지향 설계 원칙인 SOLID란?
  3. 관점지향(AOP)이란?
  4. 추상화란?
  5. 추상 클래스와 인터페이스의 특징과 차이를 설명하시오
  6. 캡슐화란?
  7. Spring Boot의 어노테이션 중 @Getter와 @Setter의 무분별한 사용을 지양해야하는 이유는 무엇인가?
  8. 상속이란?
  9. IS-A 관계와 HAS-A 관계의 차이점이란 무엇인가?
  10. 다형성이란?
  11. 자바의 컴파일 과정을 설명하시오
  12. JVM (Java Virtual Machine) 의 역할은 무엇인가?
  13. JVM의 내부 구조는?
  14. 자바의 메모리 영역의 종류와 그 특성은?
  15. 가비지 컬렉션을 위해 만들어진 heap 영역의 구조와 가비지 컬렉션의 동작방식은?
  16. Java 7의 특징은?
  17. Java 8의 특징은?
  18. Java 11의 특징은?
  19. 제네릭이란?
  20. String, StringBuilder, StringBuffer의 차이점은?
  21. String을 선언할 때 따옴표를 사용하는 것과 new를 사용하는 것의 차이점은?

 

답변

1) 객체지향(OOP)이란?

더보기

프로그래밍에서 필요한 데이터를 추상화시켜 상태와 행위를 가진 객체를 만들고 그 객체들 간의 유기적인 상호작용을 통해 로직을 구성하는 프로그래밍 방법입니다.


2) 객체지향 설계 원칙인 SOLID란?

더보기
  • SRP (Single Responsibility Principle): 단일 책임 원칙, 하나의 클래스는 하나의 책임만을 가져야합니다
  • OCP (Open/Closed Principle): 개방 폐쇄 원칙, 확장에는 열려있고 수정에는 닫혀있어야합니다
  • LSP (Liskov Substitution Principle): 리스코브 치환 원칙, 상위 타입은 하위 타입으로 치환이 가능해야합니다
  • ISP (Interface Segregation Priciple): 인터페이스 분리 원칙, 하나의 범용 인터페이스보다 다수의 특정 인터페이스가 낫습니다
  • DIP (Dependency Inversion Principle): 의존 역전 원칙, 추상화에 의존해야지 구체화에 의존해선 안됩니다. 즉, 인터페이스, 추상 클래스와 같이 자주 변하지 않는 클래스와 관계를 맺어야합니다.

3) 관점지향(AOP)이란?

더보기

OOP를 더 발전시킨 개념으로 OOP에서 비즈니스 로직을 모듈화했다면 거기서 관점을 다르게해 인프라/부가 기능 측면에서 공통된 요소를 추출하는 것입니다. 예를들면 OOP가 프로그램을 계좌이체/입출금/이자계산으로 모듈화 했다면 AOP는 그 중에서 공통적으로 발생하는 부가 기능인 인증, 권한 체크, 트랜잭션 등을 분리시켜 필요한 시점에 자동으로 삽입되게 하는 것입니다.

이를 통해 코드 재활용성을 높이고 유지보수를 더 쉽게할 수 있습니다.

 


 

4) 추상화란?

더보기

추상화란 서로 다른 객체들의 특성 중 공통적인 속성, 동작들을 추출하여 하나의 묶음으로 정의하는 것을 의미합니다. 추상화를 이용한 설계는 코드의 재사용성을 높이고 그로 인해 간결해진 코드로 생산성, 가독성, 유지 보수 시간에 긍정적인 영향을 미칩니다

5) 추상 클래스와 인터페이스의 특징과 차이를 설명하시오

더보기

추상클래스는 일반 클래스와 별 다를 것이 없습니다. 단지, 추상 메서드를 선언하여 상속을 통해서 자손 클래스에서 완성하도록 유도하는 클래스입니다. 그래서 미완성 설계도라고도 표현합니다. 상속을 위한 클래스이기 때문에 따로 객체를 생성할 수 없습니다.

추상클래스가 미완성 설계도라면 인터페이스는 기본 설계도라고 할 수 있습니다. 인터페이스도 추상클래스처럼 다른 클래스를 작성하는데 도움을 주는 목적으로 작성하고 인터페이스는 추상메서드만을 가지고있습니다. 클래스와 다르게 다중상속이 가능합니다.

추상 클래스와 인터페이스를 나눠서 사용하는 이유는 사용 의도와 공통 기능 재사용이라는 두가지가 있습니다. 추상 클래스는 '상속', 즉 is-a 의 관계가 되기 때문에 클래스의 구분을 추상 클래스로 해결하고, 다중 상속이 가능한 인터페이스는 has-a 관계로 생각해 클래스가 가지고있는 기능들에 대한 부분을 해결하는 용도로 쓰입니다. 또한 만약 모든 클래스가 인터페이스를 사용해서 기본 틀을 구성한다면 공통으로 필요한 기능들도 모든 클래스에서 오버라이딩 하여 재정의 해야하는 번거로움이 있습니다.

6) 캡슐화란?

더보기

캡슐화란 객체 내부의 구조 및 데이터를 하나의 캡슐로 감싸 외부로부터 은닉하여 보호하는 것을 의미합니다. 캡슐화를 통해 높은 응집도 낮은 결합도를 유지할 수 있게됩니다.

  • 높은 응집도란 모듈 내의 요소들이 서로 밀접한 관련이 있어 하나의 목표를 위해 긴밀하게 협력하도록 설계되는 것입니다.
  • 낮은 결합도란 낮은 의존성을 나타내며, 즉 다른 모듈에 대한 지식을 얼만큼 가지고있는지를 나타내는 척도입니다.

7) Spring Boot의 어노테이션 중 @Getter와 @Setter의 무분별한 사용을 지양해야하는 이유는 무엇인가?

더보기

Getter와 Setter의 사용은 캡슐화를 위반하는 행위이기 때문입니다. 캡슐화는 객체의 상태는 숨기고 행동만을 외부에 공개해야합니다. 그렇기에 객체의 상태를 변경하거나 조회할 수 있는 Getter와 Setter은 캡슐화를 위반하는 것이 됩니다.

8) 상속이란?

더보기

상속이란 부모 클래스를 상속하여 기능을 추가하거나 재정의한 자식 클래스를 만드는 것을 의미합니다. 상속을 통해 코드의 중복을 없앨 수 있고 클래스 사이에 계층적인 관계를 구성해 다형성의 문법적 토대를 만듭니다

 

9) IS-A 관계와 HAS-A 관계의 차이점이란 무엇인가?

더보기

IS-A 관계는 'A는 B이다'와 같은 상속 관계를 나타냅니다. 이 정의에서 A는 상속을 받는 자식 클래스, B는 부모 클래스에 해당하며 예를들면 '사자는 동물이다'와 같이 사자가 완전히 동물에 종속되는 관계를 나타냅니다.

HAS-A 관계는 'A는 B를 가지고있다'와 같은 포함 관계를 나타냅니다. 이는 상속이 아닌 클래스가 다른 클래스를 소유하는 관계로, '컴퓨터는 CPU를 가지고있다'와 같이 컴퓨터 객체가 CPU 객체를 구성하 것과 같은 관계를 나타냅니다.

10) 다형성이란?

더보기

다형성이란 하나의 클래스나 함수가 다양한 방식으로 동작이 가능한 것을 의미합니다.

상속과 overriding을 통해 같은 타입의 객체더라도 다른 생성자로 생성된 객체는 동일한 이름의 함수를 다르게 동작시킬 수 있습니다.

또한 overloading을 통해 한 클래스 내에서 동일한 이름의 함수를 서로 다른 매개변수 타입과 개수를 가지게 해 동일한 이름이더라도 다양한 방식으로 동작할 수 있습니다.

 


11) 자바의 컴파일 과정을 설명하시오

더보기

개발자가 .java 소스파일을 작성합니다.

자바 컴파일러가 소스 파일을 컴파일해 JVM이 이해할 수 있는 .class 자바 바이트코드 파일을 생성합니다.

JVM내의 클래스 로더를 통해 바이트코드 파일을 JVM 메모리 내로 로드합니다.

JVM은 각 OS가 실행할 수 있는 기계어로 변환시킵니다

12) JVM (Java Virtual Machine) 의 역할은 무엇인가?

더보기

스택 기반으로 동작하는 가상 머신인 JVM은 자바 바이트 코드 파일을 OS에 맞게 해석해주는 역할과 가비지 컬렉션을 통해 메모리 관리를 해주는 역할을 가지고있습니다.

13) JVM의 내부 구조는?

더보기

JVM의 구조는 크게 garbage collector, execution engine, class loader, runtime data area가 있고 각자의 역할에 따라 동작합니다

  • Garbage collector는 heap 메모리 영역에서 동적으로 할당했던 메모리 중 유효하지 않은 메모리인 garbage를 주기적으로 정리해 주는 역할을 합니다.
  • Execution engine는 클래스 로더를 통해 JVM 내의 Runtime Data Area에 배치된 바이트 코드들을 명렁어 단위로 읽어서 실행합니다. 
  • Class loader은 JVM 내로 .class 파일을 로드하고, JVM이 운영체제로부터 할당 받은 Runtime Data Area에 적재합니다. 런타임 시에 동적으로 클래스를 로드합니다.
  • Runtime data area는 자바 어플리케이션을 실행할 때 사용되는 데이터들을 적재하는 데이터 영역으로, method, stack, heap, PC register, native method stack과 같은 다섯가지 영역으로 나누어져있습니다.

14) 자바의 메모리 영역의 종류와 그 특성은?

더보기

자바의 메모리 공간은 method, stack, heap, PC register, native method stack 영역으로 구분되고 데이터의 타입에 따라 적절한 영역에 할당됩니다.

  • Method 영역에는 전역 변수, static으로 선언되는 것들을 저장하며, 클래스 정보, static 변수, 변수 정보, 메소드 정보, 런타임 상수풀등을 저장합니다. 프로그램의 시작부터 종료까지 메모리에 남아있으며 모든 쓰레드가 공유합니다. 그렇기 때문에 이 영역에 저장되어있는 데이터들을 어디서든 사용할 수 있게 됩니다. JVM이 동작해서 클래스가 로딩될 때 할당됩니다.
    • 런타임 상수풀: JVM은 런타임 상수풀에서 해당 메소드나 필드의 실제 메모리 상 주소를 찾아 참조합니다
  • Heap 영역에는 Object 타입의 데이터 배열을 저장합니다. 가비지 컬렉터가 주기적으로 관리하는 영역이기도합니다. Compile time시 할당되며 이 또한 모든 쓰레드가 공유합니다.
  • Stack 영역은 메서드 호출 시마다 스택 프레임(그 메서드만을 위한 공간)의 형태로 생성됩니다. 그리고 메서드 안에서 사용되는 값들을 저장하고, 호출된 메서드의 매개변수, 지역변수, 리턴 값 및 연산 시 일어나는 값들을 임시로 저장합니다. 만약, 지역변수이지만 Reference Type일 경우에는 Heap 에 저장된 데이터의 주소값을 Stack 에 저장해서 사용하게 됩니다. 마지막으로, 메서드 수행이 끝나면 프레임별로 삭제하게되고 쓰레드 당 하나씩 존재합니다.
  • PC register 영역은 쓰레드가 생성될 때마다 생성되는 영역으로 프로그램 카운터, 즉 현재 스레드가 실행되는 부분의 주소와 명령을 저장하고 있는 영역입니다.
  • Natvie method stack 영역은 자바 외 언어로 작성된 네이티브 코드를 위한 메모리 영역입니다. JNI(Java Native Interface)를 통해 호출되는 다른 언어의 코드를 수행하기 위해 존재합니다.

15) 가비지 컬렉션을 위해 만들어진 heap 영역의 구조와 가비지 컬렉션의 동작방식은?

더보기

Heap 영역은 young generation, tenured generation으로 나누어져있으며 해당 영역은 application에서 사용됩니다. Java 7까지는 이에 추가로 JVM이 사용하는 permanent generation영역이 존재했으나 Java 8부터는 OS가 관리하는 native 영역의 메모리의 Metaspace로 바뀌었습니다.

Young generation은 또다시 eden영역과 survivor 영역으로 나누어져있습니다. Heap영역에 객체가 새로 생성되면 eden에 저장이 되고 eden이 어느정도 차면 참조 정도에 따라 survivor 영역의 빈 공간으로 이동됩니다.

Tenured generation에는 old영역이 있으며 young generation 영역이 차게되면 참조 정도에 따라 이 영역으로 옮겨집니다. 이 과정은 minor garbage collection이라고 불립니다. Old 영역의 허용치가 넘어가면 old 영역에 있는 모든 객체들을 검사하여 참조되지 않는 객체들을 한꺼번에 삭제하는 major GC가 진행됩니다. Major GC가 진행되는 중에는 GC를 진행하는 쓰레드를 제외한 모든 쓰레드가 멈추는 'stop-the-world'가 발생합니다.


16) Java 7의 특징은?

더보기
  • Try-with-resources 지원: try문 안에서 사용되는 Connection, Files, Input/OutStream 등과 같은 자원들을 자동적으로 해제를 할 수 있게 되었습니다.
    • try (final InputStream inputStream = connection.getInputStream();
                   final OutputStream outputStream = connection.getOutputStream()){ /*code*/ }
  • 다이아몬드 연산자를 활용한 Type Reference(타입 추론)지원: 생성자 호출시에 필요한 파라미터(매개변수)를 다이아몬드 연산자(<>)을 사용함으로 생략할 수 있습니다.
    • Map<String, List<String>> myMap = new HashMap<>();
  • 다중 Exception Catching: 하나의 catch 블록에서 여러개의 예외처리가 가능합니다.
    • try{ /*code*/ } catch (FirstException | SecondException ex) {
           log.info(ex);
           throw ex;
      }
  • 숫자 리터럴에서 언더스코어(underscore) 지원: 숫자 리터럴의 숫자 사이에 언더스코어(_)를 사용할 수 있습니다. 이 구분자를 사용하면 의미 있는 숫자끼리 그룹화하는 것이 가능하며, 이로 인해 코드의 가독성이 높아집니다.
    • int oneMillion = 1_000_000;
  • Switch문에서 String 객체 사용가능

17) Java 8의 특징은?

더보기
  • Heap Permanent Generation 제거: 이전에는 permanent generation이라는 이름을 가지고 초기 설정시 설정해여야했던 메모리가 metaspace로 변경되었습니다. Metaspace는 런타임시 메모리 요구 사항에 따라 다이나믹하게 자체 크기 조절이 가능하며 OS레벨에서 관리되는 native 메모리 영역에 위치합니다. 
  • Interface에 Default, Static Methods를 추가할 수 있게됨: default method는 하위 클래스에서 재정의가 가능하지만 static method는 불가합니다.
  • 함수형 interfaces: 하나의 기능을 제공하는 단 하나의 추상 메소드를 정의하는 인터페이스가 추가되었습니다. 단, 추상 메소드 외에 디폴트 메소드나 정적 메소드는 원하는 만큼 사용할 수 있고, @FunctionalInterface와 함께 쓰이며, 만약 추상 메소드가 여러 개라면 컴파일 타임에서 에러를 잡아낼 수 있습니다. 주요 함수형 인터페이스로는 Consumer, Supplier, Function 등이 있습니다.
  • 람다 표현식: 람다 표현식은 함수를 식으로 나타내는 것으로 함수를 변수로 나타낼 수 있다는 장점이 있습니다.이러한 람다 표현식은 기존의 불필요한 코드를 줄여주고, 작성된 코드의 가독성을 높이는 데 그 목적이 있습니다. Java 8 버전부터는 람다 표현식을 사용하여 자바에서도 함수형 프로그래밍을 할 수 있게 되었습니다. 
  • 메서드 참조: 람다식의 가독성을 높이기 위해 사용하는 방법입니다. 종류로는 정적 메서드참조, 인스턴스 메서드 참조, 특정 유형의 객체의 인스턴스 메서드 참조, 생성자 참조 등이 있으며 모두 더블콜론을 사용하여 사용됩니다.
  • Stream API: 스트림은 컬렉션의 저장 요소를 하나씩 참조해서 람다식으로 처리할 수 있도록 해 주는 내부 반복자입니다. 스트림 API는 데이터를 추상화하여 다루므로, 다양한 방식으로 저장된 데이터를 읽고 쓰기 위한 공통된 방법을 제공합니다. 
    • 컬렉션은 데이터를 어떻게 저장/관리하고 접근하는지를 목표하고 있습니다.
      이와 반대로 스트림은 데이터를 직접 접근하거나 조작하는 기능을 제공하지 않으며, 데이터를 어떻게 계산할지에 대한 목표를 가지고있습니다.
      즉, 데이터의 저장/관리가 목적이라면 컬렉션을, 데이터의 계산이 목적이라면 스트림을 사용하는게 좋다고 볼 수 있습니다.
  • Date and time API 지원 
  • Optional 지원: null에 대한 참조를 안전하게할 수 있게됩니다.
  • 배열 정렬의 병렬처리: 이전의 Arrays.sort는 merge sort와 같은 순차적 실행이 되는 방식을 사용했으나 Arrays.parallelSort가 추가되며 병렬처리가 가능해졌습니다.
  • Base64 encoding and decoding 지원

18) Java 11의 특징은?

더보기
  • String, Files 클래스와 Collection 인터페이스에 새로운 메서드가 추가되었습니다.
  • 람다에서 로컬변수인 var을 이용할 수 있게되었습니다.
  • javac를 통해 컴파일하지 않고 바로 컴파일할 수 있게되었습니다
  • Default garbage collector이 parallelGC에서 G1GC로 변경되었으며 G1GC는 더 좋은 성능을 냅니다.

19) 많은 기업이 아직 Java 8을 사용하는 이유는?

더보기

Java 8보다 나중에 나온 LTS인 Java 11과 Java 17보다도 더 긴 지원기간을 가지고있습니다.


20) 제네릭이란?

더보기

데이터 타입을 일반화 하는 것으로, 데이터 타입에 대한 정의를 외부로 미루는 것입니다.

21) String, StringBuilder, StringBuffer의 차이점은?

더보기

String은 불변하는 특성을 가지고있기 때문에 수정이 불가합니다. 따라서 수정이 발생할때마다 새로운 인스턴스가 생성되고 이전 값들은 가비지 컬렉션 발생 시 삭제됩니다. StringBuffer은 가변하는 특성을 가지고있으며 동기화를 지원하기 때문에 멀티스레드 환경에서 안전합니다. StringBuilder 또한 가변하는 특성을 가지고있으나 동기화를 지원하지 않기에 멀티스레드 환경에서 사용하기에 적합하지 않으나 단일 스레드 환경이라면 StringBuffer보다 높은 성능을 보입니다.

22) String을 선언할 때 따옴표를 사용하는 것과 new를 사용하는 것의 차이점은?

더보기

String은 primitive type가 아니기 때문에 heap에 저장됩니다. 그러나 java는 String 객체를 다른 객체들과 달리 heap 메모리 영역 안의 String constant pool에서 관리합니다. 만약 따옴표로 선언이 되면 이 String 상수풀에서 해당 값을 가진 String이 있는지 확인하고 있다면 그 주소값을 리턴하고, 없다면 String 상수풀에 해당 객체를 생성, 할당한 뒤 그 주소값을 리턴합니다. 이를 통해서 같은 값을 가진 String 객체가 생성되는 것을 막을 수 있습니다.

만약 new를 사용한다면 다른 객체들처럼 강제로 heap 영역에 객체를 생성합니다. 그러나 이럼에도 다른 객체와 다르게 동작하는데, 만약 new를 사용했다 하더라도 String 상수풀에 그 값이 있는지 확인하고 없다면 String 상수풀에도 객체를 생성하여 총 두개의 객체를 생성합니다.

 

'CS > 면접준비' 카테고리의 다른 글

네트워크  (0) 2024.08.17
데이터베이스  (0) 2024.08.17
운영체제  (0) 2024.08.17

+ Recent posts