2009-12-07 5 views
0

누군가 내가 오해 한 것을 지적 할 수 있습니까?Java : 추상 클래스 생성자 및 this()

다음과 같이 나는 두 개의 클래스, 요약서와 콘크리트있어

:

public abstract class Abstract 
{ 
    protected static int ORDER = 1; 

    public static void main (String[] args) 
    { 
     Concrete c = new Concrete("Hello"); 
    } 

    public Abstract() 
    { 
     Class c = this.getClass(); 
     System.out.println(ORDER++ + ": Class = " 
      + c.getSimpleName() 
      + "; Abstract's no-arg constructor called."); 
    } 

    public Abstract(String arg) 
    { 
     this(); 
     Class c = this.getClass(); 
     System.out.println(ORDER++ + ": Class = " 
      + c.getSimpleName() 
      + "; Abstract's 1-arg constructor called."); 
    } 
} 

public class Concrete extends Abstract 
{ 
    public Concrete() 
    { 
     super(); 
     Class c = this.getClass(); 
     System.out.println(ORDER++ + ": Class = " 
      + c.getSimpleName() 
      + "; Concrete's no-arg constructor called."); 
    } 

    public Concrete(String arg) 
    { 
     super(arg); 
     Class c = this.getClass(); 
     System.out.println(ORDER++ + ": Class = " 
      + c.getSimpleName() 
      + "; Concrete's 1-arg constructor called."); 
    } 
} 

나는 다음과 같은 출력을 얻을이 실행하면 :

1) 클래스 = 콘크리트; Abstract의 no-arg 생성자가 호출되었습니다.
2) 클래스 = 콘크리트; Abstract의 1-arg 생성자 이 호출되었습니다.
3) Class = Concrete; 콘크리트의 1 인수 생성자가 호출되었습니다.

내 질문

은 이것이다 : 왜하지 않습니다 추상의 문자열 인수 생성자 호출에서이()에 대한 호출 콘크리트에이 인수 없음의 생성자? 아니면 좀 더 적절하게, Abstract String Arg 생성자에게 Constructor의 "적절한"연결을 허용하는 Concrete의 인수가없는 생성자를 호출 할 수있는 방법이 있습니까?

답변

7

No-constructor chaining 항상은 옆으로 (같은 유형으로) 또는 위쪽으로 (상위 유형으로) 이동합니다.

호출이 컴파일 시간에서 해결해야하는 것을 잊지 마세요 - 그리고 Abstract 다른 클래스가, 또는 그들이해야 어떤 생성자에서 파생가는 것을 알지 못합니다.

당신 Abstract 생성자 내에서 가상 메소드를 호출하고, Concrete 내에서이 메소드를 오버라이드 (override) ...하지만 난 그렇게 당신에게을 을하지 촉구 수 있습니다. 특히 Concrete의 생성자 본문은 아직 실행되지 않았으므로 변수 초기화 프로그램이 실행되지 않으므로 Concrete 특정 상태로는 아무 것도 수행 할 수 없습니다. 매우 특정 상황이 있지만 올바른 작업은 아니지만 매우 드물고주의해서 처리해야합니다.

실제로 무엇을하려고합니까? 보통 나는 "윗 방향"체인이있는 하나의 생성자로 이어지는 많은 "옆쪽"체인을 갖는 것이 낫다.

+0

감사합니다. getClass가 Object isa Concrete를 알고 있지만 this()가 추상 no-arg 생성자를 호출한다는 사실은 나에게 조금 부자연 스럽습니다. 달성하려는 체인은 나에게 생성자간에보다 자연스러운 책임 분담을 허용 한 것으로 보입니다. Concrete의 생성자에서 코드를 복제하거나 새로운 메소드로 옮겨야한다고 생각합니다. 그러나이 추상 클래스의 모든 Concrete 구현을 작성하지는 않았으므로 다른 개발자를 위해 문서화해야 할 내용입니다. . –

+1

그래서 가상 생성자 인 것처럼 생성자를 처리하려고 했습니까? 그래, 그게 효과가 없을거야. –

1

간단히 말해서 (Jon Skeet이 자세히 설명 했듯).

당신은 그러나 구체적인하기 위해 초기화 블록을 추가 할 수 있습니다

는 inizializer 블록이 항상 호출되는 기본 생성자는 달리
{ 
    Class c = this.getClass(); 
    System.out.println(ORDER++ + ": Class = " 
    + c.getSimpleName() 
    + "; Concrete's init block called."); 
} 

:

1: Class = Concrete; Abstract's no-arg constructor called. 
2: Class = Concrete; Abstract's 1-arg constructor called. 
3: Class = Concrete; Concrete's init block called. 
4: Class = Concrete; Concrete's 1-arg constructor called. 
0

이 처리하는 가장 좋은 방법은 일반적으로 클래스의 모든 생성자가 하나의 공통 생성자, 즉: 여기

public Abstract() { 
    this(null); 
} 
public Abstract(String arg) { 
    // do all Abstract init here 
} 

public Concrete() { 
    this(null); 
} 
public Concrete(String arg) { 
    super(arg); 
    // do all Concrete init here 
} 
1

는 추상 클래스의 무엇이 필요하고 어떻게이 당신을 도울 것입니다 works.May에 초점을 post입니다.

1

하위 클래스는 항상 상위 클래스에서 숨겨져 있음을 알아야합니다. 자식 클래스에서했던 것처럼 자식 클래스의 메서드 나 생성자를 직접 호출 할 수 없습니다.