Модераторы: LSD, AntonSaburov

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Быстрый способ сравнить строки 
:(
    Опции темы
DenWPF
Дата 21.9.2010, 14:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1659
Регистрация: 26.9.2009

Репутация: нет
Всего: 1



Вот как быстрее всего сравнить две строки?

equals - он как сравнивает по символьно?



PM MAIL   Вверх
Joil
Дата 21.9.2010, 15:03 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 211
Регистрация: 24.1.2008

Репутация: нет
Всего: 8



Цитата(DenWPF @  21.9.2010,  14:27 Найти цитируемый пост)
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;
    }

--------------------
Who had deceived thee so often as thyself? © Benjamin Franklin--------------------Always bear in mind that your own resolution to succeed is more important than any other. © Abraham Lincoln--------------------If you need it - do it, if you want it - take it! © ...
PM MAIL ICQ   Вверх
DenWPF
Дата 21.9.2010, 15:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1659
Регистрация: 26.9.2009

Репутация: нет
Всего: 1



по символьный, значит быстрей уже не как. ну гуд. спасибо.
PM MAIL   Вверх
Joil
Дата 21.9.2010, 18:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 211
Регистрация: 24.1.2008

Репутация: нет
Всего: 8



Цитата(DenWPF @  21.9.2010,  15:15 Найти цитируемый пост)
по символьный, значит быстрей уже не как. ну гуд. спасибо. 

Ну почему, если строки очень большие то я думаю быстрее будет взять хэш от каждой строки и сравнить хэши.
--------------------
Who had deceived thee so often as thyself? © Benjamin Franklin--------------------Always bear in mind that your own resolution to succeed is more important than any other. © Abraham Lincoln--------------------If you need it - do it, if you want it - take it! © ...
PM MAIL ICQ   Вверх
DenWPF
Дата 21.9.2010, 18:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1659
Регистрация: 26.9.2009

Репутация: нет
Всего: 1



а как хэш генерируется?
PM MAIL   Вверх
jk1
Дата 21.9.2010, 19:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 40
Всего: 75



Код

myString.hashCode();



--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
DenWPF
Дата 21.9.2010, 20:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1659
Регистрация: 26.9.2009

Репутация: нет
Всего: 1



ну я в плане механизме.
PM MAIL   Вверх
jk1
Дата 21.9.2010, 21:37 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 40
Всего: 75



Цитата

ну я в плане механизме. 

Код

 public int hashCode() {
    int h = hash;
    if (h == 0) {
        int off = offset;
        char val[] = value;
        int len = count;

            for (int i = 0; i < len; i++) {
                h = 31*h + val[off++];
            }
            hash = h;
        }
        return h;
    }


Есть кстати еще хороший способ быстрого сравнения, заключается он в вызове метода intern() у всего, что хотите в будущем сравнивать и пользоваться тем, что он вернет. После этого строки можно сравнивать по ссылкам через оператор ==, а это куда быстрее посимвольного сравнения. Подробнее тут.

Это сообщение отредактировал(а) jk1 - 21.9.2010, 21:41


--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
Skipy
Дата 22.9.2010, 09:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 487
Регистрация: 24.8.2006
Где: Москва, Россия

Репутация: 6
Всего: 16



Цитата(Joil @ 21.9.2010,  18:27)
Ну почему, если строки очень большие то я думаю быстрее будет взять хэш от каждой строки и сравнить хэши.

У неравных строк могут быть равные хеши, это не противоречит контракту. Обратное неверно. Так что НЕравенство выяснить можно по хеш-коду. Но если они равны - это ни о чем не говорит. То же верно и про хеш-функции (хотя попасть в 128 бит того же MD5 намного сложнее, чем в 32 бита hashCode). Кстати, подсчет хеша займет порядочно времени, имхо, сравнить быстрее.

Можно, конечно, попользоваться методом intern. Но во-первых, это надо делать аккуратно, во-вторых, одно сравнение все-таки будет (когда в буфере строку будут искать), в-третьих - при интенсивном использовании рискуете получить OutOfMemory:PermGen - буфер сильно разрастется.


--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
danilka
Дата 22.9.2010, 10:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 15.1.2010

Репутация: нет
Всего: нет



Цитата(Skipy @  22.9.2010,  09:50 Найти цитируемый пост)
Можно, конечно, попользоваться методом intern. Но во-первых, это надо делать аккуратно, во-вторых, одно сравнение все-таки будет (когда в буфере строку будут искать), в-третьих - при интенсивном использовании рискуете получить OutOfMemory:PermGen - буфер сильно разрастется. 


