So someone asked me to explain why the first scenario throws a compiler error and the 2nd scenario does not:
class Outer {
public Outer() {
Inner i = new Inner();
class Inner {
}
}
}
The other scenario is:
class Outer {
public Boss() {
Inner i = new Inner();
}
class Inner {
}
}
I was successful in explaining that the first scenario throws a compiler error because you can't create an object of the class Inner before the class Inner gets pushed onto the stack. Feel free to elaborate on this or correct my understanding.
My main problem was not being able to explain why we can create an Inner object even though the the code for the class Inner comes after the constructor in the 2nd scenario. I feel like the best answer to this question would be to know where exactly inner classes are stored in memory.
I'm hoping someone can provide a solid explanation. Thank you.
Nothing to do with stack, it's just the declaration order.
In this code:
class Outer {
public Outer() { // constructor "method" body BEGIN
Inner i = new Inner();
class Inner {
}
} // constructor "method" body END
}
As you are declaring Inner (a LOCAL class, not an inner class) in an ordinary block (that happens to be inside the constructor). This code is semantically equivalent to:
class Outer {
public Outer() {
String fullName = firstName + " Smith";
String firstName = "John";
}
}
Which clearly does not work.
Update:
I see where confusion may arise. Hopefully this will clarify:
There are four types of inner classes, and where they can be declared:
Static member classes: declared as fields;
Member classes: declared as fiels as well;
Local classes: declared in blocks, as a statement (just like a variable declaration);
Anonymous classes: also declared in blocks, but are expressions.
Bottom line is: Once again, as a local class is a statement, it's just like a variable declaration, you cannot access its "products" before that statement is executed.
Related
class OuterClass1 {
static private int a = 10;
void get() {
System.out.println("Outer Clas Method");
}
static class StaticInnerClass {
void get() {
System.out.println("Inner Class Method:" + a);
}
}
public static void main(String args[]) {
OuterClass1.StaticInnerClass b = new OuterClass1.StaticInnerClass();
b.get();
System.out.println(b.a);
System.out.println(b.c);
}
}
I know that static nested class can access outer class data members so why I am not able to access outer class variable throgh inner class referencebut can access it by directly using it in inner class as above?
Java language specification provides the following rules for accessing static fields:
◆ If the field is static:
The Primary expression is evaluated, and the result is discarded. [...]
If the field is a non-blank final, then the result is the value of the specified class variable in the class or interface that is the type of the Primary expression.
Note that the specification does not allow searching for static fields in other classes; only the immediate type of the primary expression is considered.
In your case the primary expression is simply b. It is evaluated, and its result is discarded with no observable effect.
The type of the primary expression b is OuterClass1.StaticInnerClass. Therefore, Java treats b.a as OuterClass1.StaticInnerClass.a. Since OuterClass1.StaticInnerClass class does not contain a static field a, the compiler produces an error.
When you access fields inside a method of the class, a different set of rules is in effect. When the compiler sees a in
System.out.println("Inner Class Method:" + a);
it searches the class itself, and continues to outer classes when the field is not there. That is where the compiler finds a, so the expression compiles correctly.
Note: Accessing static members through non-static expressions is a bad idea. See this Q&A for an explanation.
You haven't shown us an inner class, StaticInnerClass is not an inner class. There's no such thing in Java as a "static inner class" because an inner class by definition is a nested class that is not static. Only inner classes have direct access to containing types' members. Because StaticInnerClass is not an inner class, it does not have such access.
There was one MCQ ( Multiple Choice Question ) while I was reading my Java study book and that MCQ is:
Question : In case of inner and outer classes, _________
Options are :
(a) The members of outer class can not be accessed by inner class.
(b) The members of inner class can not be accessed by outer class.
(c) Members of both can be accessed by both of the classes.
(d) None of these.
The answer given on book answer key is (b) but I'm not feeling it as right answer because outer class can access members of its inner class I think. So please help me with what is right.
Thanks, have a good day :)
lets make it simple with some code
public class A {
public int a = 1;
public class B {
public int b = 2;
public int getAfromB() { return a; } // ACCESS OUTER CLASS MEMBER IMPLICITLY
public int getBfromB() { return b; }
}
public int getBfromA() {
B myB1 = new B();
B myB2 = new B();
return myB1.b + myB2.b;
}
}
An B instance is linked to a specific A instance, it belongs to the instance scope. In its scope, the members of the A class are defined.
The A class can handle several instances of the B class. It will be able to manipulate them but cannot implicitly access a specific instance members, simply because 'b' is not unique from its perspective.
Sorry for the confusion.
You can access inner and outer classes both ways. I do suggest trying a simple example though yourself as programming is one of those things you only learn through your own problems.
Refer to this as this may help: Can an outer class access the members of inner class?
There is a code which is given as a task for a junior Java developers. I use Java during five years and this piece of code completely confusing me:
public class Main {
String variable;
public static void main(String[] args) {
System.out.println("Hello World!");
B b = new B();
}
public Main(){
printVariable();
}
protected void printVariable(){
variable = "variable is initialized in Main Class";
}
}
public class B extends Main {
String variable = null;
public B(){
System.out.println("variable value = " + variable);
}
protected void printVariable(){
variable = "variable is initialized in B Class";
}
}
The output will be:
Hello World!
variable value = null
But if we change String variable = null; to String variable; we will have:
Hello World!
variable value = variable is initialized in B Class
The second output is more clear for me.
So, as far as I know the sequence of inizialisation in Java like this:
We go to the root of the class hierarchy (for Java it is always Object class), when we come to this root parent class:
All static data fields are initialized;
All static field initializers and static initialization blocks are executed;
All non-static data fields are initialized;
All non-static field initializers and non-static initialization blocks are executed;
The default constructor is executed;
Then we repeat the procedure for the underlying child class.
Also there is post which describes the behavior of the this keyword in context of a superclass - Calling base class overridden function from base class method
Based on the rules given above, I assume to have sequence like this:
We are going to create a new instance of class B;
We go to the part class Main;
Initialize main.variable with null;
Then we move to the default constructor of class Main;
Constructor calls method b.printVariable() in class Main; (Why doesn't it call main.printvariable? We don't have this key word here.)
The field b.variable "variable is initialized in B Class"
Now we come back to the class B;
We should initialize field b.variable with null value, am I right?;
The default constructor of class B executed
Please, can someone give a complete and full explanation of how this inheritance inizialisation sequence works. And why changing String variable = null; to String variable; leads to another output.
The sequence is:
Main -> "Hello"
Main -> new B()
B() -> Main() -> b.printVariable() -> sets the variable
Back to initialising B, so variable=null occurs.
So basically, the super object Main() is constructed before any intialisation events of class B. Which means variable=null occurs later. This makes sense as otherwise B could break the initialisation of Main.
Joshua Bloch covers a lot of good ground in his effective java book about how dangerous inheritance is to get right, I would recommend it.
First, you need to understand, what happens when you write variable = null;. When is that code executed. This basically determines the output.
Before I begin, I should also mention that when you create an object of class B, the printVariable() function of the main class is not called. Instead, always the printVariable() of B will be called.
Keeping this in mind, when you have variable = null, the execution for B's constructor will begin. First Main() will be called, which will call the printVariable() method. At last, variable=null, will be called overwriting the variable variable.
In the other case, where you do not initialize variable=null, the variable set by the printVariable() function will not be overwritten, hence you get what you were expecting.
In summary, this is the order of execution of statements, when you do new B():
Main() //super constructor
B#printVariable()
initializtion of variables in B's constructor (if any) [i.e. variable=null, if present]
This is a nice exercise! But it's not a fair question to ask junior developers. This one is for seniors. But to make this text useful during the technical interview, I'd modified it by adding an argument to the Main's constructor:
public Main(String something){
printVariable();
}
If the person will answer what will happen, then remove the argument and ask the original questions. If the person won't answer - there is no need to continue - s/he is junior.
You can also remove the protected qualifier in class B and ask what will happen if you have a goal not to hire this person :)
This question already has answers here:
What causes error "No enclosing instance of type Foo is accessible" and how do I fix it?
(11 answers)
Closed 6 years ago.
I am trying to initialise the array C in the loop, but it gives error :
C is array of class ipdata and I have declared it and trying to initialise it inside the loop.
import java.io.*;
import java.util.*;
public class cluster_anlysis {
class ipdata{
float a,b;
int cluster;
ipdata()
{
a=0;
}
}
public float modc(float a){
if(a<0.0)
a=-a;
return a;
}
public static void main(String[] args) {
cluster_anlysis obj=new cluster_anlysis();
ipdata C[] = new ipdata[50];
float mean1,mean2,mean3;
int i,j,n1=0,n2=0,n3=0,flag=0;
float ina=0.0f;
float inb=0.0f;
//BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
Scanner scan =new Scanner(System.in);
System.out.println("pls enter no of data: ");
Integer no = scan.nextInt();
System.out.println("\nnow enter the x and y values");
for(i=0;i<no;i++)
{
ina=scan.nextFloat();
inb=scan.nextFloat();
System.out.println(ina);
C[i]= new ipdata(); // this line is giving error
C[i].a=ina;
C[i].b=inb;
C[i].cluster=0;
}
}
}
What could be the problem ?
it says :
No enclosing instance of type cluster_anlysis is accessible. Must qualify the allocation with an enclosing instance of type cluster_anlysis (e.g. x.new A() where x is an instance of cluster_anlysis).
you create an instance of inner class from static methods of your outer class using the outer class instance.
c[i]= new cluster_anlysis().new ipdata();
as you have alread created cluster_anlysis instance in your first line of main method.
cluster_anlysis obj = new Cluster_anlysis();
you could simple do.
c[i]= obj.new ipdata();
read about Inner classes in java
but if you want to create an inner class instance from the non-static methods of your outer class you dont need the instance of your Outer Class .
public class OuterClass {
public void method(){
InnerClass inner = new InnerClass();
}
class InnerClass{
}
}
and also follow class name convention as posted by #A.R.S and #JB Nizet in their solutions.
It seems you're starting with Java. I would advise to avoid messing with inner classes for the moment. Define each Java class in its own file, and everything will be simpler.
Also learn about Java naming conventions:
classes start with an upper-case letter, and are CamelCased: ClusterAnalysis, IpData. They should not contain underscores.
variables start with a lower-case letter, and are camelCased: c. They should not contain underscores.
Once you are more comfortable with the basics, learn about inner classes and static inner classes in the Java tutorial. But inner classes should not be abused. The basic rule is to have one class per file.
Use outer class Instance to call inner class constructor
like
c[i]=new cluster_analysis().new ipdata();
I think the best thing to do would be to declare ipdata as static; that would eliminate the error. There should be no need to instantiate cluster_analysis in order to instantiate ipdata in this case, and it makes sense that ipdata should in fact be static.
Oh, and by convention, you might want to consider using the names IpData and ClusterAnalysis instead - class names generally start with a capital letter and are "CamelCased", as another answer also pointed out.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why does Java prohibit static fields in inner classes?
I was going through the specification and got that it is not possible to have the static member in the inner class which is not final compile time constant .
class HasStatic {
static int j = 100;
}
class myInnerClassTest {
class Inner extends HasStatic {
static final int x = 3; // OK: compile-time constant
static int y = 4; // Compile-time error: an inner class
}
static class NestedButNotInner{
static int z = 5; // OK: not an inner class
}
interface NeverInner {} // Interfaces are never inner
}
Whereas I got from the Why can we have static final members but cant have static method in an inner class? that it can inherit the static member from its owner class. But why it shouldn't? What OOP's principal it hurts?
Your class myInnerClassTest isn't declared as static. So what would that exactly mean for it to have a static field ?
Would it be
the same for all instances whatever the enclosing instance ?
the same for all instances of this inner class having the same enclosing instance ?
At first sight most programmers would probably think it's the first case, while the encapsulation logic of the (non static) inner class should probably lead to the second choice. Either case (or both with different modifiers) would need a new definition of static which probably wasn't seen as necessary. And in either case programmers would be confused about the exact meaning.
From the specification :
An inner class is a nested class that is not explicitly or implicitly
declared static.
Inner classes include local (§14.3), anonymous (§15.9.5) and
non-static member classes (§8.5).
Inner classes may not declare static initializers (§8.7) or member
interfaces, or a compile-time error occurs.
Inner classes may not declare static members, unless they are constant
variables (§4.12.4), or a compile-time error occurs.
According to JLS: -
8.1.3 Inner Classes and Enclosing Instances
An inner class is a nested class that is not explicitly or implicitly
declared static. Inner classes may not declare static initializers
(§8.7) or member interfaces. Inner classes may not declare static
members, unless they are compile-time constant fields (§15.28).
Any local variable, formal method parameter or exception handler
parameter used but not declared in an inner class must be declared
final. Any local variable, used but not declared in an inner class
must be definitely assigned (§16) before the body of the inner class.
Apart from these two things, which I found important.. There are many more that you can get it from there.. There is a huge explanation about inner classes, anonymous inner classes, and nested classes..
UPDATED EXPLANATION : -
Just think about it. Static block is executed during class initialization, and you cannot initialize a non-static inner class without having an instance of the enclosing class, that's the reason.
Inner classes are associated with the instance of the enclosing class.. They are like other instance attributes of the enclosing class.. Now, it doesn't make sense to embed a static field in a non-static context.. However, if you declare them as Compile Time Constants they would be allowed.
NOTE: - static final Object = null is not compile time constants.. So, you can't have them inside your inner class
On the other hand, had your inner class been static, that is actually a nested class, then you can declare your field static, as they will still be associated with the class, so you can access them even before enclosing class in instantiated..
I hope that makes sense..
UPDATE 2 : -
public class A {
class B {
static int x = 0;
}
}
In the above code, static variable x will be common for every instance of class B..
Also, each instance of class A, will have it's own copy of class B (Since JVM will have to load class B every time an instance of A is created)..
So, static variable x could not have been shared between every instance of class A, unless it is a compile time constants.. (To make it more straight foreward: - You can do - B.x if you see B as outer class.. But class B is itself different for each instance of class A. So, B.x will be different for each instance of class A.. So, static variable x is not actually shared between different instances of class A.. Doesn't make sense for a static variable.)
I hope now, that makes sense..
All the restrictions are documented in
JLS #8.1.3. Inner Classes and Enclosing Instances
Because static declarations is associated with Class if you declare it inside inner class it will get associated with instance rather than class.
Non static inner classes are members of Object. And for members initialization only happens when instance of object is created. If static variables were allowed then initialization would have happened before creation of instance.
That is why there are separate non-static and static inner classes.
You always need outer class instance to access inner class Outer.Inner only exception is static inner class for which there are no constraints which are applicable to non-static inner classes.
static class Inner {
static final int x = 3; // OK: compile-time constant
static int y = 4;// OK
static class NestedButNotInner {// OK
}
interface NeverInner {// OK
};
}
However constants are permitted and it is documented in JLS
Because the inner class in intimately associated to the top level class you must have an instance of the outer class to create an inner via
Outer o = new Outer();
Inner i = o.new Inner();
This is therefore associated with an instance and not a class.
As you know, inner class can inherit static member from its owner class.
class HasStatic {
static int j = 100;
}
class myInnerClassTest {
class Inner extends HasStatic {
}
public static void main(String[] args){
System.out.println(Inner.j);
}
}
And it prints "100".