explain the way to access inner class in java? [duplicate] - java

This question already has answers here:
Java inner class and static nested class
(28 answers)
Closed 8 years ago.
class Outer {
class Inner {
}
}
public class Demo {
public static void main(String args[]) {
Outer o = new Outer();
Outer.Inner inner = o.new Inner();
}
}
the way I create a reference for Inner class object is something like accessing static member in Outer class ? could you please explain the mechanism behind this ?

Not sure exactly what you are asking, but your code is valid.
You can only instantiate Inner if you have an instance of Outer, so you call only call Inner's constructor in the context of an instance of Outer, hence
Outer o = new Outer();
Inner i = o.new Inner();
works, but
Inner i = new Outer.Inner(); //bad
Inner i = Outer.new Inner(); //bad
are both trying to access Inner in a static way, and will not compile.
If you want create instances of Inner without first creating an instance of Outer, then Inner needs to be static

the way I create a reference for Inner class object is something like accessing static member in Outer class
Not at all - since you are using an instance of the Outer to access the constructor of the Inner, this is very much like accessing an instance member of the Outer class, not its static member. The name of the Inner class in the declaration is qualified with the name of its outer class Outer in order to avoid naming conflicts with top-level classes.
The reason for that is easy to understand: Inner is a non-static inner class, so it needs to reference an Outer. It does so implicitly, but the reference must be passed to the constructor behind the scene. Therefore, you call a constructor of Inner on an instance of Outer.
The syntax for making instances of static classes is similar to the syntax for making instances of regular classes, except the name of the nested class must be prefixed with the name of its outer class - i.e. following the static syntax:
class Outer {
static class Inner {
}
}
public class Demo {
public static void main(String args[]) {
Outer.Inner inner = new Outer.Inner();
}
}

You're actually accessing an inner class in a non-static way. A static inner class is actually different - the compiler makes a top-level class for it that is hidden from the programmer, which then works similarly to the way of instantiation that you have posted for the inner class.
You have to declare this way because since the inner class is non-static, it needs an instance of the outer class to make an instance of the inner class.
Outer o = new Outer();
is the required instance for the outer class.
Outer.Inner inner = o.new Inner();
is required for the instance of the inner class.

The reason why this looks weird is because you declared non-static inner class. That means that inner class will have access to instance variables in the enclosing class and would have to have a this reference to it.
Think of it this way: non-static inner class is a part of the enclosing class's instance like any other field. You need to specify a particular instance in order to create an object.
So just like you'd initialize a regular field like this (don't actually do that, it's bad):
o.someField = new Object(), you initialize inner class the way you did.

Related

Java new keyword with static inner class

