Home Fundamental of Java
Post
Cancel

Fundamental of Java

동등성, 동일성

동등성 (Equals)

Equals 메서드는 두 객체의 이 같은지 비교하는 메서드이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void equals1() {
    String string1 = "TEST";
    String string2 = "TEST";
    String newString1 = new String("TEST");
    String newString2 = new String("Other TEST");

    System.out.println("string1.equals(string2) = " + string1.equals(string2));
    System.out.println("string1 == string2 = " + string1 == string2);

    System.out.println("-------------------");

    System.out.println("string1.equals(newString1) = " + string1.equals(newString1));
    System.out.println("string1 == newString1 = " + string1 == newString1);

    System.out.println("-------------------");

    System.out.println("newString1.equals(newString2) = " + newString1.equals(newString2));
    System.out.println("newString1 == newString2 = " + newString1 == newString2);
}
  • string1.equals(string2)은 “TEST” 문자열을 비교한다.
    • 두 문자열은 내용이 동일하므로 equals 메서드는 true를 반환한다.
    • string1 == string2는 두 문자열이 동일한 객체를 가리키는지를 확인하는 것인데, “TEST”는 문자열 리터럴로 이미 존재하는 문자열이기 때문에 동일한 객체를 가리킨다.
  • string1.equals(newString1)은 string1과 newString1을 비교한다.
    • 두 문자열은 내용이 동일하므로 equals 메서드는 true를 반환한다.
    • string1 == newString1은 string1이 리터럴 문자열을 가리키고 newString1은 새로운 문자열 객체를 생성했기 때문에 두 객체는 서로 다르다.
  • newString1.equals(newString2)는 newString1과 newString2를 비교한다.
    • 두 문자열 내용이 다르기 때문에 equals 메서드는 false를 반환한다.
    • newString1 == newString2는 두 객체가 서로 다르기 때문에 false를 반환한다.

동일성 (==)

Equals 메서드는 두 객체의 메모리 위치가 같은지 비교하는 메서드이다.

따라서 참조값 자체를 비교한다.


동일한 hashCode의 경우 equals 가 같다고 할 수 있는가?

HashCode가 만들어지는 원리와 존재 이유를 살펴보면 답이 나온다.

HashCode의 존재 이유/생성 과정

HashCode는 여러개의 객체를 다루는 Hash컬렉션에서 주로 사용되는데, 이 때 각 객체를 유일하게 식별할 수 있는 방법이 있어야한다.

그래서 각 객체에 고유한 코드를 부여하기 위한 로직이 내부적으로 동작하게 된다. HashCode를 생성하는 것은 각 객체마다도 다르게 되어있는데 예시로 살펴보면 아래와 같다.

String의 HashCode를 구현한 부분이다.

1
2
3
4
5
6
7
8
9
10
11
12
public class String {

    @Override
    public int hashCode() {
        int hash = 0;
        for (int i = 0; i < this.length(); i++) {
            hash = 31 * hash + this.charAt(i);
        }
        return hash;
    }

}

위와 같이 각 객체마다 랜덤한 값을 부여하기 위한 로직이 동작한다.

이로써 알게된 사실은

  • HashCode가 같은 객체여도 HashCode를 생성하는 과정에서 랜덤한 요소가 있기 때문에 완전히 다른 객체일 수도 있다는 것이다.

  • 또한 Equals가 같다해도 HashCode의 결과는 다를 수도 있다.

  • == 연산자True 결과를 받은 객체들은 HashCode도 같다.

결론

  • Equals가 같아도 HashCode는 다를 수 있다.

  • HashCode가 같아도 Equals는 다를 수 있다.


JVM의 구성 요소

JVM: Architecture


final 키워드

final 변수

변수의 값 변경을 금지한다. (상수화한다.)

final 메서드

Override를 금지한다.

클래스

상속을 금지한다.


추상 클래스와 인터페이스 차이

추상 클래스는 멤버 변수를 가질 수 있고 기본 메서드를 가지고 있을 수 있으며 사용자에게 구현할 메서드를 명세할 수 있다.

인터페이스는 멤버 변수를 가질 수 없고, 기본적으로 구현할 메서드를 명세하는 기능만 존재한다. (JDK 8 버전부터는 기본 메서드를 제공한다.)

가장 큰 차이점은 다중 상속 가능 여부이다. 추상 클래스는 다중 상속이 불가능하며 인터페이스는 가능하다.


다중상속이 불가능한 이유

