Java кажется избыточной для полного новичка при создании новых объектов

#java

#java

Вопрос:

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

 import java.awt.Rectangle

Rectangle box = new Rectangle(5,10,20,30)
  

Итак, почему мы пишем Rectangle дважды? просто пишу

 box = new Rectangle(5,10,20,30)
  

разве этого недостаточно? при написании таким образом ясно, что мой объект будет создан из конструктора Rectangle

Комментарии:

1. Именно так устроен язык. Да, это многословно. Java имеет репутацию многословия.

2. Имейте в виду, что также можно написать Object box = new Rectangle(..) или GeometricObject box = new Rectangle(..) . И ваш box экземпляр все еще Rectangle будет иметь значение.

3. Чтобы расширить то, что написал @jmizv: это объявление и определение, которые могут быть одинаковыми, но также могут отличаться, вот почему вам нужны оба.

Ответ №1:

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

Они могут быть разными.

Например, вместо вашего примера вы можете написать

 Shape box = new Rectangle(5,10,20,30);
  

что позволяет вам программировать для интерфейса ( Shape ) вместо конкретной реализации ( Rectangle ).

Если вы хотите, чтобы тип переменной совпадал с типом класса, который вы создаете, вы можете использовать var начиная с Java 10:

 var box = new Rectangle(5,10,20,30);
  

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

Если вы просто напишете

 box = new Rectangle(5,10,20,30);
  

компилятор ожидает box , что переменная уже будет объявлена где-то в пределах области действия этого оператора. Добавление типа переменной (или var ) позволяет компилятору узнать, что это новая переменная.

Комментарии:

1. спасибо за ваш ответ. Что вы подразумеваете под «типом переменной»? Форма — это тип переменной?

2. @user804406 тип переменной — это класс, интерфейс или примитивный тип, который определяет, какие данные могут храниться в этой переменной. В моем примере интерфейс формы — это тип box переменной.

Ответ №2:

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

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

Если вы пишете Rectangle box = ... вместо этого, вы определяете новую переменную в этой области и присваиваете ей значение.

Причина, по которой вы не можете писать Rectangle box = (5, 10, 20, 30); , заключается в том, что потенциально может быть много разных классов, которые соответствуют классу Rectangle . Причина в неотъемлемом характере классов в Java, в том, что они являются расширяемыми (с кучей исключений). Это означает, что тип переменной ( Rectangle ) не всегда должен совпадать с типом фактического объекта.

Комментарии:

1. «Это означает, что тип переменной (прямоугольник) не всегда должен совпадать с типом фактического объекта». Не могли бы вы привести более конкретный пример?

Ответ №3:

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

В

     Rectangle box = new Rectangle(5,10,20,30)
  

правая часть, «новый прямоугольник …» создает объект и возвращает ссылку на этот объект.

В левой части, ‘Rectangle box’, объявляется переменная, которая способна содержать ссылку на прямоугольник (или на любой другой объект, подкласс Rectangle, но это не в этом уроке).

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

     draw(new Rectangle(5,10,20,30));
  

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

     Rectangle box;
  

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

И, наконец, как упоминалось в других ответах,

    Rectangle box = 

и

    box = …
  

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

И да, Java несколько многословна.

Ответ №4:

Оператор вида

 Foo f = new Bar(....);
  

говорит о двух вещах. Во-первых, в нем указывается тип переменной f is Foo . С правой стороны вы говорите, что создаете объект типа Bar . Это разрешено, если Foo является супертипом Bar . Как переменные, так и объекты в Java имеют тип.

Ответ №5:

Определение классов и переменных явно в Java. Также обратите внимание, что вы можете использовать разные реализации интерфейсов и / или использовать подклассы. Например, вы можете определить интерфейс, который нельзя использовать отдельно — например, java.util.List. В зависимости от реализации он будет выполнять другой код под капотом и может быть заменен позже (ArrayList против например, LinkedList).

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

 Shape        box1 = new Rectangle(5,10,20,30);
Serializable box2 = new Rectangle(5,10,20,30);
Cloneable    box3 = new Rectangle(5,10,20,30);
  

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

Действительно, есть некоторая избыточность по сравнению с некоторыми более новыми языками, но не предложенный вами синтаксис, который вы предложили, имеет свои собственные недостатки. Определение и назначение имеют одинаковый синтаксис. Поэтому, если вы хотите создать переменную «box», которая уже существует, вы присваиваете значение уже существующей переменной. В явном примечании вы создаете конфликт имен и получаете ошибку компилятора:

Ошибка компилятора отсутствует:

 Rectangle box; // This is not needed for some languages like JS
...
box = new Rectangle(5,10,20,30);
box = new Rectangle(6,11,21,31);
  

Ошибка компилятора:

 Rectangle box = new Rectangle(5,10,20,30);
Rectangle box = new Rectangle(6,11,21,31);
  

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

Python:

 def my_function(name):
    print(name)
  

Java:

 public static void myFunction(String name){
    System.out.print(name);
}
  

(Обратите внимание, что python также поддерживает ввод текста, но вы не обязаны это делать).

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