JAVA - 기술 면접 질문

suesue lee·2022년 2월 4일
4

JAVA

목록 보기
1/6

❕ JAVA 의 문법과 특징 및 기본적인 개념을 이해하고 기술 면접에 대비 ❕


🤍 JAVA 프로그래밍이란? 🤍

  • JAVA와 C/C++ 의 차이점
    • JAVA와 C/C++ 의 가장 큰 차이점은 실행 환경이다.
    • JAVA 에서의 개발 : 컴파일 혹은 컴파일 + .jar 압축
      자바는 링크 과정이 없이 컴파일러가 바로 bite code 를 생성한다.
    • C/C++ 에서의 개발 : 컴파일 + 링크

JAVA 언어의 장단점

  • 장점
    • 운영체제에 독립적이다.
      : JVM (자바 가상머신) 에서 동작하기 때문에, 특정 운영체제에 종속되지 않는다.
    • 객체지향 언어이다.
      : ① 객체 지향적으로 프로그래밍하기 위해 여러 언어적 지원을 하고 있다. (캡슐화, 상속, 추상화, 다형성 등)
      ② 객체지향 패러다임의 특성상 비교적 이해하기 배우기 쉽다.
    • 자동으로 메모리를 관리 해준다.
      : ① JVM 에서 Grabage Collector 라고 불리는 데몬 thread(프로그램(프로세스) 실해으이 단위)에 의해 GC(Garbage Collector)가 일어난다.
      ② GC로 인해 별도의 메모리 관리가 필요 없으며 비즈니스 로직에 집중 할 수 있다.
    • 오픈소스이다.
      : ① 정확히 OpenJDK가 오픈소스이다. OracleJDK 는 사용 목적에 따라 유료가 될 수 있다.
      ② 많은 JAVA 개발자가 존재하고 생태계가 잘 구축되어 있어, 오픈소스 라이브러리가 풍부하며, 잘 활용하면 짧은 개발 시간 내에 안정적은 애플리케이션을 쉽게 구현할 수 있다.
    • 멀티스레드를 쉽게 구현할 수 있다.
      : 자바는 스레드 생성 및 제어와 관련된 라이브러리 API 를 제공하고 있기 때문에 실행되는 운영체제에 상관없이 멀티 스레드를 쉽게 구현할 수 있다.
    • 동적 로딩(Dynamic Loading)을 지원한다.
      : 애플리케이션이 실행될 때 모든 객체가 생성되지 않고, 각 객체가 필요한 시점에 클래스를 동적 로딩해서 생성한다. 또한 유지보수 시 해당 클래스만 수정하면 되기 때문에 전체 애플리케이션을 다시 컴파일 할 필요가 없기 때문에 유지보수가 쉽고 빠르다.
  • 단점
    • 비교적 속도가 느리다.
      : 자바는 한 번의 컴파일링으로 실행 가능한 기계어가 만들어지지 않고, JVM에 의해 기계어로 번역되고 실행하는 과정을 거치기 때문에 C나 C++ 의 컴파일 단계에서 만들어지는 완전한 기계어보다는 속도가 느리다. 하지만 하드웨어의 성능 향상과 바이트 코드를 기계어로 변환해주는 JIT 컴파일러와 같은 기술 적용으로 JVM 기능이 향상되어 속도의 격차가 많이 줄어들었다.
    • 예외처리가 불편하다.
      : 프로그래머 검사가 필요한 예외가 등장하면 무조건 프로그래머가 선언을 해주어야한다.

JAVA 의 접근 제어자의 종류와 특징 (UML에서 사용하는 표시)

접근제어자표시설명
public+어떤 클래스의 객체에서든 접근 가능
private-이 클래스에서 생성된 객체들만 접근 가능
protected#이 클래스와 동일 패키지에 있거나 상속 관꼐에 있는 하위 클래스의 객체들만 접근가능
package~동일 패키지에 있는 클래스의 객체들만 접근 가능