다중 상속의 가장 큰 문제점은 다이아몬드 현상이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class GrandFather {
    void myMethod(){
        System.out.println("GrandFather");
    }
}

class FatherA extends GrandFather {
    @Override
    void myMethod(){
        System.out.println("FatherA");
    }
}

class FatherB extends GrandFather {
    @Override
    void myMethod(){
        System.out.println("FatherB");
    }
}

class Son extends FatherA, FatherB{
    @Override
    void myMethod() {
        super.myMethod(); // 어떤 메서드를 호출해야하는가?
    }
}

FatherAFatherB를 모두 상속받은 Son 클래스 입장에서는 어떤 부모의 myMethod()를 사용해야 할지 판단할 수 없다. 하라면 하겠지만 복잡성을 다루는 코드를 써야하고, 이에 따른 휴먼 에러가 발생할 가능성이 높게된다.

이렇게 코드의 복잡성을 증가시키게 되는 이유로 자바에서는 클래스 다중 상속이 불가능하다. (인터페이스는 가능하다.)


Primitive Type, Wrapper Class

Java는 Primitive Type, Wrapper Class 두 가지의 범주를 가진 데이터 타입이 존재한다.

Wrapper Class는 모두 Object를 상속받은 객체로써 다루어진다.

Primitive Type

  • Primitive Type은 메모리 사용량이 적고, 연산 속도가 빠르다.

  • Primitive Type은 Garbage Collector에 의해 자동으로 관리되지 않는다.

  • Primitive Type은 Java뿐만 아니라 다른 프로그래밍 언어에서도 사용되는 표준 타입이라서 다른 프로그래밍 언어와의 호환성을 높이는 데 도움이 된다.

Wrapper Class

  • Wrapper Class는 Null을 가질 수 있다.
    • 그래서 Null값을 다뤄야하는 상황이라면 반드시 해두는게 좋다. (Entity Class)
  • Generic에 사용될 수 있다. 컬렉션을 다루거나 제네릭을 활용한 타입의 확장성을 챙길 수 있다.
    • Generic에 기본 자료형 사용시 AutoBoxing과 AutoUnBoxing이 일어난다.
      • Boxing : Primitive -> Wrapper Class
      • UnBoxing : Wrapper Class -> Primitive

AutoBoxing/AutoUnBoxing성능 차이가 확연하게 나타나는 기술이다. 따라서 무분별하게 사용되고 있는 곳이 없는지 꼼꼼하게 체크해야한다.


Reactive Streams


Spring Reacitve Stack에 대해 이해하기


Webflux


Publish/Subscribe


Mono/Flux


스레드와 프로세스의 차이점


멀티 프로세스와 멀티 쓰레드에 대하여


자바의 바이트 코드란 무엇인가요?


컴파일된 바이트 코드는 어디에서 사용될까요?


(코틀린) 코틀린의 컴파일 과정에 대해 설명 해주세요.


JVM에 대해 아는 한도에서 최대한 설명 해주세요.


JIT 컴파일러에 대해 설명 해주세요.


컴파일 언어와 인터프리터 언어에 대해 설명 해주세요.


자바는 인터프리터, 컴파일 언어중 어느 것에 해당되는가?


자바의 메모리 할당과 해제가 이루어지는 과정

GC란?

GC 발생 시점

  • Heap 내에서 객체의 수명을 관리하기 위해 Young, Old 구역으로 나뉜다.
  • Young 영역은 다시 Eden, 두 개의 Survivor 영역으로 구분 된다.

자바 9버전에서 기본으로 적용되는 GC는 무엇이며, 구조 및 동작방식


메모리 단편화란?

  • 내부단편화
  • 외부단편화

메모리 단편화를 해소하는 방법


객체지향의 특징


객체지향의 원칙


Java는 Call By Value인가? Call By Reference인가?


Java 는 왜 포인터가 없을까?


리플렉션(Reflection)이란 무엇인가?


리플렉션의 장단점에 대해 말씀해주세요.


리플렉션은 어떤 경우에 사용되는가?


Error와 Exception의 차이를 설명해주세요.

두 타입은 어떤 인터페이스를 상속받아 구현이 되었는가?


Checked Exception, Unchecked Exception 에 대해 설명해주세요.

각각의 대표적인 예외들의 종류


JPA를 사용해 데이터를 처리 하는 프로젝트에서, 특정 트랜잭션 내에 Checked, Unchecked Exception이 발생하는 경우 강각 어떤 일이 발생하는가?

This post is licensed under CC BY 4.0 by the author.