Pertanyaan Bagaimana cara kerja pengecoran objek Java di belakang layar? [duplikat]


Kemungkinan Duplikat:
Bagaimana cara kerja operator cor Java?
Implementasi pengecoran Java 

Saya selalu bertanya-tanya bagaimana cara kerja pengecoran di Java. Saya mengerti untuk tipe primitif itu akan lebih seperti di tingkat representasi biner, tapi bagaimana dengan Object? Apakah itu seperti Polymorphism atau dynamic binding bahwa semuanya akan ditentukan pada saat runtime? Sebagai contoh:

class Parent{
     void A(){}
}
class Child extends Parent{
     @Override
     void A(){}
}

Parent p = new Parent();
Child c = (Child) p;

Bagaimana cara kerjanya di belakang layar? Apakah itu membuat contoh baru Child? Dan juga, apa yang terjadi jika Anda mencoba mentransmisi:

Child b = (Child) new Object();

Dan yang terakhir, ketika melemparkan kelas primitif ke pembungkus:

Double d = (Double) 3.3;

Saya tahu Anda tidak perlu membuangnya, tetapi bagaimana jika Anda melakukannya? Adakah sesuatu yang signifikan yang terjadi pada backend?


32
2017-11-15 20:11


asal


Jawaban:


Tidak ada objek baru yang dibuat dalam sistem ketika Anda menggunakan casting eksplisit (kecuali dalam kasus terakhir Anda, di mana Anda melemparkan tipe primitif ke suatu bungkus objek, sejak double bukan objek seperti Double aku s). Perhatikan bahwa gips eksplisit ini tidak perlu karena Java fitur autoboxing.

Di dalam Anda (Child) new Object() skenario, Anda akan menerima ClassCastException karena sebuah Object bukan sebuah Child (meskipun sebaliknya benar).

Jawaban untuk skenario pertama Anda adalah yang paling rumit. Pada dasarnya kelas induk diperlakukan seperti antarmuka mungkin. Saat Anda mentransmisikan Child ke Parent, hanya itu Parent API tersedia. Namun, metode yang ditimpa masih akan dipanggil. Jadi, jika Anda melakukannya:

Parent p = (Parent) new Child();
p.a();

... yang Child's public void a() akan dipanggil, meskipun itu sedang dilihat melalui lensa Parent kelas. Namun jika Anda memiliki metode kedua dalam Child bahwa Parent tidak memiliki (katakanlah public void b() misalnya), Anda akan tidak dapat memanggilnya tanpa mentransmisikan objek kembali ke a Child.

"Di belakang layar", seperti yang Anda katakan, satu-satunya hal baru yang dibuat adalah hal lain referensi objek yang menunjuk ke objek yang sama. Anda dapat memiliki referensi sebanyak yang Anda suka, objek tunggal yang sama. Pertimbangkan contoh ini:

Parent p = new Parent();
Parent p1 = p;
Parent p2 = p;
Parent p3 = p2;

Di sini, ada empat referensi (p, p1, p2, dan p3) yang masing-masing menunjuk ke objek yang sama yang Anda buat dengan new Parent() pernyataan.

Saya mungkin akan berdebat pada poin filosofis, bahwa, penciptaan referensi baru ini sebenarnya eksplisit daripada di belakang layar ketika Anda mengatakan Parent p = something.

Tautan:


13
2017-11-15 20:16



Jawaban sederhana untuk pertanyaan utama Anda adalah No. Semua pengecoran terjadi pada waktu pemeriksaan sintaks.

Pengecoran memengaruhi cara pemeriksa sintaks melihat objek, itu tidak mempengaruhi objek itu sendiri seorang pemeran anak menjadi seorang Orangtua, masih seorang Anak.

Namun para pemain hanya diperiksa di Runtime. Itulah mengapa itu berbahaya dan tidak boleh digunakan kecuali tidak ada jalan lain.


9
2017-11-15 21:38



Accodring untuk ini: checkcast, apa yang dilakukannya adalah memverifikasi apakah referensi itu dapat dialihkan. Jika ya, tumpukan tidak berubah dan operasi pada referensi itu disimpan.

Jadi jika Anda memiliki:

 Child c = ( Child )  anyObject; 
 c.sayHi();

Jika sukses pemain, maka metode sayHi  bisa dipanggil:

Jika objectref dapat dilemparkan ke kelas yang diselesaikan, array, atau tipe antarmuka, tumpukan operan tidak berubah; jika tidak, instruksi checkcast melempar ClassCastException.

Berikut ini "bytecode"

$ cat CastDemo.java 
class Parent {}
class Child extends Parent {}
class Main {
    Child c = (Child) new Parent();
}
$ javap -c Main
Compiled from "CastDemo.java"
class Main {
  Child c;

  Main();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0       
       5: new           #2                  // class Parent
       8: dup           
       9: invokespecial #3                  // Method Parent."<init>":()V
      12: checkcast     #4                  // class Child
      15: putfield      #5                  // Field c:LChild;
      18: return        
}

4
2017-11-15 20:22



Pertama-tama, berhati-hatilah agar tidak membingungkan konversi dengan pengecoran. Mereka mungkin berbagi sintaks permukaan, tetapi prosesnya sangat berbeda.

Di Java, Anda dapat menurunkan suatu Objek ke jenis apa pun, tetapi pada waktu proses, Anda akan mendapatkan ClassCastException jika objek tersebut sebenarnya tidak kompatibel dengan tipe target. Ini terjadi pada level bytecode: ada instruksi bytecode yang didedikasikan untuk downcasting.

Child c = (Child) new Object();

tanpa syarat akan menghasilkan a ClassCastException.

Double d = 3.3; // note: no explicit casting needed

akan tampil autoboxing menjadi sebuah instance dari Double. Jadi di sini, contoh baru sebenarnya dibuat.

Dowcast yang normal dan sukses mungkin terlihat seperti ini:

Object o = "a";
String s = (String)o;

Di sini, tidak ada objek yang dibuat: hanya nilai o disalin ke dalam s. Nilai adalah referensi.


2
2017-11-15 20:15



Mengesampingkan suatu objek tidak melakukan apa pun terhadap objek itu. Di belakang layar kompilator akan menyuntikkan checkcast operasi bytecode. Jika p sebenarnya bukan merupakan contoh dari Child, pengecualian akan dibuang. Jika tidak, pada dasarnya Anda memiliki referensi aman (type-) untuk objek yang sama dengan tipe yang berbeda dan lebih spesifik.


Child b = (Child) new Object();

Ini gagal dengan ClassCastException. JVM membandingkan getClass() dari new Object() dengan Child.class. Sejak Object.class bukan subkelas dari Child.class, pengecualian dilemparkan.


Double d = (Double) 3.3;

Di sini, casting bahkan tidak diperlukan, ini juga berfungsi: Double d = 3.3. Di balik layar ini diterjemahkan ke:

Double d = Double.valueOf(3.3);

Ini dikenal sebagai Autoboxing.


1
2017-11-15 20:17