Perilaku metode statis terakhir


123

Saya telah bermain-main dengan pengubah dengan metode statis dan menemukan perilaku yang aneh.

Seperti yang kita ketahui, metode statis tidak dapat diganti, karena metode tersebut dikaitkan dengan kelas daripada instance.

Jadi jika saya memiliki potongan di bawah ini, itu dapat dikompilasi dengan baik

//Snippet 1 - Compiles fine
public class A {
    static void ts() {
    }
}

class B extends A {
    static void ts() {
    }
}

Tetapi jika saya menyertakan pengubah terakhir ke metode statis di kelas A, maka kompilasi gagal ts () di B tidak dapat menggantikan ts () di A; metode yang diganti adalah final statis .

Mengapa ini terjadi ketika metode statis tidak dapat diganti sama sekali?


2
sepertinya aneh, +1 untuk pertanyaannya, tapi sampai sekarang tidak ada jawaban yang memuaskan.
Rakesh Juyal

1
Itu tidak diganti. Itu masih ada di A.ts ().
Alex Feinman

Jawaban:


166

Metode statis tidak dapat diganti, tetapi dapat disembunyikan. The ts()Metode B tidak mengesampingkan (tidak tunduk polimorfisme) yang ts()dari A tetapi akan menyembunyikannya. Jika Anda memanggil ts()dalam B (BUKAN A.ts()atau B.ts()... hanya ts()), yang B akan dipanggil dan bukan A. Karena ini tidak terkena polimorfisme, panggilants() di A tidak akan pernah dialihkan ke di B.

Kata kunci final akan menonaktifkan metode agar tidak disembunyikan. Jadi mereka tidak dapat disembunyikan dan upaya untuk melakukannya akan menghasilkan kesalahan kompilator.

Semoga ini membantu.


30
Mungkin untuk menyelesaikan jawaban Anda, yang benar saya percaya, masalah di sini pada dasarnya adalah pesan kesalahan compiler yang buruk: seharusnya mengatakan B tidak dapat menyembunyikan ts () di A. Mendeklarasikan metode akhir statis menyatakan itu tidak dapat disembunyikan.
Sean Owen

2
@ Sean Owen: Saya juga berpikir begitu. Istilah 'sembunyikan' bahkan digunakan dalam Spesifikasi Java jadi mengapa tidak menggunakannya dalam pesan kompilator.
NawaMan

2
Mengapa ini bahkan merupakan fitur? Dalam konteks apa ini berguna?
pengguna253751

Uji kelas publik {final public void static utama (String ... srik) {System.out.println ("Dalam metode utama"); ts (); } public static void ts () {Child c = new Child (); c.ts (); System.out.println ("Uji ts"); }} kelas publik Anak memperluas Uji {public static void ts () {System.out.println ("Anak ts"); }} Hai Tolong jelaskan apa yang terjadi dalam skenario ini
srikanth r

@SeanOwen Saya rasa ini juga tidak benar, kompilator harus mengatakan bahwa karena A#tssedang diwariskan dan metode seperti itu sudah ada B, hanya memiliki dua metode dengan tanda tangan yang sama dan pengubah yang berbeda ( final) tidak akan berfungsi sebagai kelebihan beban .. Saya berharap dapat memikirkan pesan sederhana untuk ini
Eugene

13

metode statis tidak dapat diganti

Ini tidak sepenuhnya benar. Kode contoh benar-benar berarti bahwa metode ts di B menyembunyikan metode ts di A. Jadi itu tidak sepenuhnya menimpa. Di Javaranch ada penjelasan yang bagus.


4
Memang benar hanya tidak tepat. metode statis tidak dapat diganti tetapi dapat disembunyikan jika Anda memanggilnya pada referensi instance daripada nama kelas.
John Mercier

1
Sayangnya tautan Anda tidak berfungsi lagi. Apakah mungkin untuk memperbaikinya?
Mathias Bader

Tautan javaranch tidak berfungsi, tetapi mencari kata-kata kuncinya di Google muncul tautan ini di peternakan kode
Sundeep

Saya telah mengedit postingan dengan mengganti tautan mati dengan tautan yang diposting oleh Sundeep.
Kaisar MC

10

Metode statis milik kelas, bukan instance.

A.ts()dan B.ts()akan selalu menjadi metode terpisah.

Masalah sebenarnya adalah Java memungkinkan Anda memanggil metode statis pada objek instance. Metode statis dengan tanda tangan yang sama dari kelas induk disembunyikan ketika dipanggil dari turunan subkelas. Namun, Anda tidak dapat mengganti / menyembunyikan metode terakhir .

Anda akan mengira pesan kesalahan akan menggunakan kata tersembunyi, bukan diganti ...


6

Anda mungkin menemukan diri Anda dalam posisi untuk berpikir tentang membuat final metode statis, dengan mempertimbangkan hal-hal berikut:

Memiliki kelas-kelas berikut:

