Mengapa metode statis tidak bisa abstrak di Jawa?


593

Pertanyaannya adalah di Jawa mengapa saya tidak bisa mendefinisikan metode statis abstrak? sebagai contoh

abstract class foo {
    abstract void bar( ); // <-- this is ok
    abstract static void bar2(); //<-- this isn't why?
}

9
Beberapa alasan: metode statis harus memiliki tubuh bahkan jika mereka adalah bagian dari kelas abstrak karena orang tidak perlu membuat instance dari kelas untuk mengakses metode statisnya. Cara lain untuk memikirkannya adalah jika sesaat kami menganggap itu diizinkan maka masalahnya adalah bahwa panggilan metode statis tidak memberikan Informasi Tipe Waktu Berjalan (RTTI), ingat tidak ada pembuatan instance yang diperlukan, sehingga mereka tidak dapat diarahkan ulang untuk implementasi override spesifik mereka dan dengan demikian memungkinkan abstarct statis tidak masuk akal sama sekali. Dengan kata lain, itu tidak dapat memberikan manfaat polimorfisme sehingga tidak diizinkan.
sactiw

6
Jika Anda memiliki sesuatu untuk menjawab pertanyaan, kirimkan sebagai jawaban , bukan komentar
Solomon Ucko

Jawaban:


568

Karena "abstrak" berarti: "Menerapkan fungsi tidak", dan "statis" berarti: "Ada fungsi bahkan jika Anda tidak memiliki turunan objek". Dan itu adalah kontradiksi yang logis.


353
Jawaban yang lebih ringkas adalah 'desain bahasa yang buruk.' Statis harus berarti 'milik kelas' karena itulah bagaimana itu digunakan secara intuitif seperti yang ditunjukkan oleh pertanyaan ini. Lihat "metode kelas" dengan Python.
Alexander Ljungberg

12
@ Tomalak saya minta maaf, saya tidak jelas. Tentu saja metode statis 'milik kelas'. Namun, hanya dalam arti bahwa ia hidup di namespace yang sama. Metode statis bukanlah metode objek kelas itu sendiri: ia tidak beroperasi dengan 'ini' sebagai objek kelas, dan tidak berpartisipasi dengan benar dalam rantai pewarisan. Jika itu benar-benar metode kelas abstract staticakan masuk akal. Ini akan menjadi metode objek kelas itu sendiri yang harus diimplementasikan objek subclass. Tentu saja, cara jawaban Anda benar, terlepas dari kekeliruan saya tentang bahasa.
Alexander Ljungberg

695
Ini bukan kontradiksi logis, ini adalah kekurangan bahasa, banyak bahasa lain mendukung gagasan ini. "abstrak" berarti "diimplementasikan dalam subkelas", "statis" berarti "dieksekusi pada kelas daripada instance kelas" Tidak ada kontradiksi logis.
Eric Grange

10
@ Eric: Dan masih , apa yang Anda katakan tidak berlaku untuk abstract static: Fungsi X yang "diimplementasikan dalam subclass" bisa tidak pada saat yang sama akan "dieksekusi pada kelas" - hanya pada subclass . Dimana itu tidak abstrak lagi.
Tomalak

72
@ Tomakak: Logikanya melingkar. statictidak berarti "tidak kosong" - itu hanya konsekuensi dari Java yang tidak mengizinkan metode statis menjadi abstrak. Itu berarti "callable on the class." (Seharusnya berarti " hanya dapat dipanggil di kelas" tapi itu masalah lain.) Jika Java mendukung abstract staticmetode saya berharap itu berarti bahwa metode 1) harus diimplementasikan oleh subclass, dan 2) adalah metode kelas dari subclass. Beberapa metode tidak masuk akal sebagai metode instan. Sayangnya Java tidak membiarkan Anda menentukan hal itu saat membuat kelas dasar abstrak (atau antarmuka).
Michael Carman

326

Desain bahasa yang buruk. Akan jauh lebih efektif untuk memanggil langsung metode abstrak statis daripada membuat contoh hanya untuk menggunakan metode abstrak itu. Terutama benar ketika menggunakan kelas abstrak sebagai solusi untuk enum ketidakmampuan untuk memperluas, yang merupakan contoh desain yang buruk. Semoga mereka bisa mengatasi keterbatasan itu dalam rilis berikutnya.