OOP 의 4가지 특징

  1. 추상화
    : 구체적인 사물들의 공통적인 특징을 파악해 이를 하나의 개념(집합)으로 다루는 것
  2. 캡슐화
    : 정보 은닉 (Information hiding) : 필요가 없는 정보는 외부에서 접근하지 못하도록 제한 하는 것
  3. 일반화 관계
    : 여러 개체들이 가진 공통된 특성을 부각시켜 하나의 개념이나 법칙으로 성립시키는 과정
  4. 다형성
    : 서로 다른 클래스의 객체가 같은 메세지를 받았을 때 각자의 방식으로 동작하는 능력

OOP 의 5대 원칙 (SOLID)

  • S : 단일 책임 원칙 (SRP, Single Responsibility Principle)
    → 객체는 단 하나의 책임만 가져야 한다.
  • O : 개방-폐쇄 원칙 (OCP, Open Closed Principle)
    → 기존의 코드를 변경하지 않으면서 기능을 추가 할 수 있도록 설계가 되어야 한다.
  • L : 리스코프 치환 원칙 (LSP, Liskov Substitution Principle)
    → 일반화 관계에 대한 이야기며, 자식 클래스는 최소한 자신의 부모 클래스에서 가능한 행위는 수행할 수 있어야 한다.
  • I : 의존 역전 원칙 (DIP, Dependencdy Inversion Principle)
    → 의존 관계를 맺을 때, 변화하기 쉬운 것 또는 자주 변화하는 것보다는 변화하기 어려운 것, 거의 변화가 없는 것에 의존하라는 것이다.
  • D : 인터페이스 분리 원칙 (ISP, Interface Segregation Principle)
    → 인터페이스를 클라이언트에 특화되도록 분리시키라는 설계 원칙이다.

객체지향 프로그래밍과 절차지향 프로그래밍의 차이

  • 절차지향 프로그래밍
    → 실행하고자 하는 절차를 정하고, 이 절차대로 프로그래밍 하는 방법이다.
    → 목적을 달성하기 위한 일의 흐름에 중점을 둔다.
  • 객체지향 프로그래밍
    → 실세 상의 물체를 객체로 표현하고, 이들 사이의 관계, 상호 작용을 프로그램으로 나타낸다.
    → 객체를 추출하고 객체들의 관계를 결정하고 이들의 상호 작용에 필여한 함수(메서드) 와 변수(필드)를 설계 및 구현한다.
    → 사람의 사고와 가장 비슷하게 프로그래밍을 하기 위해서 생성된 기법
    → 하나의 클래스를 바탕으로 서로 다른 상태를 가진 인스턴스를 만들면 서로 다른 행동을 하게 된다. 즉, 하나의 클래스가 여러개의 인스턴스가 될 수 있다는 점이 객체 지향이 제공하는 가장 기본적인 재활용성이라고 할 수 있다.

JAVA의 non-static 멤버와 static 멤버의 차이

  • non-static 멤버
    • 공간적 특성 :
      • 멤버는 객체마다 별도로 존재한다.
      • 인스턴스 멤버라고 부른다.
    • 시간적 특성 :
      • 객체 생성 시에 멤버가 생성된다.
      • 객체 생성 후 멤버 사용이 가능하다.
      • 객체가 사라지면 멤버도 사라진다.
    • 공유의 특성 :
      • 공유되지 않는다.
      • 멤버는 객체 내에 각각의 공간을 유지한다.
  • static 멤버
    • 공간적 특성 :
      • 멤버는 클래스당 하나가 생성된다.
      • 멤버는 별도의 공간에 생성된다. (객체 내부❌)
      • 클래스 멤버 라고 부른다.
    • 시간적 특성 :
      • 클래스 로딩 시에 멤버가 생성된다.
      • 객체가 생기기 전에 이미 생성된다.
      • 객체가 생기기 전에 사용이 가능하다. (즉, 객체를 생성하지 않고도 사용가능)
      • 객체가 사라져도 멤버는 사라지지 않는다.
      • 멤버는 프록램이 종료될 때 사라진다.
      • 공유의 특성 : 동일한 클래스의 모든 객체들에 의해 공유된다.

