У меня есть такой конструктор:
public Agent(){
this.name = "John";
this.id = 9;
this.setTopWorldAgent(this, "Top_World_Agent", true);
}
Я получаю исключение нулевого указателя здесь, в вызове метода. Похоже, это потому, что я использую this в качестве аргумента в методе setTopWorldAgent. После удаления этого вызова метода все выглядит нормально. Почему так происходит? Кто-нибудь еще испытал это?
Я хотел бы узнать, какое окончательное решение было у спрашивающего.
Это называется аргументом, а не параметром.




this не является нулем, это точно. Это было выделено.
Тем не менее, нет необходимости передавать this в метод, он автоматически доступен во всех методах экземпляра. Если метод статический, вы можете преобразовать его в метод экземпляра.
Вы можете передать это методам, но setTopWorldAgent () не может быть абстрактным. Вы не можете сделать виртуальный вызов в конструкторе.
В конструкторе объекта вы можете вызывать методы, определенные в этом объекте или базовых классах, но вы не можете ожидать вызова чего-то, что будет предоставлено производным классом, поскольку части производного класса еще не созданы. Я бы ожидал какой-то ошибки компилятора, если бы setTopWorldAgent () был абстрактным.
В Java вы можете добиться удивительного поведения с конструктором и производными классами - вот пример
http://en.wikipedia.org/wiki/Virtual_functions#Java_3
Если вы привыкли к C# или C++, вы можете подумать, что вызывать виртуальные функции безопасно, а не вызывать переопределенные. В Java виртуальный вызов выполняется, даже если производный класс не полностью построен.
Если это не то, что происходит, то, по-видимому, инициализируются все части этого, необходимые для setTopWorldAgent () - в противном случае, вероятно, это один из членов этого, который необходимо инициализировать.
Обновлено: думал, что это C#
Но даже если выполнить вызов функции не будет, произойдет сбой!
Это явно неверный ответ. Даже если класс был абстрактным и метод setTopWorldAgent также был абстрактным, создание в этот момент не имело бы значения null. Это легко показать на тестовом примере.
Блин, почему вы, люди, голосуете против этого ответа? Это верно!
В Java вы можете вызвать абстрактный метод, и он будет преобразован в метод реализации в подклассе. Но вы правы, что переменные подкласса не были инициализированы. Конструктор родительского класса вызывается перед дочерним.
Спасибо, Конрад! это не нуль - есть что-то еще. Я предлагал вещи, которые могли быть нулевыми, или способы, которыми можно было обмануть вас, думая, что что-то было вызвано, когда это не так.
@Konrad Rudolph Потому что в нем неверная информация о Java. Вы можете вызывать абстрактные методы из конструктора
Можете ли вы отредактировать свой ответ, чтобы он был яснее, вы могли явно вызывать абстрактные методы из конструкторов. Это не ноль, но я допускаю, что (как говорит sblundy) переменные подкласса для этого могут быть нулевыми.
Да, я отредактировал ответ для Java и предоставил ссылку на пример, который, на мой взгляд, близок к тому, что здесь происходит.
@sblundy: Черт. Первоначально вопрос был помечен как C#, а не Java. Но в любом случае ответ уже тогда содержал уточнение, делающее ответ абсолютно правильным.
@Konrad Rudolph: В исходном посте не было ни одного тега. Я только что проверил историю и, похоже, v2 был помечен как C#, затем владелец изменил это на Java. В исходном посте единственная подсказка, что это была java, заключалась в том, что setTopWorldAgent не был SetTopWorldAgent. Но теперь мы все правы, поэтому я изменил свой голос.
"this" никогда не должно быть нулевым. Вы уверены, что из-за этого возникает исключение?
Следует остерегаться того, что если метод является виртуальным или вызывает какие-либо виртуальные методы, то метод, принадлежащий подклассу, может быть запущен до инициализации переменных подкласса.
В Java вы можете вызывать абстрактные методы в конструкторе. Будет вызван метод реализации в подклассе.
Ошибка должна быть где-то еще, потому что приведенный выше код определенно работает, нулевая ссылка должна быть чем-то другим.
Зачем 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 в качестве параметра может привести к неожиданным проблемам с параллелизмом. По сути, вы предоставляете возможность небезопасного управления состоянием объекта потенциально небезопасным кодом.
Я предполагаю, что код в setTopWorldAgent - это то место, где возникает исключение. Возможно, вы могли бы добавить трассировку стека исключения и код этого метода.