谈谈Java的匿名内部类
在很多时候,我们需要在类的内部初始化一个静态的Map或者List,然后保存一下常量值提供给类内部方法使用。
我们通常的做法是:
首先初始化一个Map的静态变量。
然后在静态块添加常量值:
Java代码
private final static Map<String, String> CONSTANT = new HashMap<String, String>(); static { CONSTANT.put("1", "one"); CONSTANT.put("2", "two"); }
其实还可以这么写:
Java代码
private final static Map<String, String> CONSTANT = new HashMap<String, String>() { { put("1", "one"); put("2", "two"); } };
如果对于这种方式比较陌生,那先看一个熟悉的:
Java代码
new Thread() { public void run() { System.out.println("Thread running!"); }; }.start();
实际上上面这段代码的意思就是,声明一个Thread的子类并重写Thread的run()方法,然后创建一个该子类的实例然后调用其start()方法。由于声明的该Thread的子类没有名字,所以叫匿名类。又由于没有名字的类只能存在于一个类或者一个方法内部,所以又称为匿名内部类。
匿名内部类的语法也可以这么写:
Java代码
Thread thread = new Thread() { public void run() { System.out.println("Thread running!"); }; }; thread.start();
唯一的区别就是不是直接创建子类并调用其方法,而是声明一个该子类的父类引用thread,然后通过该父类引用调用子类方法。
创建完匿名类的实例后,没有立即执行start(),创建实例和执行实例的方法分开。
两者的区别相当于:
Java代码
//1 new User().setName("Boyce Zhang"); //2 User user = new User(); user.setName("Boyce Zhang");
匿名内部类的另一个语法场景:
Java代码
new Thread() { public void run() { System.out.println("Thread running!"); }; { start(); } };
实际上这种写法就是在匿名子类的类局部代码块中调用其类方法。
局部代码块内的语句是在创建该类的实例后由类加载器隐式立即执行的。
相当于:
Java代码
public class MyThread extends Thread { { start(); } public void run() { System.out.println("Thread running!"); }; }
所以三种方式在执行的时刻上略微的差别之外,效果并没有太大的区别。
这样一来,前面初始化Map的方式就不难理解了:
Java代码
private final static Map<String, String> CONSTANT = new HashMap<String, String>() { { put("1", "one"); put("2", "two"); } };
原理就是:
声明并实例化一个HashMap的子类(子类没有重写父类HashMap的任何方法),并且在子类的类局部代码块调用父类HashMap的put()方法。
最后声明一个Map接口引用CONSTANT指向实例化的HashMap子类的实例。
根据前面的例子我们知道,类局部代码块中的put()方法调用将在HashMap的匿名子类被实例化后由类加载器隐式的执行。
其实,对于Java的任何类或接口,都可以声明一个匿名类继承或实现它。如:
Java代码
//重写父类方法,局部代码块调用自己重写过的父类方法。 List<String> list = new ArrayList<String>() { public boolean add(String e) { System.out.println("Cannot add anything!"); } //代码块的顺序在前后都无所谓,可以出现在类范围的任何位置。 { add("Boyce Zhang"); } }; //局部代码块调用父类方法。 dao.add(new User(){ { setName("Boyce Zhang"); setAge(26); } }); //重写父类方法 ThreadLocal<User> threadLocal = new ThreadLocal<User>() { protected String initialValue() { return new User("Boyce Zhang", 26); } };
在匿名类的内部我们不但可以实现或重写其父类的方法。
而且也可以在其类的局部代码块中执行自己的方法或者其父类的方法。
这并不是匿名内部类的特殊语法,而是Java的语法,对于任何类都适用。
这种写法常常就是用在实例化一个类后立即执行某些方法做一些类实例的数据初始化什么的。
其作用和先实例化一个类,在使用其引用调用需要立即调用的方法是一样的,如:
Java代码
Map<String, String> map = new HashMap<String, String>(); map.put("1", "one"); map.put("2", "two");
这种语法的优点就是简单,实例化一个类后立即做一些事情,比较方便。
效果有一点儿像Javascript里的即时函数一样。但是有本质的区别。
因为Javascript没有类的概念,或者说Javascript中function就是类,类就是function,所以即时函数是加载完后执行整个function。而Java的局部代码块是可以选择执行类的任何方法。
当然这种写法也有其缺点:
每一个内部类的实例都会隐性的持有一个指向外部类的引用(静态内部类除外),这样一方面是多余的引用浪费,另一方面当串行化这个子类实例时外部类也会被不知不觉的串行化,如果外部类没有实现serialize接口时,就会报错。
更多谈谈Java的匿名内部类相关文章请关注PHP中文网!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Kelas dalaman tanpa nama boleh menyebabkan kebocoran memori Masalahnya ialah mereka memegang rujukan kepada kelas luar, menghalang kelas luar daripada dikumpul. Penyelesaian termasuk: 1. Gunakan rujukan yang lemah Apabila kelas luar tidak lagi dipegang oleh rujukan yang kuat, pemungut sampah akan segera mengitar semula objek rujukan yang lemah memerlukan ingatan semasa pengumpulan sampah Hanya kemudian objek rujukan lembut dikitar semula. Dalam pertempuran sebenar, seperti dalam aplikasi Android, masalah kebocoran memori yang disebabkan oleh kelas dalaman tanpa nama boleh diselesaikan dengan menggunakan rujukan yang lemah, supaya kelas dalaman tanpa nama boleh dikitar semula apabila pendengar tidak diperlukan.