JAVA의 final 키워드 (final/finally/finalize)

  • final 키워드
    • 개념 : 변수나 메서드 또는 클래스가 '변경 불가능'하도록 만든다.
    • 원시 (Primitive) 변수에 적용시
      • 해당 변수의 값은 변경이 불가능 하다.
    • 참조 (Reference) 변수에 적용시
      • 참조 변수가 힙(heap)내의 다른 객체를 가리키도록 변경할 수 없다.
    • 메서드에 적용 시
      • 해당 메서드를 Override 할 수 없다.
    • 클래스에 적용 시
      • 해당 클래스의 하위 클래스를 정의 할 수 없다.
  • finally 키워드
    • 개념 : try/catch 블록이 종료될 때 항상 실행될 코드 블록을 정의하기 위해 사용한다.
    • finally 는 선택적으로 try 혹은 catch 블록 뒤에 정의할 때 사용한다.
    • finally 블록은 예외가 발생하더라도 항상 실행된다.
      • 단, JVM이 try 블록 실행 중에 종료되는 경우는 제외한다.
    • finally 블록은 종종 뒷 마무리 코드를 작성하는데 사용된다.
    • finally 블록은 try 와 catch 블록 다음과, 통제권이 이전으로 다시 돌악가기 전 사이에 실행된다.
  • finalize() 메서드
    • 개념 : 쓰레기 수집기 (GC, Garbage Collector) 가 더이상의 참조가 존재하지 않는 객체를 메모리에서 삭제하겠다고 결정하는 순간 호출된다.
    • Object 클래스의 finalize() 메서드를 오버라이드해서 맞춤별 GC를 정의할 수가 있다.
     	 protected void finalize() throws Throwable { // 파일 닫기, 자원 반환 등 등 }

JAVA의 제네릭(Generic)

  • JAVA의 제네릭 (Generic)

    • 개념 : 모든 종류의 타입을 다룰 수 있도록 일반화 된 타입 매개 변수(generic type)로 클래스나 메서드를 선언하는 기법

  • 처리 방법 : 타입 제거(type erasure) 라는 개념에 근거한다.

    • 소스 코드를 JVM이 인식하는 바이트 코드로 변환할 때 인자로 주어진 타입을 제거하는 기술이다.
    • 제네릭이 있다고 해서 크게 달라지는 것은 없다. 단지 코드를 좀 더 예쁘게 만들 뿐이다.
    • 그래서 JAVA 의 제네릭(Generic)은 때로는 문법점 양념(Syntactic Sugar) 이라고 부른다.
      Vector<String> vector = new Vector<String>();
      vector.add(new String("hello"));
      String str = vector.get(0);
      // 컴파일러가 아래와 같이 변환
      Vector vector = new Vector();
      vector.add(new String("hello"));
      String str = (String) vector.get(0);

클래스, 객체, 인스턴스의 차이

  • 클래스 (Class)

    • 객체를 만들어 내기 위한 설계도 혹은 틀
    • 연관되어 있는 변수와 메서드의 집합
  • 객체 (Object)

    • 소프트웨어 세계에서 구현할 대상
    • 클래스에 선언된 모앙 그대로 생성된 실체
    • '클래스의 인스턴스(instance)' 라고도 부른다.
      → 메모리에 할당된 실체화 된 인스턴스를 '객체'라고 부른다.
    • 객체는 모든 인스턴스를 대표하는 포괄적인 의미를 갖느다.
    • OOP 의 관점에서 클래스의 타입으로 선언되었을 때 '객체' 라고 부른다.
  • 인스턴스 (Instance)

    • 설계도를 바탕으로 소프트웨어 세계에서 구현된 구체적인 실체
      → 즉, 객체를 소프트웨어에 실체화 하면 그것을 '인스턴스'라고 부른다.
      • 실체화 된 인스턴스는 메모리에 할당된다.
    • 인스턴스는 객체에 포함된다고 볼 수 있다.
    • OOP의 관점에서 객체가 메모리에 할당되어 실제 사용될 때 '인스턴스'라고 부른다.
    • 추상적인 개념(또는 명세)과 구체적인 객체 사이의 관계에 초점을 맞출 경우에 사용한다.
      • '~의 인스턴스'의 형태로 사용된다.
        객체는 클래스의 인스턴스다.
        객체 간의 링크는 클래스 간의 연관 관계의 인스턴스이다.
        * 실행 프로세스는 프로그램의 인스턴스이다.
  • 즉, 인스턴스라는 용어는 반드시 클래스와 객체 사이의 관계로 한정지어서 사용할 필요는 없다.

    • 인스턴스는 어떤 원본(추상적인 개념)으로부터 '생성된 복제본'을 의미한다.

          /* 클래스 */
                 public class Animal {
                 ...
                 }
         /* 객체와 인스턴스 */
                 public class Main {
                   public static void main(String[] args) {
                       Animal cat, dog; // '객체'
      
          // 인스턴스화
                   cat = new Animal(); // cat은 Animal 클래스의 '인스턴스'(객체를 메모리에 할당)
                   dog = new Animal(); // dog은 Animal 클래스의 '인스턴스'(객체를 메모리에 할당)
               }
             }
  • Q. 클래스 VS 객체

    • 클래스는 '설계도', 객체는 '설계도로 구현한 모든 대상'을 의미한다.
  • Q. 객체 VS 인스턴스

    • 클래스의 타입으로 선언되었을 때 객체라고 부르고, 그 객체가 메모리에 할당되어 실제 사용될 때 인스턴스라고 부른다.
    • 객체는 현실 세계에 가깝고, 인스턴스는 소프트웨어 세계에 가깝다.
    • 객체는 '실체', 인스턴스는 '관계'에 초점을 맞춘다.
      • 객체를 '클래스의 인스턴스'라고도 부른다.
    • '방금 인스턴스화하여 래퍼런스를 할당한' 객체를 인스턴스라고 말하지만, 이는 원본(추상적인 개념)으로부터 생성되었다는 것에 의미를 부여하는 것일 뿐 엄격하게 객체와 인스턴스를 나누긴 어렵다.
  • 추상화 기법
    ① 분류 (Classification)

    • 객체 → 클래스
      * 실재하는 객체들을 공통적인 속성을 공유하는 범부 또는 추상적인 개념으로 묶는 것
      ② 인스턴스화 (Instantiation)
    • 클래스 → 인스턴스
    • 분류의 반대 개념. 범주나 개념으로부터 실재하는 객체를 만드는 과정
    • 구체적으로 클래스 내의 객체에 대해 특정한 변형을 정의하고, 이름을 붙인 다음, 그것을 물리적인 어떤 장소에 위치시키는 등의 작업을 통해 인스턴스를 마드는 것을 말한다.
    • '예시(Exemplification)' 라고도 부른다.

오버로딩과 오버라이딩의 차이(Overloading VS Overriding)

  • 오버로딩 (Overloading)
    • 두 메서드가 같은 이름을 갖고 있으나 인자의 수나 자료형이 다른 경우
    • 예시)
      • public double computeArea(Circle c) {...}
      • public double computeArea(Circle c1, Circle c2 {...}
      • public double computeArea(Square c) {...}
  • 오버라이딩 (Overriding)
    • 상위 클래스의 메서드와 이름과 용례(signature)가 같은 함수를 하위 클래스에 재정의 하는 것
    • 상속 관계에 있는 클래스 간에 같은 이름의 메서드를 정의
    • 예시) Circle 에서 printMe() 메서드를 재정의 한다.
      • public abstract class Shape {
        public void printMe() { System.out.println("Shape"); }
        public abstract double computeArea();
        }
        public class Circle extends Shape {
        private double rad = 5;
        @Override // 개발자의 실수를 방지하기 위해 @Override(annotation) 쓰는 것을 권장
        public void printMe() { System.out.println("Circle"); }
        public double computeArea() { return rad * rad * 3.15; }
        }
        public class Ambiguous extends Shape {
        private double area = 10;
        public double computeArea() { return area; }
        }

