8.3 생성자는 순서를 호출

8.3.1 호출 순서 생성자
의 빌드 순서로 조합, 상속, 다형성의 역할을 보여주는 아래의 예를 살펴 보자 :
// : 다형성 / Sandwich..java가
. // 생성자의 주문 호출
다형성에 대한 패키지 페널티를;

class Meal {
    Meal() {System.out.println("Meal()");}
}
class Bread {
    Bread() {System.out.println("Bread()");}
}
class Cheese {
    Cheese() {System.out.println("Cheese()");}
}
class Lettuce {
    Lettuce() {System.out.println("Lettuce()");}
}
class Lunch extends Lettuce {
    Lunch() {System.out.println("Lunch()");}
}
class PortableLunch extends Lunch{
    PortableLunch() {System.out.println("PortableLunch()");}
}
public class Sandwich extends PortableLunch{
    private Bread b = new Bread();
    private Cheese c = new Cheese();
    private Lettuce l = new Lettuce();
    public Sandwich(){
        System.out.println("Sandwich()");
    }
    public static void main(String[] args) {
        new Sandwich();
    }
}
/* Output
Lettuce()
Lunch()
PortableLunch()
Bread()
Cheese()
Lettuce()
Sandwich()
 *///~

이 예에서, 다른 클래스는 복잡한 클래스를 생성하고, 각 클래스는 생성자의 자체 선언을 가지고있다. 가장 중요한 클래스 중 하나는 세 가지 유산을 반영 샌드위치, 개체의뿐만 아니라 세 개 회원 (개체 또한, 계정으로 즉, 네 가지를 가지고가는 경우에 암시 적으로 상속)입니다. 샌드위치 객체가 기본으로 생성되면 ()는 출력을 볼 수있는 곳. 이것은 또한 다음을 준수하는 생성자를 호출하기 위해 복잡한 객체의 순서를 보여줍니다 :

  1. 기본 클래스 생성자를 호출합니다. 이 단계는 재귀 적으로 계속 계속 반복, 모두의 첫 번째는 파생 클래스의 바닥까지, 등등 그런 다음 층 파생 클래스 다음 계층 구조의 루트 등을 구축하는 것입니다.
  2. 초기화 방법은 선언 순서의 부재라고한다.
  3. 주요 파생 클래스의 생성자를 호출.

순서의 생성자가 매우 중요하다 호출합니다. 때 상속, 우리는 기본 클래스, 기본 클래스의 모든을 가지고 대중과 보호의 구성원으로 명령문에 액세스 할 수있을 때까지. 이는 파생 클래스에서, 기본 클래스의 모든 구성원이 유효한 것으로 간주되어야 함을 의미한다. 표준 방법은 생성자 동작 촬영 장소, 그 객체의 일부의 모든 구성원이 얻어지는 구조이다. 그러나, 생성자 내에서, 우리는 건물을 완료 한 회원의 사용을 요청하는 확인해야합니다. 이를 보장하기 위해, 유일한 방법은 먼저 기본 클래스 생성자를 호출하는 것입니다. 입력 할 때 그래서 파생 클래스 생성자 싱크가 초기화 액세스 축적 된 회원에서 사용할 수 있습니다. 또한 생성자의 모든 멤버가 유효한 또한 알고 클래스 내에 정의 된 객체 멤버는 가능한 한 길게 (예를 들면, B, C 및 L의 밤으로), 즉 그들이 (초기화되어야 말할 때 때문에 클래스에 배치 된 오브젝트)의 방법을 조합함으로써. 이 규칙을 따른다면, 당신은 현재 개체의 모든 기본 클래스 구성원과 구성원 개체가 초기화되는 것을 보장 할 수있을 것입니다. 불행하게도,이 방법은 모든 경우에 적용되지 않습니다, 당신은 Benpian의 끝 부분에 표시됩니다.

8.3.2 상속 및 정리
시간이 상속 및 방법의 조합을 통해 새로운 클래스를 만들려면 해당 개체를 청소 걱정하지, 자식 객체는 일반적으로 처리를 위해 가비지 컬렉터에 남아 있습니다. 정리할 문제가 발생 할 경우, 당신은 새로운 클래스 (이름에서) 신중하게 처리 () 메소드를 작성해야합니다. 우리는 특별 정리 작업의 일부로 재활용 쓰레기를 가지고 있다면 때문에 상속을 위해서로, 이는 파생 클래스에서 처분 () 메소드를 포함하는 것이 필요하다. 그렇지 않으면, 기본 클래스의 청소 작업이 일어나지 않았을 것이다 상속 된 클래스 () 메소드를 처분 포함하는 경우 () 메소드 처분의 기본 클래스 버전을 호출하는 것을 기억해야합니다. 다음의 예는이 점을 증명 :
//:polymorphism/Frog.java
// 정리 및 상속
다형성에 대한 패키지 페널티를;

