Углубленное изучение Equals() и == различий в java

Java

«Определение равенства двух вещей» — одна из самых распространенных операций в программировании. В Java есть два способа определить, равны ли они: один — использовать тестер «==», а другой — использовать « equals()», вызывали ли вы когда-нибудь странные ошибки, смешивая их? Эта статья познакомит вас с принципом суждения, стоящим за обоими.

Тестер равенства "=="

Тестер равенства "==" используется для сравнения примитивных типов данных и данных ссылочного типа. Значения сравниваются при сравнении примитивных типов данных, а ссылки (указатели) сравниваются при сравнении ссылочных типов данных.

"==", чтобы судить об основном типе данных

Основные типы данных относятся к восьми типам данных в Java: byte, short, int, long, float, double, char, boolean.

Общая особенность этих восьми основных типов данных заключается в том, что они имеют определенные значения в памяти, такие как тип данных INT «2», который хранится в форме 0000 0010 на машине с 8-битной шиной данных Отказ (8-битная машина предполагается)

Когда вы используете == для сравнения двух примитивных типов данных, вы сравниваете их соответствующие значения в памяти.

Чтобы позаботиться о студентах, которые хотят разобраться в этом, я добавлю, как сравниваются два значения: процессор сделает разницу между двумя значениями при сравнении, а затем проверит флаг регистр. Регистр флага хранит результат операции, и есть бит флага, который равен 0. Если бит равен 1, это доказывает, что разница между ними равна 0 и они равны.

"==" оценивает данные ссылочного типа

Ссылочный тип данных также хорошо понимается буквально, это ссылка, указывающая на конкретный объект в куче памяти.

НапримерStudent stu = new Student();stu здесь является ссылкой, которая указывает на текущий новыйStudentобъект. Когда мы хотим манипулировать этимStudentобъект, вам нужно только манипулировать ссылкой, напримерint age = stu.getAge();.

Таким образом, когда вы используете "==", чтобы судить о том, равны ли два ссылочных типа данных, вы фактически оцениваете две ссылки.указать на один и тот же объект.

См. пример ниже:

public static void main(String[] args) {
    String s1 = "hello";	//s1指向字符串常量池中的"hello"字符串对象
    String s2 = "hello";	//s2也指向字符串常量池中的"hello"字符串对象
    System.out.println(s1 == s2);   //true

    String s3 = new String("hello");   //s3指向的是堆内存中的字符串对象 
    System.out.println(s1 == s3);	//false
}

Как видно из приведенного выше примера, поскольку ссылки «s1» и «s2» указывают на строку «hello» в пуле констант, возвращается значение true. (позже я опубликую подробную статью о строках Java, включающую знания об инициализации строк и пулах строковых констант)

И "S3" указывает на новый строковый объект создания, потому что пока он используетсяnewключевое слово, создаст новый объект в куче памяти.

Другими словами, s1 и s3 указывают на разные строковые объекты, поэтому возвращайте false.

Метод оценки равенства equals()

Существует существенное различие между equals() и ==. == можно рассматривать как инкапсуляцию «операционной системы для сравнения данных», тогда как equals() — это метод сравнения, который поставляется с каждым объектом. определенное сравнение, правило.

Существенная разница между equals() и == более популярна: фиксировано правило сравнения ==, то есть сравнение значений двух данных.

Правила сравнения равных () не являются исправлены и могут быть определены пользователем.

См. пример ниже:

public static void main(String[] args) {
    String s1 = "hello";
    String s3 = new String("hello");    
    System.out.println(s1.equals(s3));	//true
}

Вспомним предыдущий случай: при сравнении с == результат сравнения s1 и s3 выше ложен. При сравнении с equals() результат верен.

Чтобы понять почему, мы должны посмотреть исходный код.Ниже приведен исходный код метода equals() в классе String.

public boolean equals(Object anObject) {
    if (this == anObject) {	//先比较两个字符串的引用是否相等(是否指向同一个对象), 是直接返回true
        return true;
    }
    if (anObject instanceof String) {	//两个引用不等还会继续比较
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;	//字符串类是用字符数组实现的, 先要拿到两个字符串的字符数组
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {	//然后对两个数组逐个字符地进行比较
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

Как видно из приведенного выше исходного кода, когда вызывается метод equals() данных типа String, он сначала определяет, равны ли ссылки двух строк, то есть указывают ли две ссылки на одну и ту же строку. объект, и возвращается true.

Если они не указывают на один и тот же объект, сравните символы в двух строках один за другим. Поскольку обе строки s1 и s3 являются «привет», они могут быть успешно сопоставлены, поэтому в итоге возвращается true.

Мысль: зачем разрабатывать метод equals()?

Благодаря вышеуказанным объяснениям, я верю, что вы уже знаете разницу между == и равны (): правила сравнения фиксированы, а другой можно определить программистами.

Но почему есть метод equals(), но еще и бесплатная настройка?

Этот вопрос лежит в основе языка Java — объектно-ориентированного мышления.

Java отличается от процедурного языка C, Java является объектно-ориентированным языком высокого уровня. Если это процедурно-ориентированное программирование, если вы напрямую манипулируете данными, хранящимися в памяти, достаточно использовать правила, определенные ==, чтобы определить, равны ли два данных.

В Java все является объектом. Мы часто сталкиваемся с вопросом, равны ли эти два объекта, а не равны ли две строки двоичных чисел. Только == недостаточно.

Поскольку Java-программисты создают различные объекты, отвечающие потребностям их бизнеса,Система не может знать заранее, при каких условиях два объекта считаются равными, и Java просто дает программисту возможность судить, равны ли объекты..

Конкретные меры таковы: все классы должны наследовать класс Object, а метод equals() написан в классе Object. Программисты могут реализовать свою собственную стратегию сравнения, переопределив метод equals(), или они могут использовать стратегию сравнения equals() класса Object без переопределения.

//Object类中的equals()方法源码
public boolean equals(Object obj) {
    return (this == obj);
}

Как видно из исходного кода equals() класса Object, если программист явно не переопределяет метод equals(), по умолчанию сравнивается, указывают ли две ссылки на один и тот же объект.

Дополнение: Сравнение классов-оболочек для примитивных типов данных

Поскольку все в Java является объектом, даже базовые типы данных имеют соответствующие классы-оболочки, так каковы же их соответствующие стратегии сравнения?

public static void main(String[] args) {
    int a = 3;
    Integer b = new Integer(3);
    System.out.println(b.equals(a));	//true, 自动装箱
}

Из приведенного выше кода видно, что, несмотря на то, что две ссылки различаются, выходной результат по-прежнему верен, что доказывает, что класс-оболочка Integer переопределяет метод equals() и отслеживает его исходный код:

//Integer类中的equals方法
public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

Как видно из исходного кода, после перезаписи equals() классом-оболочкой базового типа сравнивается значение базового типа данных.

Заканчивать

Исследуя разницу между == и equals(), мы выяснили стратегию сравнения между ними, а также подумали о дизайне метода equals() в Java.