25
Java penuh dengan batasan aneh. Penutupan hanya mengakses variabel akhir adalah yang lain. Dan daftar yang tersisa hampir tak ada habisnya. Ini adalah tugas seorang programmer Java untuk mengenal mereka dan solusi mereka. Untuk bersenang-senang, kita harus menggunakan sesuatu yang lebih baik daripada Jawa di waktu luang kita. Tapi saya tidak akan peduli. Itulah benih untuk mencapai kemajuan.
ceving

22
Saya percaya bahwa apa yang Anda sebut sebagai "desain bahasa yang buruk" sebenarnya lebih dari "desain bahasa pelindung", yang tujuannya adalah untuk membatasi pelanggaran prinsip OO yang dilakukan programmer karena fitur bahasa yang tidak perlu.
ethanfar

22
Apakah konsep "abstrak statis" merupakan pelanggaran prinsip OO?
Trevor

7
@threed, Tidak sama sekali, tapi tentu saja ada orang yang mengatakan bahwa konsep staticitu sendiri sudah merupakan pelanggaran ....
Pacerier

4
Kebutuhan statis adalah demonstrasi yang jelas bahwa "prinsip-prinsip OO" tidak mencakup semua seperti yang biasanya diklaim.
Ben

147

Anda tidak dapat mengganti metode statis, jadi membuatnya abstrak akan menjadi tidak berarti. Selain itu, metode statis dalam kelas abstrak akan menjadi milik kelas itu, dan bukan kelas utama, jadi tidak bisa digunakan.


18
Ya itu benar-benar memalukan dengan cara metode statis tidak dapat diganti di Jawa.
Michel

12
@Michel: apa gunanya? Jika Anda ingin perilaku berbasis instance, gunakan metode instance.
Ran Biron

8
Jawaban ini salah. Metode statis di kelas abstrak berfungsi dengan baik dan umumnya digunakan. Hanya saja metode statis dari kelas itu sendiri mungkin tidak abstrak. @Michel tidak masuk akal untuk mengganti metode statis. Tanpa sebuah instance, bagaimana runtime tahu metode mana yang harus dipanggil?
erickson

63
@erickson - Bahkan tanpa instance, hirarki kelas masih utuh - pewarisan pada metode statis dapat bekerja sama seperti pewarisan metode instance. Smalltalk melakukannya, dan itu sangat berguna.
Jared

8
@matiasg itu bukan hal baru sama sekali. Kelas abstrak selalu diizinkan untuk memiliki metode statis, non-abstrak .
Matt Ball

70

The abstractpenjelasan untuk metode menunjukkan bahwa metode HARUS override dalam subclass.

Di Jawa, staticanggota (metode atau bidang) tidak dapat ditimpa oleh subclass (ini tidak selalu benar dalam bahasa berorientasi objek lainnya, lihat SmallTalk.) staticAnggota mungkin disembunyikan , tetapi secara fundamental berbeda dari yang ditimpa .

Karena anggota statis tidak dapat diganti dalam subkelas, abstractanotasi tidak dapat diterapkan pada mereka.

Selain itu - bahasa lain mendukung pewarisan statis, seperti halnya pewarisan contoh. Dari perspektif sintaksis, bahasa-bahasa tersebut biasanya membutuhkan nama kelas untuk dimasukkan dalam pernyataan. Sebagai contoh, di Jawa, dengan asumsi Anda menulis kode di ClassA, ini adalah pernyataan yang setara (jika methodA () adalah metode statis, dan tidak ada metode contoh dengan tanda tangan yang sama):

ClassA.methodA();

dan

methodA();

Dalam SmallTalk, nama kelas bukan opsional, jadi sintaksnya adalah (perhatikan bahwa SmallTalk tidak menggunakan. Untuk memisahkan "subjek" dan "kata kerja", melainkan menggunakannya sebagai terminator statemend):

ClassA methodA.

Karena nama kelas selalu diperlukan, "versi" yang benar dari metode selalu dapat ditentukan dengan melintasi hierarki kelas. Untuk apa nilainya, saya kadang-kadang kehilangan staticwarisan, dan digigit oleh kurangnya warisan statis di Jawa ketika saya mulai dengan itu. Selain itu, SmallTalk diketik bebek (dan karenanya tidak mendukung program-kontrak). Dengan demikian, SmallTalk tidak memiliki abstractpengubah untuk anggota kelas.


1
"Anggota statis tidak dapat ditimpa oleh subclass" salah. Mungkin saja, setidaknya di Java6. Tidak yakin sejak kapan.
Steven De Groote