class Characteristic {
    private String s;
    Characteristic(String s) {
        this.s = s;
        System.out.println("Creating Characteristic " + s);
    }
    protected void dispose() {
        System.out.println("disposing Characteristic " + s);
    }
}
class Description {
    private String s;
    Description(String s) {
        this.s = s;
        System.out.println("Creating Description " + s);
    }
    protected void dispose() {
        System.out.println("disposing Description " + s);
    }
}
class LivingCreature {
    private Characteristic p = new Characteristic("is alive");
    private Description t = new Description("Basic Living Creature");
    LivingCreature() {
        System.out.println("LivingCreature()");
    }
    protected void dispose() {
        System.out.println("LivingCreature dispose");
        t.dispose();
        p.dispose();
    }
}
class Animal extends LivingCreature {
    private Characteristic p = new Characteristic("has heart");
    private Description t = new Description("Animal not Vegetable");
    Animal(){System.out.println("Animal()");}
    protected void dispose() {
        System.out.println("Animal dispose");
        t.dispose();
        p.dispose();
        super.dispose();
    }
}
class Amphibian extends Animal {
    private Characteristic p = new Characteristic("can live in water");
    private Description t = new Description("Both water and land");
    Amphibian() {
        System.out.println(" Amphibian()");
    }
    protected void dispose() {
        System.out.println("Amphibian dispose");
        t.dispose();
        p.dispose();
        super.dispose();
    }
}
public class Frog extends Amphibian {
    private Characteristic p = new Characteristic("Croaks");
    private Description t = new Description("Eats Bugs");
    public Frog() {System.out.println("Frog()");}
    protected void dispose() {
        System.out.println("Frog dispose");
        t.dispose();
        p.dispose();
        super.dispose();
    }
    public static void main(String[] args) {
        Frog frog = new Frog();
        System.out.println("Bye!");
        frog.dispose();
    }
}
/*Output
Creating Characteristic is alive
Creating Description Basic Living Creature
LivingCreature()
Creating Characteristic has heart
Creating Description Animal not Vegetable
Animal()
Creating Characteristic can live in water
Creating Description Both water and land
 Amphibian()
Creating Characteristic Croaks
Creating Description Eats Bugs
Frog()
Bye!
Frog dispose
disposing Description Eats Bugs
disposing Characteristic Croaks
Amphibian dispose
disposing Description Both water and land
disposing Characteristic can live in water
Animal dispose
disposing Description Animal not Vegetable
disposing Characteristic has heart
LivingCreature dispose
disposing Description Basic Living Creature
disposing Characteristic is alive
 */

계층 구조의 각 클래스는 두 종류의 특성 및 구성원 개체에 대한 설명이 포함되어, 그들은 파괴해야합니다. 그래서 코트 자식 개체가 다른 개체에 의존하고, 초기화 순서는 역순으로 파괴되어야한다. 필드의 경우, (초기화 필드가 선언의 순서에 따라 실시되기 때문에) 삶의 역순을 말한다. 기본 클래스 (C ++에서 소멸자의 형태를 따라)를 들어, 먼저베이스 클래스가 파생 된 클래스 세정되어야한다. 파생 클래스 정리는 기본 클래스의 일부 메서드를 호출 할 수 있기 때문이다, 그래서 기본 클래스 멤버는 여전히 역할을 조기에 그들을 파괴하지 않아야 할 필요가있다. 개구리 객체의 일부를 볼 출력 생성 파괴의 역순으로 수행된다.

청소 작업을 수행하는 것이 필요하지 않지만 우리는이 예에서 볼 수 있지만 수행 할하면, 당신은 신중하고 조심해야합니다.

의 생성자 8.3.3 동작 내부 다형성 방법
생성자 호출의 계층 구조는 흥미있는 딜레마를 제공합니다. 생성자를 호출하는 바인딩 내부 동적 방법은 객체를 구축되는 경우, 어떤 일이 일어날까요?

개체가이 방법 또는 그 클래스의 클래스를 도출하는 클래스에 속하는 알 수 없으므로 일반적인 방법에서, 런타임에서 동적 바인딩 통화가 결정된다.

