Строки Java: «String s = новая строка (« глупо »);

Я парень C ++, изучающий Java. Я читаю «Эффективная Java», и что-то меня смутило. В нем говорится, что никогда не писать такой код:

String s = new String("silly"); 

Потому что он создает ненужные объекты String . Но вместо этого это должно быть написано так:

 String s = "No longer silly"; 

Хорошо, хорошо … Однако, учитывая этот class:

 public final class CaseInsensitiveString { private String s; public CaseInsensitiveString(String s) { if (s == null) { throw new NullPointerException(); } this.s = s; } : : } CaseInsensitiveString cis = new CaseInsensitiveString("Polish"); String s = "polish"; 
  1. Почему первое утверждение одобрено? Разве это не должно быть

    CaseInsensitiveString cis = "Polish";

  2. Как заставить CaseInsensitiveString вести себя как String поэтому приведенный выше оператор в порядке (с расширением String и без него)? Что это такое о String, которая позволяет ему просто передать это буквально? Насколько я понимаю, в Java нет понятия «конструктор экземпляров»?

String – специальный встроенный class языка. Это только для classа String в котором вам следует избегать

 String s = new String("Polish"); 

Потому что буквальный "Polish" уже имеет тип String , и вы создаете лишний ненужный объект. Для любого другого classа, говоря:

 CaseInsensitiveString cis = new CaseInsensitiveString("Polish"); 

это правильная (и только в этом случае) вещь.

Я считаю, что основное преимущество использования литеральной формы (т. Е. «Foo», а не новой String («foo»)) состоит в том, что все литералы String «интернированы» виртуальной машиной. Другими словами, он добавляется в пул, так что любой другой код, который создает ту же строку, будет использовать объединенную строку, а не создавать новый экземпляр.

Чтобы проиллюстрировать, следующий код напечатает true для первой строки, но false для второго:

 System.out.println("foo" == "foo"); System.out.println(new String("bar") == new String("bar")); 

Строки обрабатываются немного в java, они неизменяемы, поэтому для них безопасно обрабатывать подсчет ссылок.

Если вы пишете

 String s = "Polish"; String t = "Polish"; 

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

Если вы пишете

 String s = new String("Polish"); String t = new String("Polish"); 

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

То, что вы хотите написать,

 CaseInsensitiveString cis = "Polish"; 

не может работать, потому что вы думаете, что цитаты являются своего рода конструктором короткого замыкания для вашего объекта, когда на самом деле это работает только для простого старого java.lang.Strings.

 String s1="foo"; 

Литерал войдет в пул и s1 будет ссылаться.

 String s2="foo"; 

на этот раз он будет проверять литерал «foo» уже доступен в StringPool или нет, поскольку теперь он существует, поэтому s2 будет ссылаться на один и тот же литерал.

 String s3=new String("foo"); 

Литерал «foo» будет создан сначала в StringPool, а затем через конструктор строковых аргументов String Object будет создан, т. е. «foo» в куче из-за создания объекта с помощью нового оператора, тогда s3 будет ссылаться на него.

 String s4=new String("foo"); 

то же, что и s3

поэтому System.out.println(s1==s2);// **true** due to literal comparison.

и System.out.println(s3==s4);// **false** due to object

сравнение (s3 и s4 создается в разных местах в куче)

String s являются специальными в Java – они неизменяемы, а строковые константы автоматически превращаются в объекты String .

Для вашего примера SomeStringClass cis = "value" нет способа применить к любому другому classу.

Вы также не можете расширять String , потому что он объявлен как final , что означает, что не разрешено подclass.

Строки Java интересны. Похоже, ответы затронули некоторые интересные моменты. Вот мои два цента.

строки неизменяемы (вы никогда не сможете их изменить)

 String x = "x"; x = "Y"; 
  • Первая строка создаст переменную x, которая будет содержать строковое значение «x». JVM будет искать в своем пуле строковых значений и посмотреть, существует ли «x», если это так, то укажет на него переменную x, если она не существует, она создаст ее, а затем выполнит задание
  • Вторая строка удалит ссылку на «x» и посмотрит, существует ли «Y» в пуле строковых значений. Если он существует, он будет назначать его, если он этого не сделает, он сначала создаст его, затем присваивает. Когда используются строковые значения или нет, пространство памяти в пуле строковых значений будет исправлено.

