Почему вы называете этот класс дважды во время создания экземпляра на Java?

Когда вы создаете экземпляр объекта, почему вы указываете класс дважды?

OddEven number = new OddEven();

Почему вы не можете просто сказать number = new OddEven();? Когда я объявляю строку, я говорю только String один раз:

String str = "abc";

На самом деле, мой вопрос не "почему вы так делаете" - очевидно, вы это делаете, потому что вам нужно - но почему же создатели решили сделать синтаксис Java таким?

Мои мысли:

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

Ответ 1

Потому что вы можете это сделать:

Superclass x = new Subclass();

Тип ссылки может быть суперклассом фактического объявляемого объекта, поэтому вам нужно указать и то, и другое. Например, вы можете:

List<String> stringList = new ArrayList<String>();

Ваша программа взаимодействует с объектами, которые реализуют List, и вам не нужна реализация.

Ответ 2

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

С левой стороны вы объявляете переменную (место хранения) с определенным типом. С правой стороны вы создаете новый объект с определенным типом. "=" В середине вызывает ссылку на новый объект, который вы создали, для размещения в созданном хранилище.

Типы с каждой стороны не обязательно должны быть одинаковыми. Это, например, юридический код:

Object number = new OddEven();

Причина того, что ключевое слово String появляется только один раз во втором примере, означает, что тип String подразумевается справа, так как "xxx" является константой String. Это просто сокращение:

String string = new String("xxx");

Ответ 3

Когда вы пишете:

OddEven number = new OddEven();

Фактически вы делаете две вещи: 1) вы объявляете переменную number типа OddEven и 2) вы назначаете ссылку на новый экземпляр класса OddEven. Но поскольку переменная может содержать любой подтип типа, запись number = new OddEven(); будет недостаточной для того, чтобы компилятор знал реальный тип переменной number. Таким образом, вы должны заявить об этом. Java - это строго типизированный язык, что означает, что каждая переменная и каждое выражение имеют тип, который известен во время компиляции. Вы можете прочитать все Глава 4. Типы, значения и переменные Спецификации языка Java (JLS), чтобы узнать об этом подробнее.

Теперь, когда вы пишете:

String str = "abc";

Все немного отличается. Символы, заключенные в двойные кавычки, "abc" здесь, называются строковым литералом, который уже является ссылкой на экземпляр String и всегда ссылается на тот же экземпляр класса String. Цитирование раздела 3.10.5 Строковые литералы JLS:

Каждый строковый литерал является ссылкой (§4.3) в экземпляр (§4.3.1, §12.5) of класс String (§4.3.3). Stringобъекты имеют постоянное значение. строка литералы - или, в более общем смысле, строки которые являются значениями постоянной выражения (§15.28) -are "интернированный", чтобы экземпляры, используя метод String.intern.

Итак, String str = "abc";, безусловно, не преобразован в String str = new String("abc");, что абсолютно не эквивалентно, как я читал в некоторых комментариях и ответах. Выполнение следующего класса:

public class Test {
    public static void main(String[] args) {
        String one = "abc";
        String two = "abc";
        String abc = new String("abc");

        System.out.println(one == two);
        System.out.println(one == abc);
    }
}

Производит вывод ниже:

true
false

И демонстрирует, что one и two являются ссылками на один и тот же экземпляр, но abc является ссылкой на другой экземпляр (т.е. создается лишний ненужный объект).

На самом деле использование new String(String) - это неэффективный способ построения новых строк и его следует использовать только для принудительного копирования подстроки в новый базовый массив символов, как в

String tiny = new String(monster.substring(10,20))

Ответ 4

Первый OddEven - тип, второй - экземпляр. Это не должно быть даже OddEven, это может быть любой подкласс OddEven. Это не значит, что у вас есть тип дважды. В любой среде IDE есть шаблоны кода, где вы должны вводить имя только один раз.

Ответ 5

Первое объявление - это тип переменной, которую вы хотите использовать в области видимости, в этом случае это OddEven, второе объявление является конструктором, используемым для экземпляра (и в этом случае инициализации) ссылки.

Вы могли бы указать INumberInstance = new OddEven(), где INumberInstance - это некоторый класс, который OddEven может быть отличен (например, супер OddEven).

Ответ 6

Способ создания нового объекта в java:

Class_name reference_variable = new Class_name(param_if_any);

Но строковый класс является исключением.

Вы можете создать новый строковый объект как

String s = "abc";

или

String s = new String("abc");

Ответ 7

В дополнение к тому, что сказал Джим, Java - это статически типизированный язык. Это означает, что каждая переменная имеет тип, который известен во время компиляции.

Например:

public class A
{
    public void foo() { }
}

public class B
{
    public void foo() { }
}

public class Main
{
    public static void main(final String[] argv)
    {
        A a = new A();
        B b = new B();

        a.foo();
        b.foo();
    }
}

компилятор просматривает "a.foo()" и "b.foo()" и проверяет, имеет ли тип A тип A и A имеет метод "foo", который не принимает аргументов. Компилятор делает то же самое для "b.foo()".

Если вы могли бы написать так:

public class Main
{
    public static void main(final String[] argv)
    {
        a = new A(); // in Java you would really do Object a = new A();
        b = new B(); // in Java you would really do Object b = new B();

        a.foo();
        b.foo();
    }
}

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

Ответ 8

Вспомните "OddEven number" как определяющий объект и "новый OddEven();" как заполнение объекта.

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

Ответ 9

Дизайнерам Java не пришлось делать синтаксис избыточным. Scala - это другой язык, использующий JVM, а также статически типизированный. Scala использует тип вывода, чтобы вырезать многословие. Например, здесь объявление переменной типа MyPair называется x. MyPair связывает две переменные друг с другом. Это общий класс, поэтому вы можете указать, что первая переменная имеет тип Int, а второй тип String:

var x: MyPair[Int, String] = new MyPair[Int, String](1, "scala")

Scala type inferencing позволяет удалить объявление избыточного типа:

var x = new MyPair[Int, String](1, "scala")

И Scala даже вводит типы, основанные на аргументах конструктора, поэтому вы можете записать его следующим образом:

var x = new MyPair(1, "scala")

Ответ 10

Когда вы говорите String name = "foo", внутренний компилятор Java создает объект String со значением "foo" и присваивает свою ссылку переменной name. Итак, вместо создания нового объекта String мы назначаем ссылку на другой объект String.

Btw, компилятор в любом случае создает для нас "foo" . Сначала он выглядит в String Pool, если он не существует, только тогда он создает "foo" . В противном случае компилятор возвращает ссылку из пула строк. Это некоторая оптимизация, которую выполняет компилятор Java внутри.

String name = "foo" равен t23 >

Ответ 11

Рассмотрим следующий пример:

Мы можем указать тип объекта следующим образом:

List<String> abc;

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

abc = new ArrayList<String>();

В методе2(), если вы хотите использовать список Linked array, который лучше всего подходит для этого требования, мы можем создать экземпляр, как показано ниже,

abc = new LinkedList<String>();

Итак, идея состоит в том, что мы можем указать тип "SuperClass" и создать экземпляр любого подкласса, подходящего для различных требований, таких как "LinkedList" и "ArrayList" в соответствующей операции динамически.