Эффективность синтаксиса создания объектов Java? - PullRequest
7 голосов
/ 31 августа 2010

Это может звучать очень просто.Но я новичок в Java.С теми немногими начальными часами обучения, которые я потратил до сих пор, я постоянно удивляюсь избыточности синтаксиса объявления нового объекта:

TypeName a = new TypeName();

В частности,

String s = new String("abc");
Character c = new Character("A");

Почему в мире кто-то хочет ввести ключевое слово TypeName (например, String, Character и т. Д.) дважды ?Я понимаю, что есть короткие сокращения:

String s = "abc";
char c = "A";

Но это скорее исключения, чем правила.Так может ли кто-нибудь просветить меня, пожалуйста?Thx.

Ответы [ 9 ]

19 голосов
/ 31 августа 2010

Потому что иногда вы хотите сделать что-то вроде:

// Explicitly force my object to be null
String s = null;

или

// Cast a child class to its parent
MyParentClass mpc = new IneritedClassFromParent();

или

// Store and access a concrete implementation using its interface
ISomeInterface isi = new ConcreteInterfaceImplementation();

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

Возможно, вы захотите использовать новый экземпляр дочернего класса при использовании наследования или Реализацию интерфейса при использовании Интерфейсов.

Или иногда вы можете явно принудительно принудительно заставить что-то изначально быть нулевым и заполнитьэто позже.

5 голосов
/ 31 августа 2010

Почему в мире кто-то захочет дважды ввести ключевое слово TypeName (например, String, Character и т. Д.)?

Поскольку вы делаете две вещи:

  • Объявление переменной определенного типа
  • Создание объекта определенного типа

Эти два типа не обязательно совпадают, например

Map m = new HashMap();

Вы, вероятно, привыкли к "динамически типизированным" языкам, таким как PHP, где переменные не имеют типа.Преимущество, которое вы получаете с помощью статических объявлений типов Java, состоит в том, что компилятором улавливается много ошибок программирования (даже в современной IDE, когда вы печатаете).Например, если вы допустили простую ошибку:

m.siez();

Компилятор немедленно предупредит вас о том, что с вашей программой что-то не так, и может сделать это только потому, что знает, что объявленный типMap не имеет метода siez().

Некоторые современные статически типизированные языки, такие как C # и Scala, используют вывод типа , чтобы дать вам «лучшее из обоих миров», которое вы можете опуститьобъявление типа и компилятор предполагают, что оно совпадает с типом объекта, который вы ему назначаете.Однако такие языки всегда допускают явные объявления типов, потому что вывод типа не всегда возможен или желателен (например, в примере выше, где переменная должна использовать интерфейс, а не конкретный класс).

5 голосов
/ 31 августа 2010

С помощью этого синтаксиса вы можете легко создать объект типа X и назначить его переменной типа Y:

List<String> myList = new ArrayList<String>();
4 голосов
/ 31 августа 2010

Это совсем не избыточно.Существует два шага для использования переменной:

  1. объявление : этот шаг сообщает виртуальной машине, что будет статическим следом переменной.Например: Object a; будет иметь только видимый элемент Footprint, объявленный в классе Object, в то время как Integer b; будет иметь весь элемент Footprint, объявленный в классе Integer, и все унаследованные родительские классы, вплоть до Object.Это для статической части.

  2. экземпляр : этот шаг сообщает виртуальной машине, что будет динамическим следом переменной.Например: List<String> c = new LinkedList<String>();, тогда c.put("foo"); будет использовать LinkedList реализацию метода put(), даже если то, что видно - List::put().Иногда вам потребуется такое объявление / инстанцирование, но вам нужно будет переопределить, чтобы получить доступ к очень специфическому методу, невидимому со статическим пространством.Например, давайте рассмотрим метод, объявленный как public void method1(Object obj), и вы будете знать , что экземпляр obj на самом деле является Integer, таким образом, вы будете конкретно использовать динамический след при приведенииобъект в него: int value = ((Integer) obj).intValue();

