So, I ran into a wall earlier. If I have a class Parent with an inner class SubParent like this:
public class Parent
{
public class SubParent
{
}
public Parent(SubParent sp)
{
}
}
Then I have a Child class which extends Parent like this:
public class Child extends Parent
{
public Child()
{
super(new SubParent());
}
}
Then I get a "error: cannot reference this before supertype constructor has been called" with an arrow pointing at the SubParent constructor.
Now, if I have SubParent as a separate class in it's own file, everything is fine. But I would like to have it as an inner class. Is there any way to do that?
An inner class instance requires an outer class instance to exist. At the point you are calling
super(new SubParent());
the SubParent constructor would have been called before an outer class instance has been created. You can't do this.
Either declare SupParent in its own file or make it static. What relationship are you trying to achieve anyway?
Since your SubParent is not a static nested class, there's an implicit relationship between it and the Parent object it belongs to (in this case, also a Child object). It sounds like you're not needing the relationship an inner class provides; try making SubParent a public static class.
Note that there's a distinction between an inner class, which is not static (has a reference to an instance of its containing class), and a nested class, which is any class contained inside another class, whether static or not.
Your problem is that you are trying to create a SubParent very early in construction of the Child, before it is ready to use as "this" in an inner class creation. In addition to earlier suggestions, you could change Parent to have a parameterless constructor and a setter for its SubParent reference:
public Parent(){
}
public void setSub(SubParent sp){
}
The Child constructor can wait until after the super call to create the SubParent:
class Child extends Parent
{
public Child()
{
setSub(new SubParent());
}
}
Related
jdk version:1.8.0_241
There is a class extending a inner class. Code as follows:
class WithInner {
class Inner {
}
}
public class ExtendInnerClass extends WithInner.Inner {
ExtendInnerClass(WithInner withInner) {
withInner.super();
}
}
To connect WithInner class's object and Inner class's object, we have to use super() method.
But when i decompiled the class file, i find something interesting.
public class ExtendInnerClass extends Inner {
ExtendInnerClass(WithInner withInner) {
withInner.getClass();
super(withInner);
}
}
I find that compiler not only use super() method but also withInner.getClass().
why he do this?
An inner class object usually need to hold a reference to its outer class object.
Inner class has loaded before outer class without getClass(), it doesn't meet the principle of jvm, so use getclass() to load outer class in jvm before inner one.
What is happening in the code below? Please explain the output:
class Parent{
private void fun(){
System.out.println("parent fun\n");
}
public void accessFun(){
System.out.println(this);
this.fun();
}
}
class Child extends Parent{
private void fun(){
System.out.println("child fun");
}
}
class Test{
public static void main(String[] args) {
Child a = new Child();
Parent b = new Parent();
Parent c = new Child();
a.accessFun();
b.accessFun();
c.accessFun();
}
}
Output:
Child#7960847b
parent fun
Parent#3b192d32
parent fun
Child#16f65612
parent fun
Why the line this.fun() is not giving compile-time error?
I think fun is a private member in Child class and therefore can't be accessed from outside the Child class(from public member of it's Parent class).
Why Parent class version of fun() is being called by this.fun()? Note this refers to child class object.
Private members are not inherited.
I think this might be the key point that you are missing here. What this means is that Child.fun does not override Parent.fun. They are just two plain old methods that has nothing to do with each other.
When you call accessFun, control always goes into this bit of code in Parent:
public void accessFun(){
System.out.println(this);
this.fun(); <---- here
}
Now, since we are now inside Parent, we can access fun. And since Parent.fun is not overridden, it calls Parent.fun and not Child.fun.
I think fun is a private member in child class and therefore can't be accessed from outside the class(may even from public member of it's Parent class).
That is a complete misunderstanding. if private members can't be accessed from outside of the class, not even through public methods, then they will be much less useful. Why even have them in the first place?
"Private members can only be accessed by members declared in the same class" is probably a better thing to remember.
private fun() in Parent is called by public accessFun() of same Parent class. And public accessFun() is called in main() of Test class.
Here accessFun() is public so it can be called from any where.
For example just like Pojo classes private members are accessed through public setters and getters
The fun method in parent is private and the child fun() method is not overriding the parent fun() method. But the accessFun method is public so it can be called from the child class and is publicly accessible.
So when you call accessFun() method it will be calling the parent class fun() method. Not the child class fun() method as it is private. That is why you wont get an error.
I think fun is a private member in child class and therefore can't be accessed from outside the class(may even from public member of it's Parent class).
Sometimes everything comes from "outside". The main call comes from outside for example.
If a private member can not be accessed from outside, it would always be dead code and this makes no sense.
The difference is the understanding from direct-access and indirect-access.
In all cases you call the method non-directly via the method accessFun().
In Java, when a method is going to be executed, it's declaration is first searched for at the object's real class (that defines the real type of the object). If it's not found, then the superclass is checked. If isn't found there either, the next parent class is checked, and so on. However, look at the example below:
SuperClass s = new SubClass(list of parameter);
s.someMethodExistOnlyInSubClass();
This will give me a compile time error. I thought that, as mentioned above, it would first look for someMethodExistOnlyInSubClass() at SubClass, verify that it exists there and then execute it right away. If I use a variable of the type SuperClass to reference an instance of SubClass some parameters will go to SuperClass's constructor through a call to super() and the object will be instantiated there. In this context, to where have the remaining parameters gone?
By assigning a reference to an instance of SubClass to a variable of the type SuperClass, the variable is treated as if it were referencing an instance of SuperClass. Therefore, it will have no knowledge of any of the methods declared specifically in SubClass. Note, though, that the overrides performed in SubClass will still be effective.
In the context you described, to access someMethodExistOnlyInSubClass() you would have to cast s to the type SubClass. Look below:
((SubClass) s).someMethodExistOnlyInSubClass();
What you are trying to do will work only when the method is defined in both Parent class and subclass.
import java.util.*;
class Parent
{
public void sample()
{
System.out.println("Method of parent is getting Called");
}
}
class Subclass extends Parent
{
public void sample()
{
System.out.println("Method of Child class is getting Called");
}
}
public class Main
{
public static void main(String[] args){
Parent p = new Subclass();
p.sample();
}
}
OUTPUT : Method of Child class is getting Called
If the method exists only in Child class. You will have to create an instance of Child class itself.
Something like this :
import java.util.*;
class Parent
{
}
class Subclass extends Parent
{
public void sample()
{
System.out.println("Method of Child class is getting Called");
}
}
public class Main
{
public static void main(String[] args){
Subclass p = new Subclass();
p.sample();
}
}
Or you can type cast it as mentioned in the earlier post
Parent p = new Subclass();
((Subclass)p).sample();
An object is created based on its declaring class.
When you declare it as SuperClass s the object s wont have any method called someMethodExistOnlyInSubClass . So when you try to invoke this method, even before look at the subclass, you get a compile error.
The object s contrains only everything of the superclass, this object wont be aware of any subclass until u type cast the object to subclass.
public class Parent {
public void printParent()
{
System.out.println("I am the Parent");
System.out.println("----this is ::---" + this);
this.printChild();
}
private void printChild()
{
System.out.println("This is my child");
}
}
public class Child extends Parent {
private void printChild()
{
System.out.println("I am the child");
}
}
public class RelationshipTester {
#Test
public void testRelation()
{
Child parent = new Child();
parent.printParent();
}
}
This is the output :-
I am the Parent
----this is ::---datastructures.lists.inheritance.Child#1a692dec
This is my child
The object is of the type Child , yet it doesn't call the child method and the parent one. I have given this.printChild();
In the Parent class, you have declared printChild as private ... and called it. A private method cannot be overridden. Your printChild in the Child class is not known to the Parent class.
If you were to change the private modifier to public, then you would have an override, and your example should output what you are expecting.
Why won't Java let you override a private method? Well, basically, if you could do it then there would be no way to write a class with an abstraction boundary that a child class could not break. That would (IMO) be a major language design short-coming.
Why doesn't Java report an error or warning? Well there is no error because this is legal Java according to the JLS. As for a warning ... if you compile Parent in isolation there is no problem, because the code as written is declaring and using a private method. If you compile Child in isolation, the compiler can't see the private method in the Parent class. (Indeed, it may not even exist in the version of the .class file for Parent that you are compiling against.) Only if you compiled Parent and Child at the same time might the compiler spot something a bit odd.
The keyword 'this' point to the current class instance and here is the private void printChild(). And then you have created an object of class Child at RelationshipTester class. The scope of the two function is private which means to is bounded to that class only. Thus, it won't overwrite the subclass and would execute the Base class's method.
private methods are not inherited. When you call printParent, you're calling a method on Parent and when that method refers to this, it's referring to an instance of that class (Parent), which has its own printChild method. Making Parent#printChild a protected method should give the expected result.
public class Child extends Parent {
protected void printChild(){
System.out.println("I am the child");
}
}
use protected, not private
In this program we have to remember 2 points:
If we create an object for a subclass (here child) then memory also created for the super class. That means if the method that we are calling that is not found in the child class then Java Virtual Machine goes to parent class and checks for the method that we are calling and if the method is found it will execute. If the method is found in child class itself it will not go to the parent class.
private, static and final methods can't be overridden.
Since the scope of the method is private it is not visible to other class.
If I create an object of sub class then will the super class object also be created from which the sub class is inherited? If not then how by creating a sub class of Thread class (in multi-threading) calls the Thread class constructor and creates a Thread object?
An instance of the subclass is an instance of the superclass. Only one object is created, but as part of that creation, constructor calls are chained together all the way up to java.lang.Object. So for example:
public class Superclass {
// Note: I wouldn't normally use public variables.
// It's just for the sake of the example.
public int superclassField = 10;
public Superclass() {
System.out.println("Superclass constructor");
}
}
public class Subclass extends Superclass {
public int subclassField = 20;
public Subclass() {
super(); // Implicit if you leave it out. Chains to superclass constructor
System.out.println("Subclass constructor");
}
}
...
Subclass x = new Subclass();
System.out.println(x instanceof Subclass);
System.out.println(x instanceof Superclass);
System.out.println(x.superclassField);
System.out.println(x.subclassField);
The output of this is:
Superclass constructor
Subclass constructor
true
true
10
20
... because:
The first thing any constructor does is call either another constructor in the same class, or a superclass constructor. So we see "Superclass constructor" before "Subclass constructor" in the output.
The object we've created is (obviously) an instance of Subclass
The object we've created is also an instance of Superclass
The single object we've created has both fields (superclassField and subclassField). This would be true even if the fields were private (which they usually would be) - the code in Subclass wouldn't be able to access a private field declared in Superclass, but the field would still be there - and still accessible to the code within Superclass.
The fact that we've got a single object with all the state (both superclass and subclass) and all the behaviour (any methods declared within Superclass can still be used on an instance of Subclass, although some may be overridden with more specializd behaviour) is crucial to understanding Java's approach to polymorphism.
Youre only creating one object when you create a subclass of another. It is an instance of both the subclass and all its parents. Example, I create a cat object. It is a cat, and at the same time a feline, mammal, and animal, and an Object.
When you create an object, it gets one piece of memory with one set of variables to hold the all of its data.
The subclass will contain fields from the child and any fields from its ancestors. So it's a single object that acts like the child and its ancestors. There is no parent class object created when you create a subclass.
No there Is only one Object there. There Is a misconception that constructor is for creating an object. But It actually for initializing an object. So when we created child class object along with the child class constructor the parent class constructor also executed because of the first line of the child class constructor either this() or super(). Now, look at the following code.
Public class P{
public P(){
System.out.println(this.hashCode()); // Parent class Constructor
}
}
public class C extends P{
public C(){
System.out.println(this.hashCode()); // Child Class constructor
}
}
public class Test{
public static void main(String [] args){
C c = new C();
System.out.println(c.hashCode());
}
}
If you run the code you can see There is only one HashCode. and an object just has one hashCode. If the parent class object would be created then there must be another hashCode for that object.
Here I am abbreviating with an example that
If a child class object is created, does it automatically create super class object?
class P{
P(){
System.out.println(this.hashCode()); // it will print 2430287
}
}
class C extends P{
C(){
System.out.println(this.hashCode()); // it will also print 2430287
}
}
public class Test{
public static void main(String... args){
C obj = new C();
System.out.println(c.hashCode()); //Again, it will print 2430287
}
}
If you compile and run this code you will find same Object hashCode is getting printed. So, this means there is only one object is created.
Now, how is the parent class object being initialized?
In this example only one object is created which is an instance of the child class, but there are two constructors (parent and child) being executed. But the constructor are just in context of child class only.
Nope.
It will not create instance of parent class. But certainly it will create an instance.And the object reference passed to child class. Hence instance is created at parent class and invoked by child class constructor. and child class methods operates.