Сравнение строк зависит от того, что вы сравниваете

 String a1 = new String("A"); String a2 = new String("A"); 
  • a1 не равно a2
  • a1 и a2 – ссылки на объекты
  • Когда строка явно объявлена, создаются новые экземпляры, и их ссылки не будут одинаковыми.

Я думаю, что вы ошибаетесь, пытаясь использовать class caseinsensitive. Оставьте струны в покое. Что вам действительно нужно, так это то, как вы показываете или сравниваете значения. Используйте другой class для форматирования строки или для сравнения.

т.е.

 TextUtility.compare(string 1, string 2) TextUtility.compareIgnoreCase(string 1, string 2) TextUtility.camelHump(string 1) 

Поскольку вы составляете class, вы можете сделать сравнения делать то, что вы хотите – сравнить текстовые значения.

Вы не можете. Вещи в двойных кавычках в Java специально распознаются компилятором как строки, и, к сожалению, вы не можете переопределить это (или расширить java.lang.String – объявлено final ).

Лучшим способом ответить на ваш вопрос было бы познакомить вас с «String constant pool». В java строковые объекты неизменяемы (т.е. их значения не могут быть изменены после их инициализации), поэтому при редактировании строкового объекта вы создаете новый отредактированный строковый объект, где старый объект просто плавает вокруг в специальной памяти ares, называемой «string» постоянный пул “. создание нового строкового объекта

 String s = "Hello"; 

будет создавать только строковый объект в пуле, и ссылка s будет ссылаться на него, но используя

 String s = new String("Hello"); 

вы создаете два строковых объекта: один в пуле, а другой в куче. ссылка будет ссылаться на объект в куче.

– Как заставить CaseInsensitiveString вести себя как String, поэтому вышеуказанный оператор в порядке (с расширением String и без него)? Что это такое в String, что делает его достаточно, чтобы просто передать его буквально? Насколько я понимаю, в Java нет концепции «конструктор копий»?

С первого момента было сказано достаточно. «Польский» является строковым литералом и не может быть назначен classу CaseInsentiviveString.

Теперь о втором пункте

Хотя вы не можете создавать новые литералы, вы можете следовать первому элементу этой книги для «аналогичного» подхода, чтобы выполнялись следующие утверждения:

  // Lets test the insensitiveness CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg"); CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG"); assert cis5 == cis6; assert cis5.equals(cis6); 

