可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am testing the snippet below, I need to know how can I access t.x or t.hello? What is its scope?
Do developers define variables in this way?
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");
}
};
}
Edit
But why this snippet worked
Thread tr = new Thread() {
int loops = 1;
@Override
public void run() {
loops += 1;
}
};
tr.start();
回答1:
You should distinguish declaration and definition.
In your case you declare a variable of class Test
and assign it to an object of some class derived from Test
(it's an anonymous class) which has some additional stuff in it.
The code after this definition sees t
of class Test
only, it knows nothing about x
and hello
because Test
doesn't have them.
So, apart from reflection, you cannot use x
and hello
after definition of an anonymous class. And yes, developers use such variables when they need these variables inside of definition.
It was mentioned that you can call methods and access variables that are not part of Test
immediately after definition:
int y = new Test(){
int x = 0;
//System.out.print("" + x);
void hello(){
System.out.print("inside hello\n");
}
}.x;
This can be done because at this point the type of an object is know (it's the anonymous class). As soon as you assign this object to Test t
, you lose this information.
回答2:
It creates an anonymous inner class. In this case it has little use. Anonymous classes are generally used to implement an interface without creating a whole new class. When you do that, you can add as many members as you want. For example:
Runnable r = new Runnable() {
int i = 0;
public void run() {
System.out.println(i++);
}
};
By doing that, you have added a counter to your implementation of the Runnable interface (which does not have such a field) and every time you call r.run();
an incremented value gets printed.
A less contrived example that uses a similar pattern:
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());
}
});
Here, a basic implementation of ThreadFactory is provided which names each new Thread Thread #i
.
回答3:
Your code creates an anonymous inner class. It's (more-or-less) equivalent to doing this:
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();
}
}
If you look at the compiler output for that file, you'll notice a file named something like Test$1.class
– that's the anonymous class you've defined.
Since the variable you're storing the instance in is of type Test
, the fields aren't accessible through it. They're accessible through reflection, or from the constructor expression. E.g. the following works, although it's not particularly useful:
new Test() {
void hello() {
System.out.println("hello()");
}
}.hello(); // should print "hello()"
Re: your edit. start()
is a method of Thread
. The variable tr
is also of type Thread
, so you can call its methods. Just not methods you add in an AIC.
回答4:
As written, neither x nor hello can be accessed outside the object referenced by t. The problem is that they are only declared in t's anonymous class. They are not defined in Test, and it is not possible to cast the t reference to the type in which they are declared, because it is anonymous.
I have modified Test to make it abstract and add an abstract declaration of hello, allowing it to be called from outside the object referenced by t. I have also modified hello to add a use of x. Those changes illustrate the two ways of accessing anonymous class features - though the base class or internally.
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();
}
}