15
@Steven De Groote Anggota statis memang tidak dapat ditimpa oleh subclass. Jika sebuah subclass memiliki metode statis dengan tanda tangan yang sama dengan metode statis di superclass, itu tidak menimpanya, ia menyembunyikannya. http://docs.oracle.com/javase/tutorial/java/IandI/override.html Perbedaannya adalah bahwa polimorfisme hanya berfungsi untuk penggantian, tetapi tidak untuk metode tersembunyi.
John29

2
@ John29 Terima kasih atas klarifikasi, tetapi selain dari perbedaan penamaan sepertinya penggunaannya serupa.
Steven De Groote

2
@ Sebelas De Groote Ya, ini mirip dalam penggunaan, tetapi perilakunya berbeda. Itulah alasan mengapa tidak ada metode abstrak statis - apa gunanya metode abstrak statis jika mereka tidak mendukung polimorfisme?
John29

3
@Steven De Groote: Perbedaannya menjadi jelas ketika Anda memiliki panggilan ke metode itu di superclass itu sendiri. Misalkan Super.foo memanggil Super.bar. Jika subclass mengimplementasikan Subclass.bar, dan kemudian memanggil foo, maka foo masih akan memanggil Super.bar, bukan Subclass.bar. Oleh karena itu, apa yang sebenarnya Anda miliki adalah dua metode yang sama sekali berbeda dan tidak terkait yang keduanya disebut "bar". Ini tidak mengesampingkan dalam arti yang bermanfaat.
Doradus

14

Saya juga mengajukan pertanyaan yang sama, ini sebabnya

Karena kelas Abstrak mengatakan, itu tidak akan memberikan implementasi dan mengizinkan subclass untuk memberikannya

jadi Subclass harus menimpa metode Superclass,

ATURAN NO 1 - Metode statis tidak dapat diganti

Karena anggota dan metode statis mengkompilasi elemen waktu, itu sebabnya Overloading (waktu kompilasi Polimorfisme) metode statis diperbolehkan daripada Overriding (Polimorfisme Runtime)

Jadi, mereka tidak bisa abstrak.

Tidak ada hal seperti abstrak statis <--- Tidak diizinkan di Java Universe


5
-1, Tidak benar bahwa "Java tidak mengizinkan metode statis untuk ditimpa karena anggota statis dan metode mengkompilasi elemen waktu". Pengecekan tipe statis pasti dimungkinkan dengan abstract staticmelihat stackoverflow.com/questions/370962/… . The alasan sebenarnya mengapa Java tidak memungkinkan metode statis menjadi ditimpa karena Java tidak memungkinkan metode statis untuk menjadi ditimpa.
Pacerier

Overloading tidak ada hubungannya dengan polimorfisme. Overloading dan overriding tidak memiliki kesamaan kecuali awalan "over" dalam banyak cara yang sama seperti Java dan JavaScript untuk keduanya memiliki "Java" di dalamnya. Nama metode bukanlah identitasnya, melainkan tanda tangannya yang menentukan. jadi foo(String)tidak sama dengan foo(Integer)- itu saja.
Kapten Man

@CaptainMan Overloading secara harfiah disebut "parametrik polimorfisme" karena, tergantung pada jenis parameter, metode lain dipanggil yang polimorfisme.
Davor

12

Ini adalah desain bahasa yang buruk dan benar-benar tidak ada alasan mengapa itu tidak mungkin.

Sebenarnya, ini adalah implementasi bagaimana hal itu BISA dilakukan di JAWA :

public class Main {

        public static void main(String[] args) {
                // This is done once in your application, usually at startup
                Request.setRequest(new RequestImplementationOther());

                Request.doSomething();
        }

        public static final class RequestImplementationDefault extends Request {
                @Override
                void doSomethingImpl() {
                        System.out.println("I am doing something AAAAAA");
                }
        }

        public static final class RequestImplementaionOther extends Request {
                @Override
                void doSomethingImpl() {
                        System.out.println("I am doing something BBBBBB");
                }
        }

        // Static methods in here can be overriden
        public static abstract class Request {

                abstract void doSomethingImpl();

                // Static method
                public static void doSomething() {
                        getRequest().doSomethingImpl();
                }

                private static Request request;
                private static Request getRequest() {
                        // If setRequest is never called prior, it will default to a default implementation. Of course you could ignore that too. 
                        if ( request == null ) {
                                return request = new RequestImplementationDefault();
                        }
                        return request;
                }
                public static Request setRequest(Request r){
                        return request = r;
                }

        }
}

