학습목표
- 팀코칭 질문 답하기(개념 학습)
TIL
- 어노테이션
- 타입 소거 (Type Erasure)
- Immutable 클래스
- 조합 (Java)
- OOM(Out Of Memory)
어노테이션이란 무엇일까요? (자바에서 어노테이션이란 어떤 것이고 역활은 무엇이고 장점은 무엇이야?)
자바에서 어노테이션(annotation)은 코드의 특정 부분에 메타데이터를 추가하는 방법을 제공합니다. 메타데이터는 데이터에 대한 데이터로, 어노테이션은 코드에 대한 정보를 제공하는 역할을 합니다. 이러한 정보는 컴파일러, 개발 도구, 런타임 시스템 등이 사용하게 됩니다.
어노테이션의 역할:
- 컴파일러에게 정보 제공: 어노테이션은 컴파일러에게 특정 행동을 하도록 지시할 수 있습니다. 예를 들어, @Override 어노테이션은 컴파일러에게 해당 메서드가 부모 클래스의 메서드를 오버라이드해야 한다는 것을 알려줍니다. 만약 그렇지 않다면 컴파일러는 오류를 발생시킵니다.
- 개발 도구에게 정보 제공: 어노테이션은 개발 도구에게도 정보를 제공합니다. 예를 들어, 특정 메서드가 아직 완성되지 않았음을 나타내는 @Deprecated 어노테이션은 IDE가 경고를 표시하도록 만들 수 있습니다.
- 런타임 처리: 어노테이션은 런타임 시스템에게도 정보를 제공합니다. 예를 들어, @Entity 어노테이션은 JPA(Java Persistence API)와 같은 ORM(Object-Relational Mapping) 프레임워크에서 클래스가 데이터베이스 엔티티임을 나타냅니다.
어노테이션의 장점:
- 코드 가독성 향상: 어노테이션은 코드에 직접적인 명령이 아니라 힌트나 설명을 제공하므로, 코드의 가독성을 향상시킵니다.
- 유지보수 용이: 어노테이션을 사용하면 관련 코드를 쉽게 찾아 변경하거나, 관련된 동작을 일괄적으로 변경할 수 있습니다.
- 부가적인 코드 감소: 예를 들어 XML 설정 파일과 같은 별도의 구성 메커니즘 없이도 프레임워크의 동작을 제어할 수 있습니다.
- 코드 분석 용이: 어노테이션은 코드를 분석하는 도구들이 코드의 특정 부분에 대해 추가 정보를 얻는 데 사용할 수 있습니다. 이를 통해 코드 품질 검사, 테스트, 문서화 등에 도움이 됩니다.
- 선언적 프로그래밍: 어노테이션을 통해 개발자는 코드의 동작을 선언적으로 지정할 수 있습니다. 예를 들어, Spring 프레임워크에서 @Transactional 어노테이션을 사용하면 해당 메서드의 실행을 트랜잭션 내에서 처리하도록 선언할 수 있습니다.
그러나 어노테이션을 과용하면 코드가 복잡해질 수 있으며, 어노테이션에 지나치게 의존하면 코드의 흐름을 이해하는 데 어려움을 겪을 수 있습니다. 따라서 어노테이션은 적절히 사용하는 것이 중요합니다.
타입 이레이저(Type Erasure)는??
"타입 이레이저(Type Erasure)"는 특히 제네릭 프로그래밍에 대해 이야기할 때 종종 사용되는 용어입니다. 이는 컴파일 타임에만 제네릭 타입을 사용하고, 런타임에는 해당 타입 정보를 제거하는 컴파일러의 프로세스를 가리킵니다.
Java가 타입 이레이저를 가장 대표적으로 사용하는 언어 중 하나입니다. Java에서는 제네릭이 도입되었지만, 하위 호환성을 유지하기 위해 런타임에는 제네릭 타입 정보가 제거됩니다. 예를 들어, List<Integer>와 List<String> 모두 컴파일 후에는 단순히 List로 변환됩니다. 이로 인해 런타임에는 원래 제네릭 타입에 대한 정보를 알 수 없습니다. 이러한 점은 특정 상황에서는 제약 사항이 될 수 있습니다.
타입 이레이저의 장점 중 하나는 런타임에 추가 메모리 사용을 피할 수 있다는 것입니다. 제네릭 타입 정보가 컴파일 시점에만 필요하므로, 그 정보가 런타임에 남아 있을 필요가 없습니다. 이렇게 해서 메모리를 절약하고 효율성을 높일 수 있습니다.
그러나 단점도 존재합니다. 타입 안정성이 컴파일 시간에만 보장되며, 런타임에는 타입 관련 오류가 발생할 수 있습니다. 이는 주로 프로그래머의 실수로 인해 발생하며, 컴파일러가 이러한 오류를 잡아내지 못하게 됩니다.
JVM 메모리 설정 어떻게 하나 ?
Java Virtual Machine(JVM)의 메모리 설정은 주로 Java application을 시작할 때 Java 커맨드의 옵션으로 지정합니다. 여기서는 가장 일반적으로 사용되는 설정을 살펴보겠습니다.
- 힙 메모리 설정: JVM의 힙 크기는 -Xmx와 -Xms 옵션을 통해 설정할 수 있습니다. -Xmx 옵션은 힙의 최대 크기를 설정하고, -Xms 옵션은 힙의 초기 크기를 설정합니다. 일반적으로 두 크기를 동일하게 설정하여 힙 크기가 변경되는 것을 방지하고 성능을 향상시키곤 합니다. 예를 들어, 힙의 크기를 512 메가바이트로 설정하려면 -Xmx512m -Xms512m을 사용할 수 있습니다.
- 스택 메모리 설정: JVM의 스택 크기는 -Xss 옵션을 통해 설정할 수 있습니다. 이 옵션은 각 스레드에 대한 스택의 크기를 결정합니다. 예를 들어, 스택 크기를 1 메가바이트로 설정하려면 -Xss1m을 사용할 수 있습니다.
- 메타스페이스 설정: Java 8 이후, PermGen 영역이 Metaspace 영역으로 대체되었습니다. -XX:MaxMetaspaceSize 옵션을 사용하여 Metaspace의 최대 크기를 설정할 수 있습니다. 예를 들어, Metaspace의 최대 크기를 256 메가바이트로 설정하려면 -XX:MaxMetaspaceSize=256m을 사용할 수 있습니다.
이러한 옵션들은 Java application을 시작할 때 함께 제공하면 됩니다. 예를 들어, 아래와 같이 설정할 수 있습니다.
java -Xmx512m -Xms512m -Xss1m -XX:MaxMetaspaceSize=256m -jar your_application.jar
이러한 설정은 애플리케이션의 요구 사항과 가용한 시스템 자원에 따라 적절하게 조정해야 합니다. 또한, 메모리에 관련된 추가적인 JVM 옵션들이 많이 있으니, 필요에 따라 Oracle의 공식 문서 등을 참조하여 확인하시는 것이 좋습니다.
OOM이란?
OOM은 "Out Of Memory"의 약자로, 시스템이 더 이상 필요한 만큼의 메모리를 할당할 수 없을 때 발생하는 상황을 가리킵니다. 이는 주로 메모리 리소스가 고갈되었을 때 발생합니다.
Java와 같은 프로그래밍 언어에서는, 특히 JVM(Java Virtual Machine)에서 이런 상황이 발생하면 java.lang.OutOfMemoryError를 발생시킵니다. 이 오류는 JVM이 Java 애플리케이션에 필요한 메모리를 더 이상 할당할 수 없을 때 발생합니다.
OutOfMemoryError는 여러 가지 원인으로 발생할 수 있습니다. 가장 흔한 경우는 Java 힙 메모리가 부족한 경우로, 이는 애플리케이션의 데이터가 메모리에 계속해서 쌓여서 힙 메모리 공간이 부족해진 경우에 발생합니다. 이 외에도, 메타스페이스(Metaspace), 또는 JVM이 OS로부터 메모리를 할당받지 못하는 경우 등에도 발생할 수 있습니다.
이 문제를 해결하려면 먼저 OutOfMemoryError가 어떤 원인으로 인해 발생했는지 파악해야 합니다. 오류 메시지를 확인하여 문제를 진단하고, 필요에 따라 Java 애플리케이션의 메모리 사용 패턴을 조정하거나 JVM의 메모리 설정을 조절하여 해결할 수 있습니다. 또는, 메모리 누수가 있다면 코드를 수정하여 이를 해결해야 합니다.
Immutable 클래스란 ?
"Immutable 클래스"는 인스턴스가 한 번 생성된 후에는 그 상태가 변경되지 않는 클래스를 의미합니다. 다시 말해, 클래스의 객체가 한 번 생성되면 그 내부 상태를 변경할 수 없게 되는 것입니다.
Immutable 클래스의 예로는 Java의 String 클래스, Integer 클래스, Double 클래스 등이 있습니다. 이들 클래스의 인스턴스는 생성 시점에 결정된 값을 가지며, 이후에 그 값을 변경할 수 없습니다.
Immutable 클래스를 사용하는 것이 가지는 장점은 다음과 같습니다:
- Thread-Safe: Immutable 객체는 여러 스레드에서 동시에 접근해도 그 상태가 바뀌지 않으므로 동기화를 고려할 필요가 없습니다. 이는 복잡한 멀티스레드 환경에서 큰 이점이 될 수 있습니다.
- Hashing: Immutable 객체는 그 상태가 변경되지 않으므로, 이를 사용하여 HashMap의 키 등으로 사용할 수 있습니다. 상태가 변하지 않으므로 한 번 계산된 해시값이 변하지 않아, 안정적인 해시맵 동작을 보장할 수 있습니다.
- 내부 상태 보호: 객체가 가지는 값이 변경되지 않기 때문에 불변성을 유지하는 복잡한 로직을 생략하거나 줄일 수 있습니다.
Immutable 클래스를 만들려면 다음 규칙을 따르는 것이 일반적입니다:
- 모든 필드를 final과 private로 선언합니다.
- 클래스를 final로 선언하여 다른 클래스가 이 클래스를 상속받지 못하도록 합니다.
- Setter 메서드를 제공하지 않습니다.
- 객체가 가지는 복잡한 필드가 있다면, 해당 필드에 대한 변경 가능성을 제거합니다. 예를 들어, 컬렉션 필드를 반환하는 메서드가 있다면, 원본 컬렉션을 변경할 수 없는 불변 컬렉션을 반환하도록 합니다.
상속보다 조합을 사용해야 하는 이유는?
"상속보다 조합(composition)을 사용하라"는 객체지향 설계 원칙 중 하나입니다. 이 원칙은 코드의 재사용과 유연성, 유지 관리성 측면에서 중요한 의미를 가집니다.
- 상속의 문제점: 상속은 강력한 도구지만, 몇 가지 문제점을 가지고 있습니다. 상속은 부모 클래스와 자식 클래스 사이에 강력한 결합을 만들어 낸다는 점이 주요 문제입니다. 이로 인해 코드의 변경이 어렵게 되고, 부모 클래스의 변경이 자식 클래스에 영향을 미치게 됩니다. 또한, 상속은 "is-a" 관계를 표현하기 때문에, 문맥이나 요구 사항이 변했을 때 이 관계가 맞지 않을 수 있습니다.
- 조합의 장점: 조합은 클래스의 기능을 확장하거나 재사용하는 데 있어서 유연한 방법을 제공합니다. 조합은 "has-a" 관계를 표현하며, 이를 통해 필요한 기능을 가진 객체를 필드로 포함하는 방식으로 기능을 확장하거나 재사용할 수 있습니다. 조합을 사용하면 구성 요소를 독립적으로 개발하고 테스트할 수 있으며, 필요에 따라 쉽게 변경하거나 교체할 수 있습니다.
- Interface와 함께 사용: 조합은 인터페이스와 함께 사용하면 효과적입니다. 각 구성 요소는 특정 인터페이스를 구현하고, 이를 통해 제공하는 기능을 정의합니다. 이렇게 하면 구성 요소를 교체하거나 다른 구현으로 변경하는 것이 쉬워집니다.
- 코드 재사용: 조합은 코드의 재사용성을 증가시킵니다. 상속은 단일 상속 제한으로 인해 여러 클래스의 코드를 재사용하기 어렵지만, 조합을 사용하면 여러 클래스의 기능을 독립적으로 활용할 수 있습니다.
이러한 이유로, 상속보다 조합을 사용하는 것이 좋습니다. 그러나 상속이 항상 나쁜 것은 아니며, 적절하게 사용될 때는 유용한 도구가 될 수 있습니다. 일반적으로 상속은 "is-a" 관계를 나타낼 때, 조합은 "has-a" 관계를 나타낼 때 사용하는 것이 좋습니다.
자바에서 조합이란?
자바에서 "조합"은 한 클래스가 다른 클래스의 인스턴스를 포함하는 방법을 가리킵니다. 이는 "has-a" 관계를 나타내며, 클래스는 다른 클래스의 기능을 재사용하거나 확장하는 데 사용될 수 있습니다.
여기서 "조합"은 객체 지향 프로그래밍의 중요한 개념인 "캡슐화"를 철저히 지키는 방법입니다. 한 클래스가 다른 클래스를 내부에 포함시켜서, 그 클래스의 기능을 이용하거나 확장하는 것을 의미합니다.
예를 들어, `Car` 클래스와 `Engine` 클래스가 있다고 가정해 봅시다. `Car`는 `Engine`을 가지고 있어야 하므로 `Engine` 인스턴스를 `Car` 클래스의 필드로 포함시킬 수 있습니다. 이렇게 하면 `Car`는 `Engine`의 기능을 사용하거나 확장할 수 있습니다.
다음은 그 예제의 간단한 코드입니다:
class Engine {
void start() {
System.out.println("Engine started");
}
}
class Car {
// Engine instance is a field of Car class
private Engine engine;
Car(Engine engine) {
this.engine = engine;
}
void start() {
// Using the functionality of Engine
engine.start();
System.out.println("Car started");
}
}
이런 식으로 조합을 사용하면 클래스 간의 결합도를 낮추고 코드의 재사용성을 높일 수 있습니다. 또한 변경에 대한 영향을 최소화하여 코드 유지 관리성을 향상시킬 수 있습니다.
'[F-Lab 66해빗 페이백 챌린지 ]' 카테고리의 다른 글
| [F-Lab 모각코 페이백 18일차] 팀코칭 질문 (인터뷰 준비 및 개념 학습), MVVM 패턴, MVP 패턴 (0) | 2023.06.01 |
|---|---|
| [F-Lab 모각코 페이백 17일차] 팀코칭 질문 정리 (인터뷰 준비, 개념 학습) (0) | 2023.05.31 |
| [F-Lab 모각코 페이백 15일차] JSP, 서블릿(Servlet), Request 기본 객체 (0) | 2023.05.29 |
| [F-Lab 모각코 페이백 14일차] JSP, Encoding, UTF-8, Character Set (0) | 2023.05.28 |
| [F-Lab 모각코 페이백 13일차] 에러의 종류, 내부 클래스, 익명 클래스,프로퍼티 클래스 (0) | 2023.05.26 |