Call by Reference와 Call by Value 의 차이

  • Call by Value (값에 의한 호출)

    • 함수가 호출될 때, 메모리 공간 안에서는 함수를 위한 별도의 임시 공간이 생성된다.
    • 함수 호출시 인자로 전달되는 변수의 값을 복사하여 함수의 인자로 전달한다.
    • 복사된 인자는 함수 안에서 지역적으로 사용되는 local value의 특성을 가진다.
    • 따라서 함수 안에서 인자의 값이 변경되어도, 외부의 변수의 값은 변경되지 않는다.
  • Call by Reference (참조에 의한 호출)

    • 함수가 호출될 때, 메모리 공간 안에서는 함수를 위한 별도의 임시 공간이 생성된다.
    • 함수 호출 시 인자로 전달되는 변수의 레퍼런스를 전달한다. (해당 변수를 가르킨다.)
    • 따라서 함수 안에서 인자의 값이 변경되면, 인자로 전달된 변수의 값도 함께 변경된다.
  • JAVA는 Call by Value 일까? Call by Reference 일까?

    public void setName(String name) {
        this.name = name;
    	  }
    @Override
    public String toString() {
        return "name is " + this.name;
    	 }
    }
    public class FunctionCallTest {
    public static void assignNewPerson(Person p) {
      p = new Person("hee");
    	 }
    public static void changeName(Person p) {
      p.setNaem("hee");
    	 }
    public static void main(String[] args) {
      Person p = new Person("doy");
    
      assignNewPerson(p);
      System.out.println(p); // name is doy
    
      changeName(p);
      System.out.println(p); // name is hee
    	 }
    } 
  • 기본자료형은 Call By Value 이고, 참조자료형은 Call By Reference 이다?

    • 오해 1. 특정 메서드 내에서 전달 받은 객체의 상태를 변경할 수 있다.
    • changeName 메서드는 참조변수 p 가 가르키는 [이르므 속성이 "doy"인 Person객체]를 [이름 속성이 "hee"인 새로운 Person 객체]로 변경한 것이 아니라, 단지 이름 속성만 변경했을 뿐이다.
    • 오해 2. 참조변수는 임의의 객체에 대한 래퍼런스를 저장하므로 메서드로 전달한 값이 래퍼런스(Call by Reference)이다.
    • 여기서 value 란?
      • 기본자료형의 값 또는 객체에 대한 래퍼런스이다.
      • 기본자료형의 경우 해당하는 변수의 값을 복사해서 전달한다.
    • 참조자료형의 경우 해당하는 변수가 가지는 값이 레퍼런스이므로 인자로 넘길 때, Call by Value에 의해 변수가 가지고 있는 레퍼런스가 복사되어 전달된다.

