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];
Related
I would love to understand why the following instantiation will not compile:
Superclass.Subclass myObject = new Superclass.Subclass();
The error message reads:
No enclosing instance of type Superclass is accessible. Must qualify the allocation with an enclosing instance of type Superclass (e.g. x.new A() where x is an instance of Superclass).
What is meant by enclosing instance? Why is this necessary?
It seems this message is stating that the syntax must be:
Superclass mySuperObj = new Superclass();
Superclass.Subclass mySubObj = mySuperObj.new Subclass();
BUT it fails to explain what is wrong with my method or why this alternative syntax must be used.
The new [enclosing class].[enclosed class](...) idiom is used to initialize static nested classes, that is nested classes that are declared as a static member of their enclosing class.
The [enclosing class instance].new [enclosed class](...) idiom is used to initialize inner classes, that is, nested classes that are declared as an instance member of their enclosing class.
Examples
With...
class A {
static class B {}
class C {}
}
You will use:
new A.B()
new A().new C(), or with a given instance of A called a,
a.new C()
Note
See documentation
in this case you dont talk from sub class but inner class instead....
so, in this case to create an instance of an inner class you need an instance of the outer class, so you can do:
public class Foo {
public static void main(String[] args) {
Foo myFooObject = new Foo();
Foo.InnerClass myFooInnerClass = myFooObject.new InnerClass();
System.out.println(myFooObject);
System.out.println(myFooInnerClass);
}
class InnerClass {
#Override
public String toString() {
return "Am inner class";
}
}
}
The syntax to create an Inner class object is
InnerClass innerObj = new OuterClass().new InnerClass();
NOT the
Superclass.Subclass myObject = new Superclass.Subclass();
Because :
An instance of InnerClass can exist only within an instance of OuterClass.
To instantiate an inner class, you must first instantiate the outer class. Then, create the inner object within the outer object with this syntax:
InnerClass innerObj = new OuterClass().new InnerClass();
Read Java Docs for more details
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.
Is there any way to access the methods of local inner classes in Java. Following code is the sample code that I tried before. According to that what is the mechanism to access the mInner() method?
class Outer{
int a=100;
Object mOuter(){
class Inner{
void mInner(){
int y=200;
System.out.println("mInner..");
System.out.println("y : "+y);
}
}
Inner iob=new Inner();
return iob;
}
}
class Demo{
public static void main(String args[]){
Outer t=new Outer();
Object ob=t.mOuter();
ob.mInner(); // ?need a solution..
}
}
As ILikeTau's comment says, you can't access a class that you define in a method. You could define it outside the method, but another possibility is to define an interface (or abstract class). Then the code would still be inside your method, and could access final variables and parameters defined in the method (which you couldn't do if you moved the whole class outside). Something like:
class Outer {
int a = 100;
public interface AnInterface {
void mInner(); // automatically "public"
}
AnInterface mOuter() { // note that the return type is no longer Object
class Inner implements AnInterface {
#Override
public void mInner() { // must be public
int y = 200;
System.out.println("mInner..");
System.out.println("y : " + y);
}
}
Inner iob = new Inner();
return iob;
}
}
class Demo {
public static void main(String[] args) { // the preferred syntax
Outer t = new Outer();
Outer.AnInterface ob = t.mOuter();
ob.mInner();
}
}
Note: not tested
Note that the return type, and the type of ob, have been changed from Object. That's because in Java, if you declare something to be an Object, you can only access the methods defined for Object. The compiler has to know, at compile time (not at run time) that your object ob has an mInner method, and it can't tell that if the only thing it knows is that it's an Object. By changing it to AnInterface, the compiler now knows that it has an mInner() method.
The scoping rules of a local class are pretty much the same as the scoping rules of a variable, that is, it is confined to the enclosing block.
The same way you cannot access variable iob from main, you cannot access local class Inner from main.
Outside the enclosing block, there's no difference between a local class and an anonymous class. Neither can be accessed. The difference is that within the enclosing block, the local class can be accessed by name, especially useful if you need to access it repeatedly, e.g. to create multiple instances.
The only way to interact with a local/anonymous class outside the enclosing block, is through any superclass or interface implemented by the class in question.
To access the inner class create an object of inner class..
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
from your example
outer t=new outer();
outer.inner inner1=t.new inner();
Hope this helps you...
In effective java second edition, the author says,
It is possible, although rare, to establish the association manually
using the expression enclosingInstance.new MemberClass(args). As you
would expect, the association takes up space in the nonstatic member class
instance and adds time to its construction.
What does enclosingInstance.new MemberClass(args) mean? I googled for this and couldn't find anything. Can someone explain to me and shed some light? I have to take a seminar on this topic...
It means "create a new instance of MemberClass, using enclosingInstance as the reference for the new instance".
An inner class has an implicit reference to its enclosing class - normally if you just call new MemberClass() within an instance method, the enclosing class instance is implicitly this, but using enclosingInstance.new MemberClass() you can explicitly specify a different one. You can also use this approach to create an instance of the inner class from a static method, or indeed from an entirely different class.
A demonstration may help to explain:
class Outer {
private String name;
Outer(String name) {
this.name = name;
}
class Inner {
void showEnclosingName() {
System.out.println("Enclosing instance name: " + name);
}
}
void demo() {
Outer outer = new Outer("Other Outer");
Inner inner1 = new Inner(); // Implicitly this.new Inner();
Inner inner2 = outer.new Inner();
inner1.showEnclosingName(); // Prints Original Outer
inner2.showEnclosingName(); // Prints Other Outer
}
public static void main(String[] args) {
Outer outer = new Outer("Original Outer");
outer.demo();
}
}
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.