Использование this в качестве параметра вызова метода в конструкторе

У меня есть такой конструктор:

public Agent(){

    this.name = "John";
    this.id = 9;
    this.setTopWorldAgent(this, "Top_World_Agent", true);

}

Я получаю исключение нулевого указателя здесь, в вызове метода. Похоже, это потому, что я использую this в качестве аргумента в методе setTopWorldAgent. После удаления этого вызова метода все выглядит нормально. Почему так происходит? Кто-нибудь еще испытал это?

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

Dave Costa 24.09.2008 17:45

Я хотел бы узнать, какое окончательное решение было у спрашивающего.

Lou Franco 24.09.2008 18:00

Это называется аргументом, а не параметром.

Pavel 23.08.2015 17:56
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
6
3
9 478
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

this не является нулем, это точно. Это было выделено.

Тем не менее, нет необходимости передавать this в метод, он автоматически доступен во всех методах экземпляра. Если метод статический, вы можете преобразовать его в метод экземпляра.

Ответ принят как подходящий

Вы можете передать это методам, но setTopWorldAgent () не может быть абстрактным. Вы не можете сделать виртуальный вызов в конструкторе.

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

В Java вы можете добиться удивительного поведения с конструктором и производными классами - вот пример

http://en.wikipedia.org/wiki/Virtual_functions#Java_3

Если вы привыкли к C# или C++, вы можете подумать, что вызывать виртуальные функции безопасно, а не вызывать переопределенные. В Java виртуальный вызов выполняется, даже если производный класс не полностью построен.

Если это не то, что происходит, то, по-видимому, инициализируются все части этого, необходимые для setTopWorldAgent () - в противном случае, вероятно, это один из членов этого, который необходимо инициализировать.

Обновлено: думал, что это C#

Но даже если выполнить вызов функции не будет, произойдет сбой!

Konrad Rudolph 24.09.2008 17:48

Это явно неверный ответ. Даже если класс был абстрактным и метод setTopWorldAgent также был абстрактным, создание в этот момент не имело бы значения null. Это легко показать на тестовом примере.

Henry B 24.09.2008 17:55

Блин, почему вы, люди, голосуете против этого ответа? Это верно!

Konrad Rudolph 24.09.2008 17:56

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

sblundy 24.09.2008 17:56

Спасибо, Конрад! это не нуль - есть что-то еще. Я предлагал вещи, которые могли быть нулевыми, или способы, которыми можно было обмануть вас, думая, что что-то было вызвано, когда это не так.

Lou Franco 24.09.2008 17:59

@Konrad Rudolph Потому что в нем неверная информация о Java. Вы можете вызывать абстрактные методы из конструктора

sblundy 24.09.2008 18:00

Можете ли вы отредактировать свой ответ, чтобы он был яснее, вы могли явно вызывать абстрактные методы из конструкторов. Это не ноль, но я допускаю, что (как говорит sblundy) переменные подкласса для этого могут быть нулевыми.

Henry B 24.09.2008 18:03

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

Lou Franco 24.09.2008 18:07

@sblundy: Черт. Первоначально вопрос был помечен как C#, а не Java. Но в любом случае ответ уже тогда содержал уточнение, делающее ответ абсолютно правильным.

Konrad Rudolph 24.09.2008 18:17

@Konrad Rudolph: В исходном посте не было ни одного тега. Я только что проверил историю и, похоже, v2 был помечен как C#, затем владелец изменил это на Java. В исходном посте единственная подсказка, что это была java, заключалась в том, что setTopWorldAgent не был SetTopWorldAgent. Но теперь мы все правы, поэтому я изменил свой голос.

sblundy 24.09.2008 18:27

"this" никогда не должно быть нулевым. Вы уверены, что из-за этого возникает исключение?

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

В Java вы можете вызывать абстрактные методы в конструкторе. Будет вызван метод реализации в подклассе.

sblundy 24.09.2008 17:50

Ошибка должна быть где-то еще, потому что приведенный выше код определенно работает, нулевая ссылка должна быть чем-то другим.

Зачем setTopWorldAgentthis в качестве аргумента? В зависимости от вызова это метод экземпляра, поэтому он может ссылаться на this без необходимости получать его в качестве параметра.

Я думаю, что ближе к делу, почему вы передаете this в качестве параметра методу в this?

Следующее будет проверять то, что вы говорите, происходит с вами, и у меня с этим нет проблем.

public class Test {
  public Test() {
    this.hi(this);
  }
  public void hi(Test t) {
    System.out.println(t);
  }

  public static void main(String[] args) throws Exception {
    Test t = new Test();
  }
}

Учитывая, что setTopWorldAgent выглядит как метод экземпляра, почему вы все равно передаете ему this?

Из любопытства, почему вы передаете this функции-члену того же класса? setTopWorldAgent () может использовать this напрямую. Не похоже, что ваш конструктор или setTopWorldAgent () статичны, поэтому я не уверен, зачем вам передавать функцию-член, к которой у нее уже есть доступ.

Если я чего-то не упускаю ...

Если ваш агент реализует ITopWorldAgent, вам действительно следует сделать это:


Agent agent = new Agent("John", 9);
agent.setTopWorldAgent(agent, "Top_World_Agent", true);

Если нет, то почему вы настраиваете что-то так, как вы?

Я предполагаю, что что-то в методе setTopWorldAgent использует значение, которое еще не было инициализировано в вашем конструкторе.

Правила Java гласят, что вы никогда не должны передавать this другому методу из его конструктора по той простой причине, что объект не был полностью сконструирован. Объект, на который он ссылается, может находиться в несовместимом состоянии. Я удивлен, что фактическая ссылка this имеет значение null, но нисколько не удивлен, что какой-то член this имеет значение null, когда он передается в setTopWorldAgent, и что из-за этого метод генерирует исключение.

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

В этом случае, конечно, в аргументе нет необходимости, поскольку метод уже имеет ссылку на this.

Рад, что ты получил ответ. Я хотел бы добавить, что передача this в качестве параметра может привести к неожиданным проблемам с параллелизмом. По сути, вы предоставляете возможность небезопасного управления состоянием объекта потенциально небезопасным кодом.

Другие вопросы по теме