Как аргументы передаются конструкторам и методам
Если у вас есть конструктор, который принимает аргументы, эти аргументы будут полностью оценены перед его вызовом. Это означает, что если эти аргументы не являются null
ссылками на объекты, эти объекты уже существуют (иначе вы не могли бы получить ссылки на них!).
С JLS 15.9.4. Оценка выражений создания экземпляров класса во время выполнения :
Далее фактические аргументы конструктора оцениваются слева направо. Если какое-либо из вычислений аргумента завершается преждевременно, любые выражения аргумента справа от него не оцениваются, и выражение создания экземпляра класса завершается преждевременно по той же причине.
Далее вызывается выбранный конструктор указанного типа класса.
Обратите внимание, что это также относится к обычным методам. Java не имеет отложенной оценки: все аргументы должны быть полностью оценены перед вызовом любого метода / конструктора, использующего их. Ленивое вычисление может быть хорошей функцией, но Java делает ее простой, просто оценивая все аргументы перед вызовом любого метода / конструктора.
Как использовать переданные объекты в качестве полей
Итак, теперь, когда мы это выяснили, давайте поговорим о вашем вопросе:
Можно ли создать объект, чьи переменные экземпляра уже являются существующими объектами?
Сначала давайте кое-что проясним: переменные вашего экземпляра (также называемые в Java "полями") на самом деле будут ссылками на этих объектов! Итак, настоящий вопрос, который нужно задать, следующий:
Можно ли создать объект, поля которого являются ссылками на уже существующие объекты?
Ответ, конечно, да. Если ваш конструктор принимает аргументы ссылочного типа, а они не null
, то эти объекты уже существуют, и вам решать, что вы с ними делаете. Вы можете вызывать методы для них, вы можете обращаться к их полям, и, конечно же, вы можете назначать их ссылки своим полям.
Однако вы должны знать, что если эти объекты "изменяемые" , то они могут быть изменены другими объектами без вашего ведома! Теперь, возможно, это то, что вам нужно (например, несколько Dog
экземпляров могут использовать один и тот же скоропортящийся продукт Bone
), но иногда вам не нужно сохранять ссылки , а вместо этого значение , который вы не хотите, чтобы другие модифицировали, не пройдя через вас. В этом случае вы можете сделать так называемую «защитную копию» объекта. В итоге вы получите свою собственную личную копию объекта с тем же «значением» (как определено для типа), так что любая мутация в исходной копии не повлияет на вашу собственную.
Теперь это касается предмета защитного программирования, возможно, клонирования (глубокий или неглубокий), достоинств неизменяемых объектов для типов значений и т. Д., И это слишком много, чтобы обсуждать этот уже длинный ответ, но выполнять поиск переполнения стека по некоторым из этих тем: возможно, ваши вопросы уже были заданы (и даны ответы!).
Затенение имени
Я также не мог не заметить, как вы довольно неловко назвали chewyO
и squeekyO
.
Ниже приводится выдержка из Java Puzzlers , Глоссарий повторного использования имени .
Переменная, метод или тип затеняют все переменные, методы или типы, соответственно, с одним и тем же именем в текстовой области видимости. Если сущность находится в тени, вы не можете ссылаться на нее по ее простому имени; в зависимости от объекта вы вообще не можете ссылаться на него ( JLS 6.3.1 Теневые объявления ).
Хотя затенение обычно не рекомендуется, одна распространенная идиома включает затенение. Конструкторы часто используют имя поля из своего класса в качестве имени параметра, чтобы передать значение названного поля. Эта идиома не без риска, но большинство программистов на Java решили, что стилистические преимущества перевешивают риски.
Что говорит второй абзац, так это следующее:
public Dog (Bone chewy, Bone squeeky) {
this.legs = 4;
this.chewy = chewy;
this.squeeky = squeeky;
}
Однако, как говорится в цитате, эта идиома не без риска. Например, вы обнаружите, что если вы написали только chewy = chewy;
, код скомпилирует ! Конечно, тогда он будет иметь другое значение: в правой части будет значение аргумента метода chewy
, как и ожидалось, но вместо затененного поля chewy
левая часть будет также аргумент метода chewy
! По сути, это глупое задание, которое ничего не делает, что допустимо в Java!
К счастью, компилятор по-прежнему выдает предупреждение («Присвоение переменной chewy
не имеет никакого эффекта»), но если программист не обратил внимания, он / она не сразу узнает, что была допущена ошибка, так как код компилирует.
Так что do используйте эту идиому, но всегда убедитесь, что вы используете ключевое слово this
для ссылки на затененные поля. (Я заметил, что вы уже используете this
, даже когда в этом нет необходимости (т.е. this.legs = 4;
): ХОРОШАЯ РАБОТА! Это делает намерение более явным, поэтому продолжайте делать это!)
Кроме того, всегда обращайте внимание на предупреждения компилятора. Всегда пытайтесь понять, что они означают, и всегда проверяйте и перепроверяйте, прежде чем подавлять такие предупреждения. Компилятор делает все возможное, чтобы помочь вам; послушай это.
Схожий вопрос по stackoverflow
- Java - когда использовать
this
ключевое слово
- OP изначально думал, что
chewy = chewy;
компилируется, потому что Java достаточно умен, чтобы знать, что имелось в виду, и поэтому this
не является необходимым для этой идиомы затенения имени. НЕПРАВИЛЬНО !!