면접 대비 개념

신입 개발자 면접 대비 자바 개념

삼록이 2025. 6. 27. 09:19

1.객체지향 프로그래밍이란?

우리가 실생활에서 쓰는 모든 것을 객체라 하며, 객체 지향 프로그래밍은 프로그램 구현에 필요한 객체를 파악하고

그 객체를 상태와 행위를 가진 객체로 만들고 역할을 정의하며 객체들 간의 상호작용을 통해 프로그램을 만드는 것.

 

객체지향 프로그래밍의 4가지  특징

  • 캡슐화 : 객체의 데이터와 그 데이터를 조작하는 메소드를 결합하여, 외부에서 내부의 세부사항을 숨기고, 접근을 제한.
  • 상속 : 상위 클래스의 속성을 하위 클래스가 물려받는 것
  • 다형성 :  하나의 인터페이스나 메소드가 다향한 형태로 구현될 수 있는 것 ex.overriding, overloading
  • 추상화: 실제 현실 객체에서 필요 없는 부분은 빼고, 필요한 부분만 추출하여 사용하여 간단한 모델로 표현하는 것. 공통의 속성이나 기능을 묶어 클래스를 정의함으로써 복잡성을 줄인다.

오버라이딩(overriding) vs 오버로딩(oveloading)

오버라이딩은 상위 클래스에 이미 정의 되어있는 메소드를 하위 클래스에서 재정의 하는 것.

오버로딩은 매개변수의 개수나 타입을 다르게 하여 같은 이름의 메소드를 여러 개 정의하는 것.

 

클래스 vs 객체

  • 클래스는 객체를 만들어내기 위한 틀.
  • 객체는 클래스에 정의된 것을 기반으로 생성된 실체. 실제 메모리 상에 할당되어 클래스에 정의된 속성과 메서드를 사용할 수 있는 실체임.

(객체와 인스턴스는 사실상 같은 말이라 봐도 무방하다.)

 

객체지향 프로그래밍 설계 5대 원칙(SOLID)

1.단일 책임의 원칙(Single Responsibility Principle)

하나의 클래스는 하나의 책임만 가져야한다. 

여기서 말하는 책임은 기능이라고 생각하면 편하다. 즉, 하나의 클래스는 하나의 기능을 가져야한다.

 

2.개방 폐쇄의 원칙(Open Closed Principle)

클래스는 확장을 통해 손쉽게 구현하면서, 확장에 따른 클래스 수정은 최소화하도록 프로그램을 작성해야한다.

이 말은 기능을 추가하는데 기존의 코드를 변경할 필요가 없도록 설계해야하는 것을 의미한다.

이를 활용하는 것이 대표적으로 인터페이스-구현체 /  추상클래스-상속받은 클래스 경우이다.

 

3.리스코프 치환 원칙(Liskov Substituion Principle)

자식 클래스는 언제나 부모클래스를 대체할 수 있어야한다.

즉 부모 클래스 객체의 자리에 자식 클래스의 객체가 들어가도 지장이 없도록 설계하는 것이다. 

 

4.인터페이스 분리의 원칙(Interface Segregation Principle)

클래스는 자신이 사용하지 않을 메소드를 구현하도록 강요받지 않아야한다.

 

5.의존 역전 원칙(Dependency Inversion Principle)

어떤 클래스를 참조해서 사용해야한다면 그 클래스를 직접 참조하는 것이 아니라 상위요소(추상클래스,인터페이스)를 참조해야 하는것

 

각 원칙별 예시를 통해 구체적으로 파악하고 싶다면 https://www.youtube.com/watch?v=4O6k9GN8FPo

혹은

https://inpa.tistory.com/entry/OOP-%F0%9F%92%A0-%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%EC%84%A4%EA%B3%84%EC%9D%98-5%EA%B0%80%EC%A7%80-%EC%9B%90%EC%B9%99-SOLID

 

💠 객체 지향 설계의 5가지 원칙 - S.O.L.I.D

객체 지향 설계의 5원칙 S.O.L.I.D 모든 코드에서 LSP를 지키기에는 어려움. 리스코프 치환 원칙에 따르면 자식 클래스의 인스턴스가 부모 클래스의 인스턴스를 대신하더라도 의도에 맞게 작동되어

inpa.tistory.com

 

 

2.인터페이스(interface)와 추상 클래스(abstract class)

인터페이스

  • 구현체들이 같은 동작을 한다는 걸 보장하기 위해 사용한다.
    (하위 클래스가 인터페이스를 구현한다면 반드시 인터페이스의 모든 메서드를 구현(오버라이딩)해야한다)
    (대규모 프로젝트 진행시 일관된 개발을 위한 표준이 됨 <-인터페이스를 사용하는 이유)
  • 다중 상속이 가능하고, 구현체들 간에는 연관관계가 없을 수 있다.
  • 인터페이스에 존재하는 모든 메서드는 추상 메서드이다

추상 클래스

  • 객체들의 공통된 개념을 묶어서 추상화시키고, 기능 확장을 위해 사용한다.
  • 추상 클래스를 상속받는 객체들 간에는 연관관계가 있다.
  • 추상 클래스는 1개 이상의 추상 메서드를 가진다.

 

