I'd like to ask when it's required to explicitly write the name of the outer class when referring to the inner class or static nested class.
Ex:
class B {
static class Inner {
int a = 10;
}
}
class Test extends B {
public static void main(String[] args) {
Test t = new Test();
Inner obj = new Inner();
System.out.println(obj.a);
}
}
What I'd like to ask is under which circumstances it's needed to write:
B.Inner obj = new B.Inner();
instead of
Inner obj = new Inner();
For static nested classes (as G. Fiedler has mentioned in his answer) you can write new Inner() when you are within the scope of B.
You can also directly refer to Inner from within Test because it extends B.
In all other cases you need to say B.Inner and new B.Inner().
Inner classes - which are not static by definition - are initialized differently. Let's look at this example B:
class B {
public class Inner {
...
}
}
Inner classes are always tied to an instance of the outer class. That means that in this case there has to be an instance of B for us to be able to instantiate Inner. So let's do that:
B b = new B();
I'm by the way assuming we are currently somewhere outside of the scope of B
In order to create an instance of Inner we use our instance of B and write:
B.Inner inner = b.new Inner();
If we were inside of B (in a non-static method) we could, however, simply write
Inner inner = new Inner();
because we - or rather the compiler - know(s) that an instance of B has to exist for this inner to be tied to.
If you are inside the scope of class B then new Inner() can be used. Outside of class B new B.Inner() must be used.
Related
This question already has answers here:
What causes error "No enclosing instance of type Foo is accessible" and how do I fix it?
(11 answers)
Closed 8 years ago.
I'm new to Java.
My file A.java looks like this:
public class A {
public class B {
int k;
public B(int a) { k=a; }
}
B sth;
public A(B b) { sth = b; }
}
In another java file I'm trying to create the A object calling
anotherMethod(new A(new A.B(5)));
but for some reason I get error: No enclosing instance of type A is accessible. Must qualify the allocation with an enclosing instance of type A (e.g. x.new B() where x is an instance of A).
Can someone explain how can I do what I want to do? I mean, do I really nead to create instance of A, then set it's sth and then give the instance of A to the method, or is there another way to do this?
Outside the outer class, you can create instance of inner class like this
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
In your case
A a = new A();
A.B b = a.new B(5);
For more detail read Java Nested Classes Official Tutorial
In your example you have an inner class that is always tied to an instance of the outer class.
If, what you want, is just a way of nesting classes for readability rather than instance association, then you want a static inner class.
public class A {
public static class B {
int k;
public B(int a) { k=a; }
}
B sth;
public A(B b) { sth = b; }
}
new A.B(4);
Interesting puzzle there. Unless you make B a static class, the only way you can instantiate A is by passing null to the constructor. Otherwise you would have to get an instance of B, which can only be instantiated from an instance of A, which requires an instance of B for construction...
The null solution would look like this:
anotherMethod(new A(new A(null).new B(5)));
I will be amazed if anyone can answer this question. I am a beginner struggling immensely with the syntax and logic of nested classes in Java. If you run the following program, 'a' will print instead of 'b'. Why?
class MainClass
{
public static void main(String[] args)
{
Outer OuterRefVar_a = new Outer('a');
Outer OuterRefVar_b = new Outer('b');
OuterRefVar_a.InnerTypeMember = OuterRefVar_a.new Inner();
OuterRefVar_b.InnerTypeMember = OuterRefVar_a.InnerTypeMember;
OuterRefVar_b.InnerTypeMember.set_innerChar_to_outerChar();
System.out.println(OuterRefVar_b.InnerTypeMember.innerChar);
}
}
class Outer
{
char outerChar;
Outer(char outerChar)
{
this.outerChar = outerChar;
}
class Inner
{
char innerChar;
void set_innerChar_to_outerChar()
{
innerChar = outerChar;
}
}
Inner InnerTypeMember;
}
That happens because while you have set the InnerTypeMember reference of object of A onto B..
OuterRefVar_b.InnerTypeMember = OuterRefVar_a.InnerTypeMember;
The inner object of A still has a reference to it's original Outer object A and will reference its member variables. Java implements inner classes by giving the object a secret reference to "Outer.this" which doesn't change simply by setting the InnerTypeMember on the other instance.
For example, if you had a InnerTypeMember variable within a completely different class, calling set_innerChar_to_outerChar() would still be expected to find Outer.outerChar on the object for which the inner class was original constructed.
In the below code, are b and show inherently static?
public class A {
public static class B {
private int b = 0;
public void show() {
System.out.println(b);
}
}
}
No they aren't static. You need to create an instance of B to access them.
The static keyword in your code example means that instances of B can be created without an instance of A.
If B was not static:
Instances would have an implicit reference to an instance of A.
The only way to create them would be to use new B() inside class A, or using syntax like new A().new B().
Methods in B can refer to A.this (the implicit reference to an instance of A).
Methods in B can refer to A.this.someField (using that implicit reference).
Methods in B can call instance (non-static) methods in A.
However, because B is static:
Instances do not have a reference to an instance of A - you don't need an A to create a B.
Instances can be created using new A.B() (or just new B() from within in class A)
Methods in B cannot refer to A.this.
Methods in B cannot access fields in A (unless passed in as a parameter).
Methods in B cannot call instance (non-static) methods in A.
They are not static. They are instance fields in B.
Meaning you need to have an instance of B to get/set them.
B is static in A but that does not make those fields of B static.
You can create many instances of B without any reference to A.
So B is static class in A but the same is not true for B's instance fields.
The static keyword has two meanings that are actually quite different and that can be confusing.
Static on a variable/method means that it exists at the class level, not the instance level. This means that you only have one copy of that variable/method no matter how many instances of the class you create.
Static on an inner class though just means that the class does not depend upon its outer class. In your example you can create a new B() without having an A. If you didn't have the static keyword on the class you could not create a new B() unless it was within an instance of A.
B is a static inner class of A.
Need to instantiate B.
A.B innerObject = new A.B();
innerObject.show();
The identifier static has a specific purpose here that many people don't immediately grasp. I'm going to take your code and change it a bit.
public class A {
private int a;
public A(int a) {
this.a = a;
}
public class B {
public void show() {
System.out.println(a);
}
}
}
Now, what's happening in class B? Because B is a non-static class, it has access to other non-static members in class A. Essentially, it states that every class A object has their own flavor of class B objects, even thought they are functionally the same. For us to get that same behavior if B was a static class:
public class A {
private int a;
public A(int a) {
this.a = a;
}
public int getA() { return a; }
public static class B {
public void show(A a) {
System.out.println(a.getA());
}
}
}
Here, this implies that the flavor of B objects doesn't change depending on which A object created it. The B class is static so that it cannot access non-static members of the A class object that created it and must access those members explicitly from whichever A object it wants to interact with.
In the previous implementation, a B object would seamlessly access fields and non-static methods of the A object that created it.
These are two different behaviors and often it's clear exactly which one fits your objective.
I am relatively new to Java. I wanted to create an arraylist of an outer class and for each index of the outer class of the arraylist I want an arraylist of inner classes.
public Outerclass{
//Code Here
public InnerClass{
//Code Here
}
}
//My attempt at setting up the arrays
public ArrayList <Outerclass> olist;
public ArrayList <InnerClass> ilist;
olist= new ArrayList<Outerclass>();
for (int i = 0; i < 3; i++) {
Outerclass c = new Outerclass ();
ilist = new ArrayList<InnerClass>();
for(int j = 0 ; j < 4; j++){
InnerClass e = new InnerClass();
ilist.add(e);
}
olist.add(c);
}
Will this work?
First, I think that you should learn how to walk before you start running:
public Outerclass
should be
public class Outerclass
same with inner!
Second, all the last portion of your code should be in a main() method INSIDE Ourclass.
And third, no, you cannot use inner class like that, that's why these classes are inner. If you want to use inner classes from inside main() or from outside the outer class you have to use an instance of outer in order to access them, same like accessing any other instance member - you can't access it directly:
Outerclass oc = new Outerclass();
Outerclass.InnerClass in = oc.new InnerClass();
A litte refinement for answer #2, if you have nested classes for data storage, means that you have an constructor for the outer class that automatically generates a variable number of array members for the inner class like a tree structure. This solution is practically a workaround which uses one defined member - an ArrayList - which can be expanded later instead of a direct definition of an InnerClass[] array inside the OuterClass, which won't work if its not static.
public class OuterClass
{
private int NumberInnerClassInstances;
// ... other members of OuterClass
ArrayList<InnerClass> innerClassInstances = new ArrayList<>();
OuterClass( input vars ...) {
// calculate the NumberInnerClassInstances needed
for(int i = 0 ; j < NumberInnerClassInstances; i++) {
OuterClass.InnerClass in = this.new InnerClass(i);
innerClassInstances.add(in);
}
}
public class InnerClass
{
int icvar;
InnerClass(int i) {
//...construct the Inner Class Member #i
// can access the members of OuterClass
}
}
}
from outside, you can then access the InnerClass Instances with get:
oc = new OuterClass( vars ...)
var = oc.InnerClassInstances.get(i).icvar
Here are the key lines of your code:
Outerclass c = new Outerclass ();
InnerClass e = new InnerClass();
That won't work. You will get a compilation error.
Since InnerClass is an inner class, it needs to be instantiated in the context of an instance of its enclosing class (i.e. OuterClass). Like this:
Outerclass c = new Outerclass ();
InnerClass e = c.new InnerClass();
The c.new ... form is called a qualified class instance creation expression; see JLS 15.9.
Notes:
If the code that creates the inner class is in the context of an instance of the outer class (e.g. it is in an instance method of the outer class) then you don't need to qualify the new like that.
If the InnerClass is static this isn't necessary either. But then InnerClass is a nested class not an inner class ... according to the standard Java terminology.
An instance of an inner class can only exist within an instance of an outer class. (For a distinction between static and non-static inner classes, see this answer for more info).
What this means is that you create inner objects within outer objects. You can think of it as the outer objects creating and containing the inner objects (hence the name inner)
Here's an example:
import java.util.ArrayList;
public class OuterClass {
static ArrayList<InnerClass> innerClasses = new ArrayList<InnerClass>();
public static void main(String[] args) {
OuterClass oc1 = new OuterClass();
OuterClass.InnerClass ic1 = oc1.new InnerClass();
OuterClass.InnerClass ic2 = oc1.new InnerClass();
innerClasses.add(ic1);
innerClasses.add(ic2);
System.out.println(innerClasses.size());
}
class InnerClass {
}
}
Given that the InnerClass needs to maintain reference to the members of the OuterClass, I wonder why aren't you putting the ArrayList<InnerClass> inside OuterClass. If they're composed in that way it makes much more sense to have the list 'managed' by the OuterClass and just give it access methods to return the list of InnerClass instances etc.
So something like this:
public class OuterClass
{
private List<InnerClass> innerClassInstances = new ArrayList<>;
public void addInnerInstances(int count)
{
for(int j = 0 ; j < count; j++)
{
InnerClass e = new InnerClass();
innerClassInstances.add(e);
}
}
public List<InnerClass> getInnerClassInstances()
{
return innerClassInstances;
}
public class InnerClass
{
//...
}
}
//in your main class or wherever
List<Outerclass> olist;
olist= new ArrayList<Outerclass>();
for (int i = 0; i < 3; i++)
{
Outerclass c = new Outerclass ();
c.addInnerInstances(4);
olist.add(c);
}
You cannot create the InnerClass on its own with new as you're doing, you are saying that it needs to access the members of its OuterClass instance, and as you can see in your code, for each new InnerClass() you are never specifying in any way what is the OuterClass instance for it.
I have a query regarding accessibility of top level class from member inner class.
I have just read the reason why local or anonymous inner classes can access only final variables.The reason being JVM handles these two classes as entirely different classes and so, if value of variable in one class changes, it can't be reflected at run time in another class file.
Then, my question is that how an inner member class (non-static) can have access to members to members of top level class, as JVM is still treating these two classes as different class files? If value of a member variable of top level class changes, how will it possible to reflect in class file of inner class at runtime?
They're separate classes, but there's an implicit reference to the instance of the "outer" class in the "inner" class. It basically acts as a variable which you can get at either implicitly or via special syntax of ContainingClassname.this.
Note that if you don't want such an implicit reference, you should declare the nested class as static:
public class Outer
{
private class Inner
{
// There's an implicit reference to an instance of Outer in here.
// For example:
// Outer outer = Outer.this;
}
private static class Nested
{
// There's no implicit reference to an instance of Outer here.
}
}
this is implicitly final, you cannot change it. When you write some thing like
class Outer {
int a;
class Inner {
{ a = 1; }
}
}
you are actually writing the same as
class Outer {
int a;
class Inner {
{ Outer.this.a = 1; }
}
}
The a is not final but the Outer.this is, and that is the reference which is used.