class A {
    static void ts() {
        System.out.print("A");
    }
}
class B extends A {
    static void ts() {
        System.out.print("B");
    }
}

Sekarang cara yang 'benar' untuk memanggil metode ini adalah

A.ts();
B.ts();

yang akan menghasilkan ABtetapi Anda juga bisa memanggil metode pada instance:

A a = new A();
a.ts();
B b = new B();
b.ts();

yang akan menghasilkan ABjuga.

Sekarang pertimbangkan yang berikut:

A a = new B();
a.ts();

yang akan mencetak A. Itu mungkin mengejutkan Anda karena Anda benar-benar memiliki objek kelas B. Tetapi karena Anda memanggilnya dari referensi tipe A, itu akan memanggil A.ts(). Anda dapat mencetak Bdengan kode berikut:

A a = new B();
((B)a).ts();

Dalam kedua kasus, objek yang Anda miliki sebenarnya dari kelas B. Tetapi bergantung pada penunjuk yang menunjuk ke objek, Anda akan memanggil metode dari Aatau dariB .

Sekarang katakanlah Anda adalah pengembang kelas Adan Anda ingin mengizinkan sub-pengelompokan. Tetapi Anda benar-benar menginginkan metode ts(), kapan pun dipanggil, bahkan dari subclass, yaitu melakukan apa yang Anda inginkan dan tidak disembunyikan oleh versi subclass. Kemudian Anda bisa membuatnya finaldan mencegahnya disembunyikan di subclass. Dan Anda dapat yakin bahwa kode berikut akan memanggil metode dari kelas Anda A:

B b = new B();
b.ts();

Oke, harus diakui entah bagaimana dibangun, tapi mungkin masuk akal untuk beberapa kasus.

Anda tidak boleh memanggil metode statis pada instance tetapi langsung di kelas - maka Anda tidak akan mengalami masalah itu. Juga IntelliJ IDEA misalnya akan menampilkan peringatan, jika Anda memanggil metode statis pada sebuah instance dan juga jika Anda membuat metode statis final.


0

Metode ts () di B tidak menimpa metode ts () di A, itu hanya metode lain. Kelas B tidak melihat metode ts () di A karena bersifat statis, oleh karena itu kelas B dapat mendeklarasikan metodenya sendiri yang disebut ts ().

Namun, jika metode tersebut final, maka compiler akan mengambil bahwa ada metode ts () di A yang tidak boleh diganti di B.


Saya tidak berpikir ini menjelaskan mengapa 'final' tiba-tiba berarti metode ini tidak dapat hidup berdampingan. Seperti yang Anda katakan, tanpa 'final', tidak ada masalah. Anda mengatakan itu tidak menimpa, tetapi kemudian mengatakan masalahnya adalah bahwa B tidak dapat menimpa metode A.
Sean Owen

Tentu saja, saya menyatakan bahwa B tidak melihat metode ts () di A (ini 'tersembunyi'), tetapi pengubah terakhir tidak 'menyembunyikan' metode dari kelas yang memperluas yang lain. Tapi eh, oke.
amischiefr

0

Saya pikir kesalahan kompilasi cukup menyesatkan di sini. Seharusnya tidak ada kata "metode yang diganti adalah final statis", tetapi seharusnya mengatakan "metode yang diganti adalah final.". Pengubah statis tidak relevan di sini.


1
Jadi Anda menganggap metode statis di B menimpa metode di A?
Koray Tugay

@KorayTugay Saya hanya ingin tahu apakah kompilator pertama kali melihat metode yang berpotensi dapat diganti (mengabaikan statis sejenak), melihat final di gagal. Hanya tebakan liar
Eugene

Balus Saya rasa ini adalah satu-satunya jawaban berkualitas rendah yang Anda miliki di StackOverflow. Mempertimbangkan semua jawaban luar biasa Anda, yang ini bukan milik mereka. @BalusC
Koray Tugay

@KorayTugay: pada saat itu reputasi saya tidak cukup untuk berkomentar :) Jika Anda melakukan ping balik, saya akan menghapus jawabannya, tidak masalah.
BalusC

0

Metode statis tidak dapat diganti di Java, tidak seperti metode non-statis. Tetapi mereka diwariskan seperti anggota data statis dan non-statis. Itulah mengapa metode non-statis dengan nama yang sama tidak dapat dibuat di kelas induk

class Writer { 
    public static void doo(){
        System.out.println("sth");
    } 
}
class Author extends Writer{ 
    public void doo(){
        System.out.println("ok"); // error overridden method is static
    }
}

Kata finalkunci memastikan bahwa tubuh metode tertentu dijalankan setiap kali panggilan ke metode. Sekarang jika metode statis dibuat di kelas anak dengan nama yang sama dan panggilan ke metode dibuat, metode di subkelas dijalankan yang seharusnya tidak terjadi jika final diawali sebelum nama metode statis di kelas induk . Oleh karena itu kata kunci terakhir membatasi pembuatan metode dengan nama yang sama di kelas anak.

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.