개발자 기술면접 꼬리물기 질문
  • Welcome
  • 01 Java
    • 01-01. Generic
    • 01-02. Garbage Collection
    • 01-03. 자료형과 객체 비교
    • 01-04. 힙(Heap)과 메모리(Memory)
    • 01-05. Java 버전과 JDK / JRE
    • 01-06. 스레드(Thread)
    • 01-07. 예외(Throwable)
    • 01-08. Call By Value와 Call By Reference
    • 01-09. String, equals, StringBuffer
    • Thread와 비동기
  • 02 Spring
    • 02-01. Spring 동작 방식
    • 02-02. 인증(Authentication)과 인가(Authorization)
    • @Autowired, @RequiredArgsConstructor
    • 트랜잭션(Transaction)
    • QueryDSL과 SQL Injection
    • SecurityContextHolder
    • @EqualsAndHashCode
  • 03 DATABASE
    • 03-01. Join
    • 03-02. Index
    • 정규화 (Normalization)
    • 파티셔닝과 샤딩(Partitioning & Sharding)
    • 트랜잭션(Transaction)과 락(Lock)
    • 덤프(Dump)
    • Redis
    • 격리 수준(MySQL)
  • 04 Algorithms & Data Structures
    • 04-01. Set
    • 04-02. 정렬
    • 04-03. 우선순위 큐 (Priority Queue)
    • DFS와 BFS
    • 힙(Heap) 자료구조
    • 스택(Stack)과 큐(Queue)
    • 암호화 알고리즘
    • LinkedList
    • 자료구조 - 해시 테이블(HashTable)
    • 자료구조 - ConcurrentHashMap
  • 05 NETWORK
    • 05-01 Proxy Server
    • 05-02 Http 프로토콜
    • 전송 계층 (Transport Layer)
    • 네트워크 계층 (Network Layer)
    • Http와 Https
    • IP(Internet Protocol)
    • 소켓(Socket)
    • 로드 밸런싱(Load Balancing)
  • 06 WEB
    • 06-01 CORS 정책
    • 동시성 제어
    • N+1 문제
    • 웹 브라우저 동작원리
    • URI, URL, URN
    • 채팅 아키텍처 설계
  • 디자인 패턴
    • 전략 패턴 (Strategy Pattern)
    • 싱글톤 패턴 (Singleton Pattern)
    • 템플릿 메서드 패턴과 전략 패턴
    • 데코레이터 패턴 (Decorator pattern)
  • 개발자
    • 개발 방법론 TDD
  • 운영체제
    • JIT & AOT 컴파일
    • 컨텍스트 스위칭(Context Switching)
    • 프로세스와 스레드
    • 싱글 스레드와 멀티 스레드
  • 코딩테스트
    • Stack / Queue (스택 / 큐)
    • Heap(우선 순위 큐)
    • DP(동적 계획법)
    • DFS(깊이 우선 탐색)
    • BFS(너비 우선 탐색)
    • Greedy(그리디 알고리즘)
    • 해시(Hash)
    • 투 포인터 알고리즘
    • Shortest path
    • 수학적 사고
Powered by GitBook
On this page
  • Q. 자바에서 기본 자료형은 null을 허용하지 않지만, 참조 자료형은 null을 허용합니다. 이 차이에 대해서 설명해주세요.
  • Q. 그렇다면 자바에 기본 자료형과 관련된 Wrapper 클래스라는 것이 있는데, 이것이 무엇이며 null을 사용할 수 있는 이유는 무엇인가요?
  • Q. 그렇다면 Wrapper 클래스에서, Integer a = 100; Integer b = 100; 과 Integer c = 200; Integer d = 200; 코드가 있을 때, a == b와 c == d의 결과가 다르게 나올 수 있습니다. 그 이유는 무엇일까요?
  • Q. 자바에서 equals 메서드는 무엇이며, 왜 오버라이딩이 필요한가요?
  • Q. equals 메서드를 오버라이딩할 때 hashCode 메서드도 반드시 같이 오버라이딩해야 한다고 알고 있습니다. 그 이유는 무엇이며, 만약 같이 오버라이딩하지 않으면 어떤 문제가 발생할 수 있을까요?
  • Q. 자바에는 Object 클래스의 기본 hashCode() 메서드 외에 System.identityHashCode(Object obj)라는 메서드도 존재합니다. 이 System.identityHashCode() 메서드는 언제, 어떤 목적으로 사용되며, 일반적인 hashCode() 메서드와는 어떤 차이점이 있을까요?
  • Q. Comparable 인터페이스의 compareTo()와 Object의 equals()는 어떤 점에서 다르나요?
  • Q. equals()와 compareTo()의 일관성이 깨졌을 때 어떤 문제가 생기나요?
  1. 01 Java

