内部类是否轻量级?

8

内部类比普通类更轻量级吗?或者说最终java编译内部类和普通类一样吗?

我知道在java中,类本身并不都是非常轻量级的,并且它们占用了permgen内存的一部分,所以我想知道是否最好使用类似闭包的函数作为内部类,还是标准类也可以胜任?


1
JVM只有原始数据类型(intfloat等)和类。它们之间没有任何中间层。 - Gabe
3个回答

19

内部类和匿名内部类都会编译成.class文件。例如:

class Outer {
     class Inner {

     }

     Object function() {
          return new Object() {

          };
     }
}

将会生成三个.class文件,分别是Outer.classOuter$Inner.classOuter$1.class。它们并不比其他类更加“轻量级”,就我所知并没有从性能方面使用一个而不是另一个的优势。当然,在常规类难以编码的情况下,内部类特别是匿名内部类非常有用,但这是另一个问题。


8
如果说内部类有什么缺点的话,那就是它们包含了编译器为了便于实现特殊的可见性规则而创建的合成方法和字段,使得它们变得更加“笨重”。 - Thilo

7

内部类仍然是类,它们仍然需要由ClassLoader加载。事实上,相反的情况更为真实。非静态内部类可以防止其父类被垃圾回收,因为它具有对拥有它的类的引用。


1
除了父引用之外,还有一些合成方法可以允许从相关类中调用“私有”方法。 - Thilo

1

它们并不轻量级,但也有限制。据我所知,不能创建多个匿名内部类的实例,如果您的需求需要这样做,必须使用非匿名类。

编辑1:感谢所有的评论和澄清。请帮助我更好地理解这个问题...我知道您可以拥有多个匿名内部类的实例,但是如果我声明了一个单独的匿名内部ActionListener对象,如何只使用那个类而不使用反射来拥有多个该类的实例呢?提前致谢(或者我应该在自己的问题中问这个问题吗?)!

好的,既然没有人回答...让我用代码来演示一下。假设我在这里创建了一个匿名ActionListener:

  JButton button = new JButton("Button");

  button.addActionListener(new ActionListener() {
     @Override
     public void actionPerformed(ActionEvent arg0) {
        System.out.println("Button says \"Foo!\"");
     }

  });

  JOptionPane.showMessageDialog(null, button);

我创建了一个匿名的ActionListener,并在一步中创建了这个类的对象。我一直被教导,正如我在这里提到的那样(并因此受到批评),如果没有反射的魔力,要想创建另一个这个匿名类的对象是困难的,甚至是不可能的,只能创建一个对象,在只需要一个对象的情况下,这是可以接受的。但在其他情况下,这是不可取的。当然,你可以创建多个类似的匿名ActionListener类,就像在for循环中一样:

   JPanel panel = new JPanel(new GridLayout(5, 5));
  JButton[] buttons = new JButton[25];
  for (int i = 0; i < 25; i++) {
     final int btnNumber = i;
     buttons[i] = new JButton(String.valueOf(btnNumber));
     buttons[i].addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
           System.out.println("From button " + btnNumber);
        }
     });
     panel.add(buttons[i]);
  }
  JOptionPane.showMessageDialog(null, panel);

但即便如此,在这里创建的每个匿名类都是不同的。如果多个JButton使用相同类型的监听器,并且它具有状态并且其行为取决于此状态,则可能具有重要意义。同意?不同意?感谢您提前提供的任何意见!


3
例如,通过将类放入“for”循环并多次实例化,您可以拥有多个匿名内部类的实例。我认为Java要求这些类都具有相同的类型,但我不确定是否正确。 - templatetypedef
1
你想得太多了。一个匿名内部类仍然是一个类。你可以拥有任意数量的实例。你也可以有任意数量的匿名内部类。编译器会在编译时处理所有这些问题。它找到的第一个匿名规范将被赋予可爱的名称 Foo$1,第二个为 Foo$2,依此类推。类似 new Runnable(){...} 的代码会变成 Foo.new 1() - Tim Bender
感谢您的评论和有用的信息!请为我澄清一下...如果我有一个匿名内部ActionListener,那么在没有反射的情况下如何拥有这个类的两个不同实例,因为它是在创建对象时创建的。我知道我可以有许多匿名ActionListeners的实例,但我想知道如何有多个已声明的一个独特匿名类的实例。 - Hovercraft Full Of Eels
编辑:由于我没有收到澄清,我在这里创建了一个新的线程/问题来解决这个问题:https://dev59.com/02445IYBdhLWcg3wg6pm。请告诉我是否可以这样做。谢谢! - Hovercraft Full Of Eels

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接