I know this questions has been asked before, but mostly pretty specific regarding a certain library. And the answers given didn't really explain to me what was going on.
That's why I set up a pretty simple test scenario here, and tried to fiddle with it, but there are still some question marks!
Online Java Example
The simple code consists of two files:
Main.java
public class Main
{
public static void main(String[] args) {
// this works, and inner1 and inner2 seem to be new instances
Outer.Inner inner1 = new Outer.Inner();
Outer.Inner inner2 = new Outer.Inner();
inner1.setName("Mario");
inner1.say();
inner2.setName("Luigi");
inner2.say();
// if Inner is not a public static class this gives this error:
// error: an enclosing instance that contains Outer.InnerNoStatic is required
Outer.InnerNoStatic inner3 = new Outer.InnerNoStatic();
}
}
Outer.java
public class Outer {
public static class Inner {
private String name;
public void say() {
System.out.println("Hi " + name);
}
public void setName(String name) {
this.name = name;
}
}
public class InnerNoStatic {
public void say() {
System.out.println("Hi from InnerNoStatic");
}
}
}
So it seems like even though the Inner class is declared with static, we create two new instances called inner1 and inner2. Why is it called static then?
And in turn, if I remove the static, as in InnerNoStatic how would I go about getting an instance of that class?
static here dictates how Inner and InnerNoStatic are used with respect to Outer.
Because Inner is static in Outer, it is not tied to any specific instance of Outer (as always, a static member belongs to the class, not to any particular instance of that class). That explains how this compiles:
Outer.Inner inner1 = new Outer.Inner();
InnerNoStatic, however, is an instance member (that's that: if it's not static, it is tied to a given member). And that explains why the compiler raises an error here:
Outer.InnerNoStatic inner3 = new Outer.InnerNoStatic();
Because InnerNoStatic must be tied to an instance of Outer, you need to use such an instance to create inner3:
Outer.InnerNoStatic inner3 = new Outer().new InnerNoStatic(); //note the calls
Your can also use an existing instance.
Outer outer = new Outer();
Outer.InnerNoStatic inner3 = outer.new InnerNoStatic();
In both of these cases, an Outer instance is used to build an InnerNoStatic instance (there's just no variable pointing to the Outer object created with new Outer().new InnerNoStatic())
Note: It's easy to confuse new Outer.Inner(); with new Outer().new Inner();. These are not doing the same thing ("Outer" in the former is basically playing the role of a namespace, whereas new Outer() in the latter is creating an Outer object). That is, one constructor call (Inner()) in the former, but two constructor calls in the latter (Outer() and Inner()).
So it seems like even though the Inner class is declared with static, we create two new instances called inner1 and inner2. Why is it called static then?
static implies more independence for the nested class. It's designed mainly to increase encapsulation, readability, maintainability and it's a nice way to logically group classes.
And in turn, if I remove the static, as in InnerNoStatic how would I go about getting an instance of that class?
The syntax is a bit different because you need an instance of Outer.
Outer.InnerNoStatic inner3 = new Outer(). new InnerNoStatic();
So it seems like even though the Inner class is declared with static, we create two new instances called inner1 and inner2. Why is it called static then?
Objects of a "static" inner class are not tied to the objects of its enclosing class, opposite to non "static" inner classes. Having a "static" inner class instead of moving that class to the "top level" is a handy way of signalling to a user that objects of that inner class have not much use separate from the outer class, similar to e. g. Map.Entry.
And in turn, if I remove the static, as in InnerNoStatic how would I go about getting an instance of that class?
For example
public class Outer {
private InnerNoStatic innerNoStatic = new InnerNoStatic();
public InnerNoStatic getInnerNoStatic () {
return innerNoStatic;
}
// ...
and
Outer.InnerNoStatic innerNoStatic = new Outer().getInnerNoStatic();
Non-static inner classes always have a reference to a corresponding outer class. As a result, such class can be instantiated only by Outer class.
In opposite, a static inner class has no reference to Outer class and can be created by any other object, if visibility allows that. This is very similar to the behavior of static methods, that do not require an objects instance to be called.

Why can't main function instantiate inner class? [duplicate]

This question already has answers here:
How to instantiate non static inner class within a static method?
(4 answers)
Closed 5 years ago.
class Outer{
int i = 60;
class Inner{
void display(){
System.out.println(i);
}
}
public static void main(String args[]){
Inner o = new Inner();
o.display();
}
}
Main function does instantiate it's class which are non-static whereas when it comes to instantiating inner class(non-static), java compiler shows up with an error(like the above code). Why?
Edit: I am not asking how to instantiate inner class. I just want a logical reason why main() doesn't instantiate it's inner class while the following function does.
class Outer{
int i = 60;
void show(){
Inner k = new Inner();
k.display();
}
class Inner{
void display(){
System.out.println(i);
}
}
public static void main(String args[]){
Outer o = new Outer();
o.show();
}
}
You need an (enclosing) instance of Parent class as child class instance can't exist on it's own, e.g.:
Outer outer = new Outer();
Inner o = outer.new Inner();
o.display();
Outer class must be instatiated as well:
Inner o = new Outer().new Inner();
You need to have a reference of the parent class.
public static void main(String args[]){
Inner o = new Outer().new Inner();
o.display();
}
From Java Tutorials:
Static Nested Classes
As with class methods and variables, a static nested class is associated with its outer class. And like static class methods, a static nested class cannot refer directly to instance variables or methods defined in its enclosing class: it can use them only through an object reference.
Inner Classes
As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's methods and fields. Also, because an inner class is associated with an instance, it cannot define any static members itself.
So if you want to be able to instantiate an inner class, you need to have an instance of the outer class. In instance methods you don't need it because you're always referring to 'this'
The Java docs says:
An instance of InnerClass can exist only within an instance of
OuterClass and has direct access to the methods and fields of its
enclosing instance.
To instantiate an inner class, you must first instantiate the outer
class. Then, create the inner object within the outer object with this
syntax:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
So you can try like:
Inner o = new Outer().new Inner();
Because the static methods and attributes of a Class belong to the Class and not at an instance of the Class. For that reason can interact only with other static methods and attributes of the Class.

Instantiating an inner class within a main method

When we try to instantiate an Inner class (aka: non-static Nested class) in java, say we do that in two cases:
1.in a main method in the same file of the outer Class in which we have two options: (ex:)
public class Test1
{
class InnerClass
{
}
public static void main(String[] args)
{
InnerClass inner = new Test1().new InnerClass();
}
}
or :
public class Test1
{
class InnerClass
{
}
public static void main(String[] args)
{
Test1.InnerClass inner = new Test1().new InnerClass();
}
}
In a another class (say different file), then we have the second option only and using the first option requires us (of course) to import the InnerClass..,
Q: could you please explain why do we have the first option (without any import required) in the first case (the main method in the same file)?
Edit:
I guess the answer to the first question is some how related to the core idea of inner classes. but then +Q:
Q: Isn't an inner class a regular-member of an outer class, so if the inner class is not declared static (static nested class) then I suppose it is a non-static member and consequently its reference type, so why are we able to declare it within a static context (static method) ?
Simply, it is because when you instantiate the inner class from a main method outside the class in which the inner class is present, the Java compiler has no way on knowing inside which class lies that inner class. Hence you have to do
Test1.InnerClass innerClassObject = ...
instead of
InnerClass innerClassObject = ...
An instance of InnerClass can exist only within an instance of
OuterClass and has direct access to the methods and fields of its
enclosing instance.
To instantiate an inner class, you must first instantiate the outer
class. Then, create the inner object within the outer object with this
syntax:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
From Oracle Docs : https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

Member nested classes in java?

If we have a code...
public class Hello
{
public static void main(String args[])
{
Outer obj=new Outer();
obj.method1();
}
}
class Outer
{
void method1()
{
class Inner
{
}
}
}
I wanted to know,when the Inner class will be loaded by the ClassLoader.
Is it loaded at the time the method1() is called,or at the time when we will be creating its instance?And the class Inner is not performing any operation in method1(),its an empty class.Also,I wanted to know,how to create an instance of inner class in the above example?
Class Outer.Inner will be loaded the first time another class that refers to it as a variable type, method parameter type, method return type, superclass type, type parameter bound, or target type of an initializer or static method, or host class of a static variable reference is loaded. In your example, I would expect it never to be loaded.
Also,I wanted to know,how to create an instance of inner class in the above example?
As it is written, class Outer.Inner is accessible only inside method Outer.method1(), therefore it can be instantiated only within that method. There, you can just use new Inner(). If you want it to be instantiable from elsewhere then move its declaration out of the method body:
class Outer
{
class Inner
{
}
void method1()
{
}
}
That's better form for a named inner class anyway. It will not change when or whether Outer.Inner is loaded.
With that change, you can instantiate Outer.Inner anywhere within a constructor or instance method of Outer via the form new Inner(). If, however, you want to instantiate one from a different class, or in a static method of class Outer, then it's a bit trickier. The important thing to realize is that each instance of Outer.Inner needs an associated instance of Outer. This is determined from context when the instantiation is performed in an instance method of Outer, but if it is performed without such a context then the syntax is:
public static void main(String args[])
{
Outer obj=new Outer();
Outer.Inner inner = obj.new Outer.Inner();
}
Quoting from Section 12.4.1 of the JLS :
A class or interface type T will be initialized immediately before the
first occurrence of any one of the following:
T is a class and an instance of T is created.
A static method declared by T is invoked.
A static field declared by T is assigned.
A static field declared by T is used and the field is not a constant
variable (§4.12.4).
T is a top level class (§7.6) and an assert statement (§14.10)
lexically nested within T (§8.1.3) is executed.
Therefore, a class (regardless of whether is a nested class) will follow the same rules. In your particular case, Inner will not be loaded until an instance of the class is created.
To answer your second question, you can only create an instance of Inner inside method1 since Inner is a method local class whose scope is limited to method1 :
void method1()
{
class Inner
{
public Inner()
{
System.out.println("inner()");
}
}
Inner inner = new Inner();
}
To achieve the inner class, you need object anyway. If you call method1() like this, inner class never be called.
But if you define some object in method1() or public Outer() constructor, you can get result from inner class.

Can a static nested class be instantiated in Java?

From Oracle's Java tutorials I've found this text:
As with class methods and variables, a static nested class is associated with its outer class. And like static class methods, a static nested class cannot refer directly to instance variables or methods defined in its enclosing class — it can use them only through an object reference.
Note: A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class. In effect, a static nested class is behaviorally a top-level class that has been nested in another top-level class for packaging convenience.
Static nested classes are accessed using the enclosing class name:
OuterClass.StaticNestedClass
For example, to create an object for the static nested class, use this syntax:
OuterClass.StaticNestedClass nestedObject =
new OuterClass.StaticNestedClass();
I thought it is not possible to instantiate a static class, so I don't really understand the sentence in bold.
Do you have any idea what it means?
You are either confusing static with abstract as kihero says, or you are muddling the concept with a class that has static methods (which is just a class that happens to have static methods).
A static nested class is just a nested class that doesn't require an instance of its enclosing class. If you are familiar with C++, all classes in C++ are "static" classes. In Java, nested classes are not static by default (this non-static variety is also called an "inner class"), which means they require an instance of their outer class, which they track behind the scenes in a hidden field -- but this lets inner classes refer to fields of their associated enclosing class.
public class Outer {
public class Inner { }
public static class StaticNested { }
public void method () {
// non-static methods can instantiate static and non-static nested classes
Inner i = new Inner(); // 'this' is the implied enclosing instance
StaticNested s = new StaticNested();
}
public static void staticMethod () {
Inner i = new Inner(); // <-- ERROR! there's no enclosing instance, so cant do this
StaticNested s = new StaticNested(); // ok: no enclosing instance needed
// but we can create an Inner if we have an Outer:
Outer o = new Outer();
Inner oi = o.new Inner(); // ok: 'o' is the enclosing instance
}
}
Lots of other examples at How to instantiate non static inner class within a static method
I actually declare all nested classes static by default unless I specifically need access to the enclosing class's fields.
Static nested classes are themselves not static at all. In java, no class is static. Static keyword in static nested classes implies that it is another static member of the outer class. But it is just another raw class . Thats why we can instantiate this class
You are confusing static with abstract. Abstract classes can not be instantiated. static is not a valid qualifier for top level classes, but the meaning for inner classes is the one you quoted.
I guess you misunderstood the static class a little bit.
It's true that every abstract class and interface cannot be instantiated, but you do can instantiate an static class.
One thing you should notice is that every static class is a nested static class.
You cannot just create a static class, as you can see:
try to create a new class in eclipse
A static class always belongs to the "parent class" which encloses it, and the difference between static and non-static class is:
You can refer to the child static class just like a static property of the "parent class":
ParentClass.NestedStaticClass nestedstatic = new ParentClass.NestedStaticClass();
but you can only make reference to the non-static nested class by instantiating a parent class, like this:
ParentClass parent = new ParentClass();
ParentClass.NestedClass nested = parent.new NestedClass();
The difference is just like that between the static and non-static field.
Too long, didn't read: Every Concrete Class can be instantiated.
We should not expect a Concrete Static Nested Class to function identically as Static variables and Static methods, when it comes to calling and instantiation.
What do I mean by that? When we create variables and methods they can be either static or non-static. The keyword in the previous sentence is "either".
Static meaning they belong to the class and we must call them directly, like this:
Class.staticVariable();
Class.staticMethod();
Non-static meaning they belong to an Instance of that Class and we must call them like this:
Class obj = new Class();
System.out.println(obj.nonStaticVariable);
obj.nonStaticMethod();
But here we are talking about a Class, not a variable or a method.
Every Concrete Class can be instantiated. Thus we should not expect a Concrete Static Nested Class, to not be instantiable.

Categories