Сериализуемые классы и оператор == - PullRequest
0 голосов
/ 28 июня 2011

Вот исходный код метода String.equals:

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
        char v1[] = value;
        char v2[] = anotherString.value;
        int i = offset;
        int j = anotherString.offset;
        while (n-- != 0) {
            if (v1[i++] != v2[j++])
            return false;
        }
        return true;
        }
    }
    return false;
}

Поскольку String является сериализуемым, имеет ли смысл использовать оператор == в методе String.equals?Если мы попытаемся сравнить два разных объекта String, возможно, с одним и тем же адресом памяти, расположенным на разных виртуальных машинах, это будет работать правильно?

В моем собственном коде я использую метод equals для сравнения двух строк.Я знаю, что делает ==Я спрашиваю, имеет ли смысл проводить сравнение == в методе equals класса String.

Ответы [ 7 ]

3 голосов
/ 28 июня 2011

Имеет смысл использовать ==, потому что если оба экземпляра строки указывают на одну и ту же ссылку, они должны быть равны, поэтому не нужно сравнивать символы

1 голос
/ 28 июня 2011

Этот случай IF в Java API является оптимизацией. Потому что виртуальная машина содержит String Cache и оптимизирует некоторые (не все) строки в литералы. Некоторые литералы содержат одну и ту же ссылку на объект.

С моим JDK, например

String a = "ABCD";
String b = "ABCD";
if (a==b)

соответствует истине. Потому что оба находятся в кеше Literal моего jvm. Но этого недостаточно для сравнения ссылки на объект, поскольку не каждая строка сохраняется в литеральном кэше.

например.

String a = new String("ABCD");
String b = new String("ABCD");
if (a==b)

всегда будет ложным, поскольку вы явно вызываете ссылку на новый объект.

Но даже в приведенном выше случае

if(a.intern()==b.intern())

также будет равно true.

Существует также еще один пост на эту тему: Использование статических переменных для строк

1 голос
/ 28 июня 2011

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

Две JVM не могут совместно использовать экземпляры объекта, поэтому не возможно, что =Оператор = можно использовать для сравнения адресов экземпляров объектов из разных адресных пространств.

1 голос
/ 28 июня 2011

Да, это имеет смысл, поскольку в Java используется пул строк, поэтому при создании строки без использования ключевого слова new до тех пор, пока обе ссылочные переменные совпадают, String == всегда будет истинным.

Скажем, у вас есть "" в вашем пуле строк, если вы делаете

String a = "";
String b = "";

Поскольку "" находится в пуле строк, они фактически будут указывать на одну и ту же область памяти и, следовательно,

a == b 

будет правдой

На самом деле, пока вы не используете

 String c = new String("");

Ссылочная переменная всегда будет указывать на "" в пуле строк.

Однако при использовании нового ключевого слова новое выделение памяти создается вне пула строк. Поэтому, если вы делаете:

 c == b

Это вернет false, поскольку ссылка на b находится в пуле строк, а ссылка на c - нет, она находится вне пула

Однако, если бы мы сделали

 String d = c.intern()
 d == b

Это вернет true, то, что стажер делает в соответствии с комментариями к классу String,

Возвращает каноническое представление для строкового объекта. Пул строк, изначально пустой, поддерживается частным образом классом String.

При вызове метода intern, если пул уже содержит строку, равную этому объекту String, как определено методом equals (Object), возвращается строка из пула. В противном случае этот объект String добавляется в пул и возвращается ссылка на этот объект String.

Из этого следует, что для любых двух строк s и t s.intern () == t.intern () имеет значение true, если и только если s.equals (t) имеет значение true.

Как уже указывалось некоторыми при десериализации объекта на другой JVM, он будет использовать этот пул строк JVM

0 голосов
/ 29 июня 2011

Если мы попытаемся сравнить два разных Строковые объекты, возможно с тем же адрес памяти, расположенный на разных ВМ, это будет работать правильно?

Ты не можешь этого сделать. Невозможно сравнивать строки в двух виртуальных машинах с оператором == или без него. Поэтому ваш вопрос не о о ничего. Вам нужно будет поместить их обоих в одну и ту же виртуальную машину, после чего вы вызовете String.equals ().

Тест == - это просто сокращение, позволяющее избежать прохождения всего остального кода. Это не имеет ничего общего с сериализацией. И разные виртуальные машины не могут войти в него.

0 голосов
/ 28 июня 2011

Предполагая, что вы говорите о следующем фрагменте кода:

if (this == anObject) {
    return true;
}

Имеет смысл использовать оператор ==, поскольку он будет истинным, только когда обе строки указывают на один и тот же адрес памяти.Это, вероятно, делается в java.lang.String для оптимизации сравнения строк при использовании строковых литералов.Вы можете проверить http://www.javaranch.com/journal/200409/ScjpTipLine-StringsLiterally.html для подробного описания того, как строковые литералы объединяются в Java.

0 голосов
/ 28 июня 2011

Нет.Поскольку «String» не является примитивным типом, использование == просто сравнивает адрес объекта, а не само содержимое.Выполнив:

String a = "ABCD";
String b = "ABCD";

if (a == b)

Вы получите false, потому что, хотя строки a и строка b одинаковы, их представления в памяти различны.

Метод .equals () используется для сравнения строк (также объектов) в Java, поскольку он сравнивает содержимое объекта.

...