类文件名中的$1是什么意思?

74
C:\Program Files\Java\jdk1.6.0_05\CoreJava\v1\v1ch2\WelcomeApplet>dir
C:\Program Files\Java\jdk1.6.0_05\CoreJava\v1\v1ch2\WelcomeApplet>javac WelcomeApplet.java

This is a command prompt interface showing the directory path and files contained in that directory. The Java file "WelcomeApplet.java" is compiled using the "javac" command.

The Java code contained in the file creates an applet that displays a welcome message. The compiled Java program generates two class files: "WelcomeApplet$1.class" and "WelcomeApplet.class". These files can be used to run the applet.

/**
   @version 1.21 2002-06-19
   @author Cay Horstmann
*/

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;

public class WelcomeApplet extends JApplet
{
   public void init()
   {
      setLayout(new BorderLayout());

      JLabel label = new JLabel(getParameter("greeting"), SwingConstants.CENTER);
      label.setFont(new Font("Serif", Font.BOLD, 18));
      add(label, BorderLayout.CENTER);

      JPanel panel = new JPanel();

      JButton cayButton = new JButton("Cay Horstmann");
      cayButton.addActionListener(makeURLActionListener(
         "http://www.horstmann.com"));
      panel.add(cayButton);

      JButton garyButton = new JButton("Gary Cornell");
      garyButton.addActionListener(makeURLActionListener(
         "mailto:gary@thecornells.com"));
      panel.add(garyButton);

      add(panel, BorderLayout.SOUTH);
   }

   private ActionListener makeURLActionListener(final String u)
   {
      return new
         ActionListener()
         {
            public void actionPerformed(ActionEvent event)
            {
               try
               {
                  getAppletContext().showDocument(new URL(u));
               }
               catch(MalformedURLException e) 
               { 
                  e.printStackTrace(); 
               }
            }
         };
   }
}
6个回答

78

那些是存储匿名内部类.class文件。

在你的例子中,WelcomeApplet.java 包含一个顶层类(称为 WelcomeApplet)和一个匿名内部类,它将存储在 WelcomeApplet$1.class中。

请注意,持有匿名内部类文件的确切名称没有标准化,可能会有所不同。但实际上,我还没有看到过除这里描述的方案之外的其他方案。

对于enum的特定值,也是匿名内部类

枚举常量的可选类体隐式定义了一个匿名类声明 (§15.9.5),该匿名类继承了直接封闭的枚举类型。


我已经将源代码粘贴在这里,没有匿名内部类。 - omg
@Shore:是的,有这个东西。你知道匿名内部类是什么吗? - Michael Myers
8
有一个匿名类:new ActionListener() { ... } 将创建一个ActionListener的匿名子类。 - Juha Syrjälä
“匿名内部类”的定义是什么? - omg
给出的链接解释了什么是匿名内部类。它只是一个未命名的普通类……在Java Swing中大量使用,因此如果您阅读有关事件侦听器的Swing教程,您将找到更多有关它的信息,因为您似乎正在开始使用小应用程序。 - aberrant80

31

$1是您在WelcomeApplet.java文件中定义的匿名内部类。

例如编译

public class Run {
    public static void main(String[] args) {
        System.out.println(new Object() {
            public String toString() {
                return "77";
            }
        });
    }
    private class innerNamed {
    }
}

将会生成 Run.class, Run$1.classRun$innerNamed.class


但是WelcomeApplet.java文件中没有内部类。让我更新一下文件内容。 - omg
2
有的。它的开头是这样的:return new ActionListener() { public void actionPerformed ... - Juha Syrjälä
你的 applet 中有一个内部类 ActionListener,你在 makeURLActionListener() 方法中创建了它,这是一个类的内联定义。你使用 new ActionListener(),然后在 { ... } 中实现 actionPerformed 方法来定义该类。 - jitter

6
这些是由Java编译器从WelcomeApplet.java文件中的内部和静态嵌套类生成的。
还可以参考这个类似的问题和答案

但是源代码中根本没有这样的匿名内部类。 - omg
当然,在makeURLActionListener()中,您正在为ActionListener生成一个匿名内部类。这就是起源 :) - Kosi2801

5

这段代码中的“line”指的是:

return new
    ActionListener()
    {
        public void actionPerformed(ActionEvent event)
        {
            try
            {
                getAppletContext().showDocument(new URL(u));
            }
            catch(MalformedURLException e) 
            { 
                e.printStackTrace(); 
            }
        }
    };

您声明 ActionListener 的方式是每次调用该方法都创建一个匿名内部类的实例。
即使该方法未被调用,上述代码行仍会编译成匿名内部类。

如果没有调用,'$1.class' 会生成吗? - omg
无论如何,该类都会被生成。但是,您永远不会拥有这些对象的任何实例。 - jjnguy

2

WelcomeApplet$1.class文件是在WelcomeApplet.java源代码中为一个匿名类生成的(该匿名类是通过调用new new ActionListener() {...}在makeURLActionListener方法调用中生成的)。

更清楚地解释一下,匿名类是在编译时生成的,每当您实例化一个具有内联覆盖某些或所有行为的具体命名类(或接口)时,都会生成它们,如下所示:

class HelloInternalClass {
  public static final void main(String[] args) {
    // print in another thread
    new Thread(new Runnable() {
      public void run() {
        System.out.println("Printed from another thread");
      }
    }).start();
  }
}

在上面的示例代码中,javac编译器将生成2个类文件,就像您的示例中一样:HelloInternalClass.classHelloInternalClass$1.class
在此情况下的匿名类将是Runnable的子类,并将被编译为HelloInternalClass$1.class。顺便说一下,如果您从上面的示例中请求可运行实例的类名(通过调用getClass().getName()),则会发现它认为自己是“HelloInternalClass$1”。

0

创建:

public class A {
    public static void main(String[] args) {
        X x=new X();
        X x2=new X(){   
        };
        Class<? extends Object>c2=x2.getClass();
        Class<? extends Object>s2=x2.getClass().getSuperclass();

        boolean b=false;
    }
    private static class X{     
    }
}

从代码中很难看出来(new X{}()new X(){}更好),但是x2A$X的子类实例。这个子类是A$1


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