Lets say I have a Outer class. Lets say there is a non static member class Inner. So an Outer instance will have a reference to an instance of Inner if the Outer class declares a field of type Inner and that is by definition. But how does Inner instance also has a implicit reference to Outer? When is this association created?
You have it the other way around:
public class Outer {
void foo() {
// In this Outer method, we have no implicit instance of Inner.
innerbar(); // Compiler error: The method bar() is undefined for the type Outer
Inner.this.innerbar();// Compiler error: No enclosing instance of the type Outer.Inner is accessible in scope
// instead, one has to create explicitly instance of Inner:
Inner inner1 = new Inner();
Inner inner2 = new Inner();
inner1.innerbar(); // fine!
}
class Inner {
void innerbar() {};
void callOuter () {
// But Inner has an implicit reference to Outer.
callMe();
// it works also through Outer.this
Outer.this.callMe();
}
}
void callMe() {}
}
From the Java language Spec
An instance i of a direct inner class C of a class 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).
The code
class Outer {
class Inner {
void printOuterThis() {
System.out.println(Outer.this);
}
}
}
Outer.Inner oi = new Outer().new Inner();
is mostly equivalent to this:
class Outer {
static class Inner {
Outer outerThis;
public Inner(Outer outerThis) {
this.outerThis = outerThis;
}
void printOuterThis() {
System.out.println(outerThis);
}
}
}
public class Scratch {
public static void main(String[] args) {
Outer.Inner oi = new Outer.Inner(new Outer());
}
}
The compiler automatically emits code that does what happens in the second: a field (this$0 that holds the value of Outer.this) for the implicit reference and transforms all constructors of Inner and calls to them to add initialisation of this field.
Related
public class Outer{
public class Inner{
}
}
public class Main {
public static void main(String[] args) {
Outer objOut = new Outer();
//Outer.Inner object1= objOut.new Inner(); // runes without a problem
//objOut.Inner object2= objOut.new Inner(); //gives error
}
}
This might sound little amateur but, What are the difference between Outer.Inner vs objOut.Inner.
You cannot use a variable name as the type of another variable, which is what you're trying to do with objOut.Inner. The type of the variable is Inner (or optionally Outer.Inner).
Because Inner is an inner class, it's associated with an instance of its outer class (its enclosing instance). When you create an instance of it, you can optionally¹ specify what object instance it's associated with, which is what you're doing with objOut.new Inner.
This example may help make it a bit clearer:
public class Example {
private String str;
public class Inner {
void show() {
// Show the string for the Example this Inner is part of
System.out.println(Example.this.str);
}
}
public Example(String s) {
this.str = s;
}
public static void main(String[] args) {
Example e1 = new Example("e1");
Example e2 = new Example("e2");
Inner i1 = e1.new Inner();
i1.show(); // "e1"
Inner i2 = e2.new Inner();
i2.show(); // "e2"
}
}
Live Copy
Notice how the i1 Inner instance gets e1 as its enclosing Example instance, and so sees e1's str, but i2 gets e2 as its enclosing instance so it sees e2's str.
I suggest this Java tutorial for more information.
¹ Sometimes it's not optional, such as in my Example class above, since where new Inner is used, there's no default instance it could use. It would be optional in an instance method of Example, but not in that static method.
This one :
Outer.Inner = objOut.new Inner();
will not compile but if you change it to :
Outer.Inner object = objOut.new Inner();
will mean creating an instance of inner class which has reference to Outer class - objOut will be instance of Outer class.
Also this :
objOut.Inner = objOut.new Inner();
will not compile since objOut which is the instance of Outer class does not have poperty Inner.
And it is not Outer class that knows the instance of Inner class - it is Inner class instance that knows the Outer class instance with which it was created.
EDIT
The line :
objOut.Inner object2= objOut.new Inner();
will not compile since Inner type identifer belongs to Outer class and not instance of this class.
Both don't compile.
To make the former compile, a variable should be declared, and the name to that variable should be given.
Outer.Inner obj = objOut.new Inner();
The latter wouldn't compile even if you did this step since objOut.Inner is neither a type (because the primary expression objOut is not a type) nor a valid name (because . is not allowed within an identifier (jls-3.8)).
A simplified rule (jls-14.4) for your case would be
LocalVariableType VariableDeclaratorId [= VariableInitializer];
I read that an instance of an inner class cannot be created without an instance of outer class. But when I tried to create an instance of my inner class using it as an instance member of my outer class, it worked.
I understand that it is creating an inner object through a reference to my outer class object, but is it the right way to do it?
Below is my code snippet:
public class TestInner {
private Nonstatic non = null;
private static int access = 4;
public class Nonstatic {
void hello() {
access = 90;
}
}
public static void main(String[] args) {
TestInner outer = new TestInner();
TestInner.Nonstatic innern= outer.new Nonstatic();
System.out.println("Non static obj1 is "+innern);
outer.testinnerObj();
}
public void testinnerObj() {
non = new Nonstatic();
System.out.println("Non static obj2 is "+non);
non.hello();
}
}
You're writing "An instance of Inner class cannot be created without an instance of outer class". And that's exactly what you are doing.
First, you create an instance of the "outer" class:
TestInner outer = new TestInner();
Then, you create an instance of the "inner" class - it only lives
in the scope of outer:
TestInner.Nonstatic innern= outer.new Nonstatic();
So, the question maybe boils down to this: yes, you are creating the object in the static main method. But that does not matter, because you are using the syntax outer.newwhich creates it in the scope of outer.
Hope that helps.
I have the following problem. Two nested anonymous types. I want to access "this" reference of the outer anonymous class inside the most inner class. Usually if one has anonymous nested class in a named outer class (lets call it "class Outer") he/she would type inside the nested class Outer.this.someMethod(). How do I refer the outer class if it's anonymous ?
Example Code:
public interface Outer {
void outerMethod();
}
public interface Inner {
void innerMethod();
}
...
public static void main(String[] args) {
...
new Outer() {
public void outerMethod() {
new Inner() {
public void innerMethod() {
Outer.this.hashCode(); // this does not work
} // innerMethod
}; // Inner
} // outerMethod
}; // Outer
...
} // main
The error I get is
No enclosing instance of the type Outer is accessible in scope
I know that I can copy the reference like this:
final Outer outerThisCopy = this;
just before instantiating the Inner object and then refer to this variable. The real goal is that I want to compare the hashCodes of outerThisCopy and the object accessed inside the new Inner object (i.e the Outer.this) for debugging purposes. I have some good arguments to think that this two objects are different (in my case).
[Context: The argument is that calling a getter implemented in the "Outer" class which is not shadowed in the "Inner" class returns different objects]
Any ideas how do I access the "this" reference of the enclosing anonymous type ?
Thank you.
You cannot access an instance of anonymous class directly from inner class or another anonymous class inside it, since the anonymous class doesn't have a name. However, you can get a reference to the outer class via a method:
new Outer()
{
public Outer getOuter()
{
return this;
}
public void outerMethod()
{
new Inner()
{
public void innerMethod()
{
getOuter().hashCode();
}
};
}
};
Let's say I have class like this:
class Outer {
public void getOuterValue() { }
class Inner {
public void getInnerValue() { }
}
}
I understand that I could create an object of this class as:
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
But let's suppose I am getting this object from some other method:
void someMethodSomewhere(Outer o) {
// How do I call getInnerValue() here using o?
}
Is there a way to call "getInnerValue" method using "o" in the scenario above?
Please let me know.
No. You need to have an instance of Inner to call methods on it.
An instance of the outer class is not enough (it would work the other way around: the inner class instance has a reference to the outer class instance).
void someMethodSomewhere(Outer o) {
// How do I call getInnerValue() here using o?
}
You can't. getInnerValue() is a method in Inner. Outer is not an Inner and does not have a reference to an Inner. When you are handed o, there is no way to navigate from that to any instance of Inner because there isn't one associated with o.
How do you create an inner class object with reflection? Both Inner and Outer classes have default constructors that take no parameters
Outer class {
Inner class{
}
public void createO() {
Outer.Inner ob = new Inner ();//that works
Inner.class.newInstance(); //<--why does this not compile?
}
}
"If the constructor's declaring class is an inner class in a non-static context, the first argument to the constructor needs to be the enclosing instance; see section 15.9.3 of The Java™ Language Specification."
That means you can never construct an inner class using Class.newInstance; instead, you must use the constructor that takes a single Outer instance. Here's some example code that demonstrates its use:
class Outer {
class Inner {
#Override
public String toString() {
return String.format("#<Inner[%h] outer=%s>", this, Outer.this);
}
}
#Override
public String toString() {
return String.format("#<Outer[%h]>", this);
}
public Inner newInner() {
return new Inner();
}
public Inner newInnerReflect() throws Exception {
return Inner.class.getDeclaredConstructor(Outer.class).newInstance(this);
}
public static void main(String[] args) throws Exception {
Outer outer = new Outer();
System.out.println(outer);
System.out.println(outer.newInner());
System.out.println(outer.newInnerReflect());
System.out.println(outer.new Inner());
System.out.println(Inner.class.getDeclaredConstructor(Outer.class).newInstance(outer));
}
}
(Note that in standard Java terminology, an inner class is always non-static. A static member class is called a nested class.)