================= Contoh lama di bawah ini =================

Cari getRequest, dan getRequestImpl ... setInstance dapat dipanggil untuk mengubah implementasi sebelum panggilan dibuat.

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @author Mo. Joseph
 * @date 16 mar 2012
 **/

public abstract class Core {


    // ---------------------------------------------------------------        
    private static Core singleton; 
    private static Core getInstance() {
        if ( singleton == null )
            setInstance( new Core.CoreDefaultImpl() );  // See bottom for CoreDefaultImpl

        return singleton;
    }    

    public static void setInstance(Core core) {
        Core.singleton = core;
    }
    // ---------------------------------------------------------------        



    // Static public method
    public static HttpServletRequest getRequest() {      
        return getInstance().getRequestImpl();
    }


    // A new implementation would override this one and call setInstance above with that implementation instance
    protected abstract HttpServletRequest getRequestImpl();




    // ============================ CLASSES =================================

    // ======================================================================
    // == Two example implementations, to alter getRequest() call behaviour 
    // == getInstance() have to be called in all static methods for this to work
    // == static method getRequest is altered through implementation of getRequestImpl
    // ======================================================================

    /** Static inner class CoreDefaultImpl */
    public static class CoreDefaultImpl extends Core { 
        protected HttpServletRequest getRequestImpl() {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        }
    }

     /** Static inner class CoreTestImpl : Alternative implementation */
    public static class CoreTestImpl extends Core { 
        protected HttpServletRequest getRequestImpl() {
            return new MockedRequest();
        }
    }       

}

Digunakan sebagai berikut:

static {
     Core.setSingleton(new Core.CoreDefaultImpl());

     // Or

     Core.setSingleton(new Core.CoreTestImpl());

     // Later in the application you might use

     Core.getRequest(); 

}

6
Saya tidak mengerti di mana Anda telah memberikan contoh abstract staticmetode seperti yang ditanyakan dalam pertanyaan dan Anda telah menulis dengan huruf tebal DAPAT DILAKUKAN DI JAWA . Ini benar-benar salah arah.
Blip

1
Itu tidak sendiri memungkinkan Anda untuk mendefinisikannya sebagai abstrak statis, tetapi Anda dapat mencapai hasil yang serupa di mana Anda dapat mengubah implementasi metode statis menggunakan pola / hack ini. Ini hampir tidak tersesat. Itu bisa dilakukan, tetapi menggunakan semantik yang berbeda.
mmm

Ini adalah contoh memperluas kelas abstrak, kemudian meletakkan metode statis pada anak. Ini bukan contoh DAPAT DILAKUKAN DI JAWA, dengan cara apa pun.
Scuba Steve

2
@ ScubaSteve Pertama, Anda salah pada kesimpulan Anda. Kedua, mencapai hasil yang sama. Berarti akses statis ke kelas dapat diubah oleh implementasi lain. Ini bukan jawaban untuk mengatakan saya membuat kata kunci statis abstrak, tetapi menggunakan pola ini Anda bisa menggunakan metode statis dan masih mengubah implementasinya. Itu memang memiliki dampak negatif menjadi global saja, tetapi untuk lingkungan uji coba / prod / dev itu melakukan trik untuk kita.
mmm

5
  • Metode abstrak didefinisikan hanya sehingga dapat ditimpa dalam subkelas. Namun, metode statis tidak dapat diganti. Oleh karena itu, ini adalah kesalahan waktu kompilasi untuk memiliki metode abstrak dan statis.

    Sekarang pertanyaan selanjutnya adalah mengapa metode statis tidak dapat ditimpa ??

  • Itu karena metode statis milik kelas tertentu dan bukan ke instansinya. Jika Anda mencoba menimpa metode statis Anda tidak akan mendapatkan kesalahan kompilasi atau runtime tetapi kompiler hanya akan menyembunyikan metode statis superclass.


4

Metode statis, menurut definisi, tidak perlu tahu this. Dengan demikian, itu tidak bisa menjadi metode virtual (yang kelebihan beban menurut informasi subclass dinamis tersedia melalui this); sebaliknya, kelebihan metode statis semata-mata didasarkan pada info yang tersedia pada waktu kompilasi (ini berarti: setelah Anda merujuk metode statis superclass, Anda memanggil metode superclass, tetapi tidak pernah metode subclass).

Menurut ini, metode statis abstrak akan sangat berguna karena Anda tidak akan pernah memiliki referensi diganti oleh beberapa badan tertentu.


4

Saya melihat bahwa sudah ada miliaran jawaban Tuhan tetapi saya tidak melihat solusi praktis. Tentu saja ini adalah masalah nyata dan tidak ada alasan yang baik untuk mengecualikan sintaks ini di Jawa. Karena pertanyaan awal tidak memiliki konteks di mana ini mungkin diperlukan, saya memberikan konteks dan solusi:

Misalkan Anda memiliki metode statis di banyak kelas yang identik. Metode-metode ini memanggil metode statis yang spesifik kelas:

class C1 {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    private static void doMoreWork(int k) {
        // code specific to class C1
    }
}
class C2 {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    private static void doMoreWork(int k) {
        // code specific to class C2
    }
}

doWork()metode C1dan C2identik. Mungkin ada banyak calsses ini: C3 C4dll. Jika static abstractdiizinkan, Anda akan menghilangkan kode duplikat dengan melakukan sesuatu seperti:

abstract class C {
    static void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }

    static abstract void doMoreWork(int k);
}

class C1 extends C {
    private static void doMoreWork(int k) {
        // code for class C1
    }
}

class C2 extends C {
    private static void doMoreWork(int k) {
        // code for class C2
    }
}

tetapi ini tidak akan dikompilasi karena static abstractkombinasi tidak diperbolehkan. Namun, ini dapat dielakkan dengan static classkonstruk, yang diizinkan:

abstract class C {
    void doWork() {
        ...
        for (int k: list)
            doMoreWork(k);
        ...
    }
    abstract void doMoreWork(int k);
}
class C1 {
    private static final C c = new  C(){  
        @Override void doMoreWork(int k) {
            System.out.println("code for C1");
        }
    };
    public static void doWork() {
        c.doWork();
    }
}
class C2 {
    private static final C c = new C() {
        @Override void doMoreWork(int k) {
            System.out.println("code for C2");
        }
    };
    public static void doWork() {
        c.doWork();
    }
}

Dengan solusi ini, satu-satunya kode yang diduplikasi adalah

    public static void doWork() {
        c.doWork();
    }

1
Karena dalam solusi akhir Anda, kelas abstrak C tidak memiliki metode statis lalu mengapa tidak membiarkan C1 dan C2 memperluasnya dan menimpa metode doMoreWork () dan membiarkan kelas lain membuat turunannya dan memanggil metode yang diperlukan. Pada dasarnya Anda melakukan hal yang sama yaitu memperluas kelas C menggunakan kelas anonim dan kemudian di C1 dan C2 menggunakan contoh statisnya untuk memungkinkan akses dari dalam metode statis tetapi ini tidak diperlukan sama sekali.
sactiw

Saya tidak mengerti konteks yang Anda berikan di sini. Dalam solusi terakhir Anda, apa yang dapat Anda lakukan adalah menelepon C1.doWork()atau C2.doWork()Tapi Anda tidak bisa menelepon C.doWork(). Juga dalam contoh yang Anda berikan, yang tidak akan berfungsi, anggaplah jika diizinkan, lalu bagaimana kelas Cmenemukan implementasi doMoreWork()? Akhirnya saya akan menyebut kode konteks Anda desain yang buruk. Mengapa? hanya karena Anda telah membuat fungsi terpisah untuk kode yang unik alih-alih membuat fungsi untuk kode yang umum dan kemudian menerapkan fungsi statis di kelas C. Ini lebih mudah !!!
Blip

2

Asumsikan ada dua kelas, Parentdan Child. Parentadalah abstract. Deklarasi tersebut adalah sebagai berikut:

abstract class Parent {
    abstract void run();
}

class Child extends Parent {
    void run() {}
}

Ini berarti bahwa setiap instance Parentharus menentukan bagaimana run()dijalankan.

Namun, anggaplah sekarang itu Parenttidak benar abstract.

class Parent {
    static void run() {}
}

Ini berarti Parent.run()akan menjalankan metode statis.

Definisi abstractmetode adalah "Metode yang dideklarasikan tetapi tidak diimplementasikan", yang berarti tidak mengembalikan apa pun itu sendiri.

Definisi staticmetode adalah "Metode yang mengembalikan nilai yang sama untuk parameter yang sama terlepas dari instance yang dipanggil".

Sebuah abstractnilai kembali metode ini akan berubah karena perubahan misalnya. Sebuah staticmetode tidak akan. Sebuah static abstractmetode adalah cukup banyak metode di mana nilai kembali adalah konstan, tetapi tidak kembali apa-apa. Ini adalah kontradiksi yang logis.