А вот об этом можно поподробнее?
Почему это надо делать аккуратно?
Разве строка будет искаться в буфере когда для нее нужен intern(). Там нет прямой ссылки?
Если не пользоваться intern() разве буфер не разрастется?

PM MAIL   Вверх
Skipy
Дата 22.9.2010, 12:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 487
Регистрация: 24.8.2006
Где: Москва, Россия

Репутация: 6
Всего: 16



Цитата
Почему это надо делать аккуратно?


Потому что как только Вы начнете сравнивать строки через == - Вам ВЕЗДЕ надо будет использовать intern. Очень легко это забыть. Плюс есть строки, которые создаются не Вами, их тоже придется обрабатывать.

Цитата
Разве строка будет искаться в буфере когда для нее нужен intern(). Там нет прямой ссылки?


Какой ссылки? Вы себе представляете, как работает intern? Почитайте документацию: http://download.oracle.com/javase/6/docs/a...g.html#intern()

Цитата
When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned.


as determined by the equals(Object) method означает, что для определения наличия в пуле вызывается equals. Более того, происходит ПОИСК, что означает как минимум несколько сравнений, даже при оптимизациях. Таким образом, на каждый вызов intern как минимум один раз equals вызовется. А скорее всего - больше одного раза. И с ростом размера пула возможен рост времени поиска.

Цитата
Если не пользоваться intern() разве буфер не разрастется?


А с чего бы ему разрастаться? В буфер попадают строковые литералы и результаты вызова intern. Если не пользоваться intern - там будут только строковые литералы. Ну и если кто-то другой кладет строки через intern - они тоже, но на это Вы никак не влияете.


--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
danilka
Дата 22.9.2010, 13:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 15.1.2010

Репутация: нет
Всего: нет



Цитата(Skipy @  22.9.2010,  12:52 Найти цитируемый пост)
Потому что как только Вы начнете сравнивать строки через == - Вам ВЕЗДЕ надо будет использовать intern. Очень легко это забыть. Плюс есть строки, которые создаются не Вами, их тоже придется обрабатывать.


Нет ну понятно что я везде не буду использовать такое сравнение...

Цитата(Skipy @  22.9.2010,  12:52 Найти цитируемый пост)
Какой ссылки? Вы себе представляете, как работает intern? Почитайте документацию: http://download.oracle.com/javase/6/docs/a...g.html#intern()


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


Цитата(Skipy @  22.9.2010,  12:52 Найти цитируемый пост)
А с чего бы ему разрастаться? В буфер попадают строковые литералы и результаты вызова intern. Если не пользоваться intern - там будут только строковые литералы. Ну и если кто-то другой кладет строки через intern - они тоже, но на это Вы никак не влияете.


Мне почему-то казалось что строковые литералы и результаты вызова intern() это одно и тоже.
PM MAIL   Вверх
Skipy
Дата 22.9.2010, 16:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 487
Регистрация: 24.8.2006
Где: Москва, Россия

Репутация: 6
Всего: 16



Цитата
Нет ну понятно что я везде не буду использовать такое сравнение...


Вот именно. Тогда в каждом месте, где Вы будете использовать ==, необходимо будет обеспечить наличие intern-ированной строки. Т.е. ОЧЕНЬ аккуратно отслеживать, где у Вас строки из пула, а где нет. Это сложно.

Цитата
Просто у меня был мысль что после того как у строки вызван метод intern() и соответствующий инстанс в пуле найден, почему бы в строке не сохранить ссылку на него...


В какой строке? У Вас есть объект - String. Он содержит массив char-ов, длину строки и смещение в массиве. Всё. Никаких ссылок на intern-строки он не содержит и содержать не может. Потому как в общем случае в пуле аналогичной строки нет. 

Цитата
Мне почему-то казалось что строковые литералы и результаты вызова intern() это одно и тоже.


Вам казалось. Строковые литералы - это те строки, которые Вы в коде описываете как "строка". Каждый такой объект преобразуется в String и помещается в пул.

Код

package test;

public class Class1 {

    public static String getString(){
        return "test string";
    }

}


Код

package test;

public class Class2 {

    public static String getString(){
        return "test string";
    }

}


Код

package test;

public class Test {

    public static void main(String[] args) {
        System.out.println(Class1.getString() == Class2.getString());
    }

}


Вот этот тест вернет true. Но к intern это не имеет никакого отношения, этот метод тут, как видите, не вызывается. Всё делается на стадии компиляции и загрузки классов.


--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
danilka
Дата 22.9.2010, 17:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 15.1.2010

