This question already has answers here:
Non-static variable cannot be referenced from a static context
(15 answers)
Closed 3 years ago.
When instantiating an inner class in Java why do I need to create a new reference to it? In the first example code a reference to Inner is made, then using that reference there is an attempt to instantiate class Inner() which doesn't work but in the second example code (where a reference to Inner is still made), the instantiation of class Inner() is successful because instead of "inner", "Inner inner" was used. So to my (noob) understanding, a new reference had to be made?
public class Outer{
Inner inner;
private class Inner{}
public static void main(String[] args){
Outer outer = new Outer;
inner = outer.new Inner(); // doesn't work (only difference in code)
}
}
public class Outer{
Inner inner;
private class Inner{}
public static void main(String[] args){
Outer outer = new Outer;
Inner inner = outer.new Inner(); // works (only difference in code)
}
}
While in the first example, the instance inner has to be declared static to be used in another static context.
In the latter, the global variable inner is left unused as the local declaration and initialization takes priority.
From the first code, you are trying to instantiate a non-static variable in a static method which is not allowed.
But the second snippet, you are making the instantiation locally within the method (which does not affect the value of the variable outside the method). So the second snippet works in JAVA
Related
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.
This question already has answers here:
Java inner class and static nested class
(28 answers)
Closed 5 years ago.
I saw this pattern today and it confused me a lot:
abstract class A {
// does something
static class B extends A {
// does something as well
}
}
Two weird things I found about it:
Static class can be initialised using new A.B().
Static class is not unique in the application (therefore, not really static), as each initialisation creates a new object.
I am still perturbed as to why to use such a pattern? And does static class in this context mean, that you can access it's constructors statically, without needing to create an instance of A, but not really it being a unique in any way in the app?
EDIT:
OK, so I think my understanding of static classes came from C#. I am clear on the staticness of java classes now. But when would you use such a pattern (where inner static class is extending outer abstract one) and why?
static class doesnt have access to the outer class methods and variables, they keyword kind of means that it is a separated class.
class Out {
int i; void x(){}
static class In() {
i++; x(); // not valid instructions
}
class In2() {
i++; x(); // valid instructions
}
}
To instantiate a static inner class you just create a object of it:
Out.In obj = new Out.In();
non-static needs a instance of the outer class to be instantiated with:
Out o = new Out();
Out.In2 obj = new o.In2();
(If instantiating In2 inside of Out the word this is implicit)
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.
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
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.