인터페이스와 추상클래스의 차이 (Interface VS Abstract Class)

  • 추상 메서드(Abstract Method)

  • abstract 키워드와 함께 원형만 선언되고, 코드는 작성되지 않은 메서드

    public abstract String getName(); // 추상 메서드
    public abstract String fail() {return "Fail";} // 추상 메서드 X
  • 추상 클래스 (Abstract Class)

    • 개념 : abstract 키워드로 선언된 클래스
      a. 추상메서드를 최소 한 개 이상 가지고 abstract 로 선언된 클래스
      → 최소 한 개의 추상 메서드를 포함하는 경우 반드시 추상 클래스로 선언하여야 한다.
      b. 추상메서드가 없어도 abstract로 선언한 클래스
      → 그러나 추상 메서드가 하나도 없는 경우라도 추상 클래스를 선언할 수 있다.
    • 추상 클래스의 구현
      → 서브 클래스에서 슈퍼 클래스의 모든 추상 메서드를 오버라이딩하여 실행가능한 코드로 구현한다.
    • 추상 클래스의 목적
      → 객체(인스턴스)를 생성하기 위함이 아니며, 상속을 위한 부모 클래스로 활용하기 위한 것이다.
      → 여러 클래스들의 공통된 부분을 추상화(추상 메서드) 하여 상속받는 클래스에게 구현을 강제화하기 위한 것이다. (메서드의 동작을 구현하는 자식 클래스로 책임을 위임)
      → 즉, 추상 클래스의 추상 메서드를 자식 클래스가 구체화하여 그 기능을 확장하는 데 목적이 있다.
      /* 개념 a의 예시 */
      abstract class Shape { // 추상 클래스
      Shape() {...}
      void edit() {...}
      abstract public void draw(); // 추상 메서드
      }
      /* 개념 b의 예시 */
      abstract class Shape { // 추상 클래스
      Shape() {...}
      void edit() {...}
      }
      /* 추상 클래스의 구현 */
      class Circle extends Shape {
      public void draw() { System.out.println("Circle"); } // 추상 메서드 (오버라이딩)
      void show() { System.out.println("동그라미 모양");
      	}
      }
  • 인터페이스 (Interface)

    • 개념 : 추상 메서드와 상수만을 포함하여, interface 키워드를 사용하여 선언한다.
    • 인터페이스의 구현
      → 인터페이스를 상속받고, 추상 메서드를 모두 구현한 클래스를 작성한다.
      → implements 키워드를 사용하여 구현한다.
    • 인터페이스의 목적
      → 상속받을 서브 클래스에게 구현할 메서드를의 원형을 모두 알려주어, 클래스가 자신의 목적에 맞게 메서드를 구현하도록 하는 것이다.
      구현 객체의 같은 동작을 보장하기 위한 목적이 있다.
      → 즉, 서로 관련이 없는 클래스에서 공통적으로 사용하는 방식이 필요하지만 기능을 각각 구현할 필요가 있는 경우에 사용한다.
  • 인터페이스의 특징
    a. 인터페이스는 상수 필드와 추상 메서드만으로 구성된다.
    b. 모든 메서드는 추상 메서드로서, abstract public 속성이며 생략 가능하다.
    c. 상수 public static final 속성이며, 생략하여 선언할 수 있다.
    d. 인터페이스를 상속받아 새로운 인터페이스를 만들 수 있다.
    * interface MobilePhone extends Phone { }

    /* 인터페이스의 개념 */
    interface Phone { // 인터페이스
    int BUTTONS = 20; // 상수 필드 (public static final int BUTTONS = 20;과 동일)
    void sendCall(); // 추상 메서드 (abstract public void sendCall();과 동일)
    abstract public void receiveCall(); // 추상 메서드
    }
    
    /* 인터페이스의 구현 */
    class FeaturePhone implements Phone {
    // Phone의 모든 추상 메서드를 구현한다. 
    	public void sendCall() {...}
    	public void receiveCall() {...}
    // 추가적으로 다른 메서드를 작성할 수 있다.
    	public int getButtons() {...}
    } 
  • 추상 클래스와 인터페이스의 공통점

    • 인스턴스(객체)는 생성할 수 없다.
    • 선언만 있고 구현 내용이 없다.
    • 자식 클래스가 메서드의 구체적인 동작을 구현하도록 책임을 위임한다.
  • 추상 클래스와 인터페이스의 차이점

    • 서로 다른 목적을 가지고 있다.
    • 추상 클래스는 추상 메서드를 자식 클래스가 구체화하여 그 기능을 확장하는데 목적이 있다. (상속을 위한 부모 클래스)
    • 인터페이스는 서로 관련이 없는 클래스에서 공통적으로 사용하는 방식이 필요하지만 기능을 각각 구현할 필요가 있는 경우에 사용한다. (구현 객체의 같은 동작을 보장)
  • 추상 클래스는 클래스이지만 인터페이스는 클래스가 아니다.

  • 추상 클래스는 단일 상속이지만 인터페이스 다중 상속이 가능하다.

  • 추상 클래스는 "is a kind if" 인터페이는 "can do this"

    • 예) 추상 클래스 : Appliances(Abstract Class) = TV, Refrigerator
    • 예) 인터페이스 : Flyable(Interface) = Plane, Bird

