Strange syntax for instantiating an inner class - java

I didn't imagine that I would encounter radically new syntax in Java anymore at this stage, but lo and behold, I just encountered something:
The exact context and what the code below should do is pretty irrelevant - it's there just to give some kind of context.
I'm trying to synthetically create an event in IT Mill Toolkit, so I wrote this kind of line:
buttonClick(new Button.ClickEvent(button));
But, Eclipse gives me the following error message:
No enclosing instance of type Button is accessible. Must qualify the allocation with an enclosing instance of type Button (e.g. x.new A() where x is an instance of Button).
When I rewrite the line above as follows, it doesn't complain anymore:
buttonClick(button.new ClickEvent(button)); // button instanceof Button
So, my question is: What does the latter syntax mean, exactly, and why doesn't the first snippet work? What is Java complaining about, and what's it doing in the second version?
Background info: Both Button and Button.ClickEvent are non-abstract public classes.

Inner classes (like Button.ClickEvent) need a reference to an instance of the outer class (Button).
That syntax creates a new instance of Button.ClickEvent with its outer class reference set to the value of button.
Here's an example - ignore the lack of encapsulation etc, it's just for the purposes of demonstration:
class Outer
{
String name;
class Inner
{
void sayHi()
{
System.out.println("Outer name = " + name);
}
}
}
public class Test
{
public static void main(String[] args)
{
Outer outer = new Outer();
outer.name = "Fred";
Outer.Inner inner = outer.new Inner();
inner.sayHi();
}
}
See section 8.1.3 of the spec for more about inner classes and enclosing instances.

Button.ClickEvent is a non-static inner class so an instance of this class can only exist enclosed in a instance of Button.
In your second code example you have an instance of Button and you create an instance of ClickEvent enclosed in this Button instance...

A non-static inner class in Java contains a hidden reference that points to an instance of the outer class it is declared in. So the error message you got originally is telling you that you cannot create a new instance of the inner class without also specifying an instance of the outer class for it to be attached to.
Perhaps the reason you haven't seen that syntax before is that inner classes are often allocated in a method of the outer class, where the compiler takes care of this automatically.

To avoid confusing yourself and fellow programmers with this rarely-used feature you can always make inner classes static.
In case a reference to the outer class is needed you can pass it explicitly in the constructor.

You actually can do that, but you have to declare ClickEvent as static inside Button, and then you shouldn't have any problem using you sintax:
buttonClick(new Button.ClickEvent(button));
Basically static makes the class ClickEvent belong directly to the class Button instead of a specific instance(i.e. new Button()) of Button.
Following #Jon Skeet example:
// Button.java
class Button
{
public static class ClickEvent
{
public ClickEvent(Button b)
{
System.out.println("Instance: " + this.toString());
}
}
}
// Test.java
public class Test
{
public static void main(String[] args)
{
Button button = new Button();
buttonClick(new Button.ClickEvent(button));
}
public static void buttonClick (Button.ClickEvent ce) {
}
}

Your code would compile, had you typed
buttonClick(new Button().ClickEvent(button));
instead of
buttonClick(new Button.ClickEvent(button));
as a constructor is a method and when you call a method in Java you must pass the list of arguments, even when it is empty.

Related

Java why invocation of private method works [duplicate]

