«Определение равенства двух вещей» — одна из самых распространенных операций в программировании. В 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.