Juga, sebenarnya tidak ada banyak alasan untuk suatu static abstractmetode.


2

Kelas abstrak tidak dapat memiliki metode statis karena abstraksi dilakukan untuk mencapai BINDING DINAMIS sementara metode statis terikat secara fungsional dengan fungsinya. Metode statis berarti perilaku yang tidak bergantung pada variabel instan, jadi tidak ada instance / objek yang diperlukan. Hanya kelas. Metode statis milik kelas dan bukan objek. Mereka disimpan di area memori yang dikenal sebagai PERMGEN dari mana itu dibagi dengan setiap objek. Metode dalam kelas abstrak secara dinamis terikat dengan fungsinya.


1
Kelas abstrak pasti dapat memiliki metode statis. Tetapi metode abstrak tidak statis.
JacksOnF1re

2

Mendeklarasikan metode sebagai staticcara kita dapat memanggil metode itu dengan nama kelasnya dan jika kelas itu abstractjuga, tidak masuk akal untuk memanggilnya karena tidak mengandung benda apa pun, dan karenanya kita tidak dapat mendeklarasikan metode sebagai staticdan abstract.


2

Karena metode abstrak adalah milik kelas dan tidak dapat ditimpa oleh kelas pelaksana. Bahkan jika ada metode statis dengan tanda tangan yang sama, ia menyembunyikan metode tersebut, tidak menimpanya. Jadi tidak penting untuk menyatakan metode abstrak sebagai statis karena tidak akan pernah mendapatkan tubuh. Jadi, kompilasi kesalahan waktu.


1

Metode statis dapat dipanggil tanpa turunan dari kelas. Dalam contoh Anda, Anda dapat memanggil foo.bar2 (), tetapi tidak foo.bar (), karena untuk bilah Anda memerlukan sebuah instance. Kode berikut bisa digunakan:

foo var = new ImplementsFoo();
var.bar();

Jika Anda memanggil metode statis, itu akan selalu dieksekusi kode yang sama. Dalam contoh di atas, bahkan jika Anda mendefinisikan ulang bar2 di ImplementsFoo, panggilan ke var.bar2 () akan menjalankan foo.bar2 ().

Jika bar2 sekarang tidak memiliki implementasi (itu artinya abstrak), Anda dapat memanggil metode tanpa implementasi. Itu sangat berbahaya.


1
Dan metode statis abstrak dapat dipanggil tanpa instance, tetapi akan membutuhkan implementasi yang akan dibuat di kelas anak. Ini bukan polimorfisme, tetapi satu-satunya cara untuk mengatasinya adalah dengan membuat anak konkret mengimplementasikan antarmuka yang "memerlukan" metode "abstrak statis". Berantakan, tapi bisa diterapkan.
fijiaaron

3
sebenarnya saya salah. Anda tidak dapat memiliki metode statis di antarmuka. Kelemahan bahasa.
fijiaaron

1

Saya percaya saya telah menemukan jawaban untuk pertanyaan ini, dalam bentuk mengapa metode antarmuka (yang bekerja seperti metode abstrak di kelas induk) tidak bisa statis. Ini jawaban lengkapnya (bukan punyaku)

Pada dasarnya metode statis dapat diikat pada waktu kompilasi, karena untuk memanggilnya Anda perlu menentukan kelas. Ini berbeda dari metode instance, di mana kelas referensi dari mana Anda memanggil metode mungkin tidak diketahui pada waktu kompilasi (dengan demikian blok kode mana yang dipanggil hanya dapat ditentukan saat runtime).

Jika Anda memanggil metode statis, Anda sudah tahu kelas di mana itu diterapkan, atau setiap subclass langsung dari itu. Jika Anda mendefinisikan

abstract class Foo {
    abstract static void bar();
}

class Foo2 {
    @Override
    static void bar() {}
}

Maka Foo.bar();panggilan apa pun jelas ilegal, dan Anda akan selalu menggunakannya Foo2.bar();.

Dengan pemikiran ini, satu-satunya tujuan dari metode abstrak statis adalah untuk menegakkan subclass untuk menerapkan metode seperti itu. Anda mungkin awalnya berpikir ini SANGAT salah, tetapi jika Anda memiliki parameter tipe generik <E extends MySuperClass>akan lebih baik untuk menjamin melalui antarmuka yang Ebisa .doSomething(). Perlu diingat bahwa karena tipe generik penghapusan hanya ada pada waktu kompilasi.