Репутация: нет
Всего: нет



Цитата(Skipy @  22.9.2010,  16:43 Найти цитируемый пост)
В какой строке? У Вас есть объект - String. Он содержит массив char-ов, длину строки и смещение в массиве. Всё. Никаких ссылок на intern-строки он не содержит и содержать не может. Потому как в общем случае в пуле аналогичной строки нет. 


Под строкой я и имел ввиду объект класса String. То есть Вы хотите сказать что можно создать строку так чтобы в пуле не было соответствующего ей объекта intern()?

Поделитесь первоисточником плиз где описано как хранятся строковые литералы, и пул для intern-строк и в какой момент они заполняются.


PM MAIL   Вверх
Evgeni68
Дата 24.9.2010, 19:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 37
Регистрация: 9.7.2007

Репутация: 2
Всего: 3



Цитата(danilka @ 22.9.2010,  17:46)
То есть Вы хотите сказать что можно создать строку так чтобы в пуле не было соответствующего ей объекта intern()?

Код

String test = new String("Hello world");


Данный код создаст объект типа String не помещая строку в пул.
PM MAIL   Вверх
Skipy
Дата 24.9.2010, 20:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 487
Регистрация: 24.8.2006
Где: Москва, Россия

Репутация: 6
Всего: 16



Цитата(Evgeni68 @ 24.9.2010,  19:45)
Цитата(danilka @ 22.9.2010,  17:46)
То есть Вы хотите сказать что можно создать строку так чтобы в пуле не было соответствующего ей объекта intern()?

Код

String test = new String("Hello world");


Данный код создаст объект типа String не помещая строку в пул.

Ну, сам строковый литерал "Hello world!" в пуле таки будет. Так что при сравнении по equals с вновь созданной строкой вернется именно он. Не совсем удачный пример.

А вот так - строки точно не будет в пуле (разве что случайно такая окажется smile):

Код

byte[] bytes = ...;
String str = new String(bytes, encoding);





--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
Evgeni68
Дата 24.9.2010, 22:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 37
Регистрация: 9.7.2007

Репутация: 2
Всего: 3



Цитата(Skipy @ 24.9.2010,  20:05)
Ну, сам строковый литерал "Hello world!" в пуле таки будет. Так что при сравнении по equals с вновь созданной строкой вернется именно он. Не совсем удачный пример.

Да, действительно, пример не совсем удачный.
Но смысл от того что литерал будет в пуле?

Код

String test1 = "test";
String test2 = new String("test");
        
System.out.println(test1 == test2);


Выводом будет FALSE. Метод equals в классе String сначала проверяет равенство ссылок, а затем обычное сравнение строк по символам. В итоге никакого преимущества в скорости от того, что литерал в пуле - нет.

Или я чего-то не допонимаю? Поправьте.

Это сообщение отредактировал(а) Evgeni68 - 25.9.2010, 09:49
PM MAIL   Вверх
Skipy
Дата 27.9.2010, 12:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 487
Регистрация: 24.8.2006
Где: Москва, Россия

Репутация: 6
Всего: 16



Цитата(Evgeni68 @ 24.9.2010,  22:10)
Но смысл от того что литерал будет в пуле?

Код

String test1 = "test";
String test2 = new String("test");
        
System.out.println(test1 == test2);


Выводом будет FALSE. 

Код

String test1 = "test";
String test2 = new String("test").intern();
        
System.out.println(test1 == test2);


Так лучше? А то Вы как-то упустили, что test2 указывает не на тот экземпляр, который в пуле.


--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
danilka
Дата 28.9.2010, 09:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 15.1.2010

Репутация: нет
Всего: нет



Цитата(Skipy @  24.9.2010,  20:05 Найти цитируемый пост)
А вот так - строки точно не будет в пуле (разве что случайно такая окажется smile):

byte[] bytes = ...;
String str = new String(bytes, encoding);


Тут Вы имеете ввиду пул строковых литералов или пул intern()?
PM MAIL   Вверх
Skipy
Дата 28.9.2010, 11:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 487
Регистрация: 24.8.2006
Где: Москва, Россия

Репутация: 6
Всего: 16



Цитата(danilka @ 28.9.2010,  09:43)
Тут Вы имеете ввиду пул строковых литералов или пул intern()?

Пул - он один. Еще раз объясняю - строковые литералы существуют только в исходном коде. При компиляции они помещаются в пул строк. И в него же во время исполнения помещаются отсутствующие в нем строки при вызове на них метода intern().


