Jawaban singkatnya adalah: itu sepenuhnya mungkin, tetapi Java tidak melakukannya.
Berikut adalah beberapa kode yang menggambarkan keadaan terkini di Jawa:
File Base.java
:
package sp.trial;
public class Base {
static void printValue() {
System.out.println(" Called static Base method.");
}
void nonStatPrintValue() {
System.out.println(" Called non-static Base method.");
}
void nonLocalIndirectStatMethod() {
System.out.println(" Non-static calls overridden(?) static:");
System.out.print(" ");
this.printValue();
}
}
File Child.java
:
package sp.trial;
public class Child extends Base {
static void printValue() {
System.out.println(" Called static Child method.");
}
void nonStatPrintValue() {
System.out.println(" Called non-static Child method.");
}
void localIndirectStatMethod() {
System.out.println(" Non-static calls own static:");
System.out.print(" ");
printValue();
}
public static void main(String[] args) {
System.out.println("Object: static type Base; runtime type Child:");
Base base = new Child();
base.printValue();
base.nonStatPrintValue();
System.out.println("Object: static type Child; runtime type Child:");
Child child = new Child();
child.printValue();
child.nonStatPrintValue();
System.out.println("Class: Child static call:");
Child.printValue();
System.out.println("Class: Base static call:");
Base.printValue();
System.out.println("Object: static/runtime type Child -- call static from non-static method of Child:");
child.localIndirectStatMethod();
System.out.println("Object: static/runtime type Child -- call static from non-static method of Base:");
child.nonLocalIndirectStatMethod();
}
}
Jika Anda menjalankan ini (saya melakukannya di Mac, dari Eclipse, menggunakan Java 1.6) Anda akan mendapatkan:
Object: static type Base; runtime type Child.
Called static Base method.
Called non-static Child method.
Object: static type Child; runtime type Child.
Called static Child method.
Called non-static Child method.
Class: Child static call.
Called static Child method.
Class: Base static call.
Called static Base method.
Object: static/runtime type Child -- call static from non-static method of Child.
Non-static calls own static.
Called static Child method.
Object: static/runtime type Child -- call static from non-static method of Base.
Non-static calls overridden(?) static.
Called static Base method.
Di sini, satu - satunya kasus yang mungkin mengejutkan (dan yang menjadi pertanyaan adalah) adalah kasus pertama :
"Tipe run-time tidak digunakan untuk menentukan metode statis mana yang dipanggil, bahkan ketika dipanggil dengan instance objek ( obj.staticMethod()
)."
dan kasus terakhir :
"Ketika memanggil metode statis dari dalam metode objek kelas, metode statis yang dipilih adalah yang dapat diakses dari kelas itu sendiri dan bukan dari kelas yang mendefinisikan jenis run-time objek."
Memanggil dengan instance objek
Panggilan statis diselesaikan pada waktu kompilasi, sedangkan panggilan metode non-statis diselesaikan pada saat dijalankan. Perhatikan bahwa meskipun metode statis diwariskan (dari orangtua) mereka tidak diganti (oleh anak). Ini bisa menjadi kejutan jika Anda mengharapkan sebaliknya.
Memanggil dari dalam metode objek
Panggilan metode objek diselesaikan menggunakan tipe run-time, tetapi panggilan metode statis ( kelas ) diselesaikan dengan menggunakan tipe waktu kompilasi (dideklarasikan).
Mengubah aturan
Untuk mengubah aturan-aturan ini, sehingga panggilan terakhir dalam contoh yang dipanggil Child.printValue()
, panggilan statis harus disediakan dengan tipe pada saat run-time, daripada kompiler menyelesaikan panggilan pada saat kompilasi dengan kelas objek yang dideklarasikan (atau konteks). Panggilan statis kemudian dapat menggunakan hirarki tipe (dinamis) untuk menyelesaikan panggilan, seperti yang dilakukan metode panggilan objek hari ini.
Ini dengan mudah bisa dilakukan (jika kita mengubah Java: -O), dan sama sekali tidak masuk akal, bagaimanapun, ia memiliki beberapa pertimbangan menarik.
Pertimbangan utama adalah bahwa kita perlu memutuskan panggilan metode statis mana yang harus melakukan ini.
Saat ini, Java memiliki "kekhasan" dalam bahasa di mana obj.staticMethod()
panggilan diganti dengan ObjectClass.staticMethod()
panggilan (biasanya dengan peringatan). [ Catatan: ObjectClass
adalah tipe waktu kompilasi obj
.] Ini akan menjadi kandidat yang baik untuk mengganti dengan cara ini, dengan menggunakan tipe run-time obj
.
Jika kita lakukan itu akan membuat badan metode lebih sulit untuk dibaca: panggilan statis di kelas induk berpotensi secara dinamis "dialihkan kembali". Untuk menghindari ini, kita harus memanggil metode statis dengan nama kelas - dan ini membuat panggilan lebih jelas diselesaikan dengan hierarki jenis waktu kompilasi (seperti sekarang).
Cara lain untuk menggunakan metode statis lebih rumit: this.staticMethod()
harus berarti sama dengan obj.staticMethod()
, mengambil jenis run-time this
. Namun, ini dapat menyebabkan beberapa sakit kepala dengan program yang ada, yang memanggil metode statis (tampaknya lokal) tanpa dekorasi (yang bisa dibilang setara dengan this.method()
).
Jadi bagaimana dengan panggilan tanpa hiasan staticMethod()
? Saya menyarankan mereka melakukan hal yang sama seperti hari ini, dan menggunakan konteks kelas lokal untuk memutuskan apa yang harus dilakukan. Kalau tidak, akan timbul kebingungan besar. Tentu saja itu berarti bahwa method()
akan berarti this.method()
jika method
itu metode non-statis, dan ThisClass.method()
jika method
itu metode statis. Ini adalah sumber kebingungan lainnya.
Pertimbangan lainnya
Jika kami mengubah perilaku ini (dan membuat panggilan statis yang berpotensi non-lokal secara dinamis), kami mungkin ingin meninjau kembali makna final
, private
dan protected
sebagai kualifikasi pada static
metode kelas. Kita kemudian harus membiasakan diri dengan fakta bahwa private static
dan public final
metode tidak diganti, dan karena itu dapat diselesaikan dengan aman pada waktu kompilasi, dan "aman" untuk dibaca sebagai referensi lokal.