01-03. 자료형과 객체 비교

Previous01-02. Garbage CollectionNext01-04. 힙(Heap)과 메모리(Memory)

Last updated 18 days ago

Q. 자바에서 기본 자료형은 null을 허용하지 않지만, 참조 자료형은 null을 허용합니다. 이 차이에 대해서 설명해주세요.

int, boolean 같은 기본 자료형은 실제 값이 메모리에 직접 저장되기 때문에 값이 없다는 개념인 null을 가질 수 없습니다. 반면에 String, Object 같은 참조 자료형은 객체의 메모리 주소를 저장하는 변수입니다. 따라서 참조할 객체가 없거나 아직 할당되지 않은 경우, 해당 메모리 주소가 없다는 의미로 null을 가질 수 있습니다. null은 어떤 객체도 참조하고 있지 않음을 나타냅니다.

Q. 그렇다면 자바에 기본 자료형과 관련된 Wrapper 클래스라는 것이 있는데, 이것이 무엇이며 null을 사용할 수 있는 이유는 무엇인가요?

Wrapper 클래스는 기본 자료형을 객체 형태로 다루기 위해 제공되는 클래스입니다. 예를 들어 int는 Integer, char는 Character로 감싸는 식이죠. 이 Wrapper 클래스들은 일반적인 참조 자료형과 동일하게 객체의 인스턴스를 나타내기 때문에, null 값을 가질 수 있습니다. 즉, 기본 자료형의 값을 객체로 감싸서 null을 허용해야 하는 상황이나 컬렉션 프레임워크처럼 객체만을 다루는 곳에서 유용하게 사용됩니다.

Q. 그렇다면 Wrapper 클래스에서, Integer a = 100; Integer b = 100; 과 Integer c = 200; Integer d = 200; 코드가 있을 때, a == b와 c == d의 결과가 다르게 나올 수 있습니다. 그 이유는 무엇일까요?

위의 코드의 결과가 다르게 나올 수 있는 이유는 Integer 클래스의 내부 캐싱(caching) 메커니즘 때문입니다.

자바의 Integer 클래스는 성능 최적화를 위해 -128부터 127까지의 정수 값에 대해서는 미리 생성된 Integer 객체를 캐싱해둡니다. 따라서 Integer.valueOf() 메서드를 통해 이 범위 내의 값을 생성할 때는 항상 동일한 캐시된 객체의 참조를 반환합니다.

Integer a = 100; Integer b = 100; 의 경우, 100은 캐싱 범위(-128 ~ 127) 안에 있기 때문에 a와 b는 동일한 캐시된 Integer 객체를 참조하게 됩니다. 따라서 a == b는 true를 반환합니다.

반면 Integer c = 200; Integer d = 200; 의 경우, 200은 캐싱 범위를 벗어납니다. 이 값들은 매번 새로운 Integer 객체를 생성하게 됩니다. 비록 값이 같더라도 서로 다른 메모리 주소에 있는 객체가 되므로, c == d는 false를 반환하게 됩니다.

이러한 특성 때문에 Wrapper 클래스의 값을 비교할 때는 == 연산자 대신 equals() 메서드를 사용하는 것이 안전하고 권장됩니다. equals() 메서드는 항상 객체의 논리적인 값 동등성을 비교하기 때문입니다.

