JavaRush /Java Blog /Random-ID /Perluasan dan kontraksi tipe referensi

Perluasan dan kontraksi tipe referensi

Dipublikasikan di grup Random-ID
Halo! Dalam salah satu kuliah sebelumnya, kita membahas casting tipe primitif. Mari kita ingat secara singkat apa yang sedang kita bicarakan. Perluasan dan kontraksi tipe referensi - 1Kami merepresentasikan tipe primitif (dalam hal ini, numerik) sebagai boneka bersarang berdasarkan jumlah memori yang ditempati. Seperti yang Anda ingat, menempatkan boneka bersarang yang lebih kecil ke dalam boneka yang lebih besar akan mudah dilakukan baik dalam kehidupan nyata maupun dalam pemrograman Java.
public class Main {
   public static void main(String[] args) {
        short smallNumber = 100;
        int bigNumber =  smallNumber;
        System.out.println(bigNumber);
   }
}
Ini adalah contoh konversi atau ekstensi otomatis . Itu terjadi dengan sendirinya, jadi tidak perlu menulis kode tambahan. Pada akhirnya, kami tidak melakukan sesuatu yang aneh: kami hanya memasukkan boneka bersarang yang lebih kecil ke dalam boneka bersarang yang lebih besar. Lain halnya jika kita mencoba melakukan yang sebaliknya dan memasukkan boneka matryoshka yang besar ke dalam boneka yang lebih kecil. Hal ini tidak dapat dilakukan dalam kehidupan, tetapi dalam pemrograman hal ini dapat dilakukan. Tapi ada satu peringatan. Jika kita mencoba memasukkan nilai intke dalam variabel short, hasilnya tidak akan semudah itu. Lagi pula, hanya 16 bit informasi yang dapat dimasukkan ke dalam suatu variabel short, tetapi nilainya intmembutuhkan 32 bit! Akibatnya, nilai yang dikirimkan akan terdistorsi. Kompiler akan memberi kita kesalahan (" kawan, Anda melakukan sesuatu yang mencurigakan! "), tetapi jika kita secara eksplisit menentukan tipe apa yang kita gunakan untuk memberikan nilai, ia akan tetap melakukan operasi seperti itu.
public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
Pada contoh di atas, kami melakukan hal itu. Operasi selesai, tetapi karena shorthanya 16 dari 32 bit yang masuk ke dalam variabel, nilai akhirnya terdistorsi, dan sebagai hasilnya kami mendapatkan nomor -27008 . Operasi ini disebut konversi eksplisit, atau penyempitan .

Contoh ekstensi dan kontraksi tipe referensi

Sekarang kita akan berbicara tentang operasi yang sama, tetapi tidak berlaku untuk tipe primitif, tetapi untuk objek dan variabel referensi ! Bagaimana cara kerjanya di Jawa? Sebenarnya cukup sederhana. Ada objek yang tidak berhubungan satu sama lain. Masuk akal untuk berasumsi bahwa keduanya 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 kita tentu saja akan mendapatkan error. Kelas-kelas tersebut Cattidak Dogberhubungan satu sama lain, dan kami belum menulis “pengubah” dari satu kelas ke kelas lainnya. Masuk akal jika kami tidak dapat melakukan ini: kompiler tidak tahu cara mengonversi objek ini satu sama lain. Lain halnya jika benda-benda itu saling terhubung! Bagaimana? Pertama-tama, menggunakan warisan. Mari kita coba membuat sistem kelas kecil dengan pewarisan. Kami akan memiliki kelas umum yang mewakili hewan:
public class Animal {

