상세 컨텐츠

본문 제목

[BACKEND] 백엔드 개발 기술면접 준비(1) 객체지향프로그래밍과 자바

취준/1. 기술면접

by ranlan 2022. 2. 1. 02:43

본문

728x90

기술면접 준비(1) 객체지향프로그래밍(OOP)과 자바(JAVA)

 

 

Q. 자바와 C의 차이점

A. C언어대표적인 절차지향 프로그래밍 언어로 인간의 명령어를 컴퓨터가 이해할 수 있는 기계어로 변환시켜주는 역할을 한다. C언어는 시스템 간 호환이나 이식성이 좋고 고급언어와 저급언어간의 인터페이스가 용이하다는 특징이 있다. 따라서 객체지향 언어보다 처리 속도가 더 빠르다.

반면 JAVA대표적인 객체지향 프로그래밍 언어로 캡슐화, 상속, 다형성 등 객체지향 프로그래밍 언어의 특성들을 갖는다. 자바의 경우 인터넷의 분산환경에서 사용되도록 설계된 언어이며 인터넷 환경 기반의 프로그램을 만들고 수행시킬 수 있는 응용 프로그램을 만들 수 있다.

 

 

Q. 자바와 C++의 공통점과 차이점

A. 두 언어 모두 대표적인 객체지향 프로그래밍 언어이다. 

  • 자바는 보안, 이식성, 빠른 개발에 비중을 두었고 C++는 C언어와의 하위 호환성에 중점을 두고 설계되었다. 따라서 C++는 C에서 사용하는 포인터와 전처리기 같은 기능들을 모두 이용할 수 있다.
  • 자바는 가상머신 위에서 동작하며 바이트 코드로 컴파일되면 각 운영체제에 맞는 JVM을 통해 실행할 수 있다(JVM이 설치되면 OS에 독립적으로 사용 가능하다). 반면 C++는 OS에 맞는 기계어로 컴파일되어 일반적으로 C++이 자바보다 빠르다.
  • C++는 다중 상속이 가능하지만 자바는 다중 상속이 불가능하다(단 인터페이스는 다중상속을 할 수 있다).
  • 자바는 객체를 힙(Heap)영역에만 할당할 수 있으나 C++은 힙(Heap)과 스택(Stack)에 모두 할당 가능하다. 메모리 관리의 경우 C++는 개발자가 직접 메모리를 해제할 수 있으나 자바는 GC를 이용해 불필요한 메모리를 자동으로 해제한다.

 

 

Q. 자바 메모리 영역

A. Runtime Data Area는 자바 애플리케이션이 실행될 때 데이터를 적재하는 영역이다.

  • Method Area
    모든 스레드가 공유하는 영역으로 JVM이 읽어들인 클래스, 인터페이스에 대한 런타임 상수 풀, 멤버 변수, 클래스 변수 등을 저장한다.
  • Heap(힙)
    new 키워드로 생성된 객체와 배열이 저장되는 공간이다.
    런타임 시 동적으로 할당하여 사용하는 공간이다. 모든 쓰레드가 공유하고 GC가 참조되지 않는 메모리를 확인하고 제거한다.
  • Stack(스택)
    지역변수, 파라미터, 리턴 값 등 연산에 사용되는 임시 데이터를 저장한다.
    각 스레드마다 하나씩 존재하며(스레드간 공유하지 않음) 후입선출의 구조이다.
    메서드 호출 시 생성되는 스레드 수행정보를 기록하는 프레임을 저장한다.

    기본 타입 변수는 스택 영역에 직접 값을 갖고 참조 타입 변수는 힙 영역이나 메서드 영역의 객체 주소를 갖는다.
    * 참조 변수의 메모리 주소는 스택에 저장되지만 그 주소가 가르키는 메모리는 힙에 저장되어있다.
  • PC(Program Counter) 레지스터
    현재 수행중인 JVM의 명령 주소를 갖는다.
  • Native Method Stack
    자바 외 다른 언어로 작성된 코드 정보를 저장한다.

 

 

Q. JAVA의 특징

A. JAVA는 미국 썬마이크로시스템이 개발한 대표적인 객체지향 프로그래밍 언어이다.

  • JVM만 설치하면 컴퓨터 운영환경에 상관없이 작동한다(운영체제에 독립적이다).
    * 자바 컴파일러에 의해 자바 소스 파일은 바이트코드로 변환된다. 변환된 바이트코드를 JVM에서 읽어 운영체제에 맞게 실행될 수 있도록 한다.
  • JAVA는 GC(Garbage Collection)이라는 자동 메모리 관리 기능을 제공한다. JVM이 지속적으로 메모리를 감시하며 더 이상 사용되지 않는 메모리를 해제한다.
  • 객체지향 프로그래밍 언어로 캡슐화, 상속, 다형성등의 특성을 지닌다.
  • 멀티스레드를 지원한다.

 

 

Q. 스레드(Thread) / 멀티스레드(Multi-Thread) / 멀티프로그래밍(Multi-Programming)

  • 스레드란 프로세스 내에서 실행되는 흐름의 단위로 프로그램 실행의 최소 단위이다.
  • 멀티스레드하나의 프로세스내에서 여러 스레드가 실행되는 것을 의미하며
  • 멀티 프로그래밍이란 여러 프로그램이 동시에 실행되는 것을 의미한다. 멀티스레드의 경우 한 프로세스내의 메모리가 공유되지만 멀티프로그래밍에서 프로세스는 각각 다른 메모리를 부여받는다.

자바에서의 스레드 생성 방법으로는 Thread 클래스를 이용하는 방법Runnable 인터페이스를 이용하는 방법이 있다.

 

* 멀티쓰레드를 사용하는 이유

  • 프로세스를 이용하여 동시에 처리하였던 일을 쓰레드로 구현할 경우 메모리 공간과 시스템 자원 소모가 줄어든다.
  • 쓰레드 간의 통신은 별도의 자원을 이용하는 것이 아닌 전역 변수의 공간 또는 동적으로 할당된 공간인 Heap(힙)영역을 이용하여 데이터를 공유할 수 있다.
  • 프로세스의 문맥 교환과 달리 캐시 메모리를 비울 필요가 없다.
  • 시스템의 처리량이 향상되고 자원소모가 줄어 프로그램의 응답 시간이 단축된다. 

 

 

Q. 프로그램(Program) / 프로세스(Process)

A. 프로세스는 실행중인 프로그램으로 프로세스는 프로세서의 상태, 메모리 영역 주소 공간, 스레드 정보, 전역 데이터 등을 포함한 정보를 말한다. 

* 문맥교환(Context-Switch)

하나의 프로세스가 CPU를 사용하다 다른 프로세스에게 CPU 사용을 넘겨주는 상황에서 이전 프로세스의 상태(문맥)을 보관하고 새로운 프로세스의 상태를 적재하는 작업

 

 

Q. 객체지향 프로그래밍(Object-Oriented Programming, OOP)

A. 컴퓨터 프로그래밍 패러다임 중 하나로 컴퓨터 프로그램을 여러 개의 독립된 단위인 객체들의 모임으로 파악하고자 하는 것이다. 구성요소로는 클래스, 객체, 메서드가 있고 메시지를 주고 받으며 데이터를 처리한다.

 

 

Q. 객체지향 프로그래밍의 특징

