การเรียกตัวสร้าง super() ควรเป็นบรรทัดแรกของตัวสร้างหรือไม่

การเรียก super() Constructor ควรเป็นบรรทัดแรกของ Constructor หรือไม่ ถ้าเป็นเช่นนั้นทำไม? เหตุใดฉันจึงไม่สามารถคำนวณแบบจำกัดง่ายๆ ก่อนการเรียกคอนสตรัคเตอร์ได้ เช่น การคำนวณพารามิเตอร์คอนสตรัคเตอร์

ฉันพบสถานการณ์ที่มีตัวสร้างคลาสภายในซึ่งสามารถเรียกได้ด้วยข้อกำหนดการปิด:

class A {
    class Inner1 {
        Inner1() {
            // do something
        }
    }
}

class B {
    A a1 = new A();
    A a2 = new A();

    class Inner2 extends A.Inner1 {
         Inner2(boolean sel) {
             (sel?a1:a2).super();
         }
    }

}

กรณีนี้แสดงว่าเราต้องการเลือกอินสแตนซ์ที่ล้อมรอบสำหรับตัวสร้างคลาสพื้นฐาน เหตุใดตรรกะในการคัดเลือกจึงควรมีจำกัด ทำไมไม่มีใครเขียนอะไรแบบนี้ได้

if( sel ) {  
    a1.super();
}
else {
    a2.super();
}

เพิ่มเติม

จากคำถามของฉันฉันหมายถึงข้อจำกัดอาจเป็นเช่นในกรณีต่อไปนี้:

public class Base {

private final String content;

public Base(String content) {
    this.content = content;
}

public String getContent() {
    return content;
}

}


public class Derived extends Base {

public Derived(String content) {
    super(String.format("Current value of content is %s.", getContent()));
}


}

ในกรณีหลังนี้ ฉัน:

1) ปฏิบัติตามข้อกำหนดของ super() ที่จะอยู่ในบรรทัดแรก

2) ฝ่าฝืนคำสั่งก่อสร้าง

3) รับข้อผิดพลาดของคอมไพเลอร์ "ไม่สามารถอ้างถึงวิธีการอินสแตนซ์ในขณะที่เรียกใช้คอนสตรัคเตอร์อย่างชัดเจน"

เหตุใดเราจึงไม่สามารถยกเลิก "ข้อกำหนดบรรทัดแรก" และพึ่งพาเฉพาะข้อผิดพลาดเหมือนข้อสุดท้ายได้


person Suzan Cioc    schedule 23.05.2012    source แหล่งที่มา
comment
super() ต้องถูกวางเป็นบรรทัดแรกของการเรียกคอนสตรัคเตอร์หากคุณใช้ - แต่ตรวจสอบเธรดนี้: stackoverflow.com/questions/9675431/ หรือสิ่งนี้: stackoverflow.com/questions/1168345/   -  person wkl    schedule 24.05.2012
comment
ขอบคุณ! วิธีแก้ปัญหาก็น่าสนใจ แต่ก็น่าสนใจเช่นกัน เพราะเหตุใด Java จึงถูกสร้างขึ้นมา เช่น จะเกิดอะไรขึ้นถ้าฉันทำอะไรบางอย่างก่อนที่จะเรียก super ตัวอย่างเช่น ฉันอาจจำเป็นต้องไม่เข้าถึงสมาชิกของอินสแตนซ์จนกว่าจะโทรหา super   -  person Suzan Cioc    schedule 24.05.2012
comment
@SuzanCioc หากคุณทำอะไรก่อนที่จะโทร super() Java จะหยุดโปรแกรมของคุณและบอกให้คุณแก้ไข   -  person Hunter McMillen    schedule 24.05.2012
comment
@Suzan Cioc ลิงก์ที่สองที่จัดทำโดย biryree ครอบคลุมคำถามนั้น   -  person dantuch    schedule 24.05.2012
comment
@Suzan มีภาษา (python) ที่อนุญาตให้เรียกตัวสร้างของคลาส super ในภายหลังหรือไม่ได้เลย แน่นอนว่าอาจส่งผลเสีย แต่เราทุกคนก็รู้ว่าการเรียก super() ก่อนไม่ได้แก้ปัญหาทั้งหมดและสร้างปัญหาใหม่ๆ มากมาย มันเป็นการทำให้ง่ายขึ้น เพราะมันหมายความว่าเราไม่จำเป็นต้องแยกการจัดสรรอ็อบเจ็กต์และการเริ่มต้นออกเป็นสองส่วนแยกกัน และฉันคิดว่ามันจะหลีกเลี่ยงปัญหาประเภทหนึ่งที่จะเกิดขึ้นเป็นประจำ   -  person Voo    schedule 24.05.2012
comment
โปรดดูการเพิ่มของฉัน ฉันไม่ต้องการจัดการกับอินสแตนซ์ที่ไม่ได้กำหนดค่าเริ่มต้นเช่นใน C ++ ฉันแค่สงสัยว่าทำไมเราไม่สามารถพึ่งพาการตรวจสอบเช่น ไม่สามารถอ้างถึงวิธีการอินสแตนซ์ในขณะที่เรียกใช้คอนสตรัคเตอร์อย่างชัดเจน   -  person Suzan Cioc    schedule 24.05.2012


