在无限循环的上下文中有什么更好的:匿名类或嵌套类? 正如我所看到的,如果我们使用匿名类,它会为每次迭代重新定义,但是使用嵌套类我们仍然会创建一个实例,但是类本身并没有重新定义。不确定这是否正确......在这种情况下,使用one vs other是否有任何优势?
public class MainThread {
public static void main(String[] args){
while (true) {
final int data = rand.nextInt();
//Runnable task = new MyRunnable(data);
Runnable task = new Runnable() {
public void run() {
printData(data);
}
};
new Thread(task).start();
}
}
private static class MyRunnable implements Runnable {
private int data;
MyRunnable(int data){
this.data = data;
}
@Override
public void run() {
printData(data);
}
}
}
答案 0 :(得分:5)
两者之间没有区别。两者都在编译时转换为类文件,类文件可以与任何其他类一样运行,无需重新编译或重新定义"循环内的任何东西。
但是在某些情况下会有一些细微差别,这可以使内部类稍微提高效率(虽然它可能会被JIT消除)。如果匿名类在实例方法中完成,则它将被编译为非静态类,因此在构造它时需要复制它的this
引用包含类,这会添加一些字节码指令。这虽然可以忽略不计。
为了证明这一点,我写了这个小程序:
public class Test{
public void test(){
new Runnable(){
public void run(){
System.out.println("Anon");
}
}.run();
new Inner().run();
}
class Inner implements Runnable{
public void run(){
System.out.println("Inner");
}
}
static class Static implements Runnable{
public void run(){
System.out.println("Static");
}
}
}
这里是各个类推出的字节码:
测试:
public class Test {
public Test();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void test();
Code:
0: new #2 // class Test$1
3: dup
4: aload_0
5: invokespecial #3 // Method Test$1."<init>":(LTest;)V
8: invokevirtual #4 // Method Test$1.run:()V
11: new #5 // class Test$Inner
14: dup
15: aload_0
16: invokespecial #6 // Method Test$Inner."<init>":(LTest;)V
19: invokevirtual #7 // Method Test$Inner.run:()V
22: return
}
测试$ 1(匿名类):
class Test$1 implements java.lang.Runnable {
final Test this$0;
Test$1(Test);
Code:
0: aload_0
1: aload_1
2: putfield #1 // Field this$0:LTest;
5: aload_0
6: invokespecial #2 // Method java/lang/Object."<init>":()V
9: return
public void run();
Code:
0: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 // String Anon
5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
测试$ Inner(内部类):
class Test$Inner implements java.lang.Runnable {
final Test this$0;
Test$Inner(Test);
Code:
0: aload_0
1: aload_1
2: putfield #1 // Field this$0:LTest;
5: aload_0
6: invokespecial #2 // Method java/lang/Object."<init>":()V
9: return
public void run();
Code:
0: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 // String Inner
5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
测试$ Static(静态内部类):
class Test$Static implements java.lang.Runnable {
Test$Static();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void run();
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Static
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
从这里看,您可以看到唯一的区别是静态类的构造函数略小。
答案 1 :(得分:4)
匿名内部类不会为每次调用重新定义&#34; - 它们应该具有与内部类完全相同的开销,除了你的内部类是静态的,因此避免保留对外部myIframe
的引用(如果有的话)。
如果您编译上面的程序,您将看到几个生成的类:
this
反编译$ 1(=你的内部匿名类)和$ MyRunnable(=你的内部命名类)表明它们基本相同:
MainThread$1.class
MainThread.class
MainThread$MyRunnable.class
并且
MainThread$1(int);
Code:
0: aload_0
1: iload_1
2: putfield #1 // Field val$data:I
5: aload_0
6: invokespecial #2 // Method java/lang/Object."<init>":()V
9: return
public void run();
Code:
0: aload_0
1: getfield #1 // Field val$data:I
4: invokestatic #3 // Method MainThread.printData:(I)V
7: return
唯一的区别是匿名内部类不存储数据&#39;在它的构造函数中,而是从外部静态最终变量中读取它。