Saya bingung tentang perbedaan mengesampingkan dari bersembunyi di Jawa. Adakah yang bisa memberikan rincian lebih lanjut tentang perbedaannya? Saya membaca Tutorial Java tetapi kode contoh masih membuat saya bingung.
Untuk lebih jelasnya, saya memahami mengesampingkan dengan baik. Masalah saya adalah bahwa saya tidak melihat bagaimana menyembunyikan itu berbeda, kecuali fakta bahwa yang satu ada di tingkat contoh sementara yang lain ada di tingkat kelas.
Melihat kode tutorial Java:
public class Animal {
public static void testClassMethod() {
System.out.println("Class" + " method in Animal.");
}
public void testInstanceMethod() {
System.out.println("Instance " + " method in Animal.");
}
}
Kemudian kami memiliki subclass Cat
:
public class Cat extends Animal {
public static void testClassMethod() {
System.out.println("The class method" + " in Cat.");
}
public void testInstanceMethod() {
System.out.println("The instance method" + " in Cat.");
}
public static void main(String[] args) {
Cat myCat = new Cat();
Animal myAnimal = myCat;
Animal.testClassMethod();
myAnimal.testInstanceMethod();
}
}
Lalu mereka berkata:
Output dari program ini adalah sebagai berikut:
Metode kelas pada Hewan.
Metode instance di Cat.
Bagi saya, fakta bahwa memanggil metode kelas testClassMethod()
langsung dari Animal
kelas menjalankan metode di Animal
kelas cukup jelas, tidak ada yang istimewa di sana. Kemudian mereka memanggil testInstanceMethod()
dari referensi ke myCat
, jadi sekali lagi cukup jelas bahwa metode yang dieksekusi adalah yang ada di instance Cat
.
Dari apa yang saya lihat, panggilan bersembunyi berperilaku seperti menimpa, jadi mengapa membuat perbedaan itu? Jika saya menjalankan kode ini menggunakan kelas-kelas di atas:
Cat.testClassMethod();
Saya akan mendapatkan:
Metode kelas di Cat.
Tetapi jika saya menghapus testClassMethod()
dari Cat, maka saya akan mendapatkan:
Metode kelas di Animal.
Yang menunjukkan kepada saya bahwa menulis metode statis, dengan tanda tangan yang sama seperti di induk, di subkelas cukup banyak melakukan penggantian.
Mudah-mudahan saya menjelaskan di mana saya bingung dan seseorang dapat menjelaskan. Terima kasih banyak sebelumnya!
sumber
Jawaban:
Overriding pada dasarnya mendukung pengikatan yang terlambat. Oleh karena itu, diputuskan pada saat berjalan metode mana yang akan dipanggil. Ini untuk metode non-statis.
Menyembunyikan adalah untuk semua anggota lainnya (metode statis, anggota instance, anggota statis). Ini didasarkan pada pengikatan awal. Lebih jelasnya, metode atau anggota yang akan dipanggil atau digunakan ditentukan selama waktu kompilasi.
Dalam contoh Anda, panggilan pertama,
Animal.testClassMethod()
adalah panggilan ke suatustatic
metode, oleh karena itu cukup yakin metode mana yang akan dipanggil.Pada panggilan kedua
myAnimal.testInstanceMethod()
, Anda memanggil metode non-statis. Inilah yang Anda sebut polimorfisme run-time. Tidak diputuskan sampai waktu berjalan metode mana yang akan dipanggil.Untuk klarifikasi lebih lanjut, baca Mengganti Vs Menyembunyikan .
sumber
private methods
? Mereka tidak mungkinoverridden
karena subclass tidak tahu tentang keberadaan mereka .. Oleh karena itu, mereka mungkinhidden
saja.Metode statis disembunyikan, metode non-statis diganti. Perbedaannya penting ketika panggilan tidak memenuhi syarat "sesuatu ()" vs "this.something ()".
Saya tidak bisa benar-benar meletakkannya pada kata-kata, jadi inilah contohnya:
public class Animal { public static void something() { System.out.println("animal.something"); } public void eat() { System.out.println("animal.eat"); } public Animal() { // This will always call Animal.something(), since it can't be overriden, because it is static. something(); // This will call the eat() defined in overriding classes. eat(); } } public class Dog extends Animal { public static void something() { // This method merely hides Animal.something(), making it uncallable, but does not override it, or alter calls to it in any way. System.out.println("dog.something"); } public void eat() { // This method overrides eat(), and will affect calls to eat() System.out.println("dog.eat"); } public Dog() { super(); } public static void main(String[] args) { new Dog(); } }
KELUARAN:
sumber
husky.Animal();
apakah itu akan mencetak binatang.sesuatu atau anjing.sesuatu ? Saya kira SALAH untuk mengatakan ** bahwa ** Ini akan selalu memanggil Animal.something ().Animal()
, ingatAnimal()
adalah konstruktor.something()
inAnimal()
selalu memanggil Animal'ssomething()
adalah karena panggilan ke metode statis diselesaikan dalam waktu kompilasi daripada run-time. Ini berarti bahwa pemanggilan metode statisAnimal()
selalu secara implisit memanggilAnimal.something()
. Ini cukup intuitif jika Anda memikirkannya: panggilan ke metode statis harus diawali dengan nama kelas (yaituclassName.staticMethodName()
) kecuali panggilan tersebut berada di kelas yang sama.Inilah perbedaan antara menimpa dan menyembunyikan,
sumber
Jika saya memahami pertanyaan Anda dengan benar maka jawabannya adalah "Anda sudah menimpa".
"Yang menunjukkan kepada saya bahwa menulis metode statis, dengan nama yang sama seperti di induk, dalam subkelas cukup banyak melakukan penggantian."
Jika Anda menulis metode dalam subclass dengan nama yang sama persis dengan metode di superclass, metode tersebut akan menimpa metode superclass. Anotasi @Override tidak diperlukan untuk mengganti metode. Namun itu membuat kode Anda lebih mudah dibaca dan memaksa compiler untuk memeriksa bahwa Anda benar-benar mengganti metode (dan tidak salah mengeja metode subclass misalnya).
sumber
Penggantian hanya terjadi dengan metode instance. Jika tipe variabel referensi adalah Hewan dan objeknya adalah Cat, maka metode instance dipanggil dari Cat (ini menimpa). Untuk objek acat yang sama metode kelas Animal digunakan.
public static void main(String[] args) { Animal acat = new Cat(); acat.testInstanceMethod(); acat.testClassMethod(); }
Outputnya adalah:
sumber
public class First { public void Overriding(int i) { /* will be overridden in class Second */ } public static void Hiding(int i) { /* will be hidden in class Second because it's static */ } } public class Second extends First { public void Overriding(int i) { /* overridden here */ } public static void Hiding(int i) { /* hides method in class First because it's static */ } }
Aturan untuk menghafalnya sederhana: metode dalam kelas yang diperluas tidak dapat mengubah statis menjadi void dan tidak dapat mengubah void menjadi statis. Ini akan menyebabkan kesalahan kompilasi.
Tetapi jika
void Name
diubah menjadivoid Name
Overriding.Dan jika
static Name
diubah menjadistatic Name
Bersembunyi. (Baik metode statis subkelas maupun salah satu superclass dapat dipanggil, bergantung pada jenis referensi yang digunakan untuk memanggil metode tersebut.)sumber
Dalam cuplikan kode ini saya menggunakan pengubah akses 'pribadi' alih-alih 'statis' untuk menunjukkan perbedaan antara metode penyembunyian dan metode penimpaan.
class Animal { // Use 'static' or 'private' access modifiers to see how method hiding work. private void testInstancePrivateMethod(String source) { System.out.println("\tAnimal: instance Private method calling from "+source); } public void testInstanceMethodUsingPrivateMethodInside() { System.out.println("\tAnimal: instance Public method with using of Private method."); testInstancePrivateMethod( Animal.class.getSimpleName() ); } // Use default, 'protected' or 'public' access modifiers to see how method overriding work. protected void testInstanceProtectedMethod(String source) { System.out.println("\tAnimal: instance Protected method calling from "+source); } public void testInstanceMethodUsingProtectedMethodInside() { System.out.println("\tAnimal: instance Public method with using of Protected method."); testInstanceProtectedMethod( Animal.class.getSimpleName() ); } } public class Cat extends Animal { private void testInstancePrivateMethod(String source) { System.out.println("Cat: instance Private method calling from " + source ); } public void testInstanceMethodUsingPrivateMethodInside() { System.out.println("Cat: instance Public method with using of Private method."); testInstancePrivateMethod( Cat.class.getSimpleName()); System.out.println("Cat: and calling parent after:"); super.testInstanceMethodUsingPrivateMethodInside(); } protected void testInstanceProtectedMethod(String source) { System.out.println("Cat: instance Protected method calling from "+ source ); } public void testInstanceMethodUsingProtectedMethodInside() { System.out.println("Cat: instance Public method with using of Protected method."); testInstanceProtectedMethod(Cat.class.getSimpleName()); System.out.println("Cat: and calling parent after:"); super.testInstanceMethodUsingProtectedMethodInside(); } public static void main(String[] args) { Cat myCat = new Cat(); System.out.println("----- Method hiding -------"); myCat.testInstanceMethodUsingPrivateMethodInside(); System.out.println("\n----- Method overriding -------"); myCat.testInstanceMethodUsingProtectedMethodInside(); } }
Keluaran:
sumber
Berdasarkan studi Java saya baru-baru ini
Contoh dari buku OCP Java 7, halaman 70-71:
public class Point { private int xPos, yPos; public Point(int x, int y) { xPos = x; yPos = y; } public boolean equals(Point other){ .... sexy code here ...... } public static void main(String []args) { Point p1 = new Point(10, 20); Point p2 = new Point(50, 100); Point p3 = new Point(10, 20); System.out.println("p1 equals p2 is " + p1.equals(p2)); System.out.println("p1 equals p3 is " + p1.equals(p3)); //point's class equals method get invoked } }
tetapi jika kita menulis main berikut:
public static void main(String []args) { Object p1 = new Point(10, 20); Object p2 = new Point(50, 100); Object p3 = new Point(10, 20); System.out.println("p1 equals p2 is " + p1.equals(p2)); System.out.println("p1 equals p3 is " + p1.equals(p3)); //Object's class equals method get invoked }
Di main kedua, kami menggunakan kelas Object sebagai tipe statis, jadi ketika kami memanggil metode yang sama di objek Point, itu menunggu kelas Point untuk datang sebagai parameter, tapi Object datang. Jadi kelas Objek sama dengan metode yang dijalankan, karena kami memiliki sama dengan (Objek o) di sana. Dalam kasus ini, kelas Poin sama dengan dosen tidak menimpa, tetapi menyembunyikan metode kelas Objek sama dengan .
sumber
public class Parent { public static void show(){ System.out.println("Parent"); } } public class Child extends Parent{ public static void show(){ System.out.println("Child"); } } public class Main { public static void main(String[] args) { Parent parent=new Child(); parent.show(); // it will call parent show method } } // We can call static method by reference ( as shown above) or by using class name (Parent.show())
sumber
Halaman tutorial java yang ditautkan menjelaskan konsep menimpa dan menyembunyikan
Perbedaan antara menyembunyikan metode statis dan mengganti metode instance memiliki implikasi penting:
Kembali ke contoh Anda:
Animal myAnimal = myCat; /* invokes static method on Animal, expected. */ Animal.testClassMethod(); /* invokes child class instance method (non-static - it's overriding) */ myAnimal.testInstanceMethod();
Pernyataan di atas belum menunjukkan persembunyian.
Sekarang ubah kode seperti di bawah ini untuk mendapatkan output yang berbeda:
Animal myAnimal = myCat; /* Even though myAnimal is Cat, Animal class method is invoked instead of Cat method*/ myAnimal.testClassMethod(); /* invokes child class instance method (non-static - it's overriding) */ myAnimal.testInstanceMethod();
sumber
Selain contoh yang tercantum di atas, berikut adalah contoh kode kecil untuk memperjelas perbedaan antara menyembunyikan dan mengganti:
public class Parent { // to be hidden (static) public static String toBeHidden() { return "Parent"; } // to be overridden (non-static) public String toBeOverridden() { return "Parent"; } public void printParent() { System.out.println("to be hidden: " + toBeHidden()); System.out.println("to be overridden: " + toBeOverridden()); } } public class Child extends Parent { public static String toBeHidden() { return "Child"; } public String toBeOverridden() { return "Child"; } public void printChild() { System.out.println("to be hidden: " + toBeHidden()); System.out.println("to be overridden: " + toBeOverridden()); } } public class Main { public static void main(String[] args) { Child child = new Child(); child.printParent(); child.printChild(); } }
Panggilan
child.printParent()
keluaran:disembunyikan: Induk yang
akan diganti: Anak
Panggilan
child.printChild()
keluaran:disembunyikan: Anak yang
akan diganti: Anak
Seperti yang bisa kita lihat dari output di atas (terutama output yang ditandai tebal), penyembunyian metode berperilaku berbeda dari penggantian.
Java memungkinkan menyembunyikan dan mengganti hanya untuk metode. Aturan yang sama tidak berlaku untuk variabel. Variabel pengganti tidak diizinkan, jadi variabel hanya dapat disembunyikan (tidak ada perbedaan antara variabel statis atau non-statis). Contoh di bawah ini menunjukkan bagaimana metode
getName()
tersebut diganti dan variabelname
disembunyikan:public class Main { public static void main(String[] args) { Parent p = new Child(); System.out.println(p.name); // prints Parent (since hiding) System.out.println(p.getName()); // prints Child (since overriding) } } class Parent { String name = "Parent"; String getName() { return name; } } class Child extends Parent { String name = "Child"; String getName() { return name; } }
sumber
Pada waktu proses, versi turunan dari metode yang diganti selalu dieksekusi untuk sebuah instance terlepas dari apakah pemanggilan metode didefinisikan dalam metode kelas induk atau turunan. Dengan cara ini, metode induk tidak pernah digunakan kecuali panggilan eksplisit ke metode induk dirujuk, menggunakan sintaks ParentClassName.method (). Alternatifnya, pada waktu proses, versi induk dari metode tersembunyi selalu dijalankan jika panggilan ke metode ditentukan di kelas induk.
sumber
Dalam metode penggantian , resolusi metode dilakukan oleh JVM berdasarkan objek runtime. Sedangkan dalam penyembunyian metode, penyelesaian metode dilakukan oleh compiler berdasarkan referensi. Jadi,
Jika kodenya akan ditulis sebagai,
public static void main(String[] args) { Animal myCat = new Cat(); myCat.testClassMethod(); }
Outputnya akan seperti di bawah ini:
Metode kelas pada Hewan.
sumber
Disebut menyembunyikan karena kompilator menyembunyikan implementasi metode kelas super, ketika subkelas memiliki metode statis yang sama.
Compiler tidak memiliki visibilitas terbatas untuk metode yang diganti dan hanya selama runtime yang diputuskan mana yang digunakan.
sumber
Inilah perbedaan antara menimpa dan menyembunyikan:
Hewan a = Kucing baru ();
a.testClassMethod () akan memanggil metode di kelas induk karena ini adalah contoh dari metode yang disembunyikan. Metode yang akan dipanggil ditentukan oleh jenis variabel referensi dan diputuskan pada waktu kompilasi.
a.testInstanceMethod () akan memanggil metode dalam kelas anak karena ini adalah contoh dari penggantian metode. Metode yang dipanggil ditentukan oleh objek yang digunakan untuk memanggil metode saat runtime.
sumber
Saya pikir ini belum sepenuhnya dijelaskan. Silakan lihat contoh berikut.
class Animal { public static void testClassMethod() { System.out.println("The static method in Animal"); } public void testInstanceMethod() { System.out.println("The instance method in Animal"); } } public class Cat extends Animal { public static void testClassMethod() { System.out.println("The static method in Cat"); } public void testInstanceMethod() { System.out.println("The instance method in Cat"); } public static void main(String[] args) { Animal myCat = new Cat(); Cat myCat2 = new Cat(); myCat.testClassMethod(); myCat2.testClassMethod(); myCat.testInstanceMethod(); myCat2.testInstanceMethod(); } }
Outputnya adalah sebagai berikut.
The static method in Animal The static method in Cat The instance method in Cat The instance method in Cat
sumber
Bagaimana metode statis bersembunyi di java? Kelas kucing memperluas kelas Hewan. Jadi di kelas Cat akan memiliki kedua metode statis (maksud saya metode statis kelas Anak dan metode statis kelas Parent) Tapi bagaimana JVM menyembunyikan metode Parent Parent? Bagaimana cara menangani Heap dan Stack?
sumber