2013-01-06 48 views
2

我正在測試下面的代碼片段,我需要知道如何訪問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(); 
+0

有趣的是,我在我的回答中給出的例子非常接近您的編輯;-) – assylias

+1

回覆:您的編輯。 'start()'是'Thread'的一個方法。變量'tr'也是'Thread'類型,所以你可以調用它的方法。只是不是你在AIC中添加的新方法。 – millimoose

回答

3

您應該區分聲明和定義。

在你的情況下,你聲明瞭一個類Test的變量,並將它分配給一個派生自Test(它是一個匿名類)的某個類的對象,它有一些額外的東西。

這個定義後的代碼看到Testt只,因此它不知道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,就會丟失此信息。

+0

絕對正確;注意到匿名內部類是外部類的一個子類很重要。所以無論你在內部(孩子)課堂添加的成員都不能被其父親看到。 – yasserbn

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中添加的方法。

+3

它不起作用,因爲'hello'什麼都不返回,但是你把返回結果賦給'Test t'。 – tcb

+0

@tcb好的。 – millimoose

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

1

正如所寫的,x和hello都不能在t引用的對象之外訪問。問題是他們只在t的匿名類中聲明。它們沒有在Test中定義,並且不可能將t引用強制轉換爲聲明的類型,因爲它是匿名的。

我已經修改了測試以使其抽象並添加一個抽象聲明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(); 

    } 
}