Теперь, что касается String a = "A"; части.Java сделала упрощенное написание «примитивных» классов.Более конкретно, начиная с Java 1.5, вы можете делать:

Integer n1 = 1;
Integer n2 = new Integer(1);  // same thing
int n3 = n2;

И все работает.Но какая разница?Рассмотрим этот фрагмент кода:

String a = new String("A");
String b = new String("A");
String c = "A";
String d = "A";

System.out.println("a:" + a.hashCode() + " = b:" + b.hashCode() + " == " + (a == b));
System.out.println("b:" + b.hashCode() + " = c:" + c.hashCode() + " == " + (b == c));
System.out.println("c:" + c.hashCode() + " = d:" + d.hashCode() + " == " + (c == d));

выведет

a:65 = b:65 == false
b:65 = c:65 == false
c:65 = d:65 == true

Почему?Поскольку JVM пытается максимально использовать память, а a и b создают новые экземпляры String, они не разделяют одно и то же пространство памяти.Однако c и d используют строковые значения constant (это оптимизация компилятора) и, следовательно, указывают на точно такой же объект String.

1 голос
/ 31 августа 2010

Здесь много хороших ответов о том, почему это необходимо.Вы правы в том, что это часто кажется излишним.Ява часто (не несправедливо) критиковалась как немного, ээ ... многословная.Есть несколько ярлыков.например, для строк String s="Abc" (на самом деле это не ярлык, он немного другой, и лучше, потому что вы явно не создаете новый объект)Также будет некоторое сокращение дублирования в объявлениях в java 7 для обобщений.

0 голосов
/ 31 августа 2010

Существуют строго типизированные языки, которые поддерживают «вывод типов» (например, Scala). Java просто не является одним из них (хотя в Java 7 будут некоторые типы выводов общих аргументов). В этих языках, хотя тип переменной не объявлен, компилятор может однозначно вывести его и все же обнаружить ошибки типа. Например (не Java):

val str = "This is not a number!";
val x = str.intValue(); // Compiler error, because str is implicitly a String.

В Java будет много случаев, когда вы будете назначать конкретный конкретный тип справа более общему типу слева. Например:

Set students = new TreeSet();

Это хороший стиль, потому что ваш код не будет зависеть от конкретной реализации. Если вам нужно переключить реализации (например, вам нужен более быстрый поиск на основе хеша Set), изменяется только правая часть инициализатора.

По этой причине особенно важно объявлять публичные API, используя правильные абстракции, а не конкретные типы.

0 голосов
/ 31 августа 2010

Ну, переменная должна иметь тип.И когда вы создаете экземпляр объекта, вам нужно указать, какого типа он должен быть.И, конечно, они не должны быть одинаковыми.Например, вы можете установить String в переменную Object.Конечно, у вас может быть что-то вроде этого, чтобы сделать вещи немного проще:

var s = new TypeName();

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

0 голосов
/ 31 августа 2010

Когда вы доберетесь до класса generics (расширения):

class a extends b

Вы увидите, что вы можете сделать что-то вроде этого:

b=new a();
0 голосов
/ 31 августа 2010

Это потому, что не существует неявного способа присвоения значения сложного объекта.

Когда вы делаете int a = 3; или double b = 2.5;, вы можете неявно указывать тип направая сторона.

В ООП вы должны использовать конструктор, поэтому вам нужно сделать new TypeName().Это также дает вам возможность передавать параметры для настройки объекта.

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

MyInterface blah = new InterfaceImplementation();
MyInterface bar = new AnotherInterfaceImplementation();

и даже:

ParentClass foo = new DerivedClass();

Это потому, что при работе с интерфейсами вы обычно не хотите устанавливать тип переменной как реализацию интерфейса, но сам интерфейс.В противном случае не было бы никакого способа указать, какую реализацию использовать.

Еще одна полезная вещь - это обобщение:

List<SomeType> myList = new ArrayList<SomeType>();

Java 7 упростит это до

List<SomeType> myList = new ArrayList<>();

, поэтомучто вам не нужно вводить <SomeType> дважды (это особенно болезненно в Картах).

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