Kelas dalaman tanpa nama ialah kelas dalaman khas dalam Java yang tidak mempunyai nama eksplisit dan dicipta melalui ungkapan baharu Ia digunakan terutamanya untuk melaksanakan antara muka tertentu atau melanjutkan kelas abstrak dan digunakan serta-merta selepas penciptaan. Corak reka bentuk kelas dalaman tanpa nama biasa termasuk: Corak penyesuai: menukar satu antara muka kepada antara muka yang lain. Corak Strategi: Mentakrifkan dan Menggantikan Algoritma. Corak pemerhati: Daftar pemerhati dan kendalikan peristiwa. Ia sangat berguna dalam aplikasi praktikal, seperti menyusun TreeSet mengikut panjang rentetan, mencipta benang tanpa nama, dsb.

Kelas dalaman tanpa nama digunakan di Java sebagai kelas dalaman khas yang memudahkan subkelas, memudahkan kod dan mengendalikan acara (seperti klik butang). Kes praktikal termasuk: Pengendalian acara: Gunakan kelas dalaman tanpa nama untuk menambah pendengar acara klik untuk butang. Transformasi data: Isih koleksi menggunakan kaedah Collections.sort dan kelas dalaman tanpa nama sebagai pembanding.

Jangka hayat kelas dalam tanpa nama ditentukan oleh skopnya: Kaedah-kelas dalam tempatan: Sah hanya dalam skop kaedah yang menciptanya. Kelas dalaman pembina: terikat kepada contoh kelas luar dan dikeluarkan apabila tika kelas luar dikeluarkan. Kelas dalaman statik: dimuatkan dan dipunggah pada masa yang sama dengan kelas luaran.

Ralat penggunaan kelas dalaman tanpa nama: Mengakses pembolehubah di luar skop menggunakan menangkap pengecualian yang tidak diisytiharkan dalam persekitaran bukan benang selamat

Masalah prestasi kelas dalaman tanpa nama ialah ia dicipta semula setiap kali ia digunakan, yang boleh dioptimumkan melalui strategi berikut: 1. Simpan kelas dalaman tanpa nama dalam pembolehubah tempatan 2. Gunakan kelas dalaman bukan statik; ungkapan. Ujian praktikal menunjukkan bahawa pengoptimuman ekspresi lambda mempunyai kesan terbaik.

Ungkapan Lambda, sebagai alternatif kepada kelas dalaman tanpa nama, menyediakan cara yang lebih ringkas untuk mentakrifkan pelaksanaan antara muka berfungsi: gunakan sintaks pendek (parameter)->ungkapan untuk mentakrifkan fungsi tanpa nama. Sesuai untuk situasi di mana antara muka berfungsi perlu dilaksanakan (hanya satu kaedah abstrak). Boleh memudahkan tugas seperti menyusun senarai dan definisi benang.

Kelas dalaman tanpa nama memudahkan penciptaan kod berbilang benang, menghapuskan keperluan untuk menamakan dan mendayakan definisi segera dan penggunaan kelas benang. Kelebihan utama adalah untuk memudahkan kod, manakala hadnya ialah ia tidak boleh dilanjutkan. Gunakan apabila anda perlu membuat satu atau dua benang dengan cepat. Jika logik yang lebih kompleks diperlukan, fail kelas yang berasingan harus dibuat.