JVM 구조

Java Collections Framework

  • Map
  • 검색할 수 있는 인터페이스
  • 데이터를 삽입할 때 Key와 Value의 형태로 삽입되며, Key를 이용해서 Value을 얻을 수 있다.
  • Collection
    • List
      • 순서가 있는 Collection
      • 데이터를 중복해서 포함할 수 있다.
    • Set
      • 집합적인 개념의 Collection
      • 순서의 의미가 없다.
      • 데이터를 중복해서 포함할 수 없다.
  • Collections Framework 선택과정
    ① Map과 Collection 인터페이스 중 선택
    ¹-¹. Collection 선택 시 사용 목적에 따라 List와 Set 중 선택
    ② 사용 목적에 따라 Map, List, Set 각각 하위 구현체를 선택
    ²-¹. Map : HashMap, LinkedHashMap, HashTable, TreeMap
    ²-². List : LinkedList, ArrayList
    ²-³. Set : TreeSet, HashSet

JAVA Map 인터페이스 구현체의 종류

  • HashMap
    • Entry<K,V>의 배열로 저장되며, 배열의 index는 내부 해쉬 함수를 통해 계산된다.
    • 내부 hash 값에 따라서 키순서가 정해지므로 특정 규칙없이 출력된다.
    • key와 value에 null값을 허용한다.
    • 비동기 처리
    • 시간복잡도 : O(¹)
  • LinkHashMap
    • HashMap을 상속받으며, Linked List로 저장된다.
    • 입력 순서대로 출력된다.
    • 비동기 처리
    • 시간복잡도 : O(n)
  • TreeMap
    • 내부적으로 레드-블랙 트리(Red-Black tree)로 저장된다.
    • 키값이 기본적으로 오름차순으로 정렬되어 출력된다.
    • 키값에 대한 Compartor 구현으로 정렬 방법을 지정할 수 있다.
    • 시간복잡도 : O(logn)
  • ConCurrentHashMap
    • multiple lock
    • update 할 때만 동기 처리
    • key와 value에 null 값을 허용하지 않는다.
  • HashTable
    • single lock
    • 모든 메서드에 대해 동기 처리
    • key와 value에 null 값을 허용하지 않는다.

