2010-04-21 6 views
4

다음 작업을 수행 할 수 있습니까? 생성자의 객체를 참조 할 수 있습니까?

public Manager(String userName) { 
    game = new Game(userName); 
    game.addManager(this); 
} 

문제

(이것은 실제로 생성하기 전에) 나는 그것의 생성자에서 객체 ( this)를 참조한다는 것입니다.

+1

* 그 시점에서이 (그렇지 않으면 속성 중 하나에 액세스 할 수 없습니다),하지만 완전히 제대로 * 초기화 아니다. –

답변

2

그래도 완벽하게 법적 허용 범위는입니다. 그러나 권장하지 않습니다. this 키워드에 대한 자세한 내용은 here을 참조하십시오.

+1

그 기술은 Java에서 유효하지만 꽤 위험합니다. –

+2

완벽하게 유효합니까 ?? 단지 컴파일 만하면됩니다. – Roman

+2

나는 그것이 "완벽하게 합법적 인 자바"라고 말하면이 대답이 더 좋을 것이라고 생각한다. 그러나 인생에서와 마찬가지로, 그것이 합법적이라고해서 그것이 좋은 생각이되지는 않습니다. – Yishai

3

예, 당신은 수 있습니다.,하지만 당신은 은하지 말아야합니다.

생성자가 아직 실행 중일 때 일부 보편적 인 보장이 적용되지 않기 때문에 생성자가 계속 실행되는 동안 다른 유형의 이상한 부작용이 생길 수 있습니다 (예 : final 변수가 변경 될 수 있음). 그 값은 생성자가 여전히 실행되는 동안).

This IBM developerWorks article에는 개체를 구성 할 때주의 사항과 이러한주의 사항의 추론이 설명되어 있습니다. 이 기사에서는 멀티 스레딩과 관련하여 주제에 대해 설명하지만 알 수없는/신뢰할 수없는 코드가 생성 중에 this에 대한 참조를 얻으면 단일 스레드 환경에서 유사한 문제를 가질 수 있습니다.

(마지막 단락은 one of my earlier answers에서 "도난당했습니다").

1

@James에 명시된 바와 같이 할 수는 있지만 반드시하고 싶은 것은 아닙니다. game.addManager이 Manager의 특정 속성에 액세스하려고 시도하면 아직 초기화되지 않은 Manager의 속성에 액세스하려고 할 수 있습니다. 더 나은 접근법은 외부 객체가 관리자를 추가하고 생성자에서 수행하지 않는 일부 init 메소드 (또는 일부 수명주기 메소드)를 호출하도록하는 것입니다. 이 도움이된다면

0

이 기술은 자바 동시성 개념의 하나를 위반 - 안전 간행물. 이를 위해서는 init() 방법을 사용해야합니다.

참조가 이스케이프 된 후 생성자의 일부 최종 필드를 초기화 할 수 있습니다. 생성자에서 객체의 인스턴스를 다른 객체로 전달하면 생성 중에 콜백을 얻을 수 있습니다. 그리고 일관성없는 행동, NPEs, dead-locks 등을 일으킬 수 있습니다.

4

합법적 인 자바이지만, (생성자의 마지막 라인 인 경우) 당신이 (예외가있는 특정 케이스를 제외하고) 꽤 안전한 것입니다. 연습으로 나쁜 것입니다. 해야 할 일, 그리고 goto (키워드를 지원하는 언어로)을 사용하는 것과 마찬가지로, 길고도 열심히 생각해야합니다.

public static Manager createManager(String userName) { 
     Manager manager = new Manager(userName); 
     manager.game.addManager(manager); 
     return manager; 
} 

나는 또한 클래스 사이의 상호 의존성의 종류 (관리자가 알고 있다는 것을 지적한다 : 귀하의 경우를 들어, 더 좋은 방법은, 생성자 개인을 addManager에 대한 호출을 제거하고 정적 팩토리 메소드를 노출하는 것 게임에 관한 내용과 게임에 대한 매니저의 지식은 분명히 코드 냄새입니다. 나는 이것을 생성자로부터 전달하는 것과 관련하여 필요성에 대해 우려 할 것입니다.

+1

+1 상호 의존성 코드 냄새 – sleske

0

소년, 이건 안전하지 않습니다! 유효한 코드이지만 좋은 디자인은 아니지만! 이 코드는 객체가 제대로 구성되기 전에 "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(); 
    } 
} 
관련 문제