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

자료형과 객체 비교

자료형 -> null 처리 -> Wrapper -> equals -> hashCode -> compareTo

Q. 자바에서 기본 자료형과 참조 자료형의 차이는 무엇이며, null과의 관계는 어떻게 되나요?

자바에서는 자료형을 크게 두 가지로 나눌 수 있습니다. 하나는 기본 자료형이고, 다른 하나는 참조 자료형입니다.

기본 자료형에는 int, double, boolean, char 같은 것들이 있고, 이들은 실제 값 자체를 메모리에 직접 저장합니다. 예를 들어 int a = 10;이라고 하면, 변수 a에는 10이라는 값이 스택 메모리 공간에 그대로 저장됩니다.

반면에 참조 자료형은 객체를 참조하는 방식입니다. 대표적으로 String, Integer, 사용자 정의 클래스 같은 것들이 여기에 속합니다. 이 경우에는 실제 객체는 힙 메모리에 만들어지고, 변수에는 그 객체가 있는 메모리 주소, 즉 참조값이 저장됩니다.

이 구조 때문에 두 자료형의 null과의 관계가 다르게 나타납니다. 기본 자료형은 실제 값을 담고 있어야 하기 때문에, null이라는 "값 없음" 상태를 가질 수 없습니다. 하지만 참조 자료형은 단순히 객체의 주소를 참조하고 있기 때문에, "아직 어떤 객체도 참조하고 있지 않다" 는 의미로 null이 저장될 수 있습니다.

예를 들어 String name = null;이라고 하면, name이라는 변수는 현재 어떤 문자열도 참조하지 않는 상태가 되며, 이 상태에서 메서드를 호출하면 NullPointerException이 발생할 수 있습니다.

Q. Wrapper 클래스는 기본형을 객체로 바꿔주는데, 실무에서는 어떤 상황에서 사용되며 어떤 장점이 있나요?

자바에는 int, boolean 같은 기본 자료형이 있는데, 이들은 객체가 아니기 때문에 컬렉션이나 다양한 API에서 바로 사용할 수 없는 제약이 있습니다. 그래서 자바에서는 각 기본형에 대응하는 Wrapper 클래스를 제공합니다.

예를 들어 int에는 Integer, boolean에는 Boolean, double에는 Double이 대응되며, 이들은 기본값을 객체로 감싸는 일종의 포장(wrapper) 역할을 합니다.

Wrapper 클래스는 참조 자료형이기 때문에, 첫 번째로 컬렉션에 저장할 때 유용합니다. 자바의 List, Map 같은 컬렉션 클래스는 객체만 저장할 수 있기 때문에, 기본형을 저장하려면 Integer, Double 같은 Wrapper 클래스를 사용해야 합니다.

두 번째로는 null 값을 저장할 수 있다는 점입니다. 기본형은 항상 값을 가져야 해서 int age;처럼 선언하면 초기화되지 않은 상태로는 쓸 수 없지만, Integer age = null;이라고 하면 "아직 값이 없음"을 명시적으로 표현할 수 있습니다.

이건 특히 데이터베이스 연동 같은 실무 상황에서 자주 사용됩니다. 예를 들어 DB에서 특정 값이 존재하지 않을 때는 null로 처리되는데, 이걸 기본형으로 받으면 에러가 나기 때문에 Wrapper 타입으로 처리해야 합니다.

세 번째는 Optional과의 연계 사용입니다. Optional<Integer>처럼 null이 될 수 있는 값을 감쌀 때, 내부 값은 반드시 참조형이어야 하기 때문에 기본형은 사용할 수 없습니다. 이런 구조에서는 Wrapper 클래스가 필수적입니다.

Q. 그럼 Wrapper 클래스들은 서로 비교할 때 어떻게 동작하나요?

Wrapper 클래스는 모두 Object를 상속받은 참조형이기 때문에, 비교할 때는 기본형처럼 ==를 쓰는 것이 아니라 equals() 메서드를 써야 합니다.

예를 들어 Integer a = 1000; Integer b = 1000;일 때 a == b는 false지만 a.equals(b)는 true입니다.

이유는 ==는 객체의 주소(참조) 를 비교하고, equals()는 내부 값의 논리적 동등성을 비교하기 때문입니다.

다만 자바에서는 -128 ~ 127 사이의 Integer 값은 캐싱이 되어 있어서 이 범위 안에서는 ==도 true가 나올 수 있지만, 그건 예외적인 최적화입니다.

따라서 Wrapper 클래스 간 비교는 항상 equals()를 사용하는 게 안전하며, 내부적으로도 이미 equals()가 잘 오버라이딩 되어 있어서 값 비교가 정확히 되도록 설계되어 있습니다.

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

자바에서 equals() 메서드는 두 객체가 논리적으로 같은지 비교하는 기능을 합니다.

Object 클래스의 기본 구현은 ==과 마찬가지로 두 객체의 참조 주소가 같은지를 비교합니다. 즉, 같은 객체를 참조할 때만 true를 반환합니다.

하지만 대부분의 경우에는 객체의 주소가 아니라 내부 값이 같은지를 비교하고 싶을 때가 많습니다.

예를 들어, 우리가 User라는 클래스를 만들고 id와 name이 같으면 같은 사용자로 간주하고 싶다면, equals()를 오버라이딩해서 필드 값을 기준으로 비교하도록 바꿔줘야 합니다.

실제로 String, Integer, LocalDate 같은 자바의 주요 클래스들도 equals()를 오버라이딩해서 내용이 같으면 같다고 판단하도록 구현되어 있습니다.

Q. equals() 메서드를 오버라이딩할 때, hashCode()도 같이 오버라이딩해야 하나요?

네, 꼭 같이 오버라이딩해야 합니다.

자바에서는 equals()가 true인 두 객체는 반드시 동일한 hashCode() 값을 가져야 한다는 규칙이 있습니다.

이 규칙이 중요한 이유는 HashMap, HashSet 같은 해시 기반 컬렉션에서 hashCode()를 먼저 비교해서 위치를 찾고, 그 다음에 equals()로 동등성을 판단하기 때문입니다.

만약 equals()는 오버라이딩했지만 hashCode()는 그대로 두면, 논리적으로 같은 객체인데도 서로 다른 해시값을 가져서 컬렉션에서는 다른 객체로 처리되는 문제가 발생합니다.

이로 인해 데이터를 찾지 못하거나, 중복이 허용되지 않아야 할 상황에서 중복 삽입이 되는 등의 문제가 생길 수 있습니다.

그래서 실무에서는 equals()를 오버라이딩할 때는 항상 hashCode()도 함께 구현해주는 것이 중요합니다.

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를 전달해 비교 로직을 분리하는 것이 좋습니다

PreviousGarbage CollectionNext힙(Heap)과 메모리(Memory)

Last updated 17 days ago