I don't understand why this compiles. f() and g() are visible from the inner classes, despite being private. Are they treated special specially because they are inner classes?
If A and B are not static classes, it's still the same.
class NotPrivate {
private static class A {
private void f() {
new B().g();
}
}
private static class B {
private void g() {
new A().f();
}
}
}
(Edit: expanded on the answer to answer some of the comments)
The compiler takes the inner classes and turns them into top-level classes. Since private methods are only available to the inner class the compiler has to add new "synthetic" methods that have package level access so that the top-level classes have access to it.
Something like this (the $ ones are added by the compiler):
class A
{
private void f()
{
final B b;
b = new B();
// call changed by the compiler
b.$g();
}
// method generated by the compiler - visible by classes in the same package
void $f()
{
f();
}
}
class B
{
private void g()
{
final A a;
a = new A();
// call changed by the compiler
a.$f();
}
// method generated by the compiler - visible by classes in the same package
void $g()
{
g();
}
}
Non-static classes are the same, but they have the addition of a reference to the outer class so that the methods can be called on it.
The reason Java does it this way is that they did not want to require VM changes to support inner classes, so all of the changes had to be at the compiler level.
The compiler takes the inner class and turns it into a top level class (thus, at the VM level there is no such thing as an inner class). The compiler then also has to generate the new "forwarding" methods. They are made at the package level (not public) to ensure that only classes in the same package can access them. The compiler also updated the method calls to the private methods to the generated "forwarding" methods.
You can avoid having the compiler generate the method my declaring the methods as "package" (the absence of public, private, and protected). The downside to that is that any class in the package can call the methods.
Edit:
Yes, you can call the generated (synthetic) method, but DON'T DO THIS!:
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Main
{
public static void main(final String[] argv)
throws Exception
{
final Class<?> clazz;
clazz = Class.forName("NotPrivate$A");
for(final Method method : clazz.getDeclaredMethods())
{
if(method.isSynthetic())
{
final Constructor constructor;
final Object instance;
constructor = clazz.getDeclaredConstructor(new Class[0]);
constructor.setAccessible(true);
instance = constructor.newInstance();
method.setAccessible(true);
method.invoke(null, instance);
}
}
}
}
I think this quote sums it up nicely:
...inner classes can access all members of the declaring class, even private members. In fact, the inner class itself is said to be a member of the class; therefore, following the rules of object-oriented engineering, it should have access to all members of the class.
And following from that, since both inner classes are really just part of the containing class, they should be able to access each others private members as well.
Java compiles in special accessors with $ in them. So you can't write Java that access the private methods. Explained here:
http://www.retrologic.com/innerclasses.doc7.html
There is one more category of compiler-generated members. A private member m of a class C may be used by another class D, if one class encloses the other, or if they are enclosed by a common class. Since the virtual machine does not know about this sort of grouping, the compiler creates a local protocol of access methods in C to allow D to read, write, or call the member m. These methods have names of the form access$0, access$1, etc. They are never public. Access methods are unique in that they may be added to enclosing classes, not just inner classes.
As User 'A Dude' explained it in the comments of the accepted answer:
It compiles, because it is required to be working in that way by the language specifation, ie. the Java Lang Spec says so:
6.6.1 Determining Accessibility (at least since JLS6)
"Otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor."
I.e. the "access-scope" of a private member is: everywhere within the lexical boundaries of the top-level class body.
That means: all private members that are defined within the class-body of the outermost class can be accessed from everywhere else in this class-body.
For instance the private method of an inner class can be accessed from methods of the outer class or from any method of another inner class of the outer class.

Aren't Anonymous Inner Classes actually subclasses?