Q. 자바에서 equals 메서드는 무엇이며, 왜 오버라이딩이 필요한가요?

equals 메서드는 두 객체가 논리적으로 동일한지를 비교하는 데 사용됩니다.

Object 클래스에 기본적으로 구현된 equals 메서드는 두 객체의 메모리 주소를 비교하여 동일한 인스턴스인지를 확인합니다. 하지만 우리가 개발할 때는 두 객체가 비록 다른 메모리 주소에 있더라도, 내부의 값이 동일하다면 같은 객체로 취급해야 하는 경우가 많습니다.

예를 들어, 두 개의 Student 객체가 학번이 같다면 같은 학생으로 봐야 하죠. 이럴 때 equals 메서드를 오버라이딩하여 우리가 정의한 논리적인 동등성 기준에 따라 비교하도록 만드는 것입니다.

Q. equals 메서드를 오버라이딩할 때 hashCode 메서드도 반드시 같이 오버라이딩해야 한다고 알고 있습니다. 그 이유는 무엇이며, 만약 같이 오버라이딩하지 않으면 어떤 문제가 발생할 수 있을까요?

네, equals 메서드를 오버라이딩했다면 hashCode도 반드시 함께 오버라이딩해야 합니다. 자바의 Object 클래스 규약에 따르면, equals 메서드가 true를 반환하는 두 객체는 반드시 같은 hashCode 값을 가져야 합니다.

이 원칙을 지키지 않으면 HashMap, HashSet과 같은 해시 기반 컬렉션에서 문제가 발생합니다. HashMap은 키(Key) 객체의 hashCode 값을 이용해 내부 배열의 인덱스를 빠르게 찾아갑니다. 만약 equals는 true를 반환하지만 hashCode는 다른 두 객체가 있다면, HashMap은 이들을 다른 객체로 인식하여 다른 인덱스에 저장할 수 있습니다.

예를 들어, HashSet에 이미 추가된 객체와 equals는 같지만 hashCode가 다른 새 객체를 다시 추가하려 할 때, HashSet은 중복을 인식하지 못하고 같은 객체를 두 번 저장하는 문제가 발생할 수 있습니다. 또한, 기존 객체를 찾으려 할 때 다른 해시 값 때문에 찾지 못하는 상황도 발생할 수 있습니다. 따라서 equals와 hashCode의 일관성은 해시 기반 컬렉션의 정확성과 성능에 필수적입니다.

Q. 자바에는 Object 클래스의 기본 hashCode() 메서드 외에 System.identityHashCode(Object obj)라는 메서드도 존재합니다. 이 System.identityHashCode() 메서드는 언제, 어떤 목적으로 사용되며, 일반적인 hashCode() 메서드와는 어떤 차이점이 있을까요?

System.identityHashCode()는 Object 클래스의 hashCode()와는 조금 다른 목적으로 사용됩니다. 쉽게 말해, System.identityHashCode(Object obj)는 해당 객체가 메모리에 어디에 있는지에 기반한 고유한 숫자를 돌려주는 메서드라고 보시면 됩니다. 이건 마치 주민등록번호처럼, 객체 하나하나에 부여된 고유한 식별자 같은 거죠.

일반적인 Object.hashCode() 메서드는 객체의 메모리 주소를 기반으로 해시 코드를 반환합니다. 하지만 우리가 String 클래스처럼 hashCode()를 오버라이딩해서 '내용이 같으면 같은 해시 코드' 를 돌려주도록 바꿀 수 있습니다. 예를 들어, "hello"라는 문자열 두 개는 메모리 주소가 달라도 hashCode() 값은 같죠. 이처럼 논리적인 '동등성(equality)' 을 나타내는 데 사용됩니다.

반면 System.identityHashCode() 메서드는 개발자가 절대 오버라이딩할 수 없습니다. 항상 JVM이 객체에 부여한 메모리상의 실제 고유 식별자를 바탕으로 해시 코드를 반환합니다. 즉, 두 객체가 equals() 메서드로 true가 나온다고 해도 (내용은 같지만), 서로 다른 메모리 공간에 있는 별개의 객체라면 System.identityHashCode() 값은 다르게 나옵니다. 이건 객체의 '고유성(Identity)' 을 나타내는 거죠.

Q. Comparable 인터페이스의 compareTo()와 Object의 equals()는 어떤 점에서 다르나요?

Comparable 인터페이스의 compareTo()와 Object 클래스의 equals()는 객체를 비교한다는 점에서는 비슷해 보일 수 있지만, 실제 목적과 동작 방식은 서로 다릅니다.

먼저 equals()는 두 객체가 논리적으로 같은지, 즉 동등성(equality) 을 확인하는 데 사용됩니다. 기본적으로 Object 클래스에 정의되어 있고, 보통은 우리가 equals()를 오버라이딩해서 객체의 특정 필드 값이 같으면 true를 반환하도록 구현합니다. 예를 들어 User 객체의 id가 같으면 같은 사용자로 보고 싶다면 equals()를 오버라이딩해서 그 기준을 정의할 수 있습니다.

반면에 compareTo()는 Comparable 인터페이스에 정의된 메서드로, 두 객체 간의 정렬 순서를 비교하는 데 사용됩니다. 즉, 이 객체가 다른 객체보다 작다, 같다, 크다를 판단해서 정렬 기준을 제공하는 것이 목적입니다.

예를 들어 compareTo()에서 0을 반환하면 두 객체가 정렬상 같다는 의미이고, 음수를 반환하면 현재 객체가 앞에, 양수면 뒤에 정렬된다는 뜻입니다.

여기서 중요한 차이는, equals()는 단순히 “같다/다르다”를 판단하는 불리언(boolean) 비교이고, compareTo()는 정렬을 위한 정수(int) 비교라는 점입니다.

또 하나 중요한 포인트는, equals()가 true이면 compareTo()는 0을 반환해야 일관성(consistency) 이 유지된다는 것입니다. 이게 맞지 않으면 TreeSet이나 TreeMap 같은 정렬 기반 자료구조에서 예기치 않은 동작이 발생할 수 있습니다.

Q. equals()와 compareTo()의 일관성이 깨졌을 때 어떤 문제가 생기나요?

자바에서는 equals()와 compareTo() 사이에 일관성(consistency) 이 유지되는 것이 중요합니다.

그 일관성이란, 어떤 두 객체가 equals()로 비교했을 때 true라면, compareTo()로 비교했을 때도 0을 반환해야 한다는 의미입니다.

그런데 이 일관성이 깨지면, 특히 TreeSet, TreeMap, PriorityQueue 같은 정렬 기반 자료구조에서 예상하지 못한 동작이 발생할 수 있습니다.

예를 들어, 어떤 객체 A와 B가 equals()로는 같다고 판단되는데 compareTo()는 0이 아닌 값을 반환한다면, TreeSet에 A를 넣고 나서 B를 넣었을 때, TreeSet은 B를 동일한 요소로 보지 않고 중복으로 허용해버릴 수 있습니다.

반대로 compareTo()는 0을 반환했는데, equals()는 false인 경우도 문제가 됩니다. 이 경우에는 동일한 위치에 있지만 논리적으로는 다른 객체들이 들어가게 되어, contains()나 remove() 같은 메서드에서 동작이 이상해질 수 있습니다.

예를 들면, TreeSet.contains(obj)를 호출했을 때 compareTo()는 0을 반환해서 존재한다고 판단하지만, equals()는 false여서 Set에서 찾지 못하는 상황이 생깁니다.

따라서 Comparable을 구현할 때는 equals()와 compareTo()의 기준을 일치시키는 것이 중요합니다. 기준이 달라야 한다면, HashSet을 사용하거나 TreeSet에 별도의 Comparator를 전달해 비교 로직을 분리하는 것이 좋습니다