JAVA Set 인터페이스 구현체의 종류

  • HastSet
    • 저장 순서를 유지하지 않는 데이터의 집합이다.
    • 해시 알고리즘(hash algirithm)을 사요하여 검색 속도가 매우 빠르다.
    • 내부적으로 HashMap 인스턴스를 이용하여 요소를 저장한다.
  • LinkHashSet
    • 저장 순서를 유자하는 HashSet
  • TreeSet
    • 데이터가 정렬된 상태로 저장되는 이진 탐색 트리 (binary search tree)의 형태로 요소를 저장한다.
    • 이진 탐색 트리 중에 성능을 향상시킨 레드-블랙 트리 (Red-Black tree)로 구현되어 있다.
    • Compartor 구현으로 정렬 방법을 지정할 수 있다.

JAVA List 인터페이스 구현체의 종류

  • ArrayList

    • 단방향 포인터 구조로 각 데이터에 대한 인덱스를 가지고 있어 데이터 검색에 적합하다.
    • 데이터의 삽입, 삭제 시 해당 데이터 이후 모든 데이터가 복사되므로 삽입, 삭제가 빈번한 데이터에는 부적합하다.
  • LinkedList

    • 양방향 포인터 구조로 데이터의 삽입, 삭제 시 해당 노드의 주소지만 바꾸면 되므로 삽입, 삭제가 빈번한 데이터에 적합하다.
    • 데이터의 검색 시 처음부터 노드를 순회하므로 검색에는 부적합하다.
    • 스택, 큐, 양방향 큐 등을 만들기 위한 용도로 쓰인다.
  • Vector

    • 내부에서 자동으로 동기화 처리가 일어난다.
    • 성능이 좋지 않고 무거워 잘 쓰이지 않는다.

    String, StringBuilder, StringBuffer

  • String

    • 새로운 값을 할당할 때마다 새로 클래스에 대한 객체가 생성된다.
    • String에서 저장되는 문자열은 private final char[] 의 형태이기 때문에 String 값은 바꿀 수 없다.
    • private : 외부에서 접근 불가
    • final : 초기값 변경 불가
  • String + String + String ...

    • 각각의 String 주솟값이 Stack에 쌓이고, Garbage Collector가 호출되기 전까지 생성된 String 객체들은 Heap에 쌓이기 때문에 메모리 관리에 치명적이다.
    • String을 직접 더하는 것보다는 StringBuffer나 StringBuilder를 사용하는 것이 좋다.
  • StringBuilder, StringBuffer

    • memory에 append하는 방식으로, 클래스에 대한 객체를 직접 생성하지 않는다.
    • StringBuilder
    • 변경가능한 문자열
    • 비동기 처리
    • StringBuffer
    • 변경가능한 문자열
    • 동기 처리
    • multiple thred 환경에서 안전한 클래스 (thread safe)

