CodeGym /Java Blog /Acak /Pelebaran dan penyempitan jenis referensi
John Squirrels
Level 41
San Francisco

Pelebaran dan penyempitan jenis referensi

Dipublikasikan di grup Acak
Hai! Dalam pelajaran sebelumnya, kita membahas pengecoran tipe primitif. Mari kita ingat secara singkat apa yang dibahas. Pelebaran dan penyempitan jenis referensi - 1Kami membayangkan tipe primitif (dalam hal ini, tipe numerik) sebagai boneka bersarang yang ukurannya bervariasi sesuai dengan jumlah memori yang ditempati. Seperti yang akan Anda ingat, memasukkan boneka yang lebih kecil ke dalam boneka yang lebih besar itu mudah baik dalam kehidupan nyata maupun dalam pemrograman Java.

public class Main {
   public static void main(String[] args) {
       int bigNumber = 10000000;
       short smallNumber = (short) bigNumber;
       System.out.println(smallNumber);
   }
}
Ini adalah contoh konversi atau pelebaran otomatis . Itu terjadi dengan sendirinya, jadi Anda tidak perlu menulis kode tambahan. Pada akhirnya, kami tidak melakukan sesuatu yang tidak biasa: kami hanya memasukkan boneka yang lebih kecil ke dalam boneka yang lebih besar. Lain halnya jika kita mencoba melakukan yang sebaliknya dan memasukkan boneka Rusia yang lebih besar ke dalam boneka yang lebih kecil. Anda tidak dapat melakukannya dalam kehidupan nyata, tetapi dalam pemrograman Anda bisa. Tapi ada satu nuansa. Jika kita mencoba memasukkan an intke dalam shortvariabel, hal-hal tidak berjalan mulus bagi kita. Lagi pula, shortvariabel hanya menyimpan 16 bit informasi, tetapi sebuah intmenempati 32 bit! Akibatnya, nilai yang diteruskan terdistorsi. Kompiler akan memberi kami kesalahan (' Bung, Anda melakukan sesuatu yang mencurigakan!'). Tetapi jika kita secara eksplisit menunjukkan jenis yang kita ubah nilainya, itu akan melanjutkan dan melakukan operasi.

public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
Itulah yang kami lakukan pada contoh di atas. Operasi dilakukan, tetapi karena shortvariabel hanya dapat menampung 16 dari 32 byte, nilai akhir terdistorsi dan kami mendapatkan angka -27008 . Operasi semacam itu disebut konversi eksplisit, atau penyempitan .

Contoh pelebaran dan penyempitan jenis referensi

Sekarang mari kita bicara tentang operator yang sama yang diterapkan bukan pada tipe primitif, tetapi pada objek dan variabel referensi ! Bagaimana cara kerjanya di Jawa? Ini sebenarnya cukup sederhana. Ada objek yang tidak berhubungan. Masuk akal untuk berasumsi bahwa mereka tidak dapat dikonversi satu sama lain, baik secara eksplisit maupun otomatis:

public class Cat {
}

public class Dog {
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Dog(); // Error!

   }

}
Di sini, tentu saja, kami mendapatkan kesalahan. Kelas Catdan Dogtidak terkait satu sama lain, dan kami belum menulis 'konverter' untuk berpindah dari satu ke yang lain. Masuk akal jika kita tidak dapat melakukan ini: kompiler tidak tahu cara mengonversi objek ini dari satu jenis ke jenis lainnya. Jika benda-benda itu terkait, itu masalah lain! Terkait bagaimana? Apalagi melalui warisan. Mari coba gunakan pewarisan untuk membuat sistem kelas kecil. Kami akan memiliki kelas umum untuk mewakili hewan:

public class Animal {

   public void introduce() {

       System.out.println("I'm Animal");
   }
}
Semua orang tahu bahwa hewan dapat dijinakkan (hewan peliharaan) atau liar:

public class WildAnimal extends Animal {

   public void introduce() {

       System.out.println("I'm WildAnimal");
   }
}

public class Pet extends Animal {

   public void introduce() {

       System.out.println("I'm Pet");
   }
}
Misalnya, ambil gigi taring — kami memiliki anjing peliharaan dan coyote:

public class Dog extends Pet {

   public void introduce() {

       System.out.println("I'm Dog");
   }
}



public class Coyote extends WildAnimal {

   public void introduce() {

       System.out.println ("I'm Coyote");
   }
}
Kami secara khusus memilih kelas paling dasar untuk membuatnya lebih mudah dipahami. Kami tidak benar-benar membutuhkan bidang apa pun, dan satu metode sudah cukup. Mari kita coba jalankan kode ini:

public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
Menurut Anda apa yang akan ditampilkan di konsol? Akankah introducemetode kelas Petatau Animalkelas dipanggil? Cobalah membenarkan jawaban Anda sebelum melanjutkan membaca. Dan inilah hasilnya! Saya Pet Mengapa kita mendapatkan itu? Semuanya sederhana. Kami memiliki variabel induk dan objek keturunan. Dengan menulis,

Animal animal = new Pet();
kami memperluas Petreferensi dan menugaskannya ke Animalvariabel. Seperti tipe primitif, tipe referensi secara otomatis diperluas di Jawa. Anda tidak perlu menulis kode tambahan untuk mewujudkannya. Sekarang kami memiliki objek turunan yang ditugaskan ke referensi induk. Akibatnya, kita melihat bahwa pemanggilan metode dilakukan pada kelas keturunan. Jika Anda masih belum sepenuhnya memahami mengapa kode ini berfungsi, tulis ulang dalam bahasa sederhana:

Animal animal = new DomesticatedAnimal();
Tidak ada masalah dengan ini, kan? Bayangkan ini adalah kehidupan nyata, dan referensinya hanyalah sebuah label kertas dengan tulisan 'Hewan' di atasnya. Jika Anda mengambil selembar kertas itu dan menempelkannya ke kerah hewan peliharaan mana pun, semuanya akan beres. Lagi pula, hewan peliharaan apa pun adalah binatang! Proses sebaliknya — bergerak dari pohon warisan ke keturunan — menyempit:

public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
Seperti yang Anda lihat, di sini kami dengan jelas menunjukkan kelas yang ingin kami ubah objek kami. Kami sebelumnya memiliki WildAnimalvariabel, dan sekarang kami memiliki Coyote, yang lebih rendah di pohon warisan. Masuk akal bahwa tanpa indikasi eksplisit, kompiler tidak akan mengizinkan operasi seperti itu, tetapi jika kami menunjukkan jenisnya dalam tanda kurung, maka semuanya berfungsi. Pelebaran dan penyempitan jenis referensi - 2Pertimbangkan contoh lain yang lebih menarik:

public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal(); // Error!
   }
}
Kompiler menghasilkan kesalahan! Tapi kenapa? Karena Anda mencoba menetapkan objek induk ke referensi keturunan. Dengan kata lain, Anda mencoba melakukan sesuatu seperti ini:

DomesticatedAnimal domesticatedAnimal = new Animal();
Yah, mungkin semuanya akan berfungsi jika kita secara eksplisit menentukan jenis yang ingin kita konversi? Itu berhasil dengan angka - Mari kita coba! :)

public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
Pengecualian di utas "utama" java.lang.ClassCastException: Hewan tidak dapat dilemparkan ke Pet Error! Kompiler tidak membentak kami kali ini, tetapi kami berakhir dengan pengecualian. Kami sudah tahu alasannya: kami mencoba menetapkan objek induk ke referensi turunan. Tetapi mengapa Anda tidak bisa melakukan itu? Karena tidak semua Hewan adalah Hewan Domestik. Anda membuat sebuah Animalobjek dan mencoba untuk menugaskannya ke sebuah Petvariabel. Coyote juga merupakan Animal, tetapi bukan Pet. Dengan kata lain, saat Anda menulis

Pet pet = (Pet) new Animal();
new Animal()bisa mewakili binatang apa saja, belum tentu hewan peliharaan! Secara alami, Pet petvariabel Anda hanya cocok untuk menyimpan Hewan Piaraan (dan keturunannya) dan bukan jenis hewan apa pun. Itu sebabnya pengecualian Java khusus, ClassCastException, dibuat untuk kasus di mana terjadi kesalahan saat mentransmisikan kelas. Mari kita tinjau lagi untuk membuat semuanya lebih jelas. Referensi induk dapat menunjuk ke instance kelas keturunan:

public class Main {

   public static void main(String[] args) {

       Pet pet = new Pet();
       Animal animal = pet;

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
Misalnya, di sini kita tidak punya masalah. Kami memiliki Petobjek yang direferensikan oleh Petvariabel. Belakangan, Animalreferensi menunjuk ke objek yang sama. Setelah itu, kami mengonversi animalke file Pet. Ngomong-ngomong, mengapa itu berhasil untuk kita? Terakhir kali kami mendapat pengecualian! Karena kali ini objek asli kita adalah Pet!

Pet pet = new Pet();
Tapi dalam contoh terakhir, itu adalah Animalobjek:

Pet pet = (Pet) new Animal();
Anda tidak dapat menugaskan objek ancestor ke variabel turunan. Anda bisa melakukan sebaliknya.
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION