I have a following code
class OuterClass<T>{
class Innerclass{
int k;
}
public static void main(String argv[]){
OuterClass<Integer> out =new OuterClass<>();
Innerclass in; // errors out
}
}
But for a class with no generics like the following code, I could create object for inner class.
class OuterClass{
class Innerclass{
int k;
}
public static void main(String argv[]){
OuterClass out =new OuterClass();
Innerclass in; // No error
}
}
why am i not able to create object of inner class though no generics are used in the inner class in my first example? Please explain.
Your main method belongs to OuterClass and is static in there. Since InnerClass is not a static class but implicitly depends on the generic type T (the generic type is available in the inner class, even if your example isn't using it), you cannot reference it from a static method.
In other words, since InnerClass depends on the generic type, you cannot break it "lose" from OuterClass and use it outside of it.
If your inner class won't depend on the generic type, you can just make it static. However, you might want to consider just extracting it into a separate class rather than nesting classes in this case:
class OuterClass<T> {
static class InnerClass {
int k;
}
public static void main( String argv[] ) {
InnerClass inner = new InnerClass();
}
}
If the generic is important for the inner class, you can tell the compiler which generic to infer for the outer class by specifying it (note that the generic type of outer and inner must match) or by using OuterClass.InnerClass in which case the compiler will use the raw type:
class OuterClass<T> {
class InnerClass {
int k;
}
public static void main( String argv[] ) {
OuterClass<String> outer = new OuterClass<String>();
// works and has the "correct" generic type
OuterClass<String>.InnerClass inner1 = outer.new InnerClass();
// works, but uses the raw type
OuterClass.InnerClass inner2 = outer.new InnerClass();
}
}
Note that you need an enclosing instance outer of type OuterClass<T> in order to instantiate InnerClass (since the class is not static, it belongs to an instance of OuterClass).
This also goes for the example without generics: you will need an enclosing instance to instantiate the inner class, so
class OuterClass {
class InnerClass {
int k;
}
public static void main( String argv[] ) {
OuterClass outer = new OuterClass();
InnerClass in = outer.new InnerClass();
}
}
will work while
class OuterClass {
class InnerClass {
int k;
}
public static void main( String argv[] ) {
OuterClass outer = new OuterClass();
InnerClass in = new InnerClass();
}
}
won't.
Related
I was wondering if there is any way to create a method-local inner class object in main() method with the help of Outerclass object.
public class Outerclass {
// instance method of the outer class
void my_Method() {
int num = 23;
// method-local inner class
class MethodInner_Demo {
public void print() {
System.out.println("This is method inner class "+num);
}
} // end of inner class
// Accessing the inner class
MethodInner_Demo inner = new MethodInner_Demo();
inner.print();
}
public static void main(String args[]) {
Outerclass outer = new Outerclass();
outer.my_Method();
}
}
Edit-1:
I was exploring the way to instantiate a method-local inner class in the main method ( I know the method-local inner class is not visible to the main method) but still, is there any workaround?
public class Outerclass {
// instance method of the outer class
void my_Method() {
int num = 23;
// method-local inner class
class MethodInner_Demo {
public void print() {
System.out.println("This is method inner class "+num);
}
} // end of inner class
}
public static void main(String args[]) {
Outerclass outer = new Outerclass();
//inner-class object is created while calling my_Method()
// TBH IDK how to do this
outer.my_Method().new MethodInner_Demo();
}
}
Class MethodInner_Demo is a local class, not an inner class, since it is declared in the body of a method. See e.g. The Java™ Tutorials.
A local class can only be seen by code in the method where is it declared.
If you want to be able to create an instance of the class from another method, then you need to move the class outside the method, so it becomes an actual inner class.
You can then create an instance, assuming you're "authorized", as defined by the public, protected, and private access modifiers. You do that by qualifying the new operator with an instance of the outer class.
In your case, we also need to add a field to carry the value of num.
public class Outerclass {
// instance method of the outer class
void my_Method() {
int num = 23;
// Accessing the inner class
Inner_Demo inner = new Inner_Demo(num);
inner.print();
}
// inner class
class Inner_Demo {
private final int num;
Inner_Demo(int num) {
this.num = num;
}
public void print() {
System.out.println("This is inner class "+num);
}
} // end of inner class
public static void main(String args[]) {
Outerclass outer = new Outerclass();
outer.my_Method();
// Accessing the inner class
int num = 42;
Inner_Demo inner = outer.new Inner_Demo(num);
inner.print();
}
}
The type of the method local class is invisible to main. However, you can create that instance and pass it to main.
public class OuterClass {
Object createInnerClass() {
int num = 23;
class InnerClass {
#Override
public String toString() {
return "I'm InnerClass. num=" + num;
}
}
return new InnerClass();
}
public static void main(String args[]) {
OuterClass outer = new OuterClass();
Object obj = outer.createInnerClass();
System.out.println(obj);
}
}
output:
I'm InnerClass. num=23
I'm making an instance from an inner class, but I can't understand what does this syntax mean.
OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
I know that I can't get an object from an inner class without getting an object from the outer one OuterClass outerObject = new OuterClass();, then we use the object from the outer class outerObject to get an instance from the inner class outerObject.new InnerClass();, so what does OuterClass.InnerClass actually means as it is not explained in the Java documentation as it states:
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();
If I recall correctly, the syntactic meaning is as follows:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
InnerClass The class InnerClass
. which is an inner class of
OuterClass OuterClass
innerObject has an instance named innerObject
= which is assigned the value
new InnerClass() of a new InnerClass instance
. such that when you use
OuterClass.this from within
InnerClass methods invoked on
innerObject, it refers to
outerObject outerObject.
The key here is that inner classes are created through a reference to the outer class. If your InnerClass is static (one InnerClass for the entire OuterClass class), you'll see that the reference to the outer class is static:
static class InnerClass { ... }
...
//Initialization will become:
OuterClass.InnerClass innerObject = new OuterClass.InnerClass();
^ this part is a static OuterClass reference
On the other hand, in your current scenario (InnerClass is not static), the inner class must be created with a reference to the OuterClass in the form of an object - outerObject. Furthermore, you are actually able to access outerObject from within InnerClass by referring to OuterClass.this:
OuterClass.java
public class OuterClass
{
class InnerClass
{
public OuterClass getOuterClassReference()
{
return OuterClass.this;
}
}
}
Main.java
class Main
{
public static void main(String[] args)
{
OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
System.out.println(outerObject);
System.out.println(innerObject.getOuterClassReference());
System.out.println(outerObject == innerObject.getOuterClassReference());
}
}
Output:
OuterClass#36baf30c
OuterClass#36baf30c
true
Here, 36baf30c in the output is an arbitrary memory address. These two output lines will always be the same. As you can clearly see, referring to OuterClass.this from within an InnerClass instance will return the OuterClass instance that was provided at initialization. This is part of the reason that you can't just call new InnerClass() - the reference OuterClass.this cannot be initialized properly without being provided with an instance.
This is the name of the class, and it's likely named this way to make it easier for the compiler to find the definition.
If you declare your variable as just being of type InnerClass, it will look for the file InnerClass.java, but there is no such file.
The dot notation indicates that it's actually a member of OuterClass, so it will look for the definition within the file OuterClass.java.
This is the same thing as using a class from a library,
com.example.MyLibrary.ExternalClass myExternalObject;
JVM does not make a difference between OuterClass and InnerClass: both classes are POJO and separate classes. But InnerClass is not static and therefore it has internal this refers to the instance of OuterClass (therefore it should be created only with existed OuterClass instance)
public class OuterClass {
public class InnerClass {
public OuterClass getOuterClassReference() {
return OuterClass.this;
}
}
}
OuterClass outerObject = new OuterClass();
OuterClass.InnterClass innerObject = outerObject.new InnerClass(); // innerObject has this reference to outerObject
public class OuterClass {
public static class InnerClass {}
}
OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = new OuterClass.InnerClass(); // innerObject does not have this reference to outerObject
In other words, you can emulate InnterClass by yourself like this:
public class OuterClass {
}
public class InnerClass {
private final OuterClass outer;
public InnerClass(OuterClass outer) {
this.outer = outer;
}
}
Outerclass.Innerclass is just a part of the Innerclass' full path.
The full path would be something like packagename.Outerclass.Innerclass.
Thus,
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
is really no different from something like:
java.util.ArrayList<T> varName = new java.util.ArrayList<T>();
You can define the inner class as static member of OuterClass
public class OuterClass {
public static class StaticInnerClass {
int i = 0;
public String call() {
i++;
return this.getClass().getName() + " i=" + i;
}
}
}
so defining the static inner class the compile knows that members is a class, the memory area is instanced at compile time (it is accessible in static way) and you can apply the new operator and the new operator instances the class in another memory area.
For example in a main class
public class Main {
public static void main(String[] args) {
/**
* https://stackoverflow.com/questions/57581397/how-instantiating-an-inner-class-in-java-really-works
*
* ### New instance of Inner class
*/
OuterClass.StaticInnerClass staticInnerClass = new OuterClass.StaticInnerClass();
System.out.println(staticInnerClass.call());
System.out.println(staticInnerClass.call());
staticInnerClass = new OuterClass.StaticInnerClass();
System.out.println("\n" + staticInnerClass.call());
System.out.println(staticInnerClass.call());
}
}
with output
// new of inner class and i = 0
innerclass.OuterClass$StaticInnerClass i=1
innerclass.OuterClass$StaticInnerClass i=2
// new of inner class and i = 0
innerclass.OuterClass$StaticInnerClass i=1
innerclass.OuterClass$StaticInnerClass i=2
References: https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html.
When we define inner classes, I understand that static inner classes are accessed with the outer class and inner member class exist with the instance of the outer class.
The confusion is, if I want to hold an instance of an non-private inner member class, then the variable declaration goes like:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
How outer class is able to reference the inner member class like this? What is happening here?
Sample Code:
public class NestedClasses {
public static void main(String[] args) {
A.B b = new A().new B(); // <- How A is directly accessing B, B is not defined as static.
A.StaticClass staticClass = new A.StaticClass();
}
}
class A {
static int x;
int y;
A() {
System.out.println(this.getClass().getName());
}
static class StaticClass {
StaticClass() {
System.out.println(this.getClass().getName());
}
}
class B {
B() {
System.out.println(this.getClass().getName());
}
}
}
class Outer
{
int x=10;
class Inner
{
void show()
{
System.out.println(x);
}
}
public static void main(String args[])
{
Outer obj=new Outer();
Inner obj1=new Outer().new Inner();
obj1.show();
}
}
I tried making a non static nested class and tried to use non static data member of outer class in non static inner class. I did not get that if x is non static, how i am using it without object. Kindly give me the answer?
You're not using it without an object. Inner (non-static nested) classes have a reference to the outer object, whose x is used.
Inner class is just a syntactic sugar to have an implicit reference to an outer class. Internally (after javac compilation) your class Inner looks like this:
static class Inner
{
private final Outer this$0;
public Inner(Outer outer) {
this$0 = outer;
}
void show()
{
System.out.println(this$0.x);
}
}
And when you write Inner obj1=new Outer().new Inner(); the compiler changes it to something like Inner obj1=new Inner(new Outer());.
I am wondering if the following is valid in Java:
class OuterClass {
OuterClass(param1, param2) {
...some initialization code...
}
void do {
// Here is where the doubt lays
OuterClass.InnerClass ic = this.new InnerClass();
}
class InnerClass {
}
}
Basically what I am trying to achieve here is to instantiate an inner class object from the current instance of the outer class, not a new instance, the current one. I believe this comes handy is when the constructor of the outer class is not empty (takes parameters) and we don't know what pass to them (they can't be null since some might be assigned to a class variable that is accessed by the inner class object).
Let me know if I explained myself well.
Thanks in advance!
Regarding:
public class OuterClass {
OuterClass() {
// ...some initialization code...
}
void doSomething() {
OuterClass.InnerClass ic = this.new InnerClass();
}
class InnerClass {
}
You don't need the explicit OuterClass identifier nor the this as they're implied.
So this is unnecessary:
OuterClass.InnerClass ic = this.new InnerClass();
And this is fine inside of an instance method:
InnerClass ic = new InnerClass();
Things get dicier though if you're creating an object of InnerClass in a static method such as main that is held inside of OuterClass. There you'll need to be more explicit:
This won't work
public class OuterClass {
public static void main(String[] args) {
InnerClass otherInnerVar = new InnerClass(); // won't work
}
But this will work fine:
public class OuterClass {
public static void main(String[] args) {
InnerClass otherInnerVar2 = new OuterClass().new InnerClass(); // will work
}
Every instance of an inner class, unless the Class is declared as static, must have a 'connected' instance of an outer class, in order to be instantiated.
This won't work:
public class Outer {
public class Inner {
}
public static void main(String[] args) {
Inner inner = new Inner(); //compilation error
}
}
However, this will work, it doesn't need an instance of Outer, since the static keyword is used:
public class Outer {
public static class Inner {
}
public static void main(String[] args) {
Inner inner = new Inner();
}
}
more info: java inner classes
Above is the example for creating Inner class object inside outer class and outside outer class:
public class OuterClass {
public class InnerClass{
public void myMethod(){
System.out.println("inside inner class");
}
}
public void myMethod(){
System.out.println("outer class method");
InnerClass class1 = new InnerClass();
class1.myMethod();
}
public static void main(String[] args){
//OuterClass.InnerClass class1 = new OuterClass().i
OuterClass outerClassObj = new OuterClass();
OuterClass.InnerClass innerClassObj = outerClassObj.new InnerClass();
innerClassObj.myMethod();
}
}