목차
Java란 무엇인가요? Java의 특징에 대해 말해주세요.
Java란 객체지향 프로그래밍 언어입니다.
자바의 특징으로는 객체 지향 프로그래밍, 플랫폼 독립성, 자동 메모리 관리 등등이 있습니다.
자바는 객체 지향 언어로 캡슐화, 추상화, 상속, 다형성 등의 객체 지향 개념을 지원합니다.
자바는 자바 가상 머신인 JVM 위에서 실행되므로 JVM이 설치되어 있는 모든 플랫폼에서 동작할 수 있습니다.
자바는 가비지 컬렉터라는 시스템을 통해 메모리를 자동으로 관리합니다.
이 밖에도 다양한 API 라이브러리 지원, 다양한 개발 도구를 지원함으로 다양한 애플리케이션 개발에 사용되고 있습니다.
Java의 장단점은 무엇인가요?
Java의 여러 개의 장점을 가지고 있습니다.
Java의 장점 중 하나는 플랫폼 독립성 입니다. 자바는 JVM위에서 동작하므로 JVM이 설치되어 있으면 어떠한 환경, 플랫폼에서도 실행할 수 있습니다. 이는 다른 시스템 호환성 문제를 줄여줍니다.
자바는 객체지향 프로그래밍을 완벽히 지원하므로 코드의 재사용성과 유지 보수성이 높습니다.
또한 자동 메모리 관리 기능인 가비지 컬렉터가 있어 개발자가 직접 메모리를 관리할 필요가 없습니다.
반면 Java도 단점이 있습니다.
Java의 단점 중 하나는 상대적으로 느린 실행 속도 입니다. 자바 실행을 위해선 JVM을 거쳐야 하므로 다른 언어에 비해 실행 속도가 느립니다.
다른 단점은 높은 메모리 소비 입니다. 자바는 가비지 컬렉션을 사용하는데 이는 추가적인 CPU 사용을 야기함으로 메모리 소비가 높습니다.
하지만 java는 최적화 과정을 통해 많은 성능 개선을 이루었습니다.
객체 지향 프로그래밍이란 무엇인가요?
객체 지향 프로그래밍이란 프로그래밍에서 필요한 데이터를 추상화 시켜 상태와 행위를 가진 객체로 만들고, 객체들간의 상호작용을 통해 로직을 구성하는 프로그래밍 방법 입니다.
객체 지향 프로그래밍의 특징과 장점은 무엇인가요?
객체 지향 프로그래밍의 특징으론 캡슐화, 추상화, 상속, 다형성 4가지가 있습니다. 이로 인해 코드의 재사용성을 높이고, 관리를 용이하게 하며, 신뢰성 높은 프로그래밍을 가능하게 합니다.
각각의 특징은 다음과 같습니다.
캡슐화란 객체의 속성과 행위를 하나로 묶고, 구현 내용을 외부로부터 감추는 것 입니다. 이를 통해 데이터의 안정성을 보장하고 코드의 복잡성을 관리합니다.
(구현예시 - 접근제어자를 private로 설정하고 getter, setter를 통해 접근하는 것 입니다.)
추상화란 복잡한 시스템을 간단한 개념으로 표현한 것으로 실세계의 복잡한 로직을 단순화해서 중요한 정보는 표현하고 불필요한 정보를 숨깁니다. 이를 통해 프로그래밍을 보다 쉽고 관리하기 쉬운 형태로 바꿉니다.
상속이란 객체가 다른 객체로부터 특성과 행동을 상속 받는 것 입니다. 특성 행동을 주는 클래스는 부모 클래스, 받는 클래스는 자식 클래스라 불리면 이를 통해 코드의 재사용성을 높이고 중복을 줄일 수 있습니다.
다형성이란 여러 가지 형태를 가지는 것을 뜻 합니다. 같은 이름의 메소드가 다른 객체에 따라 다르게 행동 할 수 있게 함으로 코드의 유연성과 확장성을 높일 수 있습니다.
객체 지향적 설계 원칙이 무엇인가요?
객체 지향 설계 원칙은 SOLID, 단일 책임 원칙, 개방 폐쇄 원칙, 리스코프 치환 원칙, 인터페이스 분리 원칙, 의존 관계 역전 원칙으로 총 5개가 있습니다.
이 원칙들은 소프트웨어 설계와 유지 관리에 있어 중요한 역할을 하며 시스템의 확장성과 유연성, 재사용성을 높이고, 유지 보수를 용이하게 합니다.
각각의 원칙은 다음과 같이 설명할 수 있습니다.
단일 책임 원칙 (Single Responsibility Principle, SRP)
한 클래스는 하나의 책임만 가진다는 뜻 입니다. 즉, 한 클래스는 한 가지 기능만 가지며, 그 기능을 완전히 캡슐화 해야 합니다. 이를 통해 한 부분의 변화가 전체 시스템 영향에 미치는 것을 최소화 합니다.
변경이 일어났을 때 파급효과가 적으면 단일 책임 원칙을 잘 지킨 것이라 여깁니다.
개방 폐쇄 원칙 (Open-Closed Principle, OCP)
소프트웨어 요소는 확장에는 열려 있으나 수정에는 닫혀 있어야 한다는 뜻 입니다.
기존의 코드를 변경하지 않고도 시스템의 행동을 변경하거나 확장할 수 있어야 합니다.
리소코프 치환 원칙 (Liskov, Substitution Principle, LSP)
상속 관계에 있는 클래스 사이에서, 부모 클래스와 자식 클래스는 서로 치환될 수 있어야 한다는 뜻 입니다.
즉, 자식 클래스는 언제나 부모 클래스를 대체될 수 있어야 합니다.
예시로는 자동차의 액셀 기능을 구현해야 하는 상황이면 앞으로 가라는 기능을 구현해야 합니다. 뒤로 가는 기능을 구현하면 리소코프 치환 원칙을 위배한 것 입니다. 느리더라도 앞으로 가게 구현해야 원칙을 지킨 것 입니다.
인터페이스 분리 원칙 (Interface Segregation Principle, ISP)
특정 클라이언트를 위한 인터페이스 여러 개가 하나의 범용 인터페이스 보다 낫다는 뜻 입니다.
인터페이스가 명확해지고 대체 가능성이 높아집니다.
의존 관계 역전 원칙 (Dependency Inversion Principle, DIP)
개발자는 추상화에 의존해야지 구체화에 의존하면 안된다는 뜻 입니다.
구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻 입니다. 구현 클래스에 의존하게 되면 구현 클래스가 변경되면 의존하고 있는 클래스에도 영향을 미치게 됩니다. 이는 코드 유지 보수를 어렵게 하고 모듈 간의 결합도가 높아지게 됩니다.
객체와 클래스의 차이는 무엇인가요?
클래스는 객체가 가져야 할 상태를 나타내는 변수와 객체가 수행할 수 있는 행동을 나타내는 함수를 정의한 것 입니다. 즉 클래스는 객체의 상태와 동작을 정의한 설계도 같은 것 입니다. 이 클래스를 참조하여 객체를 생성합니다.
객체는 클래스에 정의된 구조를 바탕으로 메모리 공간에 할당된 인스턴스 입니다. 그러므로 클래스에서 정의한 변수와 함수를 가지게 됩니다. 각각의 객체는 자신만의 상태를 가질 수 있지만 같은 클래스에서 생성된 객체는 같은 종류의 행동을 수행할 수 있습니다.
오버로딩과 오버라이딩은 무엇인가요? 이 둘의 차이점에 대해 설명해 주세요.
오버로딩은 한 클래스 내에서 이름은 같지만 매개변수의 갯수나 타입이 다른 메소드를 여러 개 정의 한 것 입니다.
오버라이딩은 부모 클래스로부터 상속 받은 메소드를 재정의 하는 것을 뜻 합니다.
오버로딩과 오버라이딩은 메소드의 다형성을 제공합니다.
추상 클래스와 인터페이스은 무엇인가요? 이 둘의 차이점에 대해 설명해 주세요.
추상 클래스란 일반 클래스와 비슷하지만, 하나 이상의 추상 메소드가 포함된 클래스를 뜻 합니다. 추상 메소드가 있어 객체를 생성할 수 없으며 추상 클래스를 상속 받은 하위 클래스는 반드시 추상 메소드를 구현해야 합니다. 추상 클래스는 일반 클래스가 가지고 있는 필드, 일반 메소드를 가지면서 앞으로 구현해야 하는 추상 메소드를 가지고 있기 때문에 미완성 설계도로 비유할 수 있습니다.
인터페이스는 특정 클래스가 가지는 메소드를 정의하는 템플릿 역할을 합니다. 인터페이스는 추상 메소드와 상수로 이루어져 있으며 다른 클래스는 인터페이스를 구현(implement)함으로써 정의된 추상 메소드를 모두 구현합니다.
추상 클래스와 인터페이스는 클래스에게 추상 메소드 구현을 강요하는 공통점이 있지만 차이점도 있습니다. 대표적인 차이점으로는 다중 상속 여부와, 가질 수 있는 타입 종류, 접근 제어자 종류 입니다.
인터페이스는 다중 상속이 가능하지만 추상 클래스는 하나의 추상 클래스만 상속할 수 있습니다.
인터페이스는 추상 메소드와 상수만 가질 수 있지만, 추상 클래스는 필드, 생성자, 일반 메소드, 추상 메소드 모두 가질 수 있습니다.
인터페이스의 모든 메소드는 public 이지만, 추상 클래스의 메소드는 public, protected, private 등 여러 개의 접근 제어자를 가질 수 있습니다.
JVM 메모리 구조에 대해 설명해 주세요.
JVM은 시스템으로부터 프로그램을 실행하는데 필요한 메모리를 할당 받고, 용도에 따라 5개의 영역으로 나누어 관리합니다. 5개의 영역은 메소드, 힙, 스택, PC 레지스터, 네이티브 메소드 스택 영역 입니다.
각각의 특징은 다음과 같습니다.
메소드 영역
클래스의 정보가 저장되는 곳으로 클래스가 로드되면 클래스 정보가 메소드 영역에 저장 됩니다.
힙 영역
JVM의 모든 쓰레드가 공유하며, 프로그램에서 생성된 객체들이 모두 이곳에 저장됩니다. 더 이상 사용되지 않는 객체는 GC에 의해 정리됩니다.
스택 영역
메소드를 호출 할 때마다 각 메소드의 지역변수, 파라미터 등을 저장하는 영역입니다. 메소드가 실행 종료하면 사라집니다.
PC 레지스터 영역
현재 실행되고 있는 명령어의 주소를 저장합니다.
네이티브 메소드 스택 영역
Java가 아닌 다른 언어로 작성된 코드를 실행할 때 사용합니다. 네이티브 메소드가 다른 프로그래밍 언어로 작성된 메소드를 말합니다.
가비지 컬렉션에 대해 설명해 주세요.
가비지 컬렉션은 자동 메모리 관리의 한 형태로, 프로그램이 동적으로 할당했지만 더 이상 참조하지 않는 메모리를 자동으로 회수하는 과정을 말 합니다.
자바는 가비지 컬렉션을 통해 개발자가 직접 메모리를 관리하지 않아도 사용하지 않는 메모리를 자동으로 회수함으로 메모리 누수를 방지하고 효율적으로 메모리를 관리할 수 있습니다.
가비지 컬렉션이 일어날 땐 CPU를 사용하기 때문에 애플리케이션 성능이 잠시 떨어질 수 있습니다.
자바의 가비지 컬렉터는 가비지 컬렉션에 구현채로 힙 영역에 있는 객체 중 더 이상 접근할 수 없는 객체(가비지)를 찾아내고 그 메모리를 회수합니다. 가비지 컬렉션은 Mark, Sweep 이라는 두 가지 단계로 이루어 집니다.
Mark :
가바지 컬렉터는 root에서 시작해 접근 가능한 객체를 따라가며 객체들을 mark 합니다.
Sweep :
가비지 컬렉터는 힙에서 mark 되지 않은 객체를 찾아내어 메모리를 회수합니다.
다른 사용하는 언어로는 Python 이 있습니다.
제네릭에 대해 얘기해 주세요.
제네릭이란 클래스나 메소드가 다루는 데이터 타입을 일반화하고 미리 지정하게 도와주는 기능입니다.
제네릭을 사용하면 타입을 직접 지정하지 않고 외부에서 지정할 수 있습니다.
제네릭을 사용하면 타입 체크와 형변환을 생략하여 잘못된 타입으로 인한 런타임 오류를 컴파일 과정에서 알 수 있습니다. 이로 인해 타입 안정성이 증가하고 런타임 오류를 방지할 수 있습니다.
제네릭은 Java 1.5 버전부터 지원했습니다.
new String() 과 리터럴("")의 차이에 대해 얘기해 주세요.
new String() 을 사용하면 new 키워드를 사용한 것 처럼 객체를 생성하고 Heap 메모리 영역에 저장됩니다.
객체이기 때문에 같은 내용이더라도 새로운 다른 객체들을 생성합니다.
이는 메모리 사용을 비효율로 만듭니다
리터럴("") 을 사용하면 String Constant Pool 이라는 특별한 영역에 저장됩니다.
같은 내용의 String은 단 한번 생성되어 저장되고 같은 리터럴 요청을 동일한 인스턴스를 참조하게 합니다.
이는 메모리 효율성을 높여줍니다.