【问题标题】:What is the scope of the local variable/methods of an instance实例的局部变量/方法的范围是什么
【发布时间】:2013-01-06 20:10:17
【问题描述】:

我正在测试下面的sn-p,我需要知道如何访问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");
        }
    };
}

编辑

但是为什么这个 sn-p 有效

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

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

【问题讨论】:

  • 有趣的是,我在回答中给出的示例与您的编辑非常接近;-)
  • 回复:您的编辑。 start()Thread 的一个方法。变量tr 也是Thread 类型,所以你可以调用它的方法。只是不是您在 AIC 中添加的新方法。

标签: java scope


【解决方案1】:

你应该区分声明和定义。

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

这个定义之后的代码只看到Test类的t,它对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,您就会丢失此信息。

【讨论】:

  • 完全正确;需要注意的是,匿名内部类是外部类的子类。因此,您在内部(子)类中添加的任何成员都不能被其父亲看到。
【解决方案2】:

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

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】:

    您的代码会创建一个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()"
    

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

    【讨论】:

    • 它不起作用,因为hello什么都不返回,但是你将返回结果分配给Test t
    【解决方案4】:

    正如所写,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();
    
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-08-22
      • 1970-01-01
      • 2011-10-29
      • 1970-01-01
      • 2015-11-15
      • 2014-03-12
      • 2016-01-14
      • 2016-08-19
      • 2012-05-26
      相关资源
      最近更新 更多