   public void introduce() {

       System.out.println("i'm Animal");
   }
}
Hewan, seperti yang Anda tahu, bersifat domestik dan 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");
   }
}
Sebagai contoh, mari kita ambil anjing - anjing peliharaan dan anjing hutan:
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");
   }
}
Kelas kami sengaja dibuat paling primitif agar lebih mudah dipahami. Kami tidak terlalu membutuhkan kolom di sini, dan satu metode saja sudah cukup. Mari kita coba jalankan kode berikut:
public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
Menurut Anda apa yang akan dihasilkan ke konsol? introduceApakah metode kelas Petatau kelas akan berhasil Animal? Cobalah untuk membenarkan jawaban Anda sebelum melanjutkan membaca. Dan inilah hasilnya! aku Pet Kenapa jawabannya jadi seperti ini? Itu mudah. Kami memiliki variabel induk dan objek anak. Dengan menulis:
Animal animal = new Pet();
Kami telah memperluas tipe referensiPet dan menyimpan objeknya dalam sebuah variabel Animal. Seperti halnya tipe primitif, perluasan tipe referensi di Java dilakukan secara otomatis. Tidak perlu menulis kode tambahan untuk ini. Sekarang kita mempunyai objek anak yang melekat pada referensi induk, dan sebagai hasilnya kita melihat bahwa metode tersebut dipanggil pada kelas anak. Jika Anda masih belum sepenuhnya memahami mengapa kode ini berfungsi, tulis ulang dalam bahasa sederhana:
Животное животное = new ДомашнееЖивотное();
Tidak ada masalah dengan itu, kan? Bayangkan ini adalah kehidupan nyata, dan tautan dalam hal ini adalah label kertas sederhana yang bertuliskan “Hewan.” Jika Anda mengambil selembar kertas dan menempelkannya ke kerah hewan peliharaan mana pun, semuanya akan baik-baik saja. Hewan peliharaan apa pun tetaplah binatang! Proses sebaliknya, yaitu penurunan pohon warisan kepada ahli waris, bersifat penyempitan:
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 secara eksplisit menunjukkan ke kelas mana kami ingin melemparkan objek kami. Sebelumnya kita mempunyai variabel WildAnimal, dan sekarang Coyote, yang turun ke pohon warisan. Adalah logis bahwa kompiler tidak akan melewatkan operasi seperti itu tanpa indikasi yang jelas, tetapi jika Anda menentukan tipe dalam tanda kurung, semuanya akan berfungsi. Perluasan dan kontraksi tipe referensi - 2 Mari kita lihat contoh lain yang lebih menarik:
public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal();//error!
   }
}
Kompiler membuat kesalahan! Apa alasannya? Faktanya adalah Anda mencoba untuk menetapkan objek induk ke variabel anak. Dengan kata lain, Anda ingin melakukan ini:
ДомашнееЖивотное домашнееЖивотное = new Животное();
Tapi mungkin jika kita secara eksplisit menunjukkan tipe yang kita coba gunakan, kita akan berhasil? Angka-angkanya sepertinya berhasil, ayo kita coba! :)
public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
Pengecualian di thread "utama" java.lang.ClassCastException: Hewan tidak dapat dilemparkan ke Pet Error! Kompiler tidak mengeluh kali ini, tetapi sebagai hasilnya kami menerima pengecualian. Kita sudah mengetahui alasannya: kita mencoba untuk menugaskan objek induk ke variabel anak. Mengapa sebenarnya hal ini tidak bisa dilakukan? Karena tidak semua Hewan adalah Hewan Peliharaan. Anda membuat objek Animaldan mencoba menugaskannya ke variabel Pet. Namun, misalnya, seekor coyote juga merupakan hewan peliharaan Animal, namun bukan merupakan Pethewan peliharaan. Dengan kata lain, saat Anda menulis:
Pet pet = (Pet) new Animal();
new Animal()Hewan apa pun boleh berada di sana , dan tidak harus hewan peliharaan! Tentu saja, variabel Anda Pet pethanya cocok untuk menyimpan hewan peliharaan (dan keturunannya), dan tidak untuk semua orang. Oleh karena itu, untuk kasus seperti itu, pengecualian khusus dibuat di Java - ClassCastExceptionkesalahan saat mentransmisikan kelas. Mari kita ulangi lagi agar lebih jelas. Variabel induk (referensi) dapat menunjuk ke objek kelas turunan:
public class Main {

   public static void main(String[] args) {

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

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
Misalnya, kami tidak akan mendapat masalah apa pun di sini. Kami memiliki objek Petyang ditunjuk oleh tautan Pet. Kemudian link baru mulai menunjuk ke objek yang sama Animal. Setelah itu kita melakukan konversi animalke Pet. Mengapa kami melakukan ini? Terakhir kali kami mendapat pengecualian! Karena kali ini objek asli kita adalah Pet pet!
Pet pet =  new Pet();
Dan pada contoh sebelumnya itu adalah sebuah objek Animal:
Pet pet = (Pet) new Animal();
Variabel turunan tidak dapat ditetapkan sebagai objek leluhur. Sebaliknya, Anda bisa melakukannya.
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION