Outer and Inner class and static methods - java

I understand that an Inner Class it's non-static and a static method from the Outer Class can't reference it.
I have this code, that doesn't work, and I understand why that doesn't work.
class OuterClass {
class InnerClass{}
public static void outherMethod() {
InnerClass i = new InnerClass();
}
}
But then I have this other code, that DOES work, but I don't understand why it's different from the first one. Why does it work?
class OuterClass {
class InnerClass{}
public static void outherMethod() {
InnerClass i = new OuterClass.new InnerClass();
}
}
Thanks in advance!
EDIT: it's not duplicated because it isn't the same question. I'm not asking about static nested classes, I'm asking about static methods and inner classes

An inner class always requires an instance of the enclosing class in order to be instantiated.
A static method of OuterClass doesn't have an instance of OuterClass, so you can't create an instance of InnerClass without supplying an enclosing instance (of OuterClass).
InnerClass i = new InnerClass();
would work only from within an instance method of OuterClass.
InnerClass i = new OuterClass().new InnerClass();
works from within a static method since you are creating an instance of OuterClass and use it as the enclosing instance for an instance of InnerClass.

The key point to note here is Inner class is a member of Outer class.
So without an instance of it, you can't access it's members.
From docs directly
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();

Related

How to make a subclass accessible from instance only?

I'd like to create a subclass accessible only from an instance of the superclass, but not from the superclass itself, to be sure that the superclass' variables have been initialized.
For example:
public class SuperClass
{
int num;
SuperClass(int number){
num = number;
}
//Make this\/ accessible from instance only
class SubClass
{
SubClass(){}
public int read(){
return num;
}
}
}
In another file:
public void err(){
SuperClass.SubClass obj = new SuperClass.SubClass(); //Error! Superclass is not an instance
System.out.println(obj.read());
}
public void right(){
SuperClass sup = new SuperClass(3);
SuperClass.SubClass obj = new sup.SubClass(); //Correct, sup is an instance
System.out.println(obj.read()) //Print 3
That's not possible. Non-static inner classes have to be instantiated through an instance of an outer class. See this link for more info.
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.
Objects that are instances of an inner class exist within an instance of the outer class. Consider the following classes:
class OuterClass {
...
class InnerClass {
...
}
}
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();
There are two special kinds of inner classes: local classes and anonymous classes.
check the link

Visibility of inner class explanation

I want to compare two things. We know that:
Inner class can access every member from Outer class.
Outer class can't access members from Inner class.. unless you make an object of Inner class.
My question is why is that? Why can't Outer class access members of Inner class as well? Here is example to make it quite clear:
public class OuterClass {
String stringOuter;
void m1(){
//can call just stringOuter
InnerClass i = new InnerClass();
i.stringInner; //can call stringInner when you make object
}
class InnerClass{
String stringInner;
void m2(){
//can call stringOuter and stringInner
//doesn't need object from OuterClass
}
}
}
First of all, your stringOuter and stringInner are fields, not methods. Hence, you can not “call” them and your example of i.stringInner; still doesn’t compile, as it is not a statement.
To make the example valid, we may assign the values of the fields to another variable.
public class OuterClass {
String stringOuter;
void m1() {
InnerClass i = new InnerClass();
String s = i.stringInner;
}
class InnerClass {
String stringInner;
void m2() {
String s = stringOuter;
}
}
}
The reason why void m2() { String s = stringOuter; } works, is that an inner class, in contrast to a nested class which has the static modifier, always has an associated instance of the outer class.
Your example method m2() is equivalent to
void m2() {
OuterClass o = OuterClass.this;
String s = o.stringOuter;
}
In your example, the initialization of reference to the outer class instance is implicit, which only works in a context where an instance of the OuterClass is in scope. So when you change the m1() method to
static void m1() {
InnerClass i = new InnerClass(); // compiler error
String s = i.stringInner;
}
it doesn’t work anymore, as there is no instance of the OuterClass. You can provide an explicit instance instead:
static void m1() {
OuterClass outer = new OuterClass();
InnerClass i = outer.new InnerClass(); // uses outer
String s = i.stringInner;
}
But this is a rarely used feature of the Java programming language.
As said, if you change the inner class to a nested class, you can instantiate it without an instance of the outer class, but you also can not access non static members without specifying an instance explicitly:
public class OuterClass {
String stringOuter;
static void m1() {
InnerClass i = new InnerClass(); // no problem
String s = i.stringInner;
}
static class InnerClass {
String stringInner;
void m2() {
String s1 = new OuterClass().stringOuter; // works
String s = stringOuter; // does not work
}
}
}
I suppose class declarations are just the templates and that applies to Inner classes also , unless you instantiate an object from the inner class(template) or any other class you can't access its members . The exception is static members as they reside in class area .
OuterClass can access InnerClass data members depending on their type (static or non static). For non-static data members, access is allowed via objects and for static data-members, access is allowed via Class name (example explained below).
As per your example, the InnerClass is having non-static data members and they are only accessible through objects. That is why you're able to access the stringInner via object. If you'd declare a static data member in InnerClass then you can directly access it through InnerClass.staticDataMember.
Whenever we create an object of a class, it allocates a memory which consists of all the non-static data members. As these data members are part of that object, due to which we can access these data members via object.dataMember statement.
I hope it clarifies your answer?

How creation an instance of inner class works?

When I create an instance of inner class, I use this code.
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass inerClass = outerClass.new InnerClass();
But I don't understand how outerClass.new InnerClass() works, why we use .new it like new its inner class, I understand it is not, but I do not understand the syntax.
An inner class is POJO. So, when you look in the target directory, you see 2 (two) class files.
Therefore to create an instance of the inner class you use new.
OuterClass outerClass = new OuterClass(); // create instance
OuterClass.InnerClass inerClass = outerClass.new InnerClass(); // innerClass has `this` to outerClass instance
It means that InnerClass is not a static (i.e. has this reference to an object of OuterClass) and instance of OuterClass should be created prior to it.
OuterClass.InnerClass inerClass = new OuterClass.InnerClass();
It means that InnerClass is a static (i.e. has not this reference to an object of Outerlass) and it means, this is absolutely the same (from the JVM perspective) like two separate files with class OuterClass and class InnterClass.

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

Categories