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.
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.
To my knowledge, normally in Java, something that is static means you can't create an instance of it. But if that is the case, why can you create an instance of a static nested class? Doesn't that defeat the purpose of something being static?
To my knowledge, normally in Java, something that is static means you can't create an instance of it.
That's not right. static is more "does not belong to any specific instance, but to the type/class itself".
Think of a static class in the context of the enclosing class. A static class is a static member, meaning that the nested class is not tied to any particular instance of the enclosing class.
The implication of this is that you can create an instance of the nested class without having to create an instance of the outer class first.
something that is static means you can't create an instance of it.
That's not true. Not only can you not create instances of static fields, you can't create instances of non-static fields either, because it is a field, not a class.
static just means that you don't need to create an instance of the surrounding class to access it. static members belong to the class itself, instead of instances of that class.
With this definition, static classes makes total sense.
Instances of static classes can be created without creating instances of their outer class:
class Outer {
static class Inner {}
}
Outer.Inner obj = new Outer.Inner(); // no Outer instances created!
Whereas instances of non-static inner classes cannot:
class Inner {
class Outer {
}
}
Inner inner = new Inner(); // I have to create this instance, otherwise it wouldn't compile
Inner.Outer outer = inner.new Outer();
Imagine a situation where you have a method in your nested static class and you want to call that method.
Refer to this snippet below:
class OuterClass
{
// static nested class
static class StaticNestedClass
{
void display()
{
System.out.println("Static Nested Class Display Method");
}
}
static void display()
{
System.out.println("Outer Class Display Method");
}
public static void main(String[] args)
{
// accessing a static nested class
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
nestedObject.display(); // This calls the display() method of the static nested class
OuterClass.display(); // This calls the display() method of outer class
}
}
How will you access the display() of static nested class without creating an object of it.
Java allows to create an instance of static nested class so that we can access the methods defined within that class.
Hope it helps!!!
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.
I'm having a hard time wrapping my head around non-static nested classes in Java. Consider the following example, which prints "Inner" and then "Child".
class Outer {
class Inner {
Inner() { System.out.println("Inner"); }
}
}
public class Child extends Outer.Inner {
Child(Outer o) {
o.super();
System.out.println("Child");
}
public static void main(String args[]) {
new Child(new Outer());
}
}
I understand that instances of Inner always have to be associated with an Outer instance, and that that applies to Child too since it extends Inner. My question is what the o.super() syntax means - why does it call the Inner constructor?
I've only seen a plain super(args) used to call the superclass constructor and super.method() to call the superclass version of an overridden method, but never something of the form instance.super().
It's called a "qualified superclass constructor invocation".
Citing from here:
Explicit constructor invocation statements can be divided into two kinds:
Alternate constructor invocations begin with the keyword this (possibly prefaced with explicit type arguments). They are used to invoke an alternate constructor of the same class.
Superclass constructor invocations begin with either the keyword super (possibly prefaced with explicit type arguments) or a Primary expression. They are used to invoke a constructor of the direct superclass. Superclass constructor invocations may be further subdivided:
Unqualified superclass constructor invocations begin with the keyword super (possibly prefaced with explicit type arguments).
Qualified superclass constructor invocations begin with a Primary expression . They allow a subclass constructor to explicitly specify the newly created object's immediately enclosing instance with respect to the direct superclass (§8.1.3). This may be necessary when the superclass is an inner class.
Inner Classes (non-static child classes) are essentially Nested Classes (static child classes) with implicit links back to their parent objects. Here is your above code, written instead using a static nested class:
class Outer {
static class Inner {
final Outer outer;
Inner(Outer outer) {
this.outer = outer;
System.out.println("Inner");
}
}
}
public class Child extends Outer.Inner {
Child(Outer o) {
super(o); // o.super();
System.out.println("Child");
}
public static void main(String args[]) {
new Child(new Outer());
}
}
Looking at this, you should be able to understand what o.super() was doing.
Why does o.super() in Child ends up invoking Outer.Inner constructor? It's simple: because Child extends Outer.Inner, and constructor calls are always chained up the hierarchy.
Here's a slight expansion to your snippet to illustrate:
class Outer {
Outer() {
System.out.println("Outer");
}
void outerMethod() { }
class Inner {
Inner() {
System.out.println("OuterInner");
outerMethod();
}
String wealth;
}
}
class OuterChild extends Outer {
OuterChild() {
System.out.println("OuterChild");
}
}
public class OuterInnerChild extends Outer.Inner {
OuterInnerChild(Outer o) {
o.super();
System.out.println("OuterInnerChild");
this.wealth = "ONE MILLION DOLLAR!!!";
}
public static void main(String args[]) {
System.out.println(new OuterInnerChild(new Outer()).wealth);
new OuterChild();
}
}
This prints:
Outer
OuterInner
OuterInnerChild
ONE MILLION DOLLAR!!!
Outer
OuterChild
Some key observations:
Because OuterInnerChild extends Outer.Inner, it inherits wealth, just like normal subclass semantics
And just like normal subclass semantics, the constructor of OuterInnerChild chains to the constructor of Outer.Inner
Because OuterChild extends Outer, its constructor chains, even when not invoked explicitly
Whether implicitly or explicitly, the constructor chains up the hierarchy
But why does the compiler demand that OuterInnerChild constructor takes an Outer o, and that o.super() is invoked?
Now that is specific to inner class semantics: it's done to ensure that all instances of OuterInnerChild has an enclosing Outer instance for Outer.Inner, the super class of OuterInnerChild. Otherwise, the constructor of Outer.Inner would not have an enclosing instance of Outer to invoke outerMethod() on.
Conceptually, a non-static inner class “belongs” to a particular object. It's sorta like each one gets its own version of the class, much like a non-static field or method belongs to a particular object.
So that's why we have funny syntax like instance.new Inner() and instance.super() — for contexts where the answer to the question “but whose Inner?” isn't immediately obvious. (In a non-static method of the outer class, you can just say new Inner(), and as usual that's short for this.new Inner().)
Always not to forget basic principles, in process of calling a sub class constructor it's always the parent class is instantiated first irrespective of inner/outer classes. In your scenario, as you are extending inner class and your inner class is a member of parent class which needs to be instantiated then followed by calling the actual inner class constructor.