วิธีบังคับให้คลาสที่ได้รับเรียก super method? (เช่นเดียวกับ Android)


85

ฉันสงสัยว่าเมื่อสร้างActivityคลาสใหม่แล้วแทนที่onCreate()เมธอดในคราสฉันมักจะได้รับการเพิ่มอัตโนมัติ: super.onCreate(). สิ่งนี้เกิดขึ้นได้อย่างไร? มีคีย์เวิร์ด java ใน abstract หรือ parent class ที่บังคับสิ่งนี้หรือไม่?

ฉันไม่รู้ว่ามันผิดกฎหมายหรือไม่ที่จะไม่เรียกซุปเปอร์คลาส แต่ฉันจำได้ว่าในบางวิธีฉันได้รับข้อยกเว้นที่ไม่ทำ สิ่งนี้มีอยู่ใน java ด้วยหรือไม่? คุณสามารถใช้คำหลักเพื่อทำสิ่งนั้นได้หรือไม่ หรือทำอย่างไร?


ฉันอยากรู้เรื่องนี้เช่นกัน และไม่ใช่แค่ Eclipse เท่านั้นที่มีประโยชน์หากฉันลบการเรียกไปที่ super.onCreate () แอปจะแสดงข้อผิดพลาดรันไทม์โดยแจ้งว่า: "ไม่ได้เรียก super.onCreate ()" ใช่มันบังคับให้คุณเรียก super method จริงๆ แต่อย่างไร?
Rodrigo Castro

@RodrigoCastro คุณสามารถตรวจสอบ javadocs สำหรับแต่ละวิธีได้ ยกตัวอย่างเช่นonCreate ()

คำตอบ:


10

นี่คือที่มาของActivity#onCreate()- เป็นความคิดเห็นเกือบทั้งหมด ( ต้นฉบับ - ดูบรรทัด ~ 800 ):

/**
 * Called when the activity is starting.  This is where most initialization
 * should go: calling {@link #setContentView(int)} to inflate the
 * activity's UI, using {@link #findViewById} to programmatically interact
 * with widgets in the UI, calling
 * {@link #managedQuery(android.net.Uri , String[], String, String[], String)} to retrieve
 * cursors for data being displayed, etc.
 *
 * <p>You can call {@link #finish} from within this function, in
 * which case onDestroy() will be immediately called without any of the rest
 * of the activity lifecycle ({@link #onStart}, {@link #onResume},
 * {@link #onPause}, etc) executing.
 *
 * <p><em>Derived classes must call through to the super class's
 * implementation of this method.  If they do not, an exception will be
 * thrown.</em></p>
 *
 * @param savedInstanceState If the activity is being re-initialized after
 *     previously being shut down then this Bundle contains the data it most
 *     recently supplied in {@link #onSaveInstanceState}.  <b><i>Note: Otherwise it is null.</i></b>
 *
 * @see #onStart
 * @see #onSaveInstanceState
 * @see #onRestoreInstanceState
 * @see #onPostCreate
 */
protected void onCreate(Bundle savedInstanceState) {
    mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
            com.android.internal.R.styleable.Window_windowNoDisplay, false);
    mCalled = true;
}

ดังนั้นฉันเดาว่าปลั๊กอิน ADT Eclipse คือสิ่งที่เพิ่มอัตโนมัติที่เรียกร้องให้super.onCreate()คุณ เป็นการคาดเดาทั้งหมด


2
ฉันเดาว่าmCalled = trueยังใช้สำหรับข้อยกเว้นที่เป็นไปได้ อาจจะไม่ได้อยู่ในonCreate()ข้อยกเว้น แต่เมื่อเกิดข้อยกเว้นขึ้นจริงก็จะใช้รูปแบบง่ายๆ
Peterdk

194

สิ่งนี้ถูกเพิ่มในไลบรารีคำอธิบายประกอบการสนับสนุน:

dependencies {
    compile 'com.android.support:support-annotations:22.2.0'
}

