谈谈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中文网!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Les classes internes anonymes peuvent provoquer des fuites de mémoire. Le problème est qu'elles contiennent une référence à la classe externe, empêchant ainsi la classe externe d'être récupérée. Les solutions incluent : 1. Utiliser des références faibles. Lorsque la classe externe n'est plus détenue par une référence forte, le garbage collector recyclera immédiatement l'objet de référence faible ; 2. Utiliser des références logicielles lorsqu'il sera utilisé. a besoin de mémoire pendant le garbage collection. Ce n'est qu'alors que l'objet de référence logiciel est recyclé. En combat réel, comme dans les applications Android, le problème de fuite de mémoire provoqué par des classes internes anonymes peut être résolu en utilisant des références faibles, de sorte que la classe interne anonyme puisse être recyclée lorsque l'écouteur n'est pas nécessaire.

Les classes internes anonymes sont des classes internes spéciales en Java qui n'ont pas de nom explicite et sont créées via la nouvelle expression. Elles sont principalement utilisées pour implémenter des interfaces spécifiques ou étendre des classes abstraites et sont utilisées immédiatement après la création. Les modèles de conception de classe interne anonymes courants incluent : Modèle d’adaptateur : convertit une interface en une autre interface. Modèle de stratégie : définition et algorithmes de remplacement. Modèle d'observateur : enregistrez les observateurs et gérez les événements. C'est très utile dans des applications pratiques, telles que le tri d'un TreeSet par longueur de chaîne, la création de threads anonymes, etc.

Les classes internes anonymes sont utilisées en Java en tant que classes internes spéciales qui facilitent le sous-classement, la simplification du code et la gestion des événements (tels que les clics sur des boutons). Les cas pratiques incluent : Gestion des événements : utilisez des classes internes anonymes pour ajouter des écouteurs d'événements de clic pour les boutons. Transformation des données : triez les collections à l'aide de la méthode Collections.sort et d'une classe interne anonyme comme comparateur.

Erreur d'utilisation de classe interne anonyme : accès à une variable hors de portée en interceptant une exception non déclarée dans un environnement non thread-safe

Le problème de performances des classes internes anonymes est qu'elles sont recréées à chaque fois qu'elles sont utilisées, ce qui peut être optimisé grâce aux stratégies suivantes : 1. Stocker les classes internes anonymes dans des variables locales 2. Utiliser des classes internes non statiques 3. Utiliser lambda ; expressions. Des tests pratiques montrent que l'optimisation de l'expression lambda a le meilleur effet.

La durée de vie d'une classe interne anonyme est déterminée par sa portée : Classe interne locale à la méthode : valide uniquement dans la portée de la méthode qui l'a créée. Classe interne du constructeur : liée à l'instance de classe externe et libérée lorsque l'instance de classe externe est libérée. Classes internes statiques : chargées et déchargées en même temps que les classes externes.

Les classes internes anonymes ne conviennent pas lorsque : besoin d'accéder à des membres privés, besoin de plusieurs instances, besoin d'héritage, besoin d'accéder à des types génériques

Les classes internes anonymes simplifient la création de code multithread, éliminant le besoin de nommer et permettant la définition et l'utilisation instantanées des classes de thread. Le principal avantage est de simplifier le code, tandis que la limitation est qu'il ne peut pas être étendu. À utiliser lorsque vous devez créer rapidement un ou deux threads. Gardez le code court. Si une logique plus complexe est requise, un fichier de classe distinct doit être créé.