Jadi, apakah akan bermanfaat? Ya, dan mungkin itu sebabnya Java 8 memungkinkan metode statis di antarmuka (meskipun hanya dengan implementasi standar). Mengapa tidak metode statis abstrak dengan implementasi default di kelas? Sederhananya karena metode abstrak dengan implementasi default sebenarnya adalah metode konkret.

Mengapa tidak metode abstrak / antarmuka statis tanpa implementasi standar? Rupanya, hanya karena cara Java mengidentifikasi blok kode mana yang harus dijalankan (bagian pertama dari jawaban saya).


1

Karena kelas abstrak adalah konsep OOPS dan anggota statis bukan bagian dari OOPS ....
Sekarang masalahnya kita dapat mendeklarasikan metode statis lengkap dalam antarmuka dan kita dapat menjalankan antarmuka dengan mendeklarasikan metode utama di dalam antarmuka

interface Demo 
{
  public static void main(String [] args) {
     System.out.println("I am from interface");
  }
}

0

Gagasan memiliki metode statis abstrak adalah bahwa Anda tidak dapat menggunakan kelas abstrak tertentu secara langsung untuk metode itu, tetapi hanya turunan pertama yang akan diizinkan untuk menerapkan metode statis itu (atau untuk obat generik: kelas sebenarnya dari obat generik yang Anda gunakan). menggunakan).

Dengan begitu, Anda bisa membuat misalnya kelas abstrak sortableObject atau bahkan antarmuka dengan metode statis abstrak (otomatis), yang menentukan parameter opsi sortir:

public interface SortableObject {
    public [abstract] static String [] getSortableTypes();
    public String getSortableValueByType(String type);
}

Sekarang Anda dapat mendefinisikan objek yang dapat diurutkan yang dapat diurutkan berdasarkan jenis utama yang sama untuk semua objek ini:

public class MyDataObject implements SortableObject {
    final static String [] SORT_TYPES = {
        "Name","Date of Birth"
    }
    static long newDataIndex = 0L ;

    String fullName ;
    String sortableDate ;
    long dataIndex = -1L ;
    public MyDataObject(String name, int year, int month, int day) {
        if(name == null || name.length() == 0) throw new IllegalArgumentException("Null/empty name not allowed.");
        if(!validateDate(year,month,day)) throw new IllegalArgumentException("Date parameters do not compose a legal date.");
        this.fullName = name ;
        this.sortableDate = MyUtils.createSortableDate(year,month,day);
        this.dataIndex = MyDataObject.newDataIndex++ ;
    }
    public String toString() {
        return ""+this.dataIndex+". "this.fullName+" ("+this.sortableDate+")";
    }

    // override SortableObject 
    public static String [] getSortableTypes() { return SORT_TYPES ; }
    public String getSortableValueByType(String type) {
        int index = MyUtils.getStringArrayIndex(SORT_TYPES, type);
        switch(index) {
             case 0: return this.name ;
             case 1: return this.sortableDate ;
        }
        return toString(); // in the order they were created when compared
    }
}

Sekarang Anda dapat membuat

public class SortableList<T extends SortableObject> 

yang dapat mengambil jenis, membangun menu pop-up untuk memilih jenis untuk mengurutkan dan menggunakan daftar dengan mendapatkan data dari jenis itu, serta memiliki fungsi add yang, ketika jenis sortir telah dipilih, dapat otomatis -sort item baru masuk Perhatikan bahwa instance dari SortableList dapat langsung mengakses metode statis "T":

String [] MenuItems = T.getSortableTypes();

Masalah dengan harus menggunakan sebuah instance adalah bahwa SortableList mungkin belum memiliki item, tetapi sudah harus menyediakan pengurutan yang disukai.

Cheerio, Olaf.


0

Pertama, titik kunci tentang kelas abstrak - Kelas abstrak tidak dapat dipakai (lihat wiki ). Jadi, Anda tidak dapat membuat setiap instance dari kelas abstrak.

Sekarang, cara java menangani metode statis adalah dengan membagikan metode tersebut dengan semua instance dari kelas itu.

Jadi, jika Anda tidak dapat membuat instance kelas, kelas itu tidak dapat memiliki metode statis abstrak karena metode abstrak meminta untuk diperpanjang.

Ledakan.


