Is the following code the legit way to access an outer class object inside an inner class? Thanks
Class A{
A self;
public A(){
this.self=self;
}
public void test(){}
Class B{
public void test2(){
self.test();
}
}
}
There is no need for the 'self' reference; just test(); will get the job done.
inner classes that aren't marked static have a secret invisible field of the outer class's type (so, in your example, A), and it is the first parameter of the constructor. When you invoke new B() in a context where some variant of this would refer to an instance of A, then that's silently injected. If no such 'this' is available, then new B() is illegal and will not compile; the syntax to pass the secret param is someInstanceOfA.new B() in that case.
Any method invocation anywhere in java that isn't qualified (so just foo(), vs something.foo()) will first check if it makes sense on this, and if it doesn't, if it makes sense on any of these secret fields.
Add that together and:
B has an invisible field of type A.
test() would be an unqualified call, and B() itself does not have a test() method, tehrefore, thatInvisibleField.test() is how it works.
NB: Your code is not 'clearer', in the sense that your code also uses the invisible field: that self is getting the same treatment, and ends up resolving to thatInvisibleInstanceOfA.self in other to make sense.
NB2: As a general rule of thumb, inner classes should be marked static, even if you need stuff from your outer: Then make that invisible field explicit (make an actual private final A a; field, and set it in B's constructor) - non-static inner classes are surprising, and that hidden field leads to issues. For example, any instance of B that's still active will prevent garbage collection of A, even if your inner class doesn't use that instance whatsoever. Use non-static inner classes only if you really know what you're doing and it truly makes sense (it rarely does).
Related
I was going through Java inheritance and I tried the following code
class A {
public int x = 1;
public void print1() {
System.out.println("Print from A");
}
}
class B extends A {
public int x = 2;
public void print1() {
System.out.println("Print from B");
}
}
class C extends B {
public int x = 3;
public void print1() {
System.out.println("Print from C");
}
public static void main(String aa[]) {
C c = new C();
((A) c).print1();
System.out.println(c.x);
System.out.println(((A) c).x);
}
}
The output was
Print from C
3
1
Now, my question is that I am able to access class A member x from class C instance c but why am I not able to access the class A method print1(). I know, if I want I can call new A().print1();. But, I want to access it from an instance of class C directly. So by overriding methods, are the top parent class methods lost in the bottom child class? However, the parent class members are retained (although hidden). Why so? And is there a way to call a method from class A in class C without creating an instance of A?
EDIT
What's happening here?
When you say ((A)c).print1();, JVM knows that actual the instance, on which it needs to call is print1() is of type C hence class C's print1() version is executed.
But when you type ((A)c).x, you are referring to state, not behavior and that too using reference of type A. Which version of x will be picked up, is decided at compile time as compiler knows what is the type reference (In this case A). That is why you see A's state.
This statement from Java doc might also be interesting for you:
Within a class, a field that has the same name as a field in the
superclass hides the superclass's field, even if their types are
different. Within the subclass, the field in the superclass cannot be
referenced by its simple name. Instead, the field must be accessed
through super, which is covered in the next section. Generally
speaking, we don't recommend hiding fields as it makes code difficult
to read.
Why is it this way?
Answer to your questions:
Question 1:
my question is that I am able to access class A member x from class C
instance c
About variable x, since it is declared as public, no business validation can be applied on that. Moreover, the developer who's declaring it as public, is aware that concept of encapsulation can't be applied now (which is obviously not recommended). So there is no harm in allowing access to parent's state using child instance. Therefore, by using ((A)c).x, you can access x from class A.
Question 2:
However, the parent class members are retained (although hidden). Why
so?
It's because Java does not allow you to use super.super.super.. arbitrarily to access any parent's behavior in the inheritance hierarchy. And the reasoning behind it is to preserve encapsulation. You can only access behavior of the immediate parent class using super keyword but not beyond that.
To explain it more, let's say you have implementation of class B like:
class B extends A {
public int x = 2;
public void print1() {
if(x >= 2) {
System.out.println("Print from B");
}
}
}
Now if super.super was allowed, you can easily bypass validation in print1() method of class B and can invoke A's print1() method from the instance of class C.
Question 3:
However, the parent class members are retained (although hidden). Why
so?
As, mentioned earlier, to retain encapsulation.
Question 4:
And is there a way to call a method from class A in class C without
creating an instance of A?
So there is no way to access print1() from A using C's instance.
When you override a function which already implemented in base(parent) class, when you call that function within the child class, automatically the class in the child will call so in your case when you call print1() of a C object:
C c = new C();
c.print1();
you will call the override function. However if in any part of your program you feel that you need to call the top parent class for any case (which cannot be fulfilled by super) then you should reconsider your design strategy; maybe you shouldn't override the print1() or even you shouldn't put print1() in the base class in the first place
In object oriented programming, only methods have the ability to be overriden. You cannot override a data member. This explains why you get the outputs.
print1() method of A is overriden in C, and c is an object of C. So, it will call the print1() method of C. On the other hand, the variable x is not overriden.
To call the superclass method, you can do:
super.print1();
Here , Same named Instance Variable is used in all the Classes to confuse the compiler, but you should know that Only Member functions can be overridden not member variables.
So, All the three x will be stored separately in memory. but public void print1() will be overridden by its child class. So,
((A)c).print1(); this piece of Code will Call the overridden method defined in class C. doesn't matter in which class you cast the Object of Class C.
But in Second Case ((A)c).x will print the value from Class A.
((A)c).x :- this will reference to the variable x belongs to Class A not to Class C. because variables never overridden in Inheritence.
((A)c).print1(); Actually it is similar to the c.print1(); .
It doesn't matter that you typecast it with Class A, it will still call print1() function of the Class C.
I am just trying to figure out why it is possible to do such thing but it is not possible in some other programming languages like C++.
Here is an example of what I am asking:
public class A{
private A objectOfTheSameClass;
public A()
{
objectOfTheSameClass=new A();
}
}
Because it's not explicitly prohibited.
JLS section 8.8.7 that defines that body of a constructor does not mandate a compile-time error for such a case. The only case when a compile-time error should happen is when a constructor invokes itself with this:
It is a compile-time error for a constructor to directly or indirectly invoke itself through a series of one or more explicit constructor invocations involving this.
More precisely:
Except for the possibility of explicit constructor invocations, and the prohibition on explicitly returning a value (§14.17), the body of a constructor is like the body of a method (§8.4.7).
Since a method is allowed to invoke itself (recursion), a constructor is also allowed to do the same.
This will not compile because it calls this:
public class A{
private A objectOfTheSameClass;
public A() {
objectOfTheSameClass= this();
}
}
Your code, although it compiles, will throw a StackOverflowError because the constructor of A creates itself a new instance of A. The compiler can't detect every infinite loop in your code...
It can be useful sometimes, for example in the "singleton" pattern is used to have exactly one instance of a class by creating an object of the same class as a class field, making it accessible via a public method and making the constructor private.
The instances are not created until the runtime, so the class is fully defined. It's up to you to use this in a proper way.
Why can't I do this/is there a workaround to accomplish this:
package myPackage;
public class A {
public class B {
}
}
package myPackage;
import myPackage.A.B;
public class C extends B {
}
package myPackage;
public class Main {
public static void main(String[] args) {
A myA = new A();
C myC = myA.new C();
}
}
The two compilation errors are
On public class C extends B, No enclosing instance of type A is available due to some intermediate constructor invocation
On C myC = myA.new C();, A.C cannot be resolved to a type
Frankly, I think the conceptual idea is sound: I want to make a subclass of B so that when I make a B for A, I have the option of making it have the functionality in B or the functionality in C.
Four workarounds/solutions that I don't want, and why I don't want them:
"Solution: Put C inside of A." I don't want this because what if I can't modify the code for A.java (there are applications that have this restriction)? What if A is part of another API? Then I have to create a new file for C, as I've done here.
"Solution: Put C inside of a class D that extends A." I don't want this because then C is restricted to only being instantiated on instances of type D. I want to make a class that extends B that can be instantiated on all instances of type A (there are applications that need this). Therefore, I need C to not be enclosed by another class, as I've done here.
(Added as a question edit - see JoshuaTaylor's answer for a code sample) "Solution: Make B static." I don't want this because what if functionality in B needs to access its enclosing instance of A (there are applications that need this)? Therefore, I need B to not be static, as I've done here. (2nd question edit: You could make B static and have its constructor take in its enclosing instance, saving it in a protected variable for access in its children, but this is less elegant than the accepted answer by RealSkeptic)
Removed. See edit at bottom.
So, if your answer suggests that I do one of the above, it is not an answer to this question, even though it might be useful for other people.
If your answer is "This is just a flaw of the Java language, you simply can't accomplish that conceptual idea", that is an okay answer, and you should post it. Just a warning though: I will hold off on marking your answer as accepted in case you are wrong. If this is your answer, I would highly appreciate if you have an explanation for why this restriction on the language is in place (as that's the title of this question).
Thank you for any and all help.
EDIT: JoshuaTaylor's answer brings up a valid option: you can extend B anonymously and avoid having to write a constructor as in RealSkeptic's accepted answer. I originally discarded this idea because it does not allow you to access C's enclosing instance of A via "A.this". However, I have since learned that C does not have an enclosing instance of A unless it is specifically defined within the definition of A as a nested class. So please note: none of the solutions below allow you to access the enclosing instance of A that encloses C's ancestor of B via writing "A.this" in a method of C. Classes can only use ".this" to access types which they are specifically nested in. However, if B has functionality that accesses the enclosing instance of A, either an anonymous class via JoshuaTaylor's method or any other class via RealSkeptic's method is required.
Well, it can be done, but you have to remember that each constructor needs to call its super constructor, explicitly or implicitly. That's why you get the "No enclosing instance of type A is available due to some intermediate constructor invocation" error. C's no-args constructor is trying to implicitly call B's no-args constructor, and it can't do that without an A.
So you fix your C to be:
public class C extends B {
public C(A enclosing) {
enclosing.super();
}
}
And then you can create a new C by using:
A myA = new A();
C myC = new C(myA);
Answers to the questions in the comments
#Andi Turner asked:
If you are explicitly passing in an A to the constructor of C, can't C now be static, and have A as a "plain old" member variable in C on which you invoke the required methods?
It should be noted that C is neither static nor an inner class. It is an individual public class which is extending an inner class B. The implementation of the class B may not be known to the author of C, so it cannot know what methods would be using A, nor does it have access to any private members of A, as C is not a member of A. But B does, and B requires the A instance. An alternative approach would be composition rather than inheritance (where C holds a B instance and delegates operations to it), but if it wants to create that B instance rather than have it passed inside, it will still need an A instance, although it will use enclosing.new B rather than enclosing.super.
#rajuGT asked:
Is C is an individual entity? if so, why does it need A object? and what is the association between myA and myC in this case?
Yes, C is an individual entity. It wouldn't need A for any of its own methods. But if it tries to call (or inherits and doesn't override) methods from B that involve access to A - then that A is required by the implementation of B. Formally, of course, any instance of B requires a reference to A even if it doesn't actually make use of it. The association between myA and myC are is that myA is the immediate enclosing instance of myC with respect to B. This term is taken from section 8.1.3 of the JLS:
For every superclass S of C which is itself a direct inner class of a class or interface SO, there is an instance of SO associated with i, known as the immediately enclosing instance of i with respect to S. The immediately enclosing instance of an object with respect to its class' direct superclass, if any, is determined when the superclass constructor is invoked via an explicit constructor invocation statement (§8.8.7.1)
Official reference for this usage
This usage is known as a qualified superclass constructor invocation statement, and is mentioned in the JLS, section 8.8.7.1 - Explicit Constructor Invocations.
Superclass constructor invocations begin with either the keyword super
(possibly prefaced with explicit type arguments) or a Primary
expression or an ExpressionName. They are used to invoke a constructor
of the direct superclass. They are further divided:
Unqualified superclass constructor invocations begin with the
keyword super (possibly prefaced with explicit type arguments).
Qualified superclass constructor invocations begin with a Primary
expression or an ExpressionName. 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.
At the end of that section, you can find examples for explicit constructor invocation statements, including this usage.
You can easily extend nested static classes
Update: You've mentioned that you don't want this first solution, but the phrasing of the question may lead people to it who are willing to have the inner class be static, so I'll leave this in the hopes that it's useful to them. A more proper answer to your exact question is in the second section of this answer.
You can, but the inner class has to be static, because if it's not, then every instance of the inner class has a reference to the enclosing instance of the outer class. A static nested class doesn't have that reference, and you can extend it freely.
public class Outer {
public static class Inner {
}
}
public class InnerExtension extends Outer.Inner {
}
But you can also extend nested non-static classes
package test;
public class Outer {
public class Inner {
public String getFoo() {
return "original foo";
}
}
}
package test;
public class Extender {
public static void main(String[] args) {
// An instance of outer to work with
Outer outer = new Outer();
// An instance of Outer.Inner
Outer.Inner inner = outer.new Inner();
// An instance of an anonymous *subclass* of Outer.Inner
Outer.Inner innerExt = outer.new Inner() {
#Override
public String getFoo() {
return "subclass foo";
}
};
System.out.println("inner's class: "+inner.getClass());
System.out.println("inner's foo: "+inner.getFoo());
System.out.println();
System.out.println("innerExt's class: "+innerExt.getClass());
System.out.println("innerExt's foo: "+innerExt.getFoo());
}
}
inner's class: class test.Outer$Inner
inner's foo: original foo
innerExt's class: class test.Extender$1
innerExt's foo: subclass foo
I have a question about inheritance in Java.
I have two classes A and B , and class B, inherits from A:
public class A {
public A() {
System.out.println("Hi!");
}
}
public class B extends A {
public B() {
System.out.println("Bye!");
}
public static void main(String[] args) {
B b = new B();
}
}
When I run program B, the output is:
Hi!
Bye!
Question : why the constructor of class A is invoked, when I create and object of class B ?
I know that B inherits everything from A - all instance or class variables, and all methods, and in this sense an object of B has all characteristics of A plus some other characteristics defined in B. However, I didn't know and didn't imagine that when I create an object of type B, the constructor of A is also invoked.
So, writing this:
B b = new B();
creates Two objects - one of type B, and one of type A.
This is getting interesting,
can somebody explain why exactly this happens?
It doesn't create two objects, only one: B.
When inheriting from another class, you must call super() in your constructor. If you don't, the compiler will insert that call for you as you can plainly see.
The superclass constructors are called because otherwise the object would be left in an uninitialized state, possibly unbeknownst to the developer of the subclass.
Your subclass actually looks like this after the compiler inserts the super call:
public class B extends A {
public B() {
super();
System.out.println("Bye!");
}
}
It doesn't create 2 objects, it only creates one instance of B. The reason the super class constructor is invoked is because, like you said, B has all of the fields of A, and these fields need to be initialized.
Remember inheritance is an "is a" relationship between the base class and the subclass, thus every time you have an instance of a subclass, by definition you will also have an instance of the base class (as part of the instance, not as two separate instances). To initialize the base class properly the constructor is called.
Additionally, think about what would happen if you subclass depended on some internal state of the base class. Wouldn't you want the instance of the base class to be initialized then?
This is done because the constructor is used to initialize the object. Since B is also an A, it calls the constructor for A first, then the constructor for B.
As a side note, you can use super(arg1, etc) to choose which constructor of A is called based on the parameter types you pass... but it must be the first line in the constructor.
The constructor contains all of the initialization for A. You are not creating two objects. You are creating one object, then running the initializer for the superclass to initialize its members, and then running the initializer for the deriving class to initialize its members.
It does not create two objects, it just creates one object b. b is of type B and of type A. A constructor is basically saying here is what you need to do to construct me. So when you are creating a new "B" instance, you are building an object that is both a B() and an A(). Imagine the following scenario:
class Q {
int i;
public Q() {
// set default value
i= 99;
}
}
class Z extends Q {
public Z() {
}
}
If the constructor for Q WAS NOT called, how would i get its default value?
The creation of B does not create an extra A.
But by creating B, you create a kind of A, because B is a A.
Java/C++ call the constructor of A for your implicitly. Why? Language design. But doing so is fine, because the constructor of A might contain some initializations. And as B uses all the features and bugs of A, these features better be initialized properly.
The constructor of a class is very important concept in most OOP
Classes, by providing state and the means to manipulate that state, allow the easier maintenance of invariants. The constructors role is to get the class into a state that conforms to those invariants (or throws thus forbidding usage of an invliad object).
this is somewhat looser than intended in many languages since the constructor is allowed to pass its own 'this' reference elsewhere but this is at least under the control of the class (as such it can know that it is in a sufficiently stable and valid state for it to be accessible to the rest of the world)
Inheritance makes this complex since B is-a A in a very real sense and thus can invoke any of the methods provided by A. The parts of B that are A should therefore get their chance to initialize themselves before B gets a look in, thus the constructor for A is called before the real work of the B constructor begins.
If A intializes members in it's constructor and you forget to call super in your derived class then the members of A could be in a bad state. Java is trying to stop you from shooting yourself in the foot.
Only one object is created, both contractors are running on the same object.
The reason is simple, as you know B has all the variables and methods of A, so if some variable of A needs initializing so methods of A can work someone has to initialize it - and that someone is A's constructor.
for example:
public class A {
public A() {
x = 1;
}
private int x;
public int getX() {
return x;
}
}
public class B extends A {
public B() {
}
public static void main(String[] args) {
B b = new B();
System.out.println(b.getX()); // should print 1
}
}
When new object is create(B), inside B A object is created(because of extends keywords) . In B class JVM search B class constructor, but due to extends keywords it goes to super class constructor. inside A class x value is initialized. But x is private so that we can access outside class throw getXxx() method and get the result.
When sub class object is created then internally it was not created for super class object.But the memory should be allocated for super class members.
In java when you create an object of child class the constructor of parent class is always called because Object class is the parent of every super class and when you call the constructor of Object class then only your object is created and java does not support multiple inheritance in case of class so if you extends any other class then the relationship between you child class and the Object class is through the Parent class so to call the constructor of the Object class the constructor of Parent class must be called.
Every superclass has a constructor and each constructor up the hierarchy runs at the time an object of a subclass is created.
if super class object is not created then how sub class is accessing super class non static methods and variables.
I studied that non-static methods and variables can be accessed only through objects..
Given the following classes:
public abstract class Super {
protected static Object staticVar;
protected static void staticMethod() {
System.out.println( staticVar );
}
}
public class Sub extends Super {
static {
staticVar = new Object();
}
// Declaring a method with the same signature here,
// thus hiding Super.staticMethod(), avoids staticVar being null
/*
public static void staticMethod() {
Super.staticMethod();
}
*/
}
public class UserClass {
public static void main( String[] args ) {
new UserClass().method();
}
void method() {
Sub.staticMethod(); // prints "null"
}
}
I'm not targeting at answers like "Because it's specified like this in the JLS.". I know it is, since JLS, 12.4.1 When Initialization Occurs reads just:
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 a static method declared by T is invoked.
...
I'm interested in whether there is a good reason why there is not a sentence like:
T is a subclass of S and a static method declared by S is invoked on T.
Be careful in your title, static fields and methods are NOT inherited. This means that when you comment staticMethod() in Sub , Sub.staticMethod() actually calls Super.staticMethod() then Sub static initializer is not executed.
However, the question is more interesting than I thought at the first sight : in my point of view, this shouldn't compile without a warning, just like when one calls a static method on an instance of the class.
EDIT: As #GeroldBroser pointed it, the first statement of this answer is wrong. Static methods are inherited as well but never overriden, simply hidden. I'm leaving the answer as is for history.
I think it has to do with this part of the jvm spec:
Each frame (§2.6) contains a reference to the run-time constant pool (§2.5.5) for the type of the current method to support dynamic linking of the method code. The class file code for a method refers to methods to be invoked and variables to be accessed via symbolic references. Dynamic linking translates these symbolic method references into concrete method references, loading classes as necessary to resolve as-yet-undefined symbols, and translates variable accesses into appropriate offsets in storage structures associated with the run-time location of these variables.
This late binding of the methods and variables makes changes in other classes that a method uses less likely to break this code.
In chapter 5 in the jvm spec they also mention:
A class or interface C may be initialized, among other things, as a result of:
The execution of any one of the Java Virtual Machine instructions new, getstatic, putstatic, or invokestatic that references C (§new, §getstatic, §putstatic, §invokestatic). These instructions reference a class or interface directly or indirectly through either a field reference or a method reference.
...
Upon execution of a getstatic, putstatic, or invokestatic instruction, the class or interface that declared the resolved field or method is initialized if it has not been initialized already.
It seems to me the first bit of documentation states that any symbolic reference is simply resolved and invoked without regard as to where it came from. This documentation about method resolution has the following to say about that:
[M]ethod resolution attempts to locate the referenced method in C and its superclasses:
If C declares exactly one method with the name specified by the method reference, and the declaration is a signature polymorphic method (§2.9), then method lookup succeeds. All the class names mentioned in the descriptor are resolved (§5.4.3.1).
The resolved method is the signature polymorphic method declaration. It is not necessary for C to declare a method with the descriptor specified by the method reference.
Otherwise, if C declares a method with the name and descriptor specified by the method reference, method lookup succeeds.
Otherwise, if C has a superclass, step 2 of method resolution is recursively invoked on the direct superclass of C.
So the fact that it's called from a subclass seems to simply be ignored. Why do it this way? In the documentation you provided they say:
The intent is that a class or interface type has a set of initializers that put it in a consistent state, and that this state is the first state that is observed by other classes.
In your example, you alter the state of Super when Sub is statically initialized. If initialization happened when you called Sub.staticMethod you would get different behavior for what the jvm considers the same method. This might be the inconsistency they were talking about avoiding.
Also, here's some of the decompiled class file code that executes staticMethod, showing use of invokestatic:
Constant pool:
...
#2 = Methodref #18.#19 // Sub.staticMethod:()V
...
Code:
stack=0, locals=1, args_size=1
0: invokestatic #2 // Method Sub.staticMethod:()V
3: return
The JLS is specifically allowing the JVM to avoid loading the Sub class, it's in the section quoted in the question:
A reference to a static field (§8.3.1.1) causes initialization of only the class or interface that actually declares it, even though it might be referred to through the name of a subclass, a subinterface, or a class that implements an interface.
The reason is to avoid having the JVM load classes unnecessarily. Initializing static variables is not an issue because they are not getting referenced anyway.
The reason is quite simple: for JVM not to do extra work prematurely (Java is lazy in its nature).
Whether you write Super.staticMethod() or Sub.staticMethod(), the same implementation is called. And this parent's implementation typically does not depend on subclasses. Static methods of Super are not supposed to access members of Sub, so what's the point in initializing Sub then?
Your example seems to be artificial and not well-designed.
Making subclass rewrite static fields of superclass does not sound like a good idea. In this case an outcome of Super's methods will depend on which class is touched first. This also makes hard to have multiple children of Super with their own behavior. To cut it short, static members are not for polymorphism - that's what OOP principles say.
According to this article, when you call static method or use static filed of a class, only that class will be initialized.
Here is the example screen shot.
for some reason jvm think that static block is no good, and its not executed
I believe, it is because you are not using any methods for subclass, so jvm sees no reason to "init" the class itself, the method call is statically bound to parent at compile time - there is late binding for static methods
http://ideone.com/pUyVj4
static {
System.out.println("init");
staticVar = new Object();
}
Add some other method, and call it before the sub
Sub.someOtherMethod();
new UsersClass().method();
or do explicit Class.forName("Sub");
Class.forName("Sub");
new UsersClass().method();
When static block is executed Static Initializers
A static initializer declared in a class is executed when the class is initialized
when you call Sub.staticMethod(); that means class in not initialized.Your are just refernce
When a class is initialized
When a Class is initialized in Java After class loading, initialization of class takes place which means initializing all static members of class. A Class is initialized in Java when :
1) an Instance of class is created using either new() keyword or using reflection using class.forName(), which may throw ClassNotFoundException in Java.
2) an static method of Class is invoked.
3) an static field of Class is assigned.
4) an static field of class is used which is not a constant variable.
5) if Class is a top level class and an assert statement lexically nested within class is executed.
When a class is loaded and initialized in JVM - Java
that's why your getting null(default value of instance variable).
public class Sub extends Super {
static {
staticVar = new Object();
}
public static void staticMethod() {
Super.staticMethod();
}
}
in this case class is initialize and you get hashcode of new object().If you do not override staticMethod() means your referring super class method
and Sub class is not initialized.