คำตอบ (2)


ใช่ จำเป็นต้องเรียก super() เป็นการเรียกครั้งแรกในตัวสร้าง

มากเสียจนถ้าคุณปล่อยมันไว้ คอมไพเลอร์จะ (พยายาม) ใส่การเรียกให้คุณ เพื่อทำความเข้าใจสาเหตุ คุณจะต้องเข้าใจปรัชญาของนักออกแบบของ Java กอสลิงอยู่ในค่ายนักวิทยาศาสตร์คอมพิวเตอร์มาโดยตลอดซึ่งเชื่อว่าการเข้าถึงวัตถุที่เตรียมใช้งานบางส่วนเป็นหนึ่งในสาเหตุใหญ่ของข้อบกพร่องในโปรแกรมคอมพิวเตอร์ และด้วยเหตุนี้ เขาได้ออกแบบลำดับชั้นการเริ่มต้นที่เข้มงวดซึ่งจะช่วยบรรเทาปัญหานี้ได้ ไม่ว่าคุณจะเห็นด้วยกับปรัชญานี้เป็นเรื่องที่สงสัยหรือไม่ แต่สิ่งสำคัญคือต้องตระหนักว่าแนวคิดใน Java นั้นมีความสำคัญพอๆ กัน เช่น การอ้างอิงเทียบกับพอยน์เตอร์ หรืออาร์เรย์ที่มีขอบเขตจริง ควรสังเกตว่าแม้แต่ภาษาอย่าง Objective C ที่อนุญาตให้คุณเรียกใช้การกำหนดค่าเริ่มต้นได้ตลอดเวลา ก็ยังต้องใช้ความพยายามอย่างมากในการบังคับใช้ การเชื่อมโยงการกำหนดค่าเริ่มต้น ยกเว้นว่าจะต้องดำเนินการผ่านแบบแผน ซึ่งตรงข้ามกับแบบเข้มงวด กฎภาษา

ฉันไม่แน่ใจว่าคุณพยายามอธิบายอะไรในตัวอย่างของคุณ - แต่หลังจากพัฒนา Java มาหลายปี ฉันสงสัยว่าคุณจะพบหลายกรณีที่คุณ จริงๆ จำเป็นต้องใช้ตรรกะก่อนที่จะเรียกใช้ super

person Perception    schedule 23.05.2012

การเรียกคอนสตรัคเตอร์นั้นเชื่อมโยงกับ super ของทุกคลาสในลำดับชั้นที่ถูกเรียกใช้ก่อนที่จะเรียกใช้คอนสตรัคเตอร์ของคลาสนั้น เนื่องจากคลาสทั้งหมดใน Java สืบทอดมาจากคลาสอ็อบเจ็กต์ ดังนั้นคอนสตรัคเตอร์ของคลาสอ็อบเจ็กต์จึงถูกเรียกใช้ก่อนสำหรับทุกคลาสด้วยเหตุผลที่ว่าการจัดสรรหน่วยความจำสำหรับอ็อบเจ็กต์นั้นกระทำโดยคอนสตรัคเตอร์ของคลาสอ็อบเจ็กต์

person ejb_guy    schedule 23.05.2012
comment
แต่อะไรคือความแตกต่างหลักหากฉันเขียนนิพจน์เดียวที่ยาวด้วย super() และถ้าฉันเขียนโค้ดหลายบรรทัด - person Suzan Cioc; 24.05.2012
comment
คุณช่วยอธิบายได้ไหม โดยพื้นฐานแล้วหากตัวสร้างของคลาส Object ไม่ได้ถูกดำเนินการมากกว่าที่คุณไม่มีวัตถุที่จะใช้งาน และเพื่อให้แน่ใจว่าตัวสร้างของ Object ถูกเรียก การเรียก super() จะต้องเป็นบรรทัดแรก - person ejb_guy; 24.05.2012
comment
กรุณาดูคำถามของฉัน ฉันจัดเตรียมโค้ดตัวสร้างส่วนขยายไว้สองโค้ด ซึ่งเหมือนกันโดยลอจิก แต่โค้ดแรกเท่านั้นที่ได้รับอนุญาตจาก Java - person Suzan Cioc; 24.05.2012