http://tools.android.com/tech-docs/support-annotations

@CallSuper


เออคุณโดนตะปูที่หัวนี่ ขอบคุณ.
SMBiggs

ยังไม่ได้ลอง แต่อ่านเอกสาร มันจะยอดเยี่ยมมากฉันเดาว่า นี่ควรเป็นคำตอบที่ได้รับการยอมรับ
Rizwan Sohaib

1
คำตอบอื่น ๆ ทั้งหมดเป็นเรื่องไร้สาระยกเว้นสิ่งนี้ ควรได้รับการยอมรับ.
Le_Enot

3
@RizwanSohaib จะไม่บังคับให้คุณทำอะไร มันจะเน้นและแจ้งให้คุณทราบว่าคุณต้องเรียกมัน หากต้องการทำสิ่งที่ซับซ้อนมากขึ้นคุณจะต้องมีตัวประมวลผลคำอธิบายประกอบหรือใช้ตรรกะด้วยตัวเอง ขึ้นอยู่กับ IDE ควรป้องกันไม่ให้คุณสร้างเช่นกัน
หนาวจัด

1
คำตอบที่สมบูรณ์แบบ ขอบคุณมาก
Võ Quang Hòa

82

หากคุณต้องการบังคับให้คลาสย่อยเรียกใช้ตรรกะของคลาสแม่รูปแบบทั่วไปจะเป็นดังต่อไปนี้:

public abstract class SuperClass implements SomeInterface
{
    // This is the implementation of the interface method
    // Note it's final so it can't be overridden
    public final Object onCreate()
    {
        // Hence any logic right here always gets run
        // INSERT LOGIC

        return doOnCreate();

        // If you wanted you could instead create a reference to the
        // object returned from the subclass, and then do some
        // post-processing logic here
    }

    protected abstract Object doOnCreate();
}

public class Concrete extends SuperClass
{
    @Override
    protected Object doOnCreate()
    {
        // Here's where the concrete class gets to actually do
        // its onCreate() logic, but it can't stop the parent
        // class' bit from running first

        return "Hi";
    }
}

สิ่งนี้ไม่ได้ตอบคำถามของคุณอย่างแท้จริงเกี่ยวกับสิ่งที่แจ้งให้ Eclipse แทรกการเรียก superclass ลงในการนำไปใช้โดยอัตโนมัติ แต่ฉันก็ไม่คิดว่านั่นจะเป็นหนทางไปอยู่ดีเพราะมันสามารถลบได้เสมอ

คุณไม่สามารถบังคับได้จริง ๆ ว่าเมธอดต้องเรียกรุ่น superclass ด้วยคีย์เวิร์ด Java หรืออะไรทำนองนั้น ฉันสงสัยว่าข้อยกเว้นของคุณมาจากโค้ดบางอย่างในคลาสหลักที่ตรวจสอบค่าคงที่ที่คาดไว้หรือบางอย่างที่ไม่ถูกต้องโดยแนวทางของคุณ โปรดทราบว่าสิ่งนี้แตกต่างจากการโยนข้อยกเว้นเนื่องจากคุณโทรsuper.onCreate()ไม่สำเร็จ


8

หากคุณต้องการให้แน่ใจว่ามีการเรียกใช้ superclass-method ด้วยเช่นกันคุณต้องหลอกล่อเล็กน้อย: อย่าอนุญาตให้เขียนทับ superclass-method แต่ให้เรียกว่า overridable protected method

class Super
{
   public final void foo() {
      foo_stuff();
      impl_stuff();
   }

   protected void impl_stuff() {
      some_stuff_that_you_can_override();
   }
}

class Base extends Super
{
  protected void impl_stuff() { 
     my_own_idea_of_impl();
  }
}

ด้วยวิธีนี้ผู้ใช้จะต้องเรียก Super.foo () หรือ Base.foo () และจะเป็นเวอร์ชันพื้นฐานเสมอตามที่ประกาศไว้เป็นขั้นสุดท้าย สิ่งที่ใช้งานเฉพาะอยู่ใน im_stuff () ซึ่งสามารถลบล้างได้


