Accessing Constructor of an Anonymous Class

Accessing constructor of an anonymous class

From the Java Language Specification, section 15.9.5.1:

An anonymous class cannot have an
explicitly declared constructor.

Sorry :(

EDIT: As an alternative, you can create some final local variables, and/or include an instance initializer in the anonymous class. For example:

public class Test {
public static void main(String[] args) throws Exception {
final int fakeConstructorArg = 10;

Object a = new Object() {
{
System.out.println("arg = " + fakeConstructorArg);
}
};
}
}

It's grotty, but it might just help you. Alternatively, use a proper nested class :)

How to call a specific parent constructor from anonymous inner class?

You can't define a constructor for an anonymous class (part of the language specification), but you can control which super constructor is called by simply providing arguments to the new call:

MyBob my = new MyBob("foo") { // super(String) is called
// you can add fields, methods, instance blocks, etc, but not constructors
}

Java: initialization and costructor of anonymous classes

This question applies to all inner classes, not just anon classes. (Anon classes are inner classes)

JLS does not dictates how an inner class body accesses outer local variable; it only specifies that the local variables are effectively final, and definitely assigned before the inner class body. Therefore, it stands to reason that the inner class must see the definitely assigned value of the local variable.

JLS does not specify exactly how the inner class sees that value; it is up to the compiler to use whatever trick (that is possible on the bytecode level) to achieve that effect. In particular, this issue is completely unrelated to constructors (as far as the language is concerned).

A similar issue is how an inner class accesses the outer instance. This is a bit more complicated, and it does have something to do with constructors. Nevertheless, JLS still does not dictate how it is achieved by the compiler; the section contains a comment that "... compiler can represent the immediately enclosing instance how ever it wishes. There is no need for the Java programming language to ... "


From JMM point of view, this under-specification might be a problem; it is unclear how writes were done in relation to reads in inner class. It is reasonable to assume that, a write is done on a synthetic variable, which is before (in programming order) the new InnerClass() action; the inner class reads the synthetic variable to see the outer local variable or the enclosing instance.


Is there a way to replicate the behavior of the anonymous class using "normal" classes?

You may arrange the "normal" class as outer-inner class

public class B0
{
int value;
public B0(int i){ value=i; }

public class B extends A
{
protected void init()
{
System.out.println("value="+value);
}
}
}

It will be used like this, which prints 10

    new B0(10).new B();

A convenience factory method can be added to hide the syntax ugliness

    newB(10);

public static B0.B newB(int arg){ return new B0(arg).new B(); }

So we split our class into 2 parts; the outer part is executed even before the super constructor. This is useful in some cases. (another example)


( inner anonymous access local variable enclosing instance effective final super constructor)

Can the constructor call of an anonymous class have arguments

According to the Java docs:

The anonymous class expression consists of the following:

  1. The new operator

  2. The name of an interface to implement or a class to extend. In this example, the anonymous class is implementing the interface HelloWorld.

  3. Parentheses that contain the arguments to a constructor, just like a normal class instance creation expression. Note: When you implement
    an interface, there is no constructor, so you use an empty pair of
    parentheses, as in this example.

  4. A body, which is a class declaration body. More specifically, in the body, method declarations are allowed but statements are not.

Thread is a class, and it contains a constructor with a String parameter, so, this is a valid anonymous class expression.

How to pass parameters to anonymous class?

Technically, no, because anonymous classes can't have constructors.

However, classes can reference variables from containing scopes. For an anonymous class these can be instance variables from the containing class(es) or local variables that are marked final.

edit: As Peter pointed out, you can also pass parameters to the constructor of the superclass of the anonymous class.

Accessing outer variable in PHP 7 anonymous class

another solution could be

$outer = 'something';

$instance = new class($outer) {

private $outer;

public function __construct($outer) {
$this->outer = $outer
}

public function testing() {
var_dump($this->outer);
}
};

When an anonymous class with no references to its enclosing class is returned from an instance method, it has a reference to this. Why?

There is a design principle behind anonymous / inner classes: Each instance of an inner class belongs to an instance of the outer class.

Leaving out the reference to the inner class would change behavior of garbage collection: The way it's implemented, the outer class can not be garbage collected as long the inner class is alive.

This supports the idea that the inner class can not exist without the outer class.

Applications might rely on this behavior by for example by creating a temporary file and deleting it in the destructor. This way, the file will only be deleted when all inner classes are gone.

This also means that the current behavior can not be changed as changing it might break existing applications.

So you should always mark inner classes as static when you don't need the reference, because that could lead to some nice memory leaks.

Edit:
Example of what I am trying to say (sorry for the terrible code quality):

class Ideone
{
static Object[] objects = new Object[2];

public static void main (String[] args) throws java.lang.Exception
{
M1();
M2();
System.gc();
}

static void M1() {
objects[0] = new Foo().Bar();
}
static void M2() {
objects[1] = new Foo().Baz();
}
}

class Foo {
static int i = 0;
int j = i++;

public Foo() {
System.out.println("Constructed: " + j);
}

Object Bar() {
return new Object() {

};
}
static Object Baz() {
return new Object() {

};
}

protected void finalize() throws Throwable {
System.out.println("Garbage collected " + j);
}
}

Output:

Constructed: 0

Constructed: 1

Garbage collected 1

As you can see, the first Foo is not garbage collected, because there is still an "inner instance" alive. For this behavior to work, the inner class needs a reference.

Of course, it could also be implemented differently. But I would say, keeping the reference is a design decision made on purpose, so that the "inner instance" will not outlive its parent.

BTW: The Java language reference states this quite cryptically (There is no exception for inner classes which do not access the outer class):

An instance i of a direct inner class C of a class or interface O is
associated with an instance of O, known as the immediately enclosing
instance of i. The immediately enclosing instance of an object, if
any, is determined when the object is created (§15.9.2).

Reference to final object in anonymous class constructor a leak?

As you might know, you must make variables final when declaring them outside but using them in an anonymous class. The Java trick here is to copy all those variables into implicitly generated instance fields of that anonymous class.

Having said this, it means that there are indeed instance fields (in your runnable) holding copies of all accessed variables of the outer scope. In your example, it would also have a reference to the FragMyDrive as you are simply accessing it.

All those objects become eligible for garbage collection at the same time your runnable becomes eligible for garbage collection. That means the reference to your FragMyDrive inside your runnable keeps that object alive as long as it is running.

It's always a good idea to narrow down those references to what you really need:

private static void fg_downloadFile(final FragMyDrive frag, final File file, final Drive drive){
final String key = frag.getCastedActivity().getKey();
final Context context = frag.getCastedActivity().mService;

Runnable rx_downloadFile = new Runnable() {
@Override
public void run() {
bg_downloadFile(context, key, file, drive);
}
};
//.... Submit runnable to service...
}

Here the only (implicitly generated) instance fields are:

String key
Context context
File file
Drive drive


Related Topics



Leave a reply



Submit