A. 객체 관점에서 프로그래밍 하는 것으로 프로세스가 함수(프로시저) 단위로 진행되는 절차 지향 프로그램과 달리 객체들간의 유기적인 관계를 통해 프로세스가 진행된다.

  1. 동적 바인딩
    실행 시간에 실시간으로 바인딩됨으로써 상속이나 다형성을 실현한다.
    * 동적 바인딩이란 런타임에 바인딩되는 것이며 정적 바인딩이란 컴파일 시간에 바인딩되는 것이다.
    * 바인딩이란 값들이 확정되어 변할 수 없는 상태가 되는 것으로 프로그램 내 각종 요소에 메모리 주소, 데이터 타입 또는 실제 값이 배정되는 것이다.
  2.  캡슐화(Encapsulation)데이터 은닉(hidden)
    데이터와 데이터를 처리하는 함수를 하나로 묶는 것이 캡슐화로 객체 외부에서는 객체 내부 정보에 직접 접근하거나 조작할 수 없도록 정의된 메서드만 이용 가능하게 한다. 캡슐화를 통해 다른 객체에게 자신의 정보를 숨기고 연산만을 통해 접근 가능하게 한다.
    • 객체의 손상과 오용을 막아 오류를 최소화할 수 있다.
    • 객체 내부의 조작 방법이 바뀌어도 사용 방법은 바뀌지 않는다.
    • 데이터가 바뀌어도 다른 객체에 영향을 주지 않아 독립성을 유지할 수 있다.
    • 처리된 결과만 사용함으로써 객체 이식성이 좋고 유지보수와 확장에 유리하다.
  3. 다형성(Polymorphism)
    여러 객체에서 동일한 명령을 내렸을 때 서로 다르게 반응하는 현상으로 오버라이딩과 오버로딩이 있다. 
  4. 상속(Inheritance)
    부모 클래스의 속성과 기능을 그대로 이어받아 사용할 수 있으며 기능의 일부분을 변경해야 할 경우 자식 클래스에서 상속받아 다시 수정하여 사용할 수 있다.
    * 다중 상속은 2개 이상의 클래스로부터 상속받을 수 있게 하는 기능으로 상속관계에 혼란을 줄 수 있어 언어마다 사용 가능 여부가 다르다. JAVA에서는 지원하지 않으나(인터페이스 다중 상속은 지원) C++, 파이썬등은 지원한다.
    * 다이아몬드 문제란 다중 상속을 했을 때 발생하는 문제로 조부모 클래스의 메서드를 오버라이딩한 두 부모클래스를 상속받았을 때 자식클래스에서 어떤 오버라이딩 메서드를 상속받아야하는지 혼란이 오는 문제이다.

 

Q. 객체지향 프로그래밍의 장점과 단점

A. 객체지향 프로그래밍의 장점

  • 만들어진 클래스를 상속을 통해 확장이 가능하여 코드 재사용이 용이하다.
  • 수정해야할 부분이 클래스 내부 변수 혹은 메서드로 있기 때문에 해당 부분만 수정하면 됨으로 유지보수가 쉽다.
  • 클래스 단위로 모듈화시켜 개발이 가능함으로 많은 인원과 각각의 개발이 필요한 프로젝트에서 업무 분담이 쉽다.
  • 직관적인 코드 분석이 가능하다.

객체지향 프로그래밍의 단점

  • 처리 속도가 상대적으로 느리며
  • 객체가 많으면 그에 따라 용량이 커진다.
  • 설계 시 많은 노력과 시간이 필요하다.

 

 

Q. 오버라이딩과 오버로딩

A. 객체지향 프로그래밍의 특성 중 하나인 다형성을 실현한다.

  • 오버라이딩은 상속 시 부모클래스의 메서드와 같은 이름, 같은 매개변수를 재정의하는 것이다.
  • 오버로딩같은 이름의 함수를 여러 개 정의하고 매개 변수의 타입과 개수를 다르게 하여 그에 따라 다르게 호출할 수 있게 하는 것이다.

 

 

Q. 인터페이스(Interface)와 추상클래스(Abstract Class)

A. 마찬가지로 객체지향 프로그래밍의 다형성을 실현한다.

  • 인터페이스란 기본 설계도와 같이 해당 인터페이스를 구현하는 모든 클래스에 대해 특정한 메서드가 반드시 존재하도록 강제하는 역할이다. 즉, 인터페이스를 구현한 객체들이 같은 동작을 한다는 것을 보장하기 위한 목적으로 생성자를 가질 수 없으며 객체 생성이 불가능하다.
  • 추상 클래스는 미완성 설계도와 같이 클래스 내에 추상 메서드가 한 개 이상 포함되거나 abstract로 정의된 경우를 말한다. 공통적인 기능을 하는 객체들을 추상화한 것이다. 추상 클래스의 경우도 따로 객체를 생성할 수 없으며 상속을 통해 자손 클래스에서 완성하도록 유도한다.
    * 추상메서드란 내용이 없는 메서드로 구현하지 않고 선언만 한 상태이다.

 

 

