实例的局部变量/方法的范围是什么

时间:2013-01-06 20:10:17

标签: java scope

我正在测试下面的代码段,我需要知道如何访问t.x或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 个答案:

答案 0 :(得分:3)

你应该区分声明和定义。

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

此定义后的代码仅显示t类的Test,它对xhello一无所知,因为Test没有它们。

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

有人提到你可以在定义后立即调用方法并访问不属于Test的变量:

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

这可以做到,因为此时对象的类型是知道的(它是匿名类)。只要将此对象分配给Test t,就会丢失此信息。

答案 1 :(得分:1)

您的代码会创建anonymous inner class。它(或多或少)相当于这样做:

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的文件 - 这是您定义的匿名类。

由于您存储实例的变量属于Test类型,因此无法通过它访问这些字段。它们可以通过反射或构造函数表达式访问。例如。 the following works,虽然它不是特别有用:

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

Re:你的编辑。 start()Thread的一种方法。变量tr也是Thread类型,因此您可以调用其方法。不是你在AIC中添加的方法。

答案 2 :(得分: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 #i

答案 3 :(得分:1)

如上所述,在t引用的对象之外都不能访问x和hello。问题是它们只在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();

  }
}