당신은 방법의 정의가 적용됩니다 사용하는 생성자, 내부의 동적 바인딩 메소드를 호출합니다. 객체가 완전히 구축되기 전에 오버라이드 (override) 메소드가 호출 될 때문에,이 호출의 결과는 예측하기 매우 어려울 수 있습니다. 이 찾기 어려운 몇 가지 숨겨진 오류가 발생할 수 있습니다.

개념에서, 그것은 개체를 만들 수있는 생성자의 작품 (이 사소한 일이 아니다) 사실이다. 어떤 생성자 내에서 모든 객체는 부분적으로 만 형성 될 수있다 - 우리는 기본 클래스 객체가 초기화되고있는 것을 알고있다. 구성 객체의 구성 프로세스에만 단계이며,이 클래스 생성자가 속하는에서 객체의 클래스가 도출에 속하는 경우, 반출 부 아직 초기화되지 않은 호출되고 이때 구성된다. 그러나, 동적 바인딩 호출하는 방법 깊은 호출 할 수있는 클래스 메소드를 수출 상속 계층 구조로 놓치게 될 것입니다. 우리가 생성자 내에서 그렇게 할 경우, 당신은 방법을 호출 할 수 있으며이 방법의 구성원은 초기화 조작되지 않았을 수 있습니다 - 그것은 확실히 재앙으로 이어질 것입니다.

문제가 자리하고있는 곳이 예제를 다음으로 우리가 나타납니다 :
// : 다형성 / PolyConstructors.java
// 생성자와 다형성
. // 제품 돈`t 당신하여 기대하는 무엇
다형성에 대한 패키지 페널티를;

class Glyph {
    void draw(){System.out.println("Glyph.draw()");}
    Glyph() {
        System.out.println("Glyph() before draw()");
        draw();
        System.out.println("Glyph after draw()");
    }
}
class RoundGlyph extends Glyph {
    private int radius = 1;
    RoundGlyph(int r) {
        radius = r;
        System.out.println("RoundGlyph.RoundGlyph().radius = " + radius);
    }
}
public class PolyConstructors {
    public static void main(String[] args) {
        new RoundGlyph(5);
    }
}
/*Output
Glyph() before draw()
Glyph.draw()
Glyph after draw()
RoundGlyph.RoundGlyph().radius = 5
 */

Glyph.draw () 메소드를 포함하도록 설계되고,이 커버는 RoundGlyph의 장소이다. 그러나 문양 생성자 통화 교환의 방법은, 그 결과는 우리의 목표 것으로 보인다 스트립과 쌍 RoundGlyph.draw ()입니다. 당신은 출력을 볼 경우, 우리는 문양의 생성자 호출 () 메소드, 하나의 디폴트의 초기 값보다 반경을 그릴 수 있지만, 0 때 화면 만 점을 받았다, 또는 모든 것을 수행에 발생할 수 있음을 발견 할 것이다 아니오, 우리는 절망에보고, 프로그램이 작동 할 수있는 곳을 찾기 위해 노력하고 있습니다.

초기화 순서에 대한 기사의 시작하는 것은 매우 완료되지 않은,하지만 공식 거짓말이이 퍼즐을 해결하는 열쇠. 초기화의 실제 프로세스는 다음과 같습니다

  1. 다른 어떤 일이 발생하기 전에, 저장 공간은 석사 초기화 이진 객체에 할당.
  2. 위에서 언급 한 기본 클래스 생성자를 호출하는 경우. 이 경우, 통화 연신 () 메소드에 의한 1 단계로 덮은 후,이 시간은 제로 반경 것을 알게 (생성자 RoundGlyph 전에 호출한다).
  3. 초기화 방법은 선언의 순서의 부재라고한다.
  4. 파생 클래스 본문의 생성자를 호출합니다.

이것은 조금을 가지고 있으며, 그것은 단지 쓰레기 예약하기보다는, 적어도 제로 (값 또는 "제로"를 값으로 일부 특수 데이터 유형)으로 초기화 전부입니다.

그러므로 생성자를 작성하는 준 효율적인 측면이있다 : "가장 간단한 방법들은 정상적인 상태로 오브젝트를 만들기 위해, 가능한 경우, 다른 방법을 호출 피한다." 유일한 안전한 통화가 기본 클래스 마지막 방법이다 생성자 방법 (민간 방법에 적용, 그들은 자동으로 fianl 방법을 속한다). 이 방법을 적용 할 수 없으며, 따라서 위의 문제는 놀라운 표시되지 않습니다. 당신은 항상이 지침을 따를 수되지 않을 수도 있습니다,하지만 노력은 그를 향해해야한다.

추천

출처www.cnblogs.com/cgy-home/p/11130246.html