Q. Getter와 Setter는 무엇인가

A. Getter는 인스턴스 변수를 조회할 때 Setter는 인스턴스 변수를 등록, 수정할 때 사용한다.

객체 지향 프로그래밍 특성에 따르면 객체 외부에서 객체 내부에 접근하는 것을 막고 공개된 메서드를 통해 데이터를 변경하는 방법을 선호한다. 외부에서 데이터에 직접적인 접근을 막고 메서드를 공개하여 해당 메서드를 통해서만 객체 내부 변수에 접근하도록 한다.

 

 

Q. Try-Catch와 Throws는 언제 쓰이는가

A. 자바의 예외처리 방법이다.

  1. Try-Catch/Finally
    Try는 예외가 발생할 소스코드 블럭을 지정하고 Catch는 예외가 발생했을 시 처리할 내용을, Finally는 예외 발생 여부와 상관없이 실행될 소스코드 블럭을 포함한다. 발생할 에러의 이름을 안다면 각 Exception에 따른 다른 예외처리가 가능하다.
  2. Throws
    자신을 호출하는 메서드에 오류 처리를 위임한다. 한 가지 예외에 대해 상황에 따라 다른 예외 처리가 가능하다.

 

 

Q. Integer와 Int의 차이

A. Integer은 래퍼클래스이고 Int는 기본 자료형(원시 자료형)이다.

  • Primitive Type (기본 자료형, 원시 자료형)
    자바 컴파일러에 의해서 해석되는 byte, short, int, long, float, double, char, boolean 와 같은 기본 자료형이다. 실제 값을 갖는 자료형으로 자바에서 여러 형태의 타입을 미리 정의하여 제공하고 메모리 크기가 정해져있다.
    산술 연산과 0으로 초기화는 가능하지만 null값으로 초기화는 불가능하다.
  • Wrapper Class(래퍼 클래스)
    기본 타입의 데이터를 객체로 사용해야하는 경우 사용하며 각 타입에 해당되는 데이터를 인수로 전달받아 해당 값을 가지는 객체로 만들어 준다.
    언박싱(기본 타입으로 변환)없이 직접적인 산술 연산은 불가능하나 null값 처리는 가능하다.
    jdk1.5부터 자바 컴파일러가 자동 박싱/언박싱이 가능하다.

 

 

Q. 래퍼 클래스를 사용하는 이유

A. 자바는 int, char, short, long 등 기본 자료형의 값을 갖는 객체를 생성할 수 있다. 이런 객체를 래퍼 클래스(Wrapper Class)라고 한다. 

  • 기본 타입을 객체로 변환할 수 있다.
  • null값을 허용한다.
  • java.util 패키지의 클래스는 객체만 처리한다(제공하는 메서드의 파라미터로 객체만 허용하는 경우가 있다.).
  • 컬렉션 프레임워크는 객체 타입만 저장하고 자동 언박싱이 일어난다. (Generics<>)
  • 멀티 스레딩 환경에서 동기화를 위해 객체가 필요하다.

 

 

Q. 클래스(Class)객체(Object)의 차이점

A. 클래스란 객체를 만들기위한 설계도같은 것이다. 작성한 클래스를 인스턴스화(객체화)시켜 실제로 생성된 것이 객체이다.

 

 

Q. JDBC, JVM, JRE, JDK

A. 

    • JDBC는 자바와 데이터베이스 사이의 인터페이스를 제공하는 자바 API이다.
    • JVM(Java Virtual Machine)은 자바 소스코드로부터 만들어지는 바이너리 코드를 읽고 검증하고 OS에 맞게 변환하여 실행한다. JVM은 플랫폼에 의존적이나 JVM 위의 자바는 플랫폼 상관없이(OS 독립적으로) 실행된다.
      * JVM을 사용하는 이유? 자바 바이트 코드를 운영체제에 맞게 해석해준다. 또한 메모리 관리도 담당한다(GC).
    • JRE(Java Runtime Environment)는 자바 실행환경으로 자바 프로그램 동작에 필요한 라이브러리들을 갖고 있는 JVM의 실행환경을 구현한 것이다.
    • JDK(Java Development Kit)는 자바 개발도구로 자바 개발을 위해 필요한 도구들을 포함한다.

 

 

