Когда Вы инстанцируете объекта, почему Вы указываете класс дважды?
OddEven number = new OddEven();
Почему Вы не можете просто сказать number = new OddEven();
? Когда я объявляю строку, говорю я только String
однажды:
String str = "abc";
На самом деле мой вопрос не, "почему Вы делаете это этот путь" - очевидно, Вы делаете это, потому что Вы имеете к - а скорее, почему создатели принимали решение заставить синтаксис Java работать как это?
Мои мысли:
Потому что вы можете сделать это:
Superclass x = new Subclass();
Тип ссылки может быть суперклассом фактического объявляемого объекта, поэтому вам нужно указать оба. Например, вы можете:
List<String> stringList = new ArrayList<String>();
Ваша программа взаимодействует с объектами, реализующими List, и вас не волнует реализация.,
Причина кажущегося избыточным имени типа заключается в том, что вы выполняете две отдельные операции, каждая из которых требует от вас указания типа.
С левой стороны вы объявляете переменную (место хранения) определенного типа. Справа вы создаете новый объект определенного типа. Знак '=' в середине приводит к тому, что ссылка на новый созданный вами объект будет помещена в созданное вами место хранения.
Типы на каждой стороне не обязательно должны быть одинаковыми. Это, например, допустимый код:
Object number = new OddEven();
Причина, по которой ключевое слово String отображается только один раз во втором примере, заключается в том, что тип String подразумевается с правой стороны, поскольку «xxx» является константой String. Это просто сокращение от:
String string = new String("xxx");
Первое объявление - это тип переменной, которую вы хотите использовать в имеющейся у вас области, в данном случае это OddEven, второе объявление - это конструктор, который будет использоваться для создания экземпляра (и в данном случае инициализация) ссылки.
Вы могли бы сказать INumberInstance = new OddEven (), где INumberInstance - это некоторый класс, к которому может быть приведен OddEven (например, супер-класс OddEven).
Первый OddEven
- это тип, второй - это экземпляр. Это не обязательно должно быть четное OddEven
, это может быть любой подкласс OddEven
. Это не значит, что вам нужно набрать его дважды. В любой среде IDE есть шаблоны кода, в которых имя нужно ввести только один раз.
Способ создания нового объекта в java:
Class_name reference_variable = new Class_name(param_if_any);
Но строковый класс является исключением .
Вы можете создать новый строковый объект как
String s = "abc";
или
String s = new String("abc");
В дополнение к тому, что сказал Джим, 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 ()".
Если бы вы могли написать main так:
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();
}
}
, то компилятор не смог бы выполнить эту проверку, и это должно было бы произойти во время выполнения.
это не требует аргументов. Компилятор делает то же самое для "b.foo ()".Если бы вы могли написать main так:
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();
}
}
, то компилятор не смог бы выполнить эту проверку, и это должно было бы произойти во время выполнения.
это не требует аргументов. Компилятор делает то же самое для "b.foo ()".Если бы вы могли написать main так:
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();
}
}
, то компилятор не смог бы выполнить эту проверку, и это должно было бы произойти во время выполнения.
Подумайте о 'OddEven number 'как определение объекта и' new OddEven (); ' как заполнение объекта.
Я не буду вдаваться в подробности о суперклассах и подклассах, потому что другие люди уже объяснили это.
При записи:
OddEven number = new OddEven();
Вы фактически делаете две вещи : 1) Вы объявляете переменную номер
типа OddEven
и 2) Вы присваиваете ссылку на новый экземпляр класса OddEven
. Но так как переменная может содержать любой подтип типа, то записи number = new OddEven();
будет недостаточно, чтобы компилятор знал реальный тип переменной number
. Поэтому, вы должны объявить и это тоже. Java - это сильно типизированный язык, а это значит, что каждая переменная и каждое выражение имеет тип, известный во время компиляции. Вы можете захотеть прочитать всю Главу 4. Типы, значения и переменные спецификации языка Java (JLS), чтобы узнать больше об этом.
Теперь, когда вы пишете:
String str = "abc";
Все немного по-другому. Символы, заключенные в двойные кавычки, "abc"
здесь называются строковым литералом , который уже является ссылкой на экземпляр Строки
и всегда ссылается на один и тот же экземпляр класса Строки
. Цитирование раздела 3.10.5 Строковые литералы JLS:
Каждый строковый литерал является ссылкой (§4.3) к экземпляру (§4.3.1, §12.5) класса
String
(§4.3.3).String
объекты имеют постоянное значение. Строка буквально - или вообще - струны то есть значения константы expressions (§15.28)-are "интернирован", чтобы поделиться уникальным экземпляры, использующие методString.intern
.
Итак, Строковая строка str = "abc";
определенно не конвертируется в Строковая строка str = новая строка("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
И демонстрирует, что один
и два
являются ссылками на один и тот же экземпляр, но abc
является ссылкой на другой экземпляр (т.е. был создан лишний ненужный объект).
На самом деле, использование new String(String)
является неэффективным способом построения новых строк и должно использоваться только для того, чтобы заставить подстроку скопироваться в новый базовый символьный массив, как в
String tiny = new String(monster.substring(10,20))
Когда вы говорите String name = "foo"
, внутренний компилятор Java создает строковый объект со значением "foo" и присваивает его ссылку на переменную name
. Таким образом, здесь вместо создания нового объекта String мы присваиваем ссылку на другой объект String.
Btw, компилятор все равно создает для нас "foo". Сначала он смотрит в String Pool, если его нет, только потом создает "foo". В противном случае компилятор возвращает ссылку из пула строк. Это некоторая оптимизация, которую компилятор Java выполняет внутренне.
Имя строки = "foo"
simlar to OddEvenNumber oddEven = anotherOddEvenObject;
Разработчики Java не имели , чтобы сделать синтаксис избыточным. Scala - это еще один язык, использующий JVM, и он также статически типизирован. Scala использует вывод типов , чтобы исключить многословие. Например, вот объявление переменной типа MyPair с именем x. MyPair связывает две переменные друг с другом. Это общий класс, поэтому вы можете указать, что первая переменная имеет тип Int, а вторая - тип String:
var x: MyPair[Int, String] = new MyPair[Int, String](1, "scala")
Выведение типа Scala позволяет вам удалить объявление избыточного типа:
var x = new MyPair[Int, String](1, "scala")
Scala даже определяет типы на основе аргументов конструктора. , поэтому вы можете написать это так:
var x = new MyPair(1, "scala")