首页 > 编程知识 正文

java中的匿名类,java匿名内部类有什么用

时间:2023-05-04 23:16:06 阅读:241448 作者:341

匿名内部类,顾名思义,就是没有名字的类,匿名内部类格式如下:

new name(parameter){ ......}
name:父类或是接口的名字。

parameter:若name为父类,则parameter为父类构造函数的参数。


匿名内部类具有一系列的限制,原因待会解释:

1、不能具有static成员域和成员函数和类。

2、不能具有static final 修饰的引用类型。

3、不能有自定义的构造函数。

4、不能具有静态代码块。

5、匿名内部类不能有类修饰符


使用匿名内部类的方式:

class A{ int clsvalue; A(int v) { clsvalue=v; }}interface B{ int invalue=0;}public class Try { public static void main(String[] args) { /*方法一:利用父类或接口的引用指向匿名内部类,此时引用只能访问父类或是接口中的成员域和成员函数, 例如下面的a和b只能访问clsvalue和invalue,无法访问x和y。但可以使用被覆盖的方法。 */ A a= new A(1) { static final int x=0; }; B b=new B() { static final int y=0; }; /*大气的灯泡:直接通过下列代码访问,此时可以访问父类或接口、匿名内部类中定义的成员域或是成员方法。但只能使用一次(由于没有变量名)*/ new A(2){static final int y=0;}; }}


匿名内部类仅仅是局部有效的,方法一仅在作用域内有效,大气的灯泡仅在当行代码中有效。


接下来我们编译如下代码:

class A{ int clsvalue; A(int v) { clsvalue=v; }}public class Try { public static void main(String[] args) { A a= new A(1){ }; }}
首先,匿名内部类会有属于自己的class文件。反编译匿名内部类的class文件得:

Last modified 2018-2-6; size 274 bytes MD5 checksum e1349e62178fb6ad8402c5ec6ffe0bbf Compiled from "Try.java"final class Try$1 extends A minor version: 0 major version: 52 flags: ACC_FINAL, ACC_SUPERConstant pool: #1 = Methodref #3.#13 // A."<init>":(I)V #2 = Class #14 // Try$1 #3 = Class #16 // A #4 = Utf8 <init> #5 = Utf8 (I)V #6 = Utf8 Code #7 = Utf8 LineNumberTable #8 = Utf8 SourceFile #9 = Utf8 Try.java #10 = Utf8 EnclosingMethod #11 = Class #17 // Try #12 = NameAndType #18:#19 // main:([Ljava/lang/String;)V #13 = NameAndType #4:#5 // "<init>":(I)V #14 = Utf8 Try$1 #15 = Utf8 InnerClasses #16 = Utf8 A #17 = Utf8 Try #18 = Utf8 main #19 = Utf8 ([Ljava/lang/String;)V{ Try$1(int); descriptor: (I)V flags: Code: stack=2, locals=2, args_size=2 0: aload_0 //将this指针从局部变量表压入操作数栈。 1: iload_1 //将局部变量表中的int型变量的值压入操作数栈 2: invokespecial #1 // Method A."<init>":(I)V,调用父类构造函数,首先传入栈顶的int型变量,接着将值写入this指针所指内存的对应位置。 5: return LineNumberTable: line 11: 0}SourceFile: "Try.java"EnclosingMethod: #11.#12 // Try.mainInnerClasses: static #2; //class Try$1 首先注意到匿名内部类的类修饰符为final,且编译器自动加上了extends A,若name为接口,则为implements+接口名。

编译器会根据parameter创建一个匿名内部类的构造函数。

问题出现了,从类文件来看,匿名内部类和普通的类没什么不同,我们知道可以用父类引用指向子类对象,并且可以通过父类引用调用子类方法和成员域,但匿名内部类的父类引用不行(即用方法一使用匿名内部类),为什么要这么设计?下面谈谈我自己的理解:


从使用角度来看:由匿名内部类的生命周期,我们可以知道,使用匿名内部类是为了使用一种'短期"效果,若父类是抽象类(接口),我们可以随时定义一个抽象方法使用,若类不是抽象类,我们可以使用在子类中被覆盖的方法,该功能的方法我们只想使用一次(或在当前作用域使用),此时我们便不用再去另外定义一个类,代码也更加简洁,可读性也更强(不然可能还需要拼命滑鼠标去找类,一串代码找的很痛苦的!)。当然,若父类是抽象类或接口,我们要定义所有的抽象方法。

以上,匿名内部类的父类引用只能访问父类的(被覆盖的)成员方法和成员域,设计者这么做应该是让匿名内部类的使用目的更加明确。

接下来解释各种限制的原因,以下均为个人理解:


1、为什么不能具有静态成员域和成员函数、静态代码块、static final修饰的引用类型、静态内部类?


答:和实名内部类类似,“静态”意味着与实例对象无关就可以访问,从匿名内部类的使用代码(方法一、大气的灯泡)我们可以看到,其一定会实例化一个对象,此时使用“静态”便毫无意义。static final修饰引用类型的目的:1、不需要实例对象就可访问,2、不希望指针指向改变,匿名内部类的使用方式使1变得毫无意义,所以规定不能用static final修饰引用类型,由于匿名内部类没有名字,想要使用静态内部类必须通过一个匿名内部类的实例对象,与“静态”定义矛盾。


2、为什么不能有自定义构造函数?


答:从class文件中,我们可以看到匿名内部类其实含有编译器自动加上的构造函数,且JVM只调用该构造函数,自定义构造函数无效,另外,匿名内部类名字都没有怎么定义构造函数(滑稽.jpg)?


3、为什么匿名内部类不能有类修饰符?

emmmm,加类修饰符可能与有效域冲突,例如加public,但匿名内部类只在当前作用域或是当前行有效,且这些类修饰符本来就是规定访问范围的,但匿名内部类访问范围已经规定。


4、为什么可以有static final修饰的具有字面量的变量?

其实对于匿名内部类来说,static final与final修饰的具有字面量的变量效果一样,只是初始化时机不一样,保存位置不一样,对于性能没有太多影响,所以保留。


如有错误,欢迎各位指出,另附实名内部类详解:点击打开链接

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。