Q. 접근 제한자

A. 자바는 클래스 외부에서 내부로 접근할 수 있는 범위를 지정하는 접근지정자(접근제한자) 키워드를 제공한다.

  1. public
    클래스 내외, 패키지 내외 어디에서든 접근이 가능하며 공개 정도가 가장 높다.
  2. protected
    같은 패키지 내, 다른 패키지의 상속받은 자식 클래스에서만 접근이 가능하다.
  3. default(생략)
    같은 패키지 내에서만 접근이 가능하다.
  4. private
    동일 클래스 내에서만 접근 가능하며 공개 정도가 가장 낮다.
  같은 클래스 같은 패키지 다른 클래스 자식 패키지 다른 패키지
public O O O O
protected O O O X
default O O X X
private O X X X

 

Q. Static 키워드

A. static은 정적 멤버(변수, 메서드)를 생성하는 키워드이다.

* 정적 멤버란? 클래스에 고정된 멤버로 클래스 생성을 하지 않고 사용할 수 있는 필드와 메서드를 의미한다.

  • 메모리에 고정적으로 할당되어, 프로그램이 종료될 때 해제된다.
  • Heap이 아닌 Stack에 할당되며 모든 객체가 공유하여 하나의 멤버를 어디서든지 참조할 수 있는 장점을 가지지만 Garbage Collector의 관리 영역 밖에 존재하기에 프로그램 종료 시까지 메모리가 할당된 채로 존재하게 된다.
  • 공통적인 값을 유지해야하는 변수나 변하지 않는 값의 경우 static 키워드로 생성한다.
  • static 키워드로 생성된 변수는 클래스 생성 후 메모리가 할당되어 이후 인스턴스 생성 없이 사용이 가능하다.
    (호출 시간이 짧아진다)
  • static 메서드 내에서는 인스턴스 변수를 사용할 수 없다. 반대로 인스턴스 메서드 내에서는 static 멤버를 사용할 수 있다.
  • 하지만 여러번 생성되면 메모리 낭비 문제가 발생한다. 따라서 결코 변하지 않을 값인 경우 final 키워드와 함께 사용하기도 하며 상수로 사용하는 일이 많아 public 키워드와도 많이 사용된다.

 

 

Q. final 키워드

A. 엔티티를 한번만 할당하여 그 값을 수정할 수 없다. 초기화되지 않은 final 필드가 있다면 컴파일 에러가 발생한다.

final 클래스는 다른 클래스에 상속될 수 없으나 setter를 통한 접근은 가능하다.

final 메서드는 자식 클래스에서 오버라이딩될 수 없다(절대 상속되어선 안되는 함수에 사용).

 

 

Q. 컬렉션 프레임워크(Collection Framework)

A. ​​컬렉션 프레임워크는 다수의 데이터를 효과적으로 처리할 수 있는 표준화된 방법을 제공하는 클래스들의 집합이다.

크기가 고정적이고 메모리 낭비가 발생하는 배열의 단점을 해결하였다.

 

  • List(리스트)
    리스트 컬렉션은 데이터를 일렬로 늘어놓은 구조이다. 객체에 인덱스를 부여하여 인덱스로 검색, 삭제할 수 있는 기능을 제공한다. 리스트 컬렉션은 객체 자체를 저장하는 것이 아니라 객체의 주소를 참조한다. 동일한 객체를 중복 저장할 수 있는데 이 경우 동일한 주소가 참조된다. null도 저장이 가능한데 이 경우 해당 인덱스는 객체를 참조하지 않는다.
    리스트 인터페이스를 구현하는 대표적인 클래스에는 ArrayList, LinkedList, Vector가 있다.
  • Set(집합)
    선형 구조로 저장되는 리스트와 달리 집합은 순서가 저장되지 않는다. 따라서 인덱스 사용이 불가하다. 대신 객체 대상으로 반복자(Iterator)를 제공한다. 집합은 데이터를 중복해서 저장할 수 없으며 null값은 허용 가능하다(null도 마찬가지로 중복 저장 안됨).
    대표적인 구현 클래스로는 HashSet, TreeSet이 있다.
  • Map(맵)
    {키: 값}으로 구성된 객체를 저장하는 자료구조이다. 키는 중복 저장할 수 없으나 값은 중복 저장이 가능하다. 중복된 키가 들어오는 경우 새로운 값으로 대체된다.
    리스트처럼 인덱스가 아닌 키로 값에 접근하며 인덱스가 없다.
    대표적인 구현 클래스에는 HashMap, HashTable, LinkedHashMap, TreeMap등이 있다.

 

 

Q. ArrayList와 LinkedList의 차이 그리고 Vector

A. 모두 자바에서 List 인터페이스를 구현하는 방식으로 Collection구현체이다.

  • ArrayList
    내부적으로 데이터를 배열로 관리하며 데이터 추가/삭제 시 임시 배열을 생성해 데이터를 복사한다(따라서 초기에 배열 크기를 지정해주는 것이 좋다).
    인덱스를 사용하여 검색에 유리하다(O(1)). 하지만 임시 배열을 사용하기 때문에 데이터 추가/삭제의 경우 불리하다(최악의 경우 O(N)).
  • LinkedList
    내부적으로 노드 단위로 데이터를 관리한다. 따라서 자신의 앞 뒤 노드만 인지하는 상태이다.
    인덱스가 따로 없기 때문에 검색 시 모든 노드를 순회해아 함으로 검색에 불리하다(최악의 경우 O(N)). 하지만 데이터 추가/삭제 시 불필요한 데이터가 복사가 없어 유리하다(O(1)).
  • Vector
    동기화를 보장해준다. 하지만 단일스레드 상황에서는 성능 저하가 발생한다.
    데이터가 주어진 크기보다 늘어나면 공간을 두 배로 확보하기 때문에 메모리 낭비가 발생한다.

* 동기화가 필요한 경우 Vector보다는 Collection.synchronizedCollection, synchronizedList, synchronizedMap(Collection의 synchronized를 지원하는 자료구조)을 사용하는 것이 좋다.
* Array는 정적 길이를 제공하는 배열로 컬렉션 프레임워크가 아니다.

 

 

Q. Iterator vs Enumeration

A. 자바에서 제공하는 컬렉션에 대해 순차적으로 접근할 때 사용된다.

Enumeration은 초기 사용되었으며 jdk1.2 이후 등장한 Iterator은 컬렉션 인터페이스를 구현 상속한 모든 컬렉션 클래스에서 사용 가능하다. Enumeration은 컬렉션 집합을 통째로 복사하여 사용하기 때문에 Fail-Fast을 지원하지 않는다. 반면 IteratorFail-Fast 방식으로 접근자 생성 후 컬렉션에 변화가 생기면 ConcurrentModificationException이 발생한다.

 * Fail-Fast? 접근자 생성 후 컬렉션 추가, 수정 등 변화가 생기면 에러 발생

 

 

Q. 맵(Map), 해쉬맵(HashMap)과 해시테이블(HashTable)

A. 맵은 인터페이스로 해시맵과 해시테이블(jdk1.2 이후)은 Map 인터페이스 구현체이다.

해시맵과 해시테이블 둘 다 Map 인터페이스를 구현하는 키와 값으로 관리하는 자료구조이다. 키와 값을 해시 알고리즘에 의해 구현하였다. 

  • 쓰레드 동기화
    해시맵의 경우 동기화를 지원하지 않는다. 반면 해시테이블은 멀티 스레드 환경에서 동기화를 지원한다. 따라서 해시테이블이 좀 더 느리다.
    * 해시맵을 사용하고 동기화가 필요한 시점에서 ConcurrentHashMap을 사용하는 것을 권장한다. 
  • 순회
    해시맵은 저장된 요소 순회 시 Iterator(Fail-Fast)을 반환한다(ConcurrentHashMap은 Fail-Safe Iterator). 해시테이블은 Enumeration을(Not Fail-Fast) 반환한다
  • 보조 해시
    해시맵은 보조 해시를 사용하기 때문에 보조 해시를 사용하지 않는 해시테이블에 비해 해시 충돌이 덜 발생할 수 있다.
  • Null 값 허용
    해시테이블은 널을 허용하지 않지만 해시맵은 널값을 허용한다.

* ConcurrentHashMap? 해시맵에 thread-safe 하도록 만든 클래스로 키와 값에 널을 허용하지 않는다.

  • 해시맵
    HashMap<String,String> map1 = new HashMap<String,String>();
    HashMap<String,String> map2 = new HashMap<>(); // 타입 파라미터 생략가능
    HashMap<String,String> map3 = new HashMap<>(map1); //map1의 모든 값을 가진 HashMap생성
    HashMap<String,String> map4 = new HashMap<>(10); //초기 용량 지정
    HashMap<String,String> map5 = new HashMap<>(10, 0.7f);//초기 capacity, load factor지정
    HashMap<String,String> map6 = new HashMap<String,String>(){{ //초기값 지정
        put("a","b");
    }};
    
    map.put(key, value);
    map.remove(1); 
    map.clear();​

    해시맵은 저장공간보다 추가 데이터가 들어오면 크기를 늘리는데 두 배씩 늘린다. 과부하가 발생할 수 있음으로 초기 데이터 크기를 설정해주는 것이 좋다.
    HashMap<Integer,String> map = new HashMap<Integer,String>(){{
        put(1,"사과");
        put(2,"바나나");
        put(3,"포도");
    }};
    
    
    // entrySet.iterator()		
    Iterator<Entry<Integer, String>> entries = map.entrySet().iterator();
    while(entries.hasNext()){
        Map.Entry<Integer, String> entry = entries.next();
        System.out.println("[Key]:" + entry.getKey() + " [Value]:" + entry.getValue());
    }
    		
    // keySet.iterator()
    Iterator<Integer> keys = map.keySet().iterator();
    while(keys.hasNext()){
        int key = keys.next();
        System.out.println("[Key]:" + key + " [Value]:" +  map.get(key));
    }​
     
  • 해쉬테이블
    컬렉션 프레임워크가 만들어지기 전부터 있던 타입으로 컬렉션 프레임워크 명명법을 따르지 않는다. 

 

 

Q. String  / StringBuffer / StringBuilder

A. 자바에서 문자열을 다루는 클래스들이다. String과 StringBuffer, StringBuilder의 가장 큰 차이점은 불변 속성이다.

  • String
    String str = "hello"; // String str = new String("hello");
    str = str + " world";

    String 클래스의 참조 변수 str이 "hello world”라는 값을 가진 새로운 메모리 영역을 가르키도록 변경되고 처음 “hello”로 선언했던 메모리 영역은 Garbage로 남아있다가 GC(Garbage Collection)에 의해 사라진다.

    문자열을 자주 삭제, 수정하는 경우 힙 메모리에 많은 garbage가 남게 되어 힙메모리 부족으로 성능 저하로 이어진다.

    [정리] String 클래스는 힙 영역(GC가 동작하는 영역)에 생성되고 한번 생성된 객체 내부 내용을 변화시킬 수 없다. 기존 값에 변화가 생기면 새로 문자열을 저장하고 그 주소를 참조하도록 변경된다. 기존 데이터는 GC에 의해 회수된다.
    즉 수정 성능이 좋지 않다.

  • StringBuffer
    StringBuffer sb= new StringBuffer("hello");

    멀티스레딩 환경에서 안전하다(thread-safe).
  • StringBuilder
    멀티스레딩에서 동기화를 지원하지 않지만 단일스레딩 환경에서 훨씬 성능이 좋다.

