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?
}
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?
}
Jawaban:
Karena "abstrak" berarti: "Menerapkan fungsi tidak", dan "statis" berarti: "Ada fungsi bahkan jika Anda tidak memiliki turunan objek". Dan itu adalah kontradiksi yang logis.
abstract static
akan 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.
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.
static
tidak 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 static
metode 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).
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.
static
itu sendiri sudah merupakan pelanggaran ....
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.
The abstract
penjelasan untuk metode menunjukkan bahwa metode HARUS override dalam subclass.
Di Jawa, static
anggota (metode atau bidang) tidak dapat ditimpa oleh subclass (ini tidak selalu benar dalam bahasa berorientasi objek lainnya, lihat SmallTalk.) static
Anggota mungkin disembunyikan , tetapi secara fundamental berbeda dari yang ditimpa .
Karena anggota statis tidak dapat diganti dalam subkelas, abstract
anotasi 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 static
warisan, 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 abstract
pengubah untuk anggota kelas.
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
abstract static
melihat stackoverflow.com/questions/370962/… . The alasan sebenarnya mengapa Java tidak memungkinkan metode statis menjadi ditimpa karena Java tidak memungkinkan metode statis untuk menjadi ditimpa.
foo(String)
tidak sama dengan foo(Integer)
- itu saja.
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();
}
abstract static
metode seperti yang ditanyakan dalam pertanyaan dan Anda telah menulis dengan huruf tebal DAPAT DILAKUKAN DI JAWA . Ini benar-benar salah arah.
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.
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.
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 C1
dan C2
identik. Mungkin ada banyak calsses ini: C3
C4
dll. Jika static abstract
diizinkan, 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 abstract
kombinasi tidak diperbolehkan. Namun, ini dapat dielakkan dengan static class
konstruk, 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();
}
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 C
menemukan 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 !!!
Asumsikan ada dua kelas, Parent
dan Child
. Parent
adalah abstract
. Deklarasi tersebut adalah sebagai berikut:
abstract class Parent {
abstract void run();
}
class Child extends Parent {
void run() {}
}
Ini berarti bahwa setiap instance Parent
harus menentukan bagaimana run()
dijalankan.
Namun, anggaplah sekarang itu Parent
tidak benar abstract
.
class Parent {
static void run() {}
}
Ini berarti Parent.run()
akan menjalankan metode statis.
Definisi abstract
metode adalah "Metode yang dideklarasikan tetapi tidak diimplementasikan", yang berarti tidak mengembalikan apa pun itu sendiri.
Definisi static
metode adalah "Metode yang mengembalikan nilai yang sama untuk parameter yang sama terlepas dari instance yang dipanggil".
Sebuah abstract
nilai kembali metode ini akan berubah karena perubahan misalnya. Sebuah static
metode tidak akan. Sebuah static abstract
metode 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 abstract
metode.
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.
Mendeklarasikan metode sebagai static
cara kita dapat memanggil metode itu dengan nama kelasnya dan jika kelas itu abstract
juga, tidak masuk akal untuk memanggilnya karena tidak mengandung benda apa pun, dan karenanya kita tidak dapat mendeklarasikan metode sebagai static
dan abstract
.
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.
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.
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 E
bisa .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).
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");
}
}
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.
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.
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));
}
}
Karena 'abstrak' berarti metode ini dimaksudkan untuk dikesampingkan dan orang tidak dapat mengesampingkan metode 'statis'.
Metode biasa bisa abstrak ketika dimaksudkan untuk diganti oleh subclass dan dilengkapi dengan fungsionalitas. Bayangkan kelas Foo
diperpanjang oleh Bar1, Bar2, Bar3
dll. 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.
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.
Anda dapat melakukan ini dengan antarmuka di Java 8.
Ini adalah dokumentasi resmi tentangnya:
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
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.