*추상메서드란 메서드의 이름만 있을 뿐 몸체(body)는 정의되지 않은 것을 말한다.

3.자바의 특징?

자바는 객체지향 프로그래밍 언어로 기본(원시)타입 자료형을 제외한 모든 요소들이 객체로 표현 됨.

또한 JVM(Java Virtual Machine) 위에서 동작하기 때문에, OS에 독립적.

GC(Garbage Collector)를 통한 자동 메모리 관리가 되어 편리

 

기본(원시)타입?

  • 정수형 :byte(1바이트), short(2바이트), int(4바이트), long(8바이)
  • 실수형: float(4바이트), double(8바이트)
  • 문자형: char(2바이트)
  • 논리형: boolean(1바이트)

JVM(Java Virtual Machine)

말 그대로 자바를 실행하기 위한 가상 기계(컴퓨다)다.

자바는 OS에 종속적이지 않다는 특징을 가지고 있다고 말했다. 그렇게 OS에 독립되기 위해선

OS 위에서 자바를 실행시킬 무언가가 필요한데 그게 바로 JVM이다.

 

자바에서 우리가 작성하는 소스코드는 CPU가 바로 인식 하지 못한다. 기계어로 컴파일 해줘야한다.

그런데 자바는 OS에 독립적이기 위해서 OS 위에서 JVM이 작동한다.

즉 우리가 작성한 소스코드는 JVM을 거쳐서 OS에 도달한다.

그래서 우리가 작성한 소스코드는 OS가 인식할 수 있는 기계어로 곧장 컴파일 되는게 아니라, JVM이 인식할 수 있는 코드(자바 바이트 코드라고 한다)로 변환해야한다. 이 역할은 자바 컴파일러(javac) 가 하며, 자바 컴파일러는 우리가 작성한 소스코드, .java파일을 자바 바이트 코드, .class파일 .로 변환시켜준다.

그러면 JVM이 이 자바 바이트코드를 OS나 CPU가 이해할 수 있는 기계어로 변환하여 실행함으로써 자바는 OS에 독립적일 수 있는 것이다.

 

GC(Garbage Collector)

더 이상 사용하지 않아 필요 없게 된 힙 메모리에 있는 객체를 주기적으로 제거하는 것으로 이 역시도 JVM에 탑재되어 있다.

4.원시타입과 참조타입

자바에서 원시타입은 위에서 말한 8개만 존재한다. 나머지는 모두 참조타입으로 Object클래스이거나 이를 상속하는 클래스다.

원시타입은 기본값을 가지지만, 참조타입은 null을 가지는 것에 차이가 있다.

5.JVM의 구조와 Java의 실행방식

  • 클래스로더: javac(자바 컴파일러)에 의해 우리가 작성한 코드들(.java파일)이 .class파일로 컴파일 되면 그 .class파일을 가져오는 역할을 한다. 클래스로더가 .class파일을 가져와 런타임 데이터 영역(Runtime Data Area)에 로드한다.
  • 런타임데이터영역: JVM의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역.
  • 실행엔진: 클래스로더가 바이트 코드파일을 런타임데이터영역에 적재했고, 런타임 데이터 영역에 적재된 이 바이트 코드를 명령어 단위로 읽어서 실행한다.(CG역할을 수행하는 것도 이 실행엔진!)
  • JNI(Java Native Interface 그림에서 Native Method Interface를 뜻함) : 자바코드에서 C/C++ 같은 네이티브 코드와 연결할 수 있도록 도와주는 인터페이스다. 즉, 자바와 C/C++을 연결해주는 인터페이스(다리)
  • 네이티브 메서드 라이브러리: C/C++로 작성된 라이브러리. JNI는 이 라이브러리를 실행한다.

즉, 자바의 실행방식은

자바 컴파일러(javac)가 자바 소스코드(.java)를 자바 바이트코드(.class)로 변환시키면 JVM의 클래스 로더가 .class파일을 JVM의 런타임 데이터 영역으로 배치시킨다. 그러면 실행엔진을 통해 바이트 코드가 OS(CPU)가 실행할 수 있는 기계어로 번역되어 실행된다.

 

실행엔진 

바이트 코드를 실질적으로 실행시키는 역할을 하는 이 실행엔진은 인터프리터와 JIT컴파일러라는 두 가지 방식을 혼합하여 바이트코드를 실행한다.

 

  • 인터프리터 방식 : 소스코드를 실행 시점(=런타임)에 명령어 단위별로 그때그때 기계어로 번역하여 실행하는 방식.
  • 컴파일 방식 :  소스코드를 실행 전에 전체 소스 코드를 한 번에 기계어로 번역하는 방식. 코드를 수정하면 소스 코드 전체를 다시 컴파일 해야하므로 수정 사항이 빈번할 경우 불편하다는 단점이 있다.

즉, 실행엔진은 인터프리터 방식으로 바이트코드 명령어를  한 줄씩 읽고 그때그때 기계어로 번역하여 실행한다.