--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
Evgeni68
Дата 28.9.2010, 21:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 37
Регистрация: 9.7.2007

Репутация: 2
Всего: 3



Цитата(Skipy @ 27.9.2010,  12:02)
Цитата(Evgeni68 @ 24.9.2010,  22:10)
Но смысл от того что литерал будет в пуле?

Код

String test1 = "test";
String test2 = new String("test");
        
System.out.println(test1 == test2);


Выводом будет FALSE. 

Код

String test1 = "test";
String test2 = new String("test").intern();
        
System.out.println(test1 == test2);


Так лучше? А то Вы как-то упустили, что test2 указывает не на тот экземпляр, который в пуле.

Так гораздо лучше! Просто я хотел сказать, что создавать новый инстанс строки, передавая в конструктор литерал - мягко говоря не рационально.
PM MAIL   Вверх
danilka
Дата 29.9.2010, 09:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 15.1.2010

Репутация: нет
Всего: нет



Цитата(Skipy @  28.9.2010,  11:54 Найти цитируемый пост)
Пул - он один. Еще раз объясняю - строковые литералы существуют только в исходном коде. При компиляции они помещаются в пул строк. И в него же во время исполнения помещаются отсутствующие в нем строки при вызове на них метода intern(). 


То есть правильно ли я понял?
Представим что каждая из приведенных ниже строк кода выполняется в новом приложении (пул строк пустой)

Код

String s = "test"; //строка "test" помещяется в пул
String s = ss.intern(); //строка с аналогичным ss контентом помещается в пул (если ее там еще не было)
String s = new String("test"); //строка "test" НЕ помещяется в пул

PM MAIL   Вверх
Skipy
Дата 29.9.2010, 13:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 487
Регистрация: 24.8.2006
Где: Москва, Россия

Репутация: 6
Всего: 16



Цитата(Evgeni68 @ 28.9.2010,  21:39)
Просто я хотел сказать, что создавать новый инстанс строки, передавая в конструктор литерал - мягко говоря не рационально.


Ага. И Вы на эти грабли наступили...

Рассказываю.

Допустим, у Вас есть строка. Большая, в несколько тысяч символов. Вы выбираете подстроку, символов 10. Исходная строка выбрасывается. Вопрос. Освобождается ли память, которую занимала эта подстрока?

А вот не освобождается! В качестве базы строки берется текущий массив char-ов. И просто выставляется смещение и длина. Но при этом ВСЯ исходная строка, фактически, остается в памяти. Это оптимизация, чтобы избежать копирования (и память дополнительная нужна, и время).

А вот конструктор String(String) - он КОПИРУЕТ строку. Т.е. если Вы результаты Вашего substring передадите в копирующий конструктор, несмотря на внешнюю бессмысленность этого действия, - у Вас останется массив из нужных 10 символов. А исходный массив соберется как мусор, если Вы убъете на него ссылки.

Так что да, создавать строку на основе литерала прямо в коде - нерационально, если только Вы не хотите, чтобы ссылка была не на объект, находящийся в пуле. Но копирующий конструктор сам по себе - бывает весьма полезен.

Добавлено @ 13:35
Цитата(danilka @ 29.9.2010,  09:43)
Код

String s = "test"; //строка "test" помещяется в пул
String s = ss.intern(); //строка с аналогичным ss контентом помещается в пул (если ее там еще не было)
String s = new String("test"); //строка "test" НЕ помещяется в пул

Да.

Да.

Нет. "test" помещается в пул - ибо есть строковый литерал. s - по значению в пуле будет, ибо создана на основе литерала. Т.е. вызов s.intern() не приведет к помещению новых данных в пул, а вернет ссылку на "test". А вот ссылка на s - не будет совпадать со сcылкой на "test", т.е.  результатом (s =="test") будет false.

Это сообщение отредактировал(а) Skipy - 29.9.2010, 13:37


--------------------
С уважением,
Евгений aka Skipy
www.skipy.ru
PM MAIL WWW ICQ   Вверх
Evgeni68
Дата 29.9.2010, 20:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 37
Регистрация: 9.7.2007

Репутация: 2
Всего: 3



Цитата(Skipy @  29.9.2010,  13:31 Найти цитируемый пост)
Так что да, создавать строку на основе литерала прямо в коде - нерационально, если только Вы не хотите, чтобы ссылка была не на объект, находящийся в пуле. Но копирующий конструктор сам по себе - бывает весьма полезен.


Спасибо, очень полезно. О копирующем конструкторе не задумывался smile .
PM MAIL   Вверх
Страницы: (2) [Все] 1 2 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1344 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.