Is there a way to access an anonymous outer class? A normal class can be accessed by ClassName.this. This doesn't work, as an anonymous class obviously doesn't have a name. I also tried using the extended class/interface (like Runnable.this) but it doesn't seem like it would work this way.
I'm sure this may be not the best coding style, I'm just curious if it's possible without storing this of the outer in a variable.
Example, watch out for outer.this:
public class A
{
public static void main(String[] args) {
new Thread(new Runnable() {
#Override
public void run() {
new Thread(new Runnable() {
#Override
public void run() {
synchronized (outher.this) {
outher.this.notify();
}
}
}).start();
try {
synchronized (this) {
wait();
}
} catch (final InterruptedException ex) {}
}
}).start();
}
}
No, there is no way to access anonymous classes from anywhere, except from inside them (i.e. otherwise than by this reference). Or by an explicitly declared variable.
final Runnable r1 = new Runnable() {...};
Runnable r2 = new Runnable() {
public void run() {
synchronized(r1) {...}
}
};
You could add a method to return this middle this. It would be in scope but not hidden (is that the right term? Shadowed? I forget.).
public static void main(String[] args) {
new Thread(new Runnable() {
Runnable middleThis() { return this; } // <-- this
#Override
public void run() {
new Thread(new Runnable() {
#Override
public void run() {
synchronized (middleThis()) {
middleThis().notify();
Note, although anonymous inner classes have no name, they still are types. So adding members is visible to the immediate expression (new X() { Y z; }.z) and inside. You can't do middleThis().middleThis().
Related
I have such code:
package x.y.z;
public class Test
{
private static class MyRunnable implements Runnable
{
#Override
public void run()
{
System.out.println("World");
}
}
public static void main(String[] args)
{
final Runnable r1 = new Runnable() {
#Override
public void run()
{
System.out.println("Hello");
}
};
final Runnable r2 = new MyRunnable();
r1.run();
r2.run();
}
}
I am working on some code analysis module, and I want to prove that r1 is an anonymous class instance and r2 is not. Both of them are valid objects having the same base class or an interface. How can I do this?
Refinement: All classes are being loaded, so I do not need to analyze the text.
There's the isAnonymousClass method on Class, so:
if (r1.getClass().isAnonymousClass()) {
// ...
How can I do this in java without using the Runnable class or implementing my threaded code in a run() method?
public void dud()
{
System.out.println("create me on a new thread");
}
public void main()
{
Thread t1 = new Thread(dud).start();
Thread t2 = new Thread(dud).start();
}
Since Java 8, you can use a Lambda:
public void main ()
{
// direct way
new Thread(() -> dud()).start();
// indirect way
Thread t = new Thread(() -> dud());
t.start();
}
Before Java 8, on Java 7, you need to use an anonymus inner class:
public void main ()
{
// direct way
new Thread(new Runnable() { public void run() { dud(); } }).start();
// indirect way
Thread t = new Thread(new Runnable() { public void run () { dud(); } });
t.start();
}
I think you might be able to do it implicitly if you take advantage of Java 8 features :
public class ThreadTest
{
public static void dud()
{
System.out.println("create me on a new thread");
}
public static void main(String[] args)
{
Thread t1 = new Thread(()->dud()).start();
// it might even work with a method reference :
Thread t2 = new Thread(ThreadTest::dud).start();
}
}
You are basically declaring a Runnable implicitly with a lambda expression.
Of course you'll need to either change dud() to be static or create an instance before invoking it.
In the code below, I am wondering why the run() in the inline class is able to access the outer class variable - semaphore (even though it is not declared final).
private Semaphore semaphore = new Semaphore(bufferSize);
private Runnable producerRunnable = new Runnable(){
#Override
public void run()
{
try
{
semaphore.acquire();
}
catch(InterruptedException e)
{
System.out.println("producer was interrupted while trying to acquire semaphore");
}
}
};
I expected Eclipse to flag a compilation error - since semaphore reference is not declared final
This is normal. The final requirement is only described to apply to local variables and parameters (JLS):
Any local variable, formal parameter, or exception parameter used but not declared in an inner class must either be declared final [...].
Members of the enclosing instance don't need to be final to access them.
Because you have defined semaphore as a global variable to that class and all the local variables should be declared as final if you want to access it in the runnable .
public class KamalTest {
/**
* #param args the command line arguments
*/
private Semaphore semaphore = new Semaphore(2);
private Runnable producerRunnable = new Runnable() {
#Override
public void run() {
try {
semaphore.acquire();
} catch (InterruptedException e) {
System.out.println("producer was interrupted while trying to acquire semaphore");
}
}
};
public void startThread1() {
Thread th = new Thread(producerRunnable);
th.start();
}
public void startThread2() {
final Semaphore semPhore = new Semaphore(2);
Runnable runnable = new Runnable() {
#Override
public void run() {
try {
semPhore.acquire();
} catch (InterruptedException ex) {
Logger.getLogger(KamalTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
Thread th = new Thread(runnable);
th.start();
}
public static void main(String[] args) {
KamalTest kt = new KamalTest();
kt.startThread1();
System.out.println("Internet Available : " + isInternetAvailable());
}
}
}
So the situation is something like this:
private void myMethod()
{
System.out.println("Hello World"); //some code
System.out.println("Some Other Stuff");
System.out.println("Hello World"); //the same code.
}
We don't want to be repeating our code.
The technique described here works pretty well:
private void myMethod()
{
final Runnable innerMethod = new Runnable()
{
public void run()
{
System.out.println("Hello World");
}
};
innerMethod.run();
System.out.println("Some other stuff");
innerMethod.run();
}
But what if I want to pass in a parameter to that inner method?
eg.
private void myMethod()
{
final Runnable innerMethod = new Runnable()
{
public void run(int value)
{
System.out.println("Hello World" + Integer.toString(value));
}
};
innerMethod.run(1);
System.out.println("Some other stuff");
innerMethod.run(2);
}
gives me: The type new Runnable(){} must implement the inherited abstract method Runnable.run()
While
private void myMethod()
{
final Runnable innerMethod = new Runnable()
{
public void run()
{
//do nothing
}
public void run(int value)
{
System.out.println("Hello World" + Integer.toString(value));
}
};
innerMethod.run(1);
System.out.println("Some other stuff");
innerMethod.run(2);
}
gives me The method run() in the type Runnable is not applicable for the arguments (int).
Nope, that isn't a method but an anonymous object. You can create an extra method to use for the object.
Thread thread = new Thread( new Runnable()
{
int i,j;
public void init(int i, int j)
{
this.i = i;
this.j=j;
}
});
thread.init(2,3);
thread.start();
And wrap runnable in a Thread, and call start! Not run().
Because you can't call the constructor of an anonymous class, as pointed out by #HoverCraft you could extend a named class that implements Runnable.
public class SomeClass implements Runnable
{
public SomeClass(int i){ }
}
Looks like you just want inner methods. Java does't let you have them, so the Runnable hack you describe lets you sort-of declare an inner method.
But since you want more control over it, why not define your own:
interface Inner<A, B> {
public B apply(A a);
}
Then you can say:
private void myMethod(..){
final Inner<Integer, Integer> inner = new Inner<Integer, Integer>() {
public Integer apply(Integer i) {
// whatever you want
}
};
// then go:
inner.apply(1);
inner.apply(2);
}
Or use some library that provides functor objects. There should be many. Apache Commons has a Functor that you can use.
suppose we have these classes and read the comments
class Work {
void doWork(){ }
void commit(){}
}
class MyRunable implements Runnable {
run(){
Work work=new Work();
work.doWork();
//i can't write work.commit() here, because sometimes i want Thread runs both methods
//and sometimes runs only doWork()
}
}
class Tasks{
main(){
MyRunable myRunable=new MyRunable();
Thread t=new Thread(myRunable);
t.start();
//suppose now i need to call commit() method by the same thread (t)
//how can i do that
}
}
also i don't want to use constructor to determine if i want to call both method or not
You could try using a thread pool with a single thread and keep enqueuing methods as needed:
class Tasks {
public static void main(String[] args) {
ExecutorService exec = Executors.newSingleThreadExecutor();
final Work work = new Work();
exec.submit(new Runnable() {
public void run() {
work.doWork();
}
});
// later
exec.submit(new Runnable() {
public void run() {
work.commit();
}
});
}
}
This way, both methods will be executed in a sequence by the same thread, but separately.
Add parameter to your class MyRunnable. Call this parameter "runingMode". It could be an enum:
enum RunningMode {
DO_WORK {
public void work(Work work) {
work.doWork();
}
},
COMMIT {
public void work(Work work) {
work.commit();
}
};
public abstract void work();
}
Now your class MyRunnable should have list of modes:
class MyRunable implements Runnable {
private Collection<RunningMode> modes;
MyRunable(Collection<RunningMode> modes) {
this.modes = modes;
}
}
Implement run() method as following:
Work work=new Work();
for (RunningMode mode : modes) {
mode.work(work);
}
work.doWork();
Create instance of your class passing to it the mode you currently need:
MyRunable myRunable=new MyRunable(Arrays.asList(RunningMode.DO_WORK, RunningMode.COMMIT));
You could use an anonymous class.
final boolean condition = ...
Thread t = new Thread(new Runnable() {
public void run() {
Work work=new Work();
work.doWork();
if(condition)
work.commit();
}});
t.start();