이 방식의 장점은 빠르게 바로 시작 한다는 것이다. 그러나 실행 중에 같은 메소드라도 여러번 호출이 된다면 매번 똑같은 걸 다시 번역해야하고 실행해야하므로 전체적인 속도가 느려진다는 단점이 있다. 이 단점을 보완하기 위해 JIT 컴파일러 방식도 사용된다.

JIT 컴파일러는 인터프리터가 한 줄씩 해석하며 실행하는 그 과정에서 자주 호출되는 메서드나 자주 실행되는 코드 블럭을 감지하여 해당 코드만 기계어로 번역하여 따로 저장 한다는 것이다. 그러면 이후에 또 동일한 메서드나 코드블럭이 나오면 인터프리터하지 않고 저장한 걸 꺼내 씀으로 속도를 높이는 것이다.

(JIT 컴파일러는 일반적인 컴파일 방식처럼  전체 소스코드를 컴파일 하는 것이 아니 프로그램 실행 중 필요한 부분만 번역하여 저장하는 개념으로 이해하면 더 적절해보인다)

 

런타임 데이터 영역

JVM의 메모리 영역이다. 런타임 데이터 영역은 다시 5가지 영역으로 나뉜다.

  • 메서드 영역: 클래스 정보, static변수 등이 저장되는 영역으로 JVM 메모리에서 모든 스레드가 공유하는 영역이다.
  • 힙 영역: new 키워드로 생성된 객체와 배열이 저장되는 영역으로 JVM메모리에서 모든 스레드가 공유하는 영역이다.(이 힙 메모리에 있는 객체가 쓰이지 않을 시, 실행엔진에 있는 CG가 작동되어 자동으로 제거해주는 것이다)
  • 스택 영역: 각 스레드마다 독립적으로 할당되는 공간으로, 메서드 호출시마다 프레임이 생성되어 지역변수, 매개 변수 등이 저장된다.(프레임이란, 스택영역 안에서 메서드 하나가 실행 될 때마다 생성되는 메모리 단위(공간)을 말한다)
  • PC 레지스터 : 마찬가지로 각 스레드 별로 처리하며 현재 실행중인 JVM 명령의 주소를 저장한다.
  • 네이티브 메서드 스택: 자바 외부의 네이티브 코드(C/C++)를 실행할 때 사용되는 메모리 영역이다

6.Static?

static은 한 클래스에 있는 모든 객체가 공유해야 하는 속성이나 동작(메서드)을 정의할 때 사용하는 키워드다.

객체가 없어도 클래스 이름으로 속성에 접근하거나 메서드를 호출 할 수 있다. 

static 변수는 위에서 말했듯이 일반적인 객체가 힙 영역에 저장되는 것과 달리 메서드 영역에 저장된다.

그러므로 CG의 관리 영역 밖이니 너무 남발하게 되면 프로그램 종료 시까지 메모리가 할당된 채로 존재하므로 시스템의 성능을 떨어트릴 수도 있다. 

 

 

7.생성자란?

생성자는 클래스와 같은 이름의 메서드로, 객체가 생성될 때 호출 되는 메서드.

클래스 내에 명시적으로 생성자를 만들지 않아도 기본으로 가진다.

 

8.Java의 접근 제어자?

  • public: 어디서나 사용할 수 있도록 열어두는 것
  • protected: 같은 패키지 내에서만 사용할 수 있게 하는 것인데 다른 패키지에서 상속받으면 접근 가능.
  • default: 명시하지 않고 생략할 수 있는 접근 제어자로 같은 패키지 내에서만 사용할 수 있는 것
  • private: 같은 클래스 내에서만 사용할 수 있게 하는 것

 

9.에러(Error)와 예외(Exception)

에러는 메모리 부족이나 스택오버플로우와 같은 시스템 레벨에서 발생한 문제로 프로그램 코드에 의해서 수습될 수 없는 오류를 말한다.

예외는 프로그램 코드에 의해서 수습될 수 있는 심각하지 않은 오류로 개발자가 코드의 수정을 통해 해결 할 수 있는 문제를 말한다. 

(프로그램 코드에 의해서 수습될 수 있다/없다 라는 뜻은 개발자가 try-catch 같은 법이나 로직을 통해 문제에 대응할 수 있다/없다를 뜻한다.)

 

Checked Exception vs Unchecked Exception

 

Checked Exception은 말 그대로 확인된 예외. 즉 컴파일 시점에서 예외가 확인되므로 try-catch 혹은 throws로 예외처리를 강제한다. 주로 네트워크,DB 등 외부 환경과의 통신에서 발생한다.

Unchecked Exception은 컴파일 시점에서 예외가 확인되는 것이 아니라 예외처리를 강제하지 않는다. 즉 컴파일은 성공하지만, 문제가 있는 코드가 실행 될 때 예외가 발생하는 것이다.

 

10.제네릭(Generic)이란

하나의 클래스나 메서드가 여러 가지 타입을 처리할 수 있게 하는 문법. 이를 통해, 코드 재사용성을 높이고 타입 안정성을 확보할 수 있음.