#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 и двойного функционального синтаксиса.