Вот код.

 C:\oreyes\samples\java\insensitive>type CaseInsensitiveString.java import java.util.Map; import java.util.HashMap; public final class CaseInsensitiveString { private static final Map innerPool = new HashMap(); private final String s; // Effective Java Item 1: Consider providing static factory methods instead of constructors public static CaseInsensitiveString valueOf( String s ) { if ( s == null ) { return null; } String value = s.toLowerCase(); if ( !CaseInsensitiveString.innerPool.containsKey( value ) ) { CaseInsensitiveString.innerPool.put( value , new CaseInsensitiveString( value ) ); } return CaseInsensitiveString.innerPool.get( value ); } // Class constructor: This creates a new instance each time it is invoked. public CaseInsensitiveString(String s){ if (s == null) { throw new NullPointerException(); } this.s = s.toLowerCase(); } public boolean equals( Object other ) { if ( other instanceof CaseInsensitiveString ) { CaseInsensitiveString otherInstance = ( CaseInsensitiveString ) other; return this.s.equals( otherInstance.s ); } return false; } public int hashCode(){ return this.s.hashCode(); } 

// Тестируем class, используя ключевое слово “assert”

  public static void main( String [] args ) { // Creating two different objects as in new String("Polish") == new String("Polish") is false CaseInsensitiveString cis1 = new CaseInsensitiveString("Polish"); CaseInsensitiveString cis2 = new CaseInsensitiveString("Polish"); // references cis1 and cis2 points to differents objects. // so the following is true assert cis1 != cis2; // Yes they're different assert cis1.equals(cis2); // Yes they're equals thanks to the equals method // Now let's try the valueOf idiom CaseInsensitiveString cis3 = CaseInsensitiveString.valueOf("Polish"); CaseInsensitiveString cis4 = CaseInsensitiveString.valueOf("Polish"); // References cis3 and cis4 points to same object. // so the following is true assert cis3 == cis4; // Yes they point to the same object assert cis3.equals(cis4); // and still equals. // Lets test the insensitiveness CaseInsensitiveString cis5 = CaseInsensitiveString.valueOf("sOmEtHiNg"); CaseInsensitiveString cis6 = CaseInsensitiveString.valueOf("SoMeThInG"); assert cis5 == cis6; assert cis5.equals(cis6); // Futhermore CaseInsensitiveString cis7 = CaseInsensitiveString.valueOf("SomethinG"); CaseInsensitiveString cis8 = CaseInsensitiveString.valueOf("someThing"); assert cis8 == cis5 && cis7 == cis6; assert cis7.equals(cis5) && cis6.equals(cis8); } } C:\oreyes\samples\java\insensitive>javac CaseInsensitiveString.java C:\oreyes\samples\java\insensitive>java -ea CaseInsensitiveString C:\oreyes\samples\java\insensitive> 

То есть, создайте внутренний пул объектов CaseInsensitiveString и верните экземпляр corrensponding.

Таким образом, оператор «==» возвращает true для двух объектов, представляющих одно и то же значение .

Это полезно, когда подобные объекты используются очень часто, а стоимость стоит дорого.

В документации по classу строк указано, что class использует внутренний пул

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

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

Он работает для classа String, потому что он используется интенсивно, а пул состоит только из «интернированного» объекта.

Он отлично подходит для булевого classа, потому что есть только два возможных значения.

И, наконец, это также причина, почему valueOf (int) в classе Integer ограничен -128 до 127 значений int.

В первом примере вы создаете String, «глупый», а затем передаете его как параметр другому конструктору копии String, что делает вторую String идентичной первой. Так как строки Java неизменяемы (что часто укусывает людей, которые используются для строк C), это бесполезная трата ресурсов. Вместо этого вы должны использовать второй пример, потому что он пропускает несколько ненужных шагов.

Однако строковый литерал не является CaseInsensitiveString, поэтому вы не можете делать то, что хотите в своем последнем примере. Кроме того, нет способа перегрузить оператор кастинга, как вы можете на C ++, чтобы буквально не было возможности делать то, что вы хотите. Вместо этого вы должны передать его как параметр в конструктор вашего classа. Конечно, я бы просто использовал String.toLowerCase () и покончил с этим.

Кроме того, ваша CaseInsensitiveString должна реализовывать интерфейс CharSequence, а также, возможно, интерфейсы Serializable и Comparable. Конечно, если вы реализуете Comparable, вы должны переопределить equals () и hashCode ().

Просто потому, что у вас есть слово String в вашем classе, не означает, что вы получаете все специальные функции встроенного classа String .

CaseInsensitiveString не является String хотя содержит String . String литерал, например «пример», может быть назначен только для String .

CaseInsensitiveString и String – разные объекты. Вы не можете:

 CaseInsensitiveString cis = "Polish"; 

потому что «польский» – это строка, а не caseInsensitiveString. Если String расширяет CaseInsensitiveString String, тогда вы будете в порядке, но, очевидно, это не так.

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

В случае String s = new String («foobar») он делает что-то другое. Сначала вы создаете литеральную строку «foobar», а затем создаете ее копию, создавая из нее новую строку. Нет необходимости создавать эту копию.

когда они говорят писать

 String s = "Silly"; 

вместо

 String s = new String("Silly"); 

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

Но когда вы пишете

 CaseInsensitiveString cis = new CaseInsensitiveString("Polish"); 

вы не создаете String, вместо этого вы создаете объект classа CaseInsensitiveString. Следовательно, вам нужно использовать новый оператор.

Если я правильно понял, ваш вопрос означает, почему мы не можем создать объект, просто присваивая ему значение, не ограничивая его classом Wrapper classа String в java.

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

Это точно означает, что если интерпретатор увидит 3, он будет преобразован в объект Integer, потому что integer – это тип, определенный для таких литералов.

Если интерпретатор видит что-либо в одинарных кавычках, таких как «a», он будет непосредственно создавать объект типа символа, вам не нужно указывать его, поскольку язык определяет для него объект по умолчанию для символа типа.

Аналогично, если интерпретатор видит что-то в «”, он будет рассматриваться как объект его типа по умолчанию, то есть строка. Это некоторый собственный код, работающий в фоновом режиме.

Благодаря лекционной лекции MIT 6.00, где я получил намек на этот ответ.

В Java синтаксис «text» создает экземпляр classа java.lang.String. Назначение:

 String foo = "text"; 

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

 MyString bar = "text"; 

Это незаконно, что вы делаете, потому что class MyString не является java.lang.String или суперclassом java.lang.String.

Во-первых, вы не можете создать class, который простирается от String, потому что String является окончательным classом. И java управляет строками по-другому от других classов, поэтому только с помощью String вы можете делать

 String s = "Polish"; 

Но, несмотря на свой class, вы должны вызвать конструктор. Итак, этот код в порядке.

Я бы просто добавил, что Java имеет конструкторы Copy …

Ну, это обычный конструктор с объектом того же типа, что и аргумент.

В большинстве версий JDK две версии будут одинаковыми:

Строка s = новая строка («глупая»);

Строка s = «Больше не глупо»;

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

Чтобы прояснить – когда вы говорите «String s =», вы определяете новую переменную, которая занимает место в стеке, – тогда вы говорите: «Больше не глупо» или новая String («глупо»), то же самое происходит – новый константная строка скомпилирована в ваше приложение и указывает на это.

Я не вижу здесь различия. Однако для вашего собственного classа, который не является неизменным, это поведение не имеет значения, и вы должны назвать свой конструктор.

ОБНОВЛЕНИЕ: Я был неправ! Основываясь на приведенном ниже голосовании и комментариях, я протестировал это и понял, что мое понимание ошибочно – новый String («Глупо») действительно создает новую строку, а не повторно использует существующую. Я не понимаю, почему это было бы (в чем польза?), Но код говорит громче слов!

String – один из специальных classов, в котором вы можете создать их без новой Sring-части

это то же самое, что и

int x = y;

или

char c;

Основной закон состоит в том, что строки в java неизменяемы и чувствительны к регистру.

  String str1 = "foo"; String str2 = "foo"; 

Оба str1 и str2 принадлежат к одному и тому же объекту String, «foo», b’coz Java управляет Strings в StringPool, поэтому, если новая переменная относится к одной и той же String, она не создает другого, а назначает тот же alerady, присутствующий в StringPool ,

  String str1 = new String("foo"); String str2 = new String("foo"); 

Здесь str1 и str2 принадлежат к различным объектам, b’coz new String () принудительно создает новый объект String.

Java создает объект String для каждого строкового литерала, который вы используете в своем коде. Каждый раз, когда используется "" , это то же самое, что и вызов new String() .

Строки – это сложные данные, которые просто «действуют» как примитивные данные. Строковые литералы на самом деле являются объектами, хотя мы делаем вид, что они примитивные литералы, такие как 6, 6.0, 'c', т. Д. Таким образом, строковый «литерал» "text" возвращает новый объект String со значением char[] value = {'t','e','x','t} . Поэтому вызов

 new String("text"); 

на самом деле сродни вызову

 new String(new String(new char[]{'t','e','x','t'})); 

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

Для справки, вот реализация String: http://www.docjar.com/html/api/java/lang/String.java.html

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

Еще одна хорошая рекомендация – это учебник по Java по Strings: http://docs.oracle.com/javase/tutorial/java/data/strings.html

  • Подсчитайте количество появлений слова в строке
  • C #: class для декодирования кодировки с кодовым кодированием?
  • Как конкатенировать строку и int в C?
  • Как интерполировать переменные в строках в JavaScript, без конкатенации?
  • Когда следует использовать амперсанд с scanf ()
  • Конкатенация строк в Java - когда использовать +, StringBuilder и concat
  • Количество слов в строке Swift для вычисления количества слов
  • C # Double - ToString () форматирование с двумя десятичными знаками, но без округления
  • Как использовать sed / grep для извлечения текста между двумя словами?
  • Разбиение строки Java на символ канала с помощью split ("|")
  • Зачем использовать String.Equals над ==?
  • Interesting Posts

    Почему Chromium не может подключаться к http: // : 8080 / (то есть IPv6 localhost)?

    Является ли производительность процессора затронутой по мере его возраста?

    Как проверить, является ли файл Unix .tar.gz действительным файлом без разжатия?

    Извлечение коэффициентов DCT из кодированных изображений и видео

    У Haskell есть рекурсивная оптимизация?

    Создайте ведро в Amazon S3

    Обфускация в Android Studio

    Как подключиться к веб-серверу, работающему на виртуальной машине, когда виртуальная машина находится в режиме NAT?

    Избегайте возврата на веб-приложение JSF

    Откройте файл и замените строки в C #

    Сделки в REST?

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

    Как найти особенности того, что Defender обнаружил в режиме реального времени?

    Как я могу сохранить результат команды find в виде массивов в Bash

    Android-устройство Chooser – устройство не отображается

    Давайте будем гением компьютера.