Строки Java: "String s = new String (" глупо ");" - PullRequest
84 голосов
/ 02 декабря 2008

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

String s = new String("silly");

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

String s = "No longer silly";

Хорошо, пока хорошо ... Однако, учитывая этот класс:

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 нет понятия "конструктор копирования"?

Ответы [ 23 ]

3 голосов
/ 02 декабря 2008

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

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

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

3 голосов
/ 05 мая 2010

То, что в вашем классе есть слово String, не означает, что вы получаете все особенности встроенного класса String.

2 голосов
/ 19 мая 2012

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

String s = "Silly";

вместо

String s = new String("Silly");

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

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

CaseInsensitiveString cis = new CaseInsensitiveString("Polish");

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

2 голосов
/ 02 декабря 2008

CaseInsensitiveString и String - это разные объекты. Вы не можете сделать:

CaseInsensitiveString cis = "Polish";

потому что "Polish" - это String, а не CaseInsensitiveString. Если бы String расширил CaseInsensitiveString String, то все было бы в порядке, но, очевидно, это не так.

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

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

1 голос
/ 24 мая 2012

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

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

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

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

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

Благодаря видеокурсу MIT 6.00, где я получил подсказку для этого ответа.

0 голосов
/ 27 декабря 2013
 String str1 = "foo"; 
 String str2 = "foo"; 

И str1, и str2 принадлежат к одному и тому же объекту String, "foo", b'coz Java управляет строками в StringPool, поэтому, если новая переменная ссылается на ту же строку, она не создает другую, а назначает одну и ту же последовательность присутствует в StringPool.

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

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

0 голосов
/ 06 января 2013

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

0 голосов
/ 15 июля 2009

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

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

int x = y;

или

char c;

0 голосов
/ 02 декабря 2008

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

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

0 голосов
/ 02 декабря 2008

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

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

String s = "Больше не глупо";

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...