jdk1.5 이후 컴파일 단계에서 String 객체를 사용하더라도 StringBuilder로 컴파일되도록 변경되었다. String 클래스와 StringBuilder 사용 시 성능 차이가 많이 없어졌으나 반복문을 사용해 문자열을 더할 경우 객체를 계속 추가한다는 사실은 변함없다.

 

 

Q. 자바 Generic(제네릭)

A. 클래스 내부에서 타입을 지정하는 것이 아닌 사용자가 외부에서 타입을 지정하는 것이다. 사용할 내부 데이터 타입을 컴파일 시 지정하는 것이다.
자바 코드에서 선언되고 사용된 제네릭 타입은 컴파일 시 컴파일러에 의해 자동으로 검사되어 타입 변환된다. 그 이후 모든 제네릭 타입은 제거되며 컴파일된 .class 파일에는 어떠한 제네릭 타입도 포함되지 않는다. 이는 제네릭을 사용하지 않는 코드와의 호환성을 위한 것이다.

  • 잘못된 타입이 들어오는 것을 컴파일 단계에서 알 수 있다.
  • 클래스 외부에서 타입을 지정해주기 때문에 따로 타입 변환을 거칠 필요가 없다.
  • 코드 재사용성이 높아진다.

 

 

Q. Junit

A. @Test 메서드가 호출될 때마다 새로운 인스턴스를 생성하며 독립적인 테스트를 수행한다. assert___ 메서드로 테스트 케이스의 수행 결과를 판단한다. 어노테이션을 제공하여 매우 쉽고 간결하게 테스트 코드 작성이 가능하다.

가장 최신 버전은 Junit 5이다.

 

 

Q. GC(Garbage Collection, 가비지 컬렉션)

A. 유효하지 않은 메모리가 바로 가비지이다. JVM의 엔진 중 하나로 GC는 사용하지 않는 메모리를 해제하여 자동으로 메모리 관리를 해준다.

JVM의 힙 영역은 두 가지를 전제로 설계되었다.

  • 대부분의 객체는 금방 접근 불가능한 상태(unreachable)가 된다.
  • 오래된 객체에서 새로운 객체로의 참조는 아주 적게 존재한다.

객체는 대부분 일회성이며 메모리에 오랫동안 남아있는 경우는 드물다는 것으로 따라서 객체의 생존 기간에 따라 물리적인 힙 영역을 나누게 된다.

* 힙(Heap)은 런타임시 동적으로 할당되는 공간으로 GC가 작용한다.

  • Young(Minor GC)
    새롭게 생성된 객체가 할당받는 영역으로 많은 객체가 이곳에서 생성되었다가 사라진다.
  • Old(Major GC, Full GC)
    Young 상태에서 살아남아 유지한 객체가 복사되는 영역
    복사되는 과정에서 Young 영역보다 크게 할당되며 크기가 큰 만큼 가비지는 적게 발생한다.

예외적인 상황으로 Old 영역의 객체가 Young 객체를 참조하는 경우도 존재하는데 이런 경우를 대비하여 Old 영역에는 512바이트의 덩어리(청크)로 되어있는 카드 테이블이 존재한다. 

 

카드테이블에는 Old 영역의 객체가 Young 객체를 참조할 때마다 그에 대한 정보가 표시된다

Young 영역에서 GC가 실행될 때 Old 영역에 존재하는 객체를 검사하여 참조되지 않은 Young 영역의 객체를 식별하는 것이 비효율적이기 때문에 카드 테이블만 조회하여 GC의 대상인지 식별할 수 있다.

 

GC 동작 방식은 크게 두 과정으로 나뉜다.

  1. Stop the World
    JVM이 애플리케이션의 실행을 멈춘다. 모든 쓰레드의 작업이 멈추고 GC 작업이 완료되면 다시 재개된다.
  2. Mark and Sweep
    GC가 모든 작업을 중단시키면 모든 변수와 객체를 스캔하며 각각이 어떤 객체를 참고하고 있는지 탐색한다. 사용되고 있는 메모리를 식별(mark)하고 식별되지 않은 객체를 메모리에서 제거(sweep)한다.

 

728x90

관련글 더보기

댓글 영역