Assume that A is a custom class, and consider the following declaration of an anonymous inner class:
A Obj = new A() {
#Override
public String toString() {
return "Hello!";
}
}
In this scenario, Obj is an instance of an anonymous inner class whose toString method has been overridden. Since it was declared with type A, the anonymous class must be a subclass of A. So then, why isn't this class called an Anonymous Subclass instead of an anonymous inner class? Where does the 'inner' come from?
Yes, obj is an instance of a subclass of A. And you can verify the superclass by calling obj.getClass().getSuperclass():
That prints something like:
class stackoverflow.Test$1 //obj.getClass()
class stackoverflow.A //obj.getClass().getSuperclass()
So then, why isn't this class called an Anonymous Subclass instead of an anonymous inner class?
Those are just semantics. It's a name. There could be many reasons, however, one of which being that anonymous classes can implement interfaces directly:
Runnable r = new Runnable() {
public void run() {}
}
This is not a subclass of anything (but Object, but what isn't a subclass of Object...), but it's an anonymous class too.
Why isn't this class called an Anonymous Subclass instead of an anonymous inner class?
Because (in general) anonymous inner class aren't necessarily subclasses1. An anonymous inner class can extend an interface rather than a class.
Because the "subclass-ness" is not important2 in most contexts where we talk about anonymous inner classes.
Because humans are lazy3 and "Anonymous Inner Subclasses" is one extra syllable. Or to put it another way, there is a natural tendency for people to optimize their speech and writing patterns.
Because ... convention.
Where does the 'inner' come from?
Inner has a technical meaning in Java. It means two things.
It means that the class is declared inside another class.
It means that the class is permitted to refer to the this of an instance of the enclosing class.
See the nice taxonomy in #Andreas's answer.
Historical footnote.
In fact, the official terminology is Anonymous Class. Indeed, Sun used the terminology "Anonymous Class" rather than "Anonymous Inner Class" way back in Java 1.1 when the construct was added to the language. For example, the "Inner Class Specification" from the Java 1.1.4 release notes refers to them as "Anonymous Classes" ... most of the time.
I suspect that what happened was that there was some inconsistency in earlier Sun presentations or papers, and various non-Sun authors latched onto the "anonymous inner class" version in their writings. The Sun team tried to quietly correct this by using "Anonymous Class" in the official Java Language Spec and Tutorial. But it was too late. The books were in the bookshops, the articles were on the web.
1 - Except in the trivial sense. Every class that isn't Object must be a subclass of some class.
2 - Likewise, you would normally say "I am taking the dog for a walk", not "I am taking the black Labrador for a walk".
3 - In this case, "good lazy".
Subclass and inner class are two different aspects of the anonymous class. Because of the syntax, an anonymous class is obviously a subclass of the named class, so the inner aspect is more relevant for the categorization.
Java classes are categories like this1:
Top-Level class (§7.6)
Nested class (§8.5, §9.5)
Static Nested class
Inner class (§8.1.3)
Local class (§14.3)
Anonymous class (§15.9.5)
As you can see, an anonymous class is an inner nested class.
The categorization doesn't specify whether the class is a subclass, a base class, or a standalone class. Classes of any category can be a subclass or base class. As ernest_k mentioned in another answer, an anonymous class may be defined from an interface, in which case it's not a subclass at all.
1) Excerpt of bigger hierarchy at end of this other answer.
To answer your question's title, yes, they are. Anonymous inner classes are actually subclasses.
"Since it was declared with type A, the anonymous class, [Obj], must be a subclass of A."
Good job. :)
Anyways, to answer why the "inner" is there: If you declare an anonymous class inside another class (and the anonymous class isn't declared statically, more on that below) then it would be able to access its surrounding class just like an inner class would. For example:
public class Outer {
private final int someRandomValue = 4;
public final Object anonymousInnerInstance = new Object() {
#Override
public String toString() {
// Notice how this class has access to a field declared inside a different
// class. More specifically, this anonymous class can access someRandomValue,
// even though someRandomValue belongs to the class, Outer.
return "Anonymous Inner Class: " + someRandomValue;
}
};
public class RegularInner {
#Override
public String toString() {
// This regular inner class is inside Outer, (just like the anonymous class),
// and can access any of Outer's fields (amongst Outer's other things).
return "Regular Inner Class: " + someRandomValue;
}
}
public final RegularInner regularInnerInstance = new RegularInner();
public static void main(String[] args) {
Outer outerInstance = new Outer();
System.out.println(outerInstance.anonymousInnerInstance);
System.out.println(outerInstance.regularInnerInstance);
// By the way, you can make new RegularInner instances off of our Outer
// instance:
RegularInner newInnerInstance = outerInstance.new RegularInner();
// When you write "outerInstance.new SomeClass()" you're saying:
// "I'd like to initialize my 'SomeClass' object with 'outerInstance',
// as its container." This effectively means that any variables that
// belong to Outer that your SomeClass needs to access, it will access
// from the Outer instance you gave it.
}
}
So, anonymousInnerInstance's underlying class, and the class RegularInner, both have access to Outer's fields, and other instance-specific content belonging to Outer. That's why an anonymous class may sometimes be called an "inner" class.
Any instance of an inner class needs to be created with an instance of an outer class to back it up, or it won't know which object, (not class), it belongs to.
Static Trash
If an anonymous class is declared as static, it won't have access to its surrounding class's content and wouldn't be an "inner" class (instead, it would be an anonymous "nested" class).
public class Outer {
private final int someRandomValue = 4;
public static final Object anonymousStaticInstance = new Object() {
#Override
public String toString() {
// someRandomValue belongs to an INSTANCE of Outer. (So each Outer object you
// have has its own someRandomValue). Since this anonymous class
// is now static, it is no longer tied to an instance of Outer. It doesn't have
// an Outer object that it can read "someRandomValue" from. The same goes for
// RegularStatic, below.
return "Anonymous Inner Class: " + someRandomValue;
}
};
public static class RegularStatic {
#Override
public String toString() {
return "Regular Inner Class: " + someRandomValue;
}
}
public final RegularStatic regularInnerInstance = new RegularStatic();
public static void main(String[] args) {
Outer outerInstance = new Outer();
System.out.println(outerInstance.anonymousStaticInstance);// Java warns you here and
// tells you to access anonymousStaticInstance statically. This is because
// anonymousStaticInstance no longer belongs to any given instance of Outer.
// There is only one anonymousStaticInstance, that "belongs" to the class Outer,
// rather than multiple anonymousInnerInstances which each belong to an instance
// of Outer.
System.out.println(outerInstance.regularInnerInstance);
}
}
Remember that anonymous classes can be "inner" OR "nested". So when talking about them in general, just say "anonymous class". (Anonymous inner classes are a type of anonymous class). Also, do make sure to read the comments as they give most of the explanation.
Any questions? :)

How it's called the java overriding functions after a new