Setiap metode dalam kelas abstrak membutuhkan kelasnya untuk diperluas tetap dieksekusi, jadi ini bukan alasan. Anda bisa memperluas kelas abstrak (pada saat yang sama, menerapkan metode abstrak). Jadi ini tidak berfungsi sebagai penjelasan.
Pere

0

Sesuai dokumen Java :

Metode statis adalah metode yang dikaitkan dengan kelas di mana ia didefinisikan daripada dengan objek apa pun. Setiap instance kelas membagikan metode statisnya

Di Java 8, bersama dengan metode standar, metode statis juga diizinkan dalam sebuah antarmuka. Ini membuatnya lebih mudah bagi kami untuk mengatur metode pembantu di perpustakaan kami. Kita dapat menyimpan metode statis khusus untuk antarmuka di antarmuka yang sama daripada di kelas yang terpisah.

Contoh yang bagus dari ini adalah:

list.sort(ordering);

dari pada

Collections.sort(list, ordering);

Contoh lain dari menggunakan metode statis juga diberikan dalam dokumen itu sendiri:

public interface TimeClient {
    // ...
    static public ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default public ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }    
}

0

Karena 'abstrak' berarti metode ini dimaksudkan untuk dikesampingkan dan orang tidak dapat mengesampingkan metode 'statis'.


Jawaban ini tidak menambahkan apa pun yang belum dijawab oleh jawaban sebelumnya.
MarsAtomic

@MarsAtomic Saya pikir ini lebih tepat daripada jawaban teratas. Juga, ini ringkas.
Praveen Kumar

Kemudian Anda dapat mengedit jawaban sebelumnya untuk memperbaikinya saat Anda memiliki perwakilan yang cukup. Yang Anda lakukan hanyalah menambahkan derau ke sinyal dengan membuat jawaban rangkap. Harap ikuti aturan dan kebiasaan Stack Overflow yang sudah ada daripada membuat sendiri dan mengharapkan orang lain untuk mengikuti.
MarsAtomic

Saya tidak setuju, tolong bandingkan jawaban saya dengan yang lain, terutama jawaban yang terpilih teratas.
Praveen Kumar

"Kenapa aku tidak bisa melakukan ini?" Jawab: "karena kamu tidak bisa".
JacksOnF1re

0

Metode biasa bisa abstrak ketika dimaksudkan untuk diganti oleh subclass dan dilengkapi dengan fungsionalitas. Bayangkan kelas Foodiperpanjang oleh Bar1, Bar2, Bar3dll. Jadi, masing-masing akan memiliki versi sendiri dari kelas abstrak sesuai dengan kebutuhan mereka.

Sekarang, metode statis menurut definisi adalah milik kelas, mereka tidak ada hubungannya dengan objek kelas atau objek subkelasnya. Mereka bahkan tidak membutuhkannya, mereka dapat digunakan tanpa membuat instance kelas. Oleh karena itu, mereka harus siap-untuk-pergi dan tidak dapat bergantung pada subclass untuk menambahkan fungsionalitas kepada mereka.


0

Karena abstrak adalah kata kunci yang diterapkan pada metode abstrak tidak menentukan tubuh. Dan jika kita berbicara tentang kata kunci statis itu milik area kelas.


tolong jelaskan sedikit tentang jawaban Anda.
Blip

0

karena jika Anda menggunakan anggota statis atau variabel statis di kelas itu akan memuat pada waktu pemuatan kelas.


3
dan mengapa itu menjadi masalah?
eis

-1

Anda dapat melakukan ini dengan antarmuka di Java 8.

Ini adalah dokumentasi resmi tentangnya:

https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html


2
Bagaimana? Saya sudah mencari solusi dan tidak dapat menemukannya.
thouliha

Apa? Kamu tidak bisa. Semua metode antarmuka statis harus dipanggil menggunakan kelas antarmuka.
mmm

8
Jawaban ini salah dan menyesatkan orang-orang baru di java. Ini tidak menunjukkan contoh metode statis abstrak karena tidak dapat diimplementasikan dan dinyatakan dalam jawaban lain
Blip

-1

Karena jika sebuah kelas memperluas kelas abstrak maka ia harus menimpa metode abstrak dan itu wajib. Dan karena metode statis adalah metode kelas yang diselesaikan pada waktu kompilasi sedangkan metode yang diganti adalah metode instan yang diselesaikan pada saat runtime dan mengikuti polimorfisme dinamis.


Harap gunakan huruf besar dan beri tanda baca kekacauan ini.
Marquis of Lorne
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.