2

我正在测试下面的代码片段,我需要知道如何访问 tx 或 t.hello?它的范围是什么?开发人员是否以这种方式定义变量?

public class Test{

public Test(){
    System.out.print("constructor\n");
}

public static void main(String[] args) {

    Test t = new Test(){
        int x = 0;
        //System.out.print("" + x);
        void hello(){
            System.out.print("inside hello\n");
        }
    };
}

编辑

但是为什么这个片段有效

 Thread  tr = new Thread() {
int loops = 1;

 @Override
 public void run() {
    loops += 1;
}
};
tr.start();
4

4 回答 4

3

你应该区分声明和定义。

在您的情况下,您声明一个类变量Test并将其分配给某个派生自Test(它是一个匿名类)的类的对象,其中包含一些额外的东西。

这个定义之后的代码只看到tTest,它一无所知xhello因为Test没有它们。

因此,除了反射之外,您不能在定义匿名类之后使用x和。hello是的,当开发人员在定义中需要这些变量时,他们会使用这些变量。

有人提到,您可以Test在定义后立即调用不属于其中的方法和访问变量:

int y = new Test(){
    int x = 0;
    //System.out.print("" + x);
    void hello(){
        System.out.print("inside hello\n");
    }
}.x;

可以这样做,因为此时对象的类型是已知的(它是匿名类)。一旦将此对象分配给Test t,您就会丢失此信息。

于 2013-01-06T20:36:14.677 回答
1

您的代码创建了一个匿名内部类。它(或多或少)相当于这样做:

public class Test {
    // ...
    private class TestAnonymousInner extends Test {
        int x = 0;
        //System.out.print("" + x);
        void hello(){
            System.out.print("inside hello\n");
        }
    }

    public static void main(String[] args) {
        Test t = new TestAnonymousInner();
        // invalid:
        // t.hello(); 
    }
}

如果您查看该文件的编译器输出,您会注意到一个名为类似的文件Test$1.class——这就是您定义的匿名类。

由于您存储实例的变量是 type Test,因此无法通过它访问字段。它们可以通过反射或构造函数表达式访问。例如以下作品,虽然它不是特别有用:

new Test() {
    void hello() {
        System.out.println("hello()");
    }
}.hello(); // should print "hello()"

回复:您的编辑。start()是一种方法Thread。变量tr也是 type Thread,所以你可以调用它的方法。只是不是您在 AIC 中添加的方法。

于 2013-01-06T20:16:50.790 回答
1

它创建了一个匿名内部类。在这种情况下,它几乎没有用。匿名类通常用于在不创建全新类的情况下实现接口。当您这样做时,您可以添加任意数量的成员。例如:

Runnable r = new Runnable() {
    int i = 0;
    public void run() {
        System.out.println(i++);
    }
};

通过这样做,您为 Runnable 接口(没有这样的字段)的实现添加了一个计数器,并且每次调用r.run();递增的值时都会打印出来。

一个使用类似模式的不太人为的示例:

private final ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactory() {
    private final AtomicInteger threadId = new AtomicInteger();

    @Override
    public Thread newThread(Runnable r) {
        return new Thread(r, "Thread #" + threadId.incrementAndGet());
    }
});

在这里,提供了 ThreadFactory 的基本实现,它为每个新的 Thread 命名Thread #i

于 2013-01-06T20:32:16.240 回答
1

正如所写,x 和 hello 都不能在 t 引用的对象之外访问。问题是它们只在 t 的匿名类中声明。它们没有在 Test 中定义,并且不可能将 t 引用转换为声明它们的类型,因为它是匿名的。

我修改了 Test 使其抽象化,并添加了 hello 的抽象声明,允许从 t 引用的对象外部调用它。我还修改了 hello 以添加对 x 的使用。这些更改说明了访问匿名类功能的两种方式——通过基类或内部。

public abstract class Test {

  abstract void hello();

  public Test() {
    System.out.print("constructor\n");
  }

  public static void main(String[] args) {

    Test t = new Test() {
      int x = 0;

      // System.out.print("" + x);
      void hello() {
        System.out.print("inside hello\n");
        System.out.print("My value of x is "+x);
      }
    };
    t.hello();

  }
}
于 2013-01-06T20:51:32.230 回答