PS: 觉得写得可以,喜欢就点个赞啦亲们
今天在看别人的代码的时候,发现有
Yyy uu=new Xxx(){ public void aaa(){ //这里写代码。。。 } } 12345
这种形式,以前偶尔看见过,也知道是匿名内部类的情况,但一直没有仔细去研究,今天特意花点时间去写了点很简单也易懂的例子,初学时需要的技术不在于复杂程度,能让人看得懂的代码才是好代码,希望能帮助大家:
a.新建一个接口:
public interface InterfaceTest {public String getName();public String getAge(); } 1234
b.新建一个测试类:
package test; public class NewInterfaceDemo {public static void main(String[] args) {InterfaceTest test=new InterfaceTest() {//直接就new InterfaceTest() 敲回车后下面的方法会自动出来的@Overridepublic String getName() {return "小明";}@Overridepublic String getAge() {return "5";}};System.out.println(test.getName()+test.getAge()+"岁啦");} } 1234567891011121314151617181920
运行后打印出:
这是最简单的匿名内部类的例子,实际上看得懂就可以举一反三了,比如不是接口,而是抽象类的抽象方法,也是可以直接new 抽象类(){抽象方法}的。以上的例子相当于写了一个实现类,如:
public class InterfaceTestImpl implements InterfaceTest {@Overridepublic String getName() {return "小明";}@Overridepublic String getAge() {return "5";}public static void main(String[] args) {InterfaceTest test=new InterfaceTestImpl();System.out.println(test.getName()+test.getAge()+"岁啦");} } 1234567891011121314151617
有时候我们看到的new一个Class,虽然这个class不是抽象类也不是接口,就是一个实实在在的类,然后后面也可以跟一个大括号,这又是怎么回事呢?我们可以直接拿非常常见的HashMap类来做这个例子:
public class Test { public static void main(String[] args) { Map<String, String> map2=new HashMap<String,String>(){@Overridepublic String put(String var1, String var2) {var1="key_value";//a行var2="重写后的值";//b行return super.put(var1, var2);} }; map2.put("start_key", "不知道start_key的值是不是这个"); System.out.println("找到start_key的值: "+map2.get("start_key")); System.out.println("虽然没有明显把key_value当key赋值,尝试尝试key_value的值: "+map2.get("key_value"));} } 123456789101112131415
这例子够简单吧,我们这里看下输出:
明明后面是写了map2.put(“start_key”, “不知道start_key的值是不是这个”);,为什么输出map2.get(“start_key”)的值是null呢?原因是代码中的a行b行重写了hashmap的put方法,把值给改过来了,实际上他们操作的是map2.put(“key_value”,“重写后的值”)! 所以从这里可以看出,在new 对象后,后面还跟着大括号,又直接写了个方法,这种情况下就是重写当前类的这个方法了,不过需要注意的是:该重写的方法只对当前对象有用!
不知道这种写法怎么说,就是new对象后,后面跟着两个大括号,比如:
List<String> list = new ArrayList<String>() { { add("a"); add("b"); } }; System.out.println("list长度: "+list.size()); 1234567
然后这代码输出的是list长度:2 事实上就可以知道,在new ArrayList的时候,创建构造函数时顺便给list对象添加了a b两个值了,所以list的长度为2
再弄个hashmap的:
Map<String, String> map=new HashMap<String,String>(){{put("haha", "heiehi");} }; System.out.println(map.get("haha")); 123456
输出heihei
好了 这是怎么实现的呢?
从表面上看,其实内大括号使用的是this.add()方法,也就是说,这个方法也只是当前对象有效,其他你再new ArrayList()的时候,所得的对象长度就是0 而不是2了。
如果深入了解,我们可以把这个文件进行编译,源代码为:
public class BianyiClass {public static void main(String[] args) { List<String> list = new ArrayList<String>() { { add("a"); add("b"); } };} } 12345678910
提取出来放入D盘:
然后进行编译:
得到class文件:
可以看到产生了两个class文件,我们使用java自带的javap进行反编译查看BianyiClass.class文件:
太长了复制出来看一下:
D:>javap -verbose BianyiClass.class//这是直接在cmd窗口写的,下面是反编译出来的代码 Classfile /D:/BianyiClass.class Last modified 2018-11-16; size 344 bytes MD5 checksum a180fea3ce00b955e16a1fff9242e64a Compiled from "BianyiClass.java" public class test.BianyiClass minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #5.#15 // java/lang/Object."<init>":()V #2 = Class #16 // test/BianyiClass$1 #3 = Methodref #2.#15 // test/BianyiClass$1."<init>":()V #4 = Class #17 // test/BianyiClass #5 = Class #18 // java/lang/Object #6 = Utf8 InnerClasses #7 = Utf8 <init> #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 main #12 = Utf8 ([Ljava/lang/String;)V #13 = Utf8 SourceFile #14 = Utf8 BianyiClass.java #15 = NameAndType #7:#8 // "<init>":()V #16 = Utf8 test/BianyiClass$1 #17 = Utf8 test/BianyiClass #18 = Utf8 java/lang/Object { public test.BianyiClass(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 6: 0 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: new #2 // class test/BianyiClass$1 3: dup 4: invokespecial #3 // Method test/BianyiClass$1."<init>":()V 7: astore_1 8: return LineNumberTable: line 9: 0 line 15: 8 } SourceFile: "BianyiClass.java" InnerClasses: static #2; //class test/BianyiClass$1 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
有点眼花缭乱。。。。。。。。。。。。。。。。。。。缓一下神。。。。。。。。。。。
仔细看一看,发现其实查看时,自动有备注的,哈哈,继续往下,发现
class test/BianyiClass$1
这个备注,说明了这个编译文件,new了一个对象,在BianyiClass$1里面,然后我们继续javapBianyiClass$1文件吧:
把得到的信息粘贴出来:
D:>javap -verbose BianyiClass$1.class Classfile /D:/BianyiClass$1.class Last modified 2018-11-16; size 468 bytes MD5 checksum edefcd30c6aa2ed4935340e149a2c92f Compiled from "BianyiClass.java" final class test.BianyiClass$1 extends java.util.ArrayList<java.lang.String> minor version: 0 major version: 52 flags: ACC_FINAL, ACC_SUPER Constant pool: #1 = Methodref #6.#18 // java/util/ArrayList."<init>":()V #2 = String #19 // a #3 = Methodref #5.#20 // test/BianyiClass$1.add:(Ljava/lang/Object;)Z #4 = String #21 // b #5 = Class #22 // test/BianyiClass$1 #6 = Class #24 // java/util/ArrayList #7 = Utf8 <init> #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 Signature #12 = Utf8 Ljava/util/ArrayList<Ljava/lang/String;>; #13 = Utf8 SourceFile #14 = Utf8 BianyiClass.java #15 = Utf8 EnclosingMethod #16 = Class #25 // test/BianyiClass #17 = NameAndType #26:#27 // main:([Ljava/lang/String;)V #18 = NameAndType #7:#8 // "<init>":()V #19 = Utf8 a #20 = NameAndType #28:#29 // add:(Ljava/lang/Object;)Z #21 = Utf8 b #22 = Utf8 test/BianyiClass$1 #23 = Utf8 InnerClasses #24 = Utf8 java/util/ArrayList #25 = Utf8 test/BianyiClass #26 = Utf8 main #27 = Utf8 ([Ljava/lang/String;)V #28 = Utf8 add #29 = Utf8 (Ljava/lang/Object;)Z { test.BianyiClass$1(); descriptor: ()V flags: Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/util/ArrayList."<init>":()V 4: aload_0 5: ldc #2 // String a 7: invokevirtual #3 // Method add:(Ljava/lang/Object;)Z 10: pop 11: aload_0 12: ldc #4 // String b 14: invokevirtual #3 // Method add:(Ljava/lang/Object;)Z 17: pop 18: return LineNumberTable: line 9: 0 line 11: 4 line 12: 11 line 13: 18 } Signature: #12 // Ljava/util/ArrayList<Ljava/lang/String;>; SourceFile: "BianyiClass.java" EnclosingMethod: #16.#17 // test.BianyiClass.main InnerClasses: static #5; //class test/BianyiClass$1 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
又是眼花缭乱。。。
注意看这一句:final class test.BianyiClass$1 extends java.util.ArrayList<java.lang.String> 原来是new了一个ArrayList的子类,只不过这个子类是匿名子类。
这个大括号里面的内容,实际上是创建构造函数时的内容,抽取出来看一下:
{ test.BianyiClass$1(); descriptor: ()V flags: Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/util/ArrayList."<init>":()V 4: aload_0 5: ldc #2 // String a 7: invokevirtual #3 // Method add:(Ljava/lang/Object;)Z 10: pop 11: aload_0 12: ldc #4 // String b 14: invokevirtual #3 // Method add:(Ljava/lang/Object;)Z 17: pop 18: return LineNumberTable: line 9: 0 line 11: 4 line 12: 11 line 13: 18 } 1234567891011121314151617181920212223
然后再看这句:
11 7: invokevirtual #3 // Method add:(Ljava/lang/Object;)Z
还有这句:
15 14: invokevirtual #3 // Method add:(Ljava/lang/Object;)Z
明白了吧,实际上在初始化对象时,这个对象已经添加两次信息了,也就是那个a和b!
至此,就已经知道执行原理了!
PS: 觉得写得可以,喜欢就点个赞啦亲们
相关知识
用c语言写一朵最简单的花
怎么用Python按照笔画顺序来写自己的名字
[JAVASE错题]01
《JAVA语言程序设计》期末考试试题及答案
Java基于j2ee+mysql的花鸟鱼虫花卉市场管理系统
matlab绘制花朵
python绘制一朵栀子花
python画栀子花代码
网上售花系统(含源代码)资源
Kotlin 学习笔记 (九) 可怕的 lambda 及 高级函数
网址: java匿名内部类的使用 (比如new对象后的大括号, List<String> list = new ArrayList<String>() { { }}这用用法等) https://m.huajiangbk.com/newsview1143855.html
上一篇: 奇妙鲜花房常见问题 |
下一篇: 办公室装修吊顶有哪几种? |