English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Java의 비교 문제는 매우 기본적이면서도 혼란스러운 문제 중 하나이다. 오늘은 몇 가지 잘못된 점을 상세히 정리하여, 모두의 학습과 면접에 도움이 되기를 바란다.
1. ==와 equals()의 차이
먼저, ==와 equals()의 차이를 알아야 한다. ==는 항상 주소 값을 비교하는 것이며, 기본 데이터 타입에 대해서는 == 비교는 실제로는 변수 값이 같은지 확인하는 것이며, 참조 데이터 타입에 대해서는 주소 값을 비교한다. 특히 String 타입은 ==를 자연스럽게 사용할 수 있지만, 실수하기 쉬운 부분이다. equals() 메서드는 Object 클래스의 메서드로, 모든 클래스는 Java에서 기본적으로 Object 클래스를 상속받기 때문에 모든 클래스 객체는 equals() 메서드를 가지고 있다. Object 클래스의 equals() 메서드는 다음과 같다:
소스 코드를 보면 Object 클래스의 equals() 메서드가 ==를 사용하여 루프를 사용하는 것을 알 수 있으며, 따라서 그것이 비교하는 것은 실제로는 주소 값이다. 따라서 equals() 메서드를 다른 비교를 위해 사용하고자 한다면 equals() 메서드를 재정의해야 한다.
2. 기본 데이터 타입 및 패키지 클래스
모두가 알고 있듯이, byte, short, int, long, boolean, char, double, float 이 tám개는 기본 데이터 타입이며, 이들은 스택 메모리에 저장된다. 그리고 이들을 대표하는 패키지 타입(Byte, Short, Integer, Long, Boolean, Character, Double)가 정의된 변수는 힙 메모리에 존재한다. 기본 데이터 타입에 대해서는, 비교는 상대적으로 간단하며, 같은지 확인하는 것은 ==를 사용하고, 크기를 비교하는 것은 <, >, <=, >=를 사용하면 된다. 하지만 패키지 타입에 대해서는 다르다.
먼저, 등가 여부를�断정하는 경우, 다음 코드의 실행 결과를 확인해야 합니다:
package dailytest; import org.junit.Test; /** * Java에서의 비교 요약 * @author yrr */ public class JavaCompareTest { /** * Integer 타입의 등가 여부判断 */ @Test public void test01() { int n3 = 48; System.out.println("--------new 객체를 사용할 때는 값이 [-127,128] 사이에 있을 때---------"); Integer n7 = new Integer(48); Integer n8 = new Integer(48); System.out.println(n7 == n8); //false System.out.println(n7 == n3); //true System.out.println("--------직접 할당 방식에서는 값이 [-128,127] 사이에 있을 때---------"); Integer n1 = 48; Integer n2 = 48; System.out.println(n3 == n1); //true System.out.println(n1 == n2); //true System.out.println(n1.equals(n2)); //true System.out.println(n1.equals(n3)); //true System.out.println(n1.intValue() == n2.intValue()); //true System.out.println("--------직접 할당 방식에서는 값이 [-127,128] 사이에 있을 때---------"); Integer n4 = 128; Integer n5 = 128; int n6 = 128; System.out.println(n4 == n5); //false System.out.println(n4 == n6); //true System.out.println(n4.equals(n5)); //true System.out.println(n4.equals(n6)); //true System.out.println(n4.intValue() == n5.intValue()); //true //Integer.intValue() 메서드를 사용할 때는 null 여부를 확인하여 NullPointException이 발생하지 않도록 주의해야 합니다 } /** * Long 타입의 등가 여부�断정 */ @Test public void test02() { //이곳에서는 long으로 정의할 때 L이나 l을 추가하지 않아도 됩니다. Long으로 정의할 때는 반드시 추가해야 하지 않으면 오류가 발생합니다 //구축할 때 구분을 위해 추가해야 합니다 long n3 = 48L; System.out.println("--------new 객체를 사용할 때는 값이 [-127,128] 사이에 있을 때---------"); Long n7 = new Long(48); Long n8 = new Long(48); System.out.println(n7 == n8); //false System.out.println(n7 == n3); //true System.out.println("--------직접 할당 방식에서는 값이 [-127,128] 사이에 있을 때---------"); Long n1 = 48L; Long n2 = 48L; System.out.println(n3 == n1); //true System.out.println(n1 == n2); //true System.out.println(n1.equals(n2)); //true System.out.println(n1.equals(n3)); //true System.out.println(n1.intValue() == n2.intValue()); //true System.out.println("--------직접 할당 방식에서는 값이 [-127,128] 사이에 있을 때---------"); Long n4 = 128L; Long n5 = 128L; long n6 = 128; System.out.println(n4 == n5); //false System.out.println(n4 == n6); //true System.out.println(n4.equals(n5)); //true System.out.println(n4.equals(n6)); //true System.out.println(n4.intValue() == n5.intValue()); //true //Long.intValue() 메서드를 사용할 때는 null 여부를 확인하여 NullPointException이 발생하지 않도록 주의해야 합니다 } }
위의 실행 결과에 대해 다음과 같이 설명합니다:
먼저, new 메서드를 사용하여 Integer 또는 Long 객체를 선언하는 경우, new 객체는 모두 스택에서 공간을 할당하기 때문에, 두 값을 같게 할당해도 ==로 비교할 때 주소 값을 비교하기 때문에 false를 반환합니다. 기본 데이터类型的 包装类은 모두 equals() 메서드를 재정의하여 값의 크기를 비교합니다. 따라서 equals() 메서드를 사용하면 값을 기준으로 비교할 수 있습니다. Integer 변수와 int 변수를 비교할 때, 비교 값은 값의 크기에 기반하여 나오는 것을 발견할 수 있습니다. 이는 Integer 타입이 비교할 때 자동으로 박싱되어 int 타입으로 변환되기 때문입니다. 이전의 설명은 모든 包装类型에 적용됩니다 직접 할당 방식에서는 값이48의 두 Integer 변수에 대해 ==로 비교할 때 true로 나타나지만, 값이128이후에도 false로 나타납니다. 이는 Integer n1 = 48이렇게 직접 할당하는 방식은 Integer.value() 메서드를 호출하는 것입니다. Integer.value() 메서드의 소스 코드를 간단히 보면 다음과 같습니다:
여기서 볼 수 있듯이, 이곳에 if 조건문이 있으며, 입력된 i가 [에 포함되어 있을 때-128,127의 범위 내에서는 IntegerCache 배열에서 직접 반환됩니다. 따라서 이 범위 내의数值는 해당 배열의 주소 값을 반환합니다. 따라서 ==로 판단하면 true를 반환합니다. 이 범위 밖의 것은 new로 생성된 객체이므로 false를 반환합니다. 이 결과는 Byte, Short, Integer, Long 타입 모두에 대해 적용됩니다. (관심이 있는 경우 해당 value() 메서드의 소스 코드를 확인할 수 있습니다). Byte 타입의 범위는 [}}-128,127이렇게 되어 Byte 타입에 대해 ==와 equals()는 다를 바 없습니다.
대소 비교를 위해 >, <, <=, >=를 사용하는 것은 문제가 없습니다. 자동 해박이 수행됩니다. 그러나 우리는 일반적으로 다음 두 가지 방식을 추천합니다:
xxxValue() 메서드를 호출하여 기본 데이터 타입으로 변환하여 비교합니다. compareTo() 메서드를 사용하여 비교합니다. 패키지 클래스에서compareTo() 메서드를 재정의했습니다. compareTo() 소스 코드를 확인하면, 실제로는 자동 해박으로 변환하여 기본 데이터 타입으로 비교하는 것을 볼 수 있습니다.
2. Java 객체 비교
위의 설명을 통해 객체 비교는 쉬워집니다. 원리는 모두 동일합니다.
1. String 타입의 비교
String 타입은 >, <=, >=, <를 직접 사용할 수 없습니다. 컴파일 예외가 발생합니다.
package dailytest; import org.junit.Test; /** * Java에서의 비교 요약 * @author yrr */ public class JavaCompareTest { @Test public void test03() { String s1 = new String("123"); String s2 = new String("123"); System.out.println(s1 == s2); //false System.out.println(s1.equals(s2)); String s3 = "234"; String s4 = "234"; System.out.println(s3 == s4); //true System.out.println(s3.equals(s4)); //true //System.out.println(s1 <= s3); //The operator < is undefined for the argument type(s) java.lang.String, java.lang.String System.out.println(s1.compareTo(s3) < 0); //true } }
2. 객체 비교
클래스 객체 비교 결과도 동일하지만, 기본 데이터 타입과 String 타입에 비해 약간 복잡합니다.
某一規則에 따라 두 개의 객체가 같은지 여부를 판단하려면, 판단되는 클래스에서 equals() 메서드를 재정의해야 합니다. 예제 코드는 다음과 같습니다:
package dailytest; import org.junit.Test; /** * Java에서의 비교 요약 * @author yrr */ public class JavaCompareTest { @Test public void test04() { Person p1 = new Person("yrr",18); Person p2 = new Person("yrr",18); System.out.println(p1 == p2); //false System.out.println(p2.equals(p1)); //true } } class Person{ private String name; private Integer age; public Person() { } public Person(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public Integer getAge() { return age; } @Override public boolean equals(Object obj) { Person person = (Person) obj; return name.equals(person.getName()) && age.equals(person.getAge()); } }
또한 두 개의 객체를 비교할 때(이것은 자주 물어보는 면접 질문 중 하나입니다), 두 가지 방법이 있습니다:
비교 대상 클래스가 Comparable 인터페이스를 구현하고 compareTo() 메서드를 재정의하면, 또는 Comparator 인터페이스를 구현한 클래스를 정의하거나 내부 클래스를 사용하여 compare() 메서드를 재정의하면 됩니다. 두 방법의 차이는 다음과 같습니다: 전자는 비교 대상 클래스 내에 정의되며, 후자는 비교 대상 클래스 외에 정의됩니다. 이러한 차이로 두 방법의 장단점도 명확하게 나타납니다. 전자는 간단하지만 비교 대상 클래스를 수정해야 하며, 후자는 원래 코드를 수정하지 않아도 더 유연합니다.
첫 번째 방법, 예제 코드는 다음과 같습니다:
package dailytest; import org.junit.Test; /** * Java에서의 비교 요약 * @author yrr */ public class JavaCompareTest { @Test public void test5() { Person p1 = new Person("yrr",18); Person p2 = new Person("wx",19); System.out.println(p1.compareTo(p2) < 0); } } class Person implements Comparable<Person>{ private String name; private Integer age; public Person() { } public Person(String name, Integer age) { this.name = name; this.age = age; } public Integer getAge() { return age; } @Override public int compareTo(Person o) { return this.getAge(); - o.getAge(); } }
두 번째 방법, 예제 코드는 다음과 같습니다:
package comparator; import java.util.Arrays; import java.util.Comparator; public class MyComparator { public static void main(String[] args) { User[] users = new User[] { new User("u")}1001", 25),}} new User("u1002", 20), new User("u1003", 21) }; Arrays.sort(users, new Comparator<User>() { @Override public int compare(User o1, User o2) { return o1.getAge() - o2.getAge(); } ); for (int i = 0; i < users.length; i++) { User user = users[i]; System.out.println(user.getId() + " " + user.getAge()); } } } class User { private String id; private int age; public User(String id, int age) { this.id = id; this.age = age; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getId() { return id; } public void setId(String id) { this.id = id; } }
이제 여러분께 말씀드린 Java에서 비교 문제에 대한 내용이 모두입니다. 다른 질문이 있으면 아래 댓글 영역에서 논의해 주세요. 감사합니다.
명시: 이 글의 내용은 인터넷에서 가져왔으며, 저작권자는 누구인지 모릅니다. 내용은 인터넷 사용자가 자발적으로 기여하고 업로드한 것이며, 이 사이트는 소유권을 가지지 않으며, 인공적인 편집 처리를 하지 않았으며, 관련 법적 책임도 부담하지 않습니다. 저작권 침해가 의심되는 내용을 발견하면, 메일을 보내 주시기 바랍니다: notice#oldtoolbag.com(메일을 보내면, #을 @으로 바꿔주세요. 신고하고 관련 증거를 제공해 주시면, 사이트는 즉시 저작권 침해 내용을 삭제할 것입니다。)