다음 작업을 수행 할 수 있습니까? 생성자의 객체를 참조 할 수 있습니까?
public Manager(String userName) {
game = new Game(userName);
game.addManager(this);
}
문제
(이것은 실제로 생성하기 전에) 나는 그것의 생성자에서 객체 (this
)를 참조한다는 것입니다.
다음 작업을 수행 할 수 있습니까? 생성자의 객체를 참조 할 수 있습니까?
public Manager(String userName) {
game = new Game(userName);
game.addManager(this);
}
문제
(이것은 실제로 생성하기 전에) 나는 그것의 생성자에서 객체 (this
)를 참조한다는 것입니다.
예, 당신은 수 있습니다.,하지만 당신은 은하지 말아야합니다.
생성자가 아직 실행 중일 때 일부 보편적 인 보장이 적용되지 않기 때문에 생성자가 계속 실행되는 동안 다른 유형의 이상한 부작용이 생길 수 있습니다 (예 : final
변수가 변경 될 수 있음). 그 값은 생성자가 여전히 실행되는 동안).
This IBM developerWorks article에는 개체를 구성 할 때주의 사항과 이러한주의 사항의 추론이 설명되어 있습니다. 이 기사에서는 멀티 스레딩과 관련하여 주제에 대해 설명하지만 알 수없는/신뢰할 수없는 코드가 생성 중에 this
에 대한 참조를 얻으면 단일 스레드 환경에서 유사한 문제를 가질 수 있습니다.
(마지막 단락은 one of my earlier answers에서 "도난당했습니다").
@James에 명시된 바와 같이 할 수는 있지만 반드시하고 싶은 것은 아닙니다. game.addManager
이 Manager의 특정 속성에 액세스하려고 시도하면 아직 초기화되지 않은 Manager의 속성에 액세스하려고 할 수 있습니다. 더 나은 접근법은 외부 객체가 관리자를 추가하고 생성자에서 수행하지 않는 일부 init 메소드 (또는 일부 수명주기 메소드)를 호출하도록하는 것입니다. 이 도움이된다면
그것은 C는 실제로 참조/C++하지만 난 자바에 대한 그 같은 생각 :
이 기술은 자바 동시성 개념의 하나를 위반 - 안전 간행물. 이를 위해서는 init()
방법을 사용해야합니다.
참조가 이스케이프 된 후 생성자의 일부 최종 필드를 초기화 할 수 있습니다. 생성자에서 객체의 인스턴스를 다른 객체로 전달하면 생성 중에 콜백을 얻을 수 있습니다. 그리고 일관성없는 행동, NPEs, dead-locks 등을 일으킬 수 있습니다.
합법적 인 자바이지만, (생성자의 마지막 라인 인 경우) 당신이 (예외가있는 특정 케이스를 제외하고) 꽤 안전한 것입니다. 연습으로 나쁜 것입니다. 해야 할 일, 그리고 goto
(키워드를 지원하는 언어로)을 사용하는 것과 마찬가지로, 길고도 열심히 생각해야합니다.
public static Manager createManager(String userName) {
Manager manager = new Manager(userName);
manager.game.addManager(manager);
return manager;
}
나는 또한 클래스 사이의 상호 의존성의 종류 (관리자가 알고 있다는 것을 지적한다 : 귀하의 경우를 들어, 더 좋은 방법은, 생성자 개인을 addManager에 대한 호출을 제거하고 정적 팩토리 메소드를 노출하는 것 게임에 관한 내용과 게임에 대한 매니저의 지식은 분명히 코드 냄새입니다. 나는 이것을 생성자로부터 전달하는 것과 관련하여 필요성에 대해 우려 할 것입니다.
+1 상호 의존성 코드 냄새 – sleske
소년, 이건 안전하지 않습니다! 유효한 코드이지만 좋은 디자인은 아니지만! 이 코드는 객체가 제대로 구성되기 전에 "this"참조가 이스케이프되도록 허용합니다.
game.addManager()가 "this"참조에서 xxx() 메소드를 호출한다고 가정 해 보겠습니다. 그리고 Manager, ChildManager의 하위 클래스가 있습니다.이 하위 클래스는 메서드 xxx()를 재정의하며이 메서드는 SuperManager가 마지막 코드 줄에 도달하면 초기화되지 않는 ChildManager의 필드에 따라 달라집니다. GameManager.addManager()는 ChildManager에서 필드의 초기화되지 않은 값을 볼 수 있습니다. 이는 매우 위험합니다!
예제 코드 : 아직 * 기술적 오브젝트가 이미 * 생성
public class Manager {
Game game;
public Manager (String userName){
game = new Game(userName);
game.addManager(this);
}
public void xxx(){
}
}
public class ChildManager extends Manager {
String name;
public ChildManager (String username){
super(username);
name = username;
}
public void xxx(){
System.out.println(name);
}
}
public class Game {
public Game (String userName){
}
public void addManager (Manager m){
m.xxx();
}
}
* 그 시점에서이 (그렇지 않으면 속성 중 하나에 액세스 할 수 없습니다),하지만 완전히 제대로 * 초기화 아니다. –