🤍 JAVA의 리플렉션(Reflection) 이란 🤍

  • 리플렉션(Reflection) 이란?

    • 자바에서 이미 로딩이 완료된 클래스에서 또 다른 클래스를 동적으로 로딩 (Dynamic Loading)하여 생성자(Constructor), 멤버 필드(Member Variables) 그리고 멤버 메서드 (Member Method) 등을 사용할 수 있는 기법이다.
    • 클래스의 패키지 정보, 접근 지정자, 수퍼 클래스, 어노테이션(Annotation) 등을 얻을 수 있다.
    • 컴파일 시간(Compile Time)이 아니라 실행 시간(Run Time)에 동적으로 특정 클래스의 정보를 객체화를 통해 분석 및 추출해낼 수 있는 프로그래밍 기법이다.
  • 사용 방법

    • Class.forName("클래스이름")

    • 클래스의 이름으로부터 인스턴스를 생성할 수 있고, 이를 이용하여 클래스의 정보를 가져올 수 있다.

      public class DoHee {
        public String name;
        public int number;
        public void setDoHee (String name, int number) {
            this.name = name;
            this.number = number;
       	 }
        public void setNumber(int number) {
              this.number = number;
      	  }
        public void sayHello(String name) {
            System.out.println("Hello, " + name);
      	 }
      }
      
      
      import java.lang.reflect.Method;
      import java.lang.reflect.Field;
      /* ReflectionTest 클래스 */
      public class ReflectionTest {
        public void reflectionTest() {
            try {
                Class myClass = Class.forName("DoHee");
                Method[] methods = myClass.getDeclaredMethods();
                /* 클래스 내 선언된 메서드의 목록 출력 */
                /* 출력 : public void DoHee.setDoHee(java.lang.String,int)
                         public void DoHee.setNumber(int)
                         public void DoHee.sayHello(java.lang.String) */
                for (Method method : methods) {
                    System.out.println(method.toString());
               	 }
                /* 메서드의 매개변수와 반환 타입 확인 */
                /* 출력 : Class Name : class DoHee
                         Method Name : setDoHee
                         Return Type : void */
                Method method = methods[0];
                System.out.println("Class Name : " + method.getDeclaringClass());
                System.out.println("Method Name : " + method.getName());
                System.out.println("Return Type : " + method.getReturnType());
                /* 출력 : Param Type : class java.lang.String
                         Param Type : int */
                Class[] paramTypes = method.getParameterTypes();
                for(Class paramType : paramTypes) {
                    System.out.println("Param Type : " + paramType);
              	  }
                /* 메서드 이름으로 호출 */
                Method sayHelloMethod = myClass.getMethod("sayHello", String.class);
                sayHelloMethod.invoke(myClass.newInstance(), new String("DoHee")); // 출력 : Hello, DoHee
                /* 다른 클래스의 멤버 필드의 값 수정 */
                Field field = myClass.getField("number");
                DoHee obj = (DoHee) myClass.newInstance();
                obj.setNumber(5);
                System.out.println("Before Number : " + field.get(obj)); // 출력 : Before Number : 5
                field.set(obj, 10);
                System.out.println("After Number : " + field.get(obj)); // 출력 : After Number : 10
            } catch (Exception e) {
                // Exception Handling
           	 }
        }
        public static void main(String[] args) {
            new ReflectionTest().reflectionTest();
      	   }
      }
  • 왜 사용할까?
    • 실행 시간에 다른 클래스를 동적으로 로딩하여 접근할 때
    • 클래스와 멤버 필드 그리고 메서드 등에 관한 정보를 얻어야할 때
    • 리플렉션 없이도 완성도 높은 코드를 구현할 수 있지만, 사용한다면 조금 더 유연한 코드를 만들 수 있다.
  • 주의점
profile
미래의 웹프로그래머

0개의 댓글