Làm thế nào để buộc lớp dẫn xuất gọi phương thức siêu? (Giống như Android)


85

Tôi đã tự hỏi, khi tạo mới Activitycác lớp học và sau đó trọng các onCreate()phương pháp, trong eclipse tôi luôn luôn được tự động thêm vào: super.onCreate(). Làm thế nào điều này xảy ra? Có từ khóa java trong lớp trừu tượng hoặc lớp cha buộc điều này không?

Tôi không biết việc không gọi super class là bất hợp pháp hay không, nhưng tôi nhớ trong một số phương thức, tôi đã nhận được một ngoại lệ do không thực hiện điều này. Điều này cũng được tích hợp sẵn trong java? Bạn có thể sử dụng một số từ khóa để làm điều đó? Hay nó được thực hiện như thế nào?


Tôi cũng muốn biết điều này. Và không chỉ Eclipse hữu ích, nếu tôi xóa lệnh gọi tới super.onCreate (), ứng dụng sẽ báo lỗi thời gian chạy: "không gọi super.onCreate ()". Vì vậy, có, nó thực sự buộc bạn phải gọi phương pháp siêu. Nhưng bằng cách nào?
Rodrigo Castro

@RodrigoCastro Bạn có thể xem lại javadocs cho từng phương pháp. Ví dụ onCreate () .

Câu trả lời:


10

Đây là nguồn Activity#onCreate()- hầu như là tất cả các bình luận ( bản gốc - xem dòng ~ 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;
}

vì vậy, tôi đoán rằng plugin ADT Eclipse là thứ tự động thêm lệnh gọi đó super.onCreate()cho bạn. Đó là một phỏng đoán hoàn toàn, mặc dù.


2
Tôi đoán mCalled = truecũng được sử dụng cho một ngoại lệ có thể xảy ra. Có thể không có trong onCreate()nhưng khi thực sự có một ngoại lệ như vậy, nó sẽ sử dụng mẫu đơn giản đó.
Peterdk

192

Điều này được thêm vào thư viện chú thích hỗ trợ:

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

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

@CallSuper


Đúng, bạn đã đánh đinh vào đầu ở đây. Cảm ơn.
SMBiggs

Chưa thử nhưng hãy đọc tài liệu. Tôi đoán điều này sẽ rất tuyệt. Đây phải là câu trả lời được chấp nhận.
Rizwan Sohaib

1
Tất cả các câu trả lời khác đều hoàn toàn tào lao, ngoại trừ điều này. Nên được chấp nhận.
Le_Enot 20/02/16

3
@RizwanSohaib nó sẽ không bắt bạn phải làm gì cả. Nó sẽ làm nổi bật và cho bạn biết bạn cần gọi nó. Để làm bất cứ điều gì phức tạp hơn, bạn sẽ cần một bộ xử lý chú thích hoặc tự thực hiện logic. tùy thuộc vào IDE, nó cũng sẽ ngăn bạn xây dựng.
frostymarvelous

1
Câu trả lời hoàn hảo. Cảm ơn nhiều
Võ Quang Hòa

82

Nếu bạn muốn buộc các lớp con thực hiện logic của lớp cha, một mẫu phổ biến là như sau:

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";
    }
}

Điều này không thực sự trả lời câu hỏi của bạn về điều gì sẽ nhắc Eclipse tự động chèn một lệnh gọi siêu lớp vào việc triển khai; nhưng sau đó tôi không nghĩ đó là cách để đi vì điều này luôn có thể bị xóa.

Bạn thực sự không thể thực thi rằng một phương thức phải gọi phiên bản siêu lớp với từ khóa Java hoặc bất cứ thứ gì tương tự. Tôi nghi ngờ rằng các ngoại lệ của bạn chỉ đơn giản đến từ một số mã trong lớp cha kiểm tra các bất biến dự kiến ​​hoặc một cái gì đó, đã bị vô hiệu bởi cách tiếp cận của bạn. Lưu ý rằng điều này hoàn toàn khác với việc ném một ngoại lệ bạn không gọi được super.onCreate().


8

Nếu bạn muốn chắc chắn rằng phương thức siêu lớp cũng được gọi, bạn phải lừa một chút: Không cho phép phương thức siêu lớp bị ghi đè, nhưng hãy gọi phương thức được bảo vệ có thể ghi đè.

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();
  }
}

Theo cách đó, người dùng phải gọi Super.foo () hoặc Base.foo () và nó sẽ luôn là phiên bản lớp cơ sở vì nó được khai báo là cuối cùng. Nội dung cụ thể về triển khai nằm trong impl_stuff (), có thể được ghi đè.


8

Để trả lời câu hỏi thực tế của bạn, tự động tạo lệnh gọi tới super.onCreate () là một tính năng của plugin ADT. Trong java, bạn không thể trực tiếp buộc một lớp con gọi việc thực thi siêu phương thức, afaik (xem mẫu được mô tả trong các câu trả lời khác để giải quyết vấn đề). Tuy nhiên, hãy nhớ rằng trong Android, bạn không khởi tạo trực tiếp các đối tượng Hoạt động (hoặc đối tượng Dịch vụ) - bạn chuyển một Intent cho hệ thống và hệ thống khởi tạo đối tượng và gọi onCreate () dựa trên nó (cùng với các phương thức vòng đời khác). Vì vậy, hệ thống có một tham chiếu đối tượng trực tiếp đến cá thể Activity và có thể kiểm tra (có lẽ) một số Boolean được đặt thành true trong quá trình triển khai lớp cha của onCreate (). Mặc dù tôi không biết chính xác nó được triển khai như thế nào, nhưng nó có thể trông giống như sau:

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

Và trong lớp cấp độ "hệ thống" nhận Intent và khởi tạo đối tượng Activity từ nó:

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

Tôi đoán là nó có thể phức tạp hơn thế một chút, nhưng bạn hiểu đấy. Eclipse tự động tạo cuộc gọi vì plugin ADT yêu cầu nó, như một sự tiện lợi. Chúc bạn viết mã vui vẻ!


4

Không có gì trong Java buộc phải gọi super, và có rất nhiều ví dụ khi bạn không muốn. Nơi duy nhất mà bạn có thể buộc gọi super là trong các hàm tạo. Tất cả các hàm tạo phải gọi một hàm tạo siêu lớp. Một (phương thức khởi tạo không có đối số) sẽ được chèn nếu bạn không viết một cách rõ ràng và nếu không có hàm tạo không đối số thì bạn phải gọi nó một cách rõ ràng.


3

Eclipse thực sự hữu ích, nhắc nhở bạn rằng bạn có thể gọi việc triển khai lớp cha nếu muốn.

bạn có thể gặp lỗi vì bạn không làm điều gì đó cần thiết mà lớp cha làm, vì bạn không gọi việc thực thi nó.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.