8

เพื่อตอบคำถามที่แท้จริงของคุณการสร้างการโทรไปที่ super.onCreate () โดยอัตโนมัติเป็นคุณลักษณะของปลั๊กอิน ADT ใน java คุณไม่สามารถบังคับให้ subclass เรียกใช้ super ของ method ได้โดยตรง afaik (ดูรูปแบบที่อธิบายไว้ในคำตอบอื่น ๆ สำหรับการแก้ไขปัญหา) อย่างไรก็ตามโปรดทราบว่าใน Android คุณไม่ได้สร้างอินสแตนซ์อ็อบเจ็กต์กิจกรรม (หรือเซอร์วิสอ็อบเจ็กต์) โดยตรง - คุณส่ง Intent ไปยังระบบและระบบจะสร้างอินสแตนซ์อ็อบเจ็กต์และเรียกใช้ onCreate () ตามนั้น (พร้อมกับวิธีการใช้งานอื่น ๆ ) ดังนั้นระบบจึงมีการอ้างอิงอ็อบเจ็กต์โดยตรงไปยังอินสแตนซ์กิจกรรมและสามารถตรวจสอบ (น่าจะเป็น) บูลีนบางตัวที่ตั้งค่าเป็น true ในการใช้งาน superclass ของ onCreate () แม้ว่าฉันจะไม่รู้ว่ามันถูกนำไปใช้อย่างไร แต่ก็อาจมีลักษณะดังนี้:

class Activity
{
  onCreate()
  {
    superCalled = true;
    ...
  }
  ...
}

และในคลาสระดับ "ระบบ" ที่รับ Intent และอินสแตนซ์อ็อบเจ็กต์ Activity จากมัน:

...
SomeActivitySubclass someActivitySubclassObject = new SomeActivitySubclass();
someActivitySubclassObject.onCreate();
if (!someActivityObject.isSuperCalled())
{
  Exception e = new Exception(...) //create an exception with appropriate details
  throw e;
}

ฉันเดาว่ามันอาจจะซับซ้อนกว่านั้นเล็กน้อย แต่คุณเข้าใจแล้ว Eclipse จะสร้างการโทรโดยอัตโนมัติเนื่องจากปลั๊กอิน ADT บอกให้เพื่อความสะดวก ขอให้สนุกกับการเขียนโค้ด!


4

ไม่มีอะไรใน Java ที่บังคับให้เรียก super และมีตัวอย่างมากมายที่คุณไม่ต้องการ สถานที่เดียวที่คุณสามารถบังคับให้เรียกซุปเปอร์อยู่ในตัวสร้าง ผู้สร้างทั้งหมดต้องเรียกตัวสร้างชั้นยอด หนึ่ง (ตัวสร้างไม่มีอาร์กิวเมนต์) จะถูกแทรกหากคุณไม่ได้เขียนอย่างชัดเจนและหากไม่มีตัวสร้างที่ไม่มีอาร์กิวเมนต์คุณต้องเรียกมันอย่างชัดเจน


3

Eclipse มีประโยชน์เพียงเตือนคุณว่าคุณสามารถเรียกใช้ superclass ได้หากต้องการ

คุณอาจได้รับข้อผิดพลาดเนื่องจากคุณไม่ได้ทำสิ่งที่จำเป็นที่ซูเปอร์คลาสทำเนื่องจากคุณไม่ได้เรียกใช้งาน


1

Eclipse ช่วยให้คุณทำสิ่งต่างๆได้อย่างถูกต้องและหลีกเลี่ยงข้อยกเว้น

จากhttp://developer.android.com/reference/android/app/Activity.html#onCreate(android.os.Bundle )

คลาสที่ได้รับจะต้องเรียกผ่านเพื่อใช้วิธีนี้ของซูเปอร์คลาส หากไม่ทำเช่นนั้นข้อยกเว้นจะถูกโยนทิ้ง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.