Java中的私有内部类是否存在性能开销?

时间:2021-11-23 23:28:40

When I have inner classes with private methods or fields the compiler has to create synthetic package-protected accessor methods to allow the outer class to access those private elements (and vice-versa).

当我有具有私有方法或字段的内部类时,编译器必须创建合成包保护的访问器方法,以允许外部类访问这些私有元素(反之亦然)。

To avoid that, I usually make all fields and methods and constructors package-protected instead of private.

为了避免这种情况,我通常将所有字段、方法和构造函数都设置为包保护,而不是私有。

But how about the visibility of the class itself? Is there an overhead to

但是类本身的可见性呢?有开销吗

 private static class A {
      A(){}
 }

versus

 static class A {
      A(){}
 }

Note that the constructor is package-protected in both cases, or does making the class private change that?

注意,构造函数在这两种情况下都是受包保护的,或者使类private更改这一点吗?

3 个解决方案

#1


16  

Have you tried compiling it and comparing the byte code? Here are my results. For:

您试过编译它并比较字节码吗?这是我的结果。:

public class Example {
  public static void main(String[] args) {
    System.out.println("Hello world!");
  }
  private static class A {
    A(){}
  }
}

The above yields the following *.class files:

上述结果产生如下*。类文件:

-rw-r--r--    1 michaelsafyan  staff   238 Feb 10 00:11 Example$A.class
-rw-r--r--    1 michaelsafyan  staff   474 Feb 10 00:11 Example.class

Now, if I move the class files, delete the private modifier, and recompile, I get:

现在,如果我移动类文件,删除私有修饰符,重新编译,我得到:

 -rw-r--r--    1 michaelsafyan  staff   238 Feb 10 00:15 Example$A.class
 -rw-r--r--    1 michaelsafyan  staff   474 Feb 10 00:15 Example.class

If you look at the VM Spec on class files, you'll see that there is a constant-sized bit field for specifying the access modifiers, so it should not be any surprise that the generated files are the same size.

如果查看类文件上的VM规范,您将看到有一个常量大小的位字段用于指定访问修饰符,因此生成的文件大小相同并不奇怪。

In short, your access modifiers won't affect the size of the generated byte code (it also should not have any performance impact, either). You should use the access modifier that makes the most sense.

简而言之,您的访问修饰符不会影响生成的字节代码的大小(它也不应该对性能产生任何影响)。您应该使用最有意义的访问修饰符。

I should also add that there is a slight difference if you change the inner class from being declared static to not being declared static, as it implies an additional field referencing the outer class. This will take up slightly more memory than if you declared the inner class static, but you'd be insane to optimize for this (use static where it makes sense, and where you need it to be non-static, make it non-static, but don't convolute your design just to save a pointer of memory here or there).

我还应该补充一点,如果您将内部类从声明为静态更改为不声明为静态,则会有少许不同,因为它意味着引用外部类的附加字段。这将占用内存略高于如果你宣布静态内部类,但你会疯狂的优化(使用静态,它是有意义的,你需要非静态,非静态,但不要旋卷设计为了节省内存的指针在这里或那里)。

#2


7  

There should be no performance difference between a private inner class and a non-private inner class.

私有内部类和非私有内部类之间不应该存在性能差异。

There should be no performance difference between a static inner class (private or not) and an outer class.

静态内部类(私有类或非私有类)和外部类之间不应存在性能差异。

There is a small performance difference between a static inner class and a non-static inner class. This difference is due to the fact that the non-static case has an hidden reference to the instance of its enclosing class. This is passed as an extra parameter to the inner classes constructor, and stored in a hidden variable.

静态内部类和非静态内部类的性能差异很小。这种差异是由于非静态情况对其封闭类的实例有一个隐藏引用。它作为一个额外的参数传递给内部类构造函数,并存储在一个隐藏的变量中。

#3


4  

It is very unlikely this will ever cause any significant slow-down.

这很不可能导致任何重大的放缓。

One issue to be aware of with non-static inner classes is that they contain a reference to the instance of the enclosing class.

非静态内部类要注意的一个问题是,它们包含对封闭类实例的引用。

As such, this can cause 'memory leaks', as the enclosing instance can't be garbage collected. If you pass instances of inner classes out to callers, you are also passing out an instance of the enclosing class.

因此,这会导致“内存泄漏”,因为封装实例不能被垃圾收集。如果您将内部类的实例传递给调用者,那么您也在传递封闭类的实例。

This is not the case with static inner classes!

这不是静态内部类的情况!

Making all fields package protected to prevent synthetic methods is not advisable. You are giving up encapsulation which is a valuable thing to have. What are your concerns? Size of your class files for the additional code?

不建议使所有的字段包被保护以防止合成方法。您正在放弃封装,这是一个有价值的东西。你的担忧是什么?附加代码的类文件的大小?

#1


16  

Have you tried compiling it and comparing the byte code? Here are my results. For:

您试过编译它并比较字节码吗?这是我的结果。:

public class Example {
  public static void main(String[] args) {
    System.out.println("Hello world!");
  }
  private static class A {
    A(){}
  }
}

The above yields the following *.class files:

上述结果产生如下*。类文件:

-rw-r--r--    1 michaelsafyan  staff   238 Feb 10 00:11 Example$A.class
-rw-r--r--    1 michaelsafyan  staff   474 Feb 10 00:11 Example.class

Now, if I move the class files, delete the private modifier, and recompile, I get:

现在,如果我移动类文件,删除私有修饰符,重新编译,我得到:

 -rw-r--r--    1 michaelsafyan  staff   238 Feb 10 00:15 Example$A.class
 -rw-r--r--    1 michaelsafyan  staff   474 Feb 10 00:15 Example.class

If you look at the VM Spec on class files, you'll see that there is a constant-sized bit field for specifying the access modifiers, so it should not be any surprise that the generated files are the same size.

如果查看类文件上的VM规范,您将看到有一个常量大小的位字段用于指定访问修饰符,因此生成的文件大小相同并不奇怪。

In short, your access modifiers won't affect the size of the generated byte code (it also should not have any performance impact, either). You should use the access modifier that makes the most sense.

简而言之,您的访问修饰符不会影响生成的字节代码的大小(它也不应该对性能产生任何影响)。您应该使用最有意义的访问修饰符。

I should also add that there is a slight difference if you change the inner class from being declared static to not being declared static, as it implies an additional field referencing the outer class. This will take up slightly more memory than if you declared the inner class static, but you'd be insane to optimize for this (use static where it makes sense, and where you need it to be non-static, make it non-static, but don't convolute your design just to save a pointer of memory here or there).

我还应该补充一点,如果您将内部类从声明为静态更改为不声明为静态,则会有少许不同,因为它意味着引用外部类的附加字段。这将占用内存略高于如果你宣布静态内部类,但你会疯狂的优化(使用静态,它是有意义的,你需要非静态,非静态,但不要旋卷设计为了节省内存的指针在这里或那里)。

#2


7  

There should be no performance difference between a private inner class and a non-private inner class.

私有内部类和非私有内部类之间不应该存在性能差异。

There should be no performance difference between a static inner class (private or not) and an outer class.

静态内部类(私有类或非私有类)和外部类之间不应存在性能差异。

There is a small performance difference between a static inner class and a non-static inner class. This difference is due to the fact that the non-static case has an hidden reference to the instance of its enclosing class. This is passed as an extra parameter to the inner classes constructor, and stored in a hidden variable.

静态内部类和非静态内部类的性能差异很小。这种差异是由于非静态情况对其封闭类的实例有一个隐藏引用。它作为一个额外的参数传递给内部类构造函数,并存储在一个隐藏的变量中。

#3


4  

It is very unlikely this will ever cause any significant slow-down.

这很不可能导致任何重大的放缓。

One issue to be aware of with non-static inner classes is that they contain a reference to the instance of the enclosing class.

非静态内部类要注意的一个问题是,它们包含对封闭类实例的引用。

As such, this can cause 'memory leaks', as the enclosing instance can't be garbage collected. If you pass instances of inner classes out to callers, you are also passing out an instance of the enclosing class.

因此,这会导致“内存泄漏”,因为封装实例不能被垃圾收集。如果您将内部类的实例传递给调用者,那么您也在传递封闭类的实例。

This is not the case with static inner classes!

这不是静态内部类的情况!

Making all fields package protected to prevent synthetic methods is not advisable. You are giving up encapsulation which is a valuable thing to have. What are your concerns? Size of your class files for the additional code?

不建议使所有的字段包被保护以防止合成方法。您正在放弃封装,这是一个有价值的东西。你的担忧是什么?附加代码的类文件的大小?