I'm finding this kind of overriding after a new in java code very often
classB body
....
ClassA a = new ClassA(){
#Override
public void funcion(){
atributeClassB = whatever
}
} ;
....
How is it called this kind of constructing ? when is executed the code between brackets ? how this code can have access to a classB attribute ?
in fact if i only know how this way of working is called i can document myselve in google but without a key name i couldn't find it.
the code where i've found it is this here on line 151
It's called an anonymous local derived class (or "anonymous inner class", though there's a difference between just being "inner" and being local [all local classes are inner; not all inner classes are local; more below]). The code within the curly braces forms part of the class definition of the anonymous class.
This
ClassA a = new ClassA(){#Override public void funcion(){ atributeClassB = whatever } } ;
...is effectively equivalent to this:
ClassA a = new SubClassA();
...where SubClassA is defined within the containing class:
class SubClassA extends ClassA {
#Override public void funcion(){ atributeClassB = whatever }
}
...although there's a bit more to it than that because the anonymous class in your example is defined within a method (that's the "local" vs. "inner" thing), more in the various sections starting here.
That's an anonymous inner class.
The other two answers are correct. I just want to add that the #Override annotation means exactly the same thing here as it would in an ordinary method declaration. It is saying that the method is overriding a method declared in a superclass or (Java 6 and later) implementing a method declared in an interface or abstract superclass.

Why getClass returns the name of the class + $1 (or $*)

I'm writing a piece of code in which I have to cast an Object if it is an instance of a certain class.
As usual I'm using instanceof for checking the compatibility.
The problem is that the check is never satisfied because the objects belong to "strange" classes.
For example; when I call the method getClass().getSimpleName() on this object it return me the name of the class + $* (e.g. ViewPart$1 instead of ViewPart).
What does this $* means?
Is there a solution or a workaround?
That shows an inner class (either anonymous (if it has a number) or named). For example:
class Foo {
static class Bar {
}
}
The name of class Foo.Bar is Foo$Bar. Now if we had:
class Foo {
static void bar() {
Runnable r = new Runnable() {
public void run() {};
};
System.out.println(r.getClass());
}
}
That will print Foo$1.
You can see the same effect in the naming of the class files created by javac.
These are instances of an anonymous class. ViewPart$1 is the first anonymous class defined inside ViewPart - but that doesn't mean it's a subclass of ViewPart. It's most likely an anoymous implementation of some Listener interface.
$ denotes for inner class. For example consider two classes
public class TopClass {
class SubClass {
// some methods
}// inner class end
} // outer class end
If you compile this code you will get two class files TopClass.class and TopClass$SubClass.class.
Check your ViewPart class whether it has any inner classes.
Hope it helps.

How to pass object into implements and pass out the local object?

How do I pass a object to an implement and pass the local object to object that is outside? I think the SwingUtilities.invokeLater is nessasary for a Swing object , right?
Sensors sens = new Sensors();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
GUI application = new GUI(sens);
application.getJFrame().setVisible(true);
}
});
SMS sms = new SMS(application);
this is me try to solve the problem , but i get a No enclosing instance of type GUI is accessible. Must qualify the allocation with an enclosing instance of type GUI (e.g. x.new A() where x is an instance of GUI). problem.
// in main
Sensors sens = new Sensors();
GUI application = null;
SwingUtilities.invokeLater(new GUIthread(sens , application));
SMS sms = new SMS(application);
//a class inside GUI.java , but not inside GUI class
class GUIthread implements Runnable{
Sensors s;
GUI g;
public GUIthread(Sensors s , GUI g){
this.s = s;
this.g = g;
}
#Override
public void run() {
// TODO Auto-generated method stub
g = new GUI(s);
g.getJFrame().setVisible(true);
}
}
the sourcecode
This problem arises when you try to create an instance of a non-static inner class in a context that does not specify (or imply) an instance of the enclosing class.
From this, I deduce that you have declared one of your classes as a non-static inner class; e.g. something like this:
public class Outer {
...
public class Inner {
public Inner() {
...
}
...
}
...
}
If you now try to create an instance of Inner in some other code using new Inner(), you will get a compilation error like the one you are seeing.
You can do one of two things to "fix" the problem:
If you change public class Inner { to public static class Inner {, you can use new Inner() as you are currently doing. But this will mean that the code of Inner cannot access the (final) instance variables of the enclosing class; i.e. Outer.
If you don't want to change Inner to a static class, you will need to instantiate it as follows:
Outer outer = ...
...
Inner inner = outer.new Inner(); // qualified creation
FOLLOWUP
any down side using static class to call swing?
Only the one that I identified above.
SO , all the instantiate happen inside Outer constructor? right?
No. The code in the "qualified creation" example above can appear anywhere that the Inner class is accessible. And since we declared it as public ...
If you instantiate Inner inside a constructor (or instance method) for Outer, you can just use new Inner(). The enclosing Outer instance is the same as this.
Try
final Sensors sens = new Sensors();
instead.
Easy, declare the reference final and it will be seen by the anon class code.
I agree with Zach and suspect that GUIthread is an inner class. If so, you may do well to make it a stand-alone class or a static inner class, but it's difficult to know if this is the true solution without more information and without the actual error message.

Categories

Resources