G'day people,
I am feeling embarrass by asking such a naive question. But I can't understand one thing,
I have Inheritance structure like this,
B extends A, code I have wrote is as below,
Class A
public class A{
private int pos = 0;
public A(){
this.pos = 12;
}
public int getPos(){
return this.pos;
}
}
Class B
public class B extends A{
int spec = 15;
public B(){
super();
}
public int getSpec(){
return this.spec;
}
}
And I have one more class to test, Which will get us to my question.
Class Test
import java.util.*;
public class Test{
public static void main(String[] args){
B a = new B();
ArrayList<A> c = new ArrayList<A>();
c.add(a);
System.out.println(c.get(0).getPos());
System.out.println(c.get(0).getSpec());
}
}
Question : Now I am creating an instance of B, Which means I can access to my parent class's method getPos() and B's own method getSpec(). But if I create ArrayList with type A(...B is type A too, as it extends A...) and add my B's instance it losses it's ability to access it's own method. What am I doing wrong? Does ArrayList implementation is casting my B to A internally?
Note : My basic understanding of inheritance is parent cannot access
child's method except they are protected. But Child can access their
parent class's method.
There's no casting involved. What you're doing is no different from this:
A bAsA = new B():
While the object referred by bAsA is truly a B object, it is held by an A variable and thus only A methods are available (unless you explicitly cast it as a B variable).
Since your ArrayList is an ArrayList of A, each item in the ArrayList is treated as an A variable and only A methods are available.
Does ArrayList implementation is casting my B to A internally?
No. There is no "internal casting." You, the programmer, have told the compiler it's a list of A.
You have declared the List as List<A>, which you can read as "a list of A". Since all B are A, you can add any B to a List<A>. On retrieval, however, you're only guaranteed to get back an A, not a B — because it's a List<A>, remember — so the compiler treats everything that comes out of the list as an A, even if (at runtime) it's an instance of B.
In addition to the answers provided by #Matt Ball and #Hovercraft Full Of Eels, you can avoid having to explicitly cast by declaring methods implemented by the subclass as abstract methods in the superclass.
public abstract class A{
.
.
public abstract int getSpec();
}
EDIT-
As mentioned by #Kublai Khan, it is necessary to then make the superclass an abstract class.
Related
I am studying overriding member functions in Java and thought about experimenting with overriding member variables.
So, I defined classes
public class A{
public int intVal = 1;
public void identifyClass()
{
System.out.println("I am class A");
}
}
public class B extends A
{
public int intVal = 2;
public void identifyClass()
{
System.out.println("I am class B");
}
}
public class mainClass
{
public static void main(String [] args)
{
A a = new A();
B b = new B();
A aRef;
aRef = a;
System.out.println(aRef.intVal);
aRef.identifyClass();
aRef = b;
System.out.println(aRef.intVal);
aRef.identifyClass();
}
}
The output is:
1
I am class A
1
I am class B
I am not able to understand why when aRef is set to b intVal is still of class A?
When you make a variable of the same name in a subclass, that's called hiding. The resulting subclass will now have both properties. You can access the one from the superclass with super.var or ((SuperClass)this).var. The variables don't even have to be of the same type; they are just two variables sharing a name, much like two overloaded methods.
Variables are not polymorphic in Java; they do not override one another.
There is no polymorphism for fields in Java.
Variables decision happens at a compile time so always Base Class variables (not child’s inherited variables) will be accessed.
So whenever upcasting happens always remember
1) Base Class variables will be accessed.
2) Sub Class methods(overridden methods if overriding happened else inherited methods as it is from parent) will be called.
Variables are resolved compile-time, methods run-time. The aRef is of type A, therefore aRef.Intvalue is compile-time resolved to 1.
OverRiding Concept in Java
Functions will override depends on object type and variables will accessed on reference type.
Override Function: In this case suppose a parent and child class both have same name of function with own definition. But which function will execute it depends on object type not on reference type on run time.
For e.g.:
Parent parent=new Child();
parent.behaviour();
Here parent is a reference of Parent class but holds an object of Child Class so that's why Child class function will be called in that case.
Child child=new Child();
child.behaviour();
Here child holds an object of Child Class, so the Child class function will be called.
Parent parent=new Parent();
parent.behaviour();
Here parent holds the object of Parent Class, so the Parent class function will be called.
Override Variable: Java supports overloaded variables. But actually these are two different variables with same name, one in the parent class and one in the child class. And both variables can be either of the same datatype or different.
When you trying to access the variable, it depends on the reference type object, not the object type.
For e.g.:
Parent parent=new Child();
System.out.println(parent.state);
The reference type is Parent so the Parent class variable is accessed, not the Child class variable.
Child child=new Child();
System.out.println(child.state);
Here the reference type is Child, so the Child class variable is accessed not the Parent class variable.
Parent parent=new Parent();
System.out.println(parent.state);
Here the reference type is Parent, so Parent class variable is accessed.
From JLS Java SE 7 Edition §15.11.1:
This lack of dynamic lookup for field accesses allows programs to be run efficiently with straightforward implementations. The power of late binding and overriding is available, but only when instance methods are used.
Answers from Oliver Charlesworth and Marko Topolnik are correct, I would like to elaborate a little bit more on the why part of the question:
In Java class members are accessed according the type of the reference and not the type of the actual object. For the same reason, if you had a someOtherMethodInB() in class B, you wouldn't be able to access it from aRef after aRef = b is run. Identifiers (ie class, variable, etc names) are resolved at compile time and thus the compiler relies on the reference type to do this.
Now in your example, when running System.out.println(aRef.intVal); it prints the value of intVal defined in A because this is the type of the reference you use to access it. The compiler sees that aRef is of type A and that's the intVal it will access. Don't forget that you have both fields in the instances of B. JLS also has an example similar to yours, "15.11.1-1. Static Binding for Field Access" if you want to take a look.
But why do methods behave differently? The answer is that for methods, Java uses late binding. That means that at compile time, it finds the most suitable method to search for during the runtime. The search involves the case of the method being overridden in some class.
I hope this can help:
public class B extends A {
// public int intVal = 2;
public B() {
super();
super.intVal = 2;
}
public void identifyClass() {
System.out.println("I am class B");
}
}
So overriding variable of base class is not possible, but base class variable value can be set (changed) from constructor of inherited class.
This is called variable hiding. When you assign aRef = b; , aRef has two intVal, 1 is named just intVal another is hidden under A.intVal (see debugger screenshot), Because your variable is of type class A , even when you print just intVal java intelligently picks up A.intVal.
Answer 1: One way of accessing child class's intVal is System.out.println((B)aRef.intVal);
Answer 2: Another way of doing it is Java Reflection because when you use reflection java cant intelligently pickup hidden A.intVal based on Class type, it has to pick up the variable name given as string -
import java.lang.reflect.Field;
class A{
public int intVal = 1;
public void identifyClass()
{
System.out.println("I am class A");
}
}
class B extends A
{
public int intVal = 2;
public void identifyClass()
{
System.out.println("I am class B");
}
}
public class Main
{
public static void main(String [] args) throws Exception
{
A a = new A();
B b = new B();
A aRef;
aRef = a;
System.out.println(aRef.intVal);
aRef.identifyClass();
aRef = b;
Field xField = aRef.getClass().getField("intVal");
System.out.println(xField.get(aRef));
aRef.identifyClass();
}
}
Output -
1
I am class A
2
I am class B
Well, I hope u got the answer. If not, you can try seeing in the debug mode. the subclass B has access to both the intVal. They are not polymorphic hence they are not overriden.
If you use B's reference you will get B's intVal. If you use A's reference , you will get A's intVal. It's that simple.
As per the Java specifications, the instance variables are not overridden from a super class by a sub class when it is extended.
Hence the variable in the sub class only can be seen as one sharing the same name.
Also when the constructor of A is called during the instance creation of B the variable (intVal) is initialized and hence the output.
It is because when you assign b to aRef, it is resolved, leading aRef to just be of class A. This means that aRef does not have access to any of class B's fields or methods. If you call for intVal instead by using b.intVal, you will get 2.
Java has a feather of encapsulation means it tightly binds the property and the behavior of an object. so only via a class reference we can call it's behavior to change it's property.
and in inheritance only method overrides so that it can affects only it's property.
As Many users have already pointed out, this is not polymorphism. Polymorphism only applies to methods(functions).
Now as to why the value of the intVal of class A is printed, this happens because as you can see the reference aRef is of type A.
I can see why you are confused by it. By the same procedure you have accessed the overridden methods for ex. the method identifyClass() but the not the variables which directly proves the first line that I have written .
Now in order to access the variable you can do ((Superclass)c).var
Note here that the Superclass can be many levels up for example
A<-B<-C. That is C extends B and B extends A. If you wanted the value of var of A then you could have done ((A)c).var .
EDIT: as one of the users have pointed out this 'trick' does not apply to static methods, because they are static.
I am studying overriding member functions in Java and thought about experimenting with overriding member variables.
So, I defined classes
public class A{
public int intVal = 1;
public void identifyClass()
{
System.out.println("I am class A");
}
}
public class B extends A
{
public int intVal = 2;
public void identifyClass()
{
System.out.println("I am class B");
}
}
public class mainClass
{
public static void main(String [] args)
{
A a = new A();
B b = new B();
A aRef;
aRef = a;
System.out.println(aRef.intVal);
aRef.identifyClass();
aRef = b;
System.out.println(aRef.intVal);
aRef.identifyClass();
}
}
The output is:
1
I am class A
1
I am class B
I am not able to understand why when aRef is set to b intVal is still of class A?
When you make a variable of the same name in a subclass, that's called hiding. The resulting subclass will now have both properties. You can access the one from the superclass with super.var or ((SuperClass)this).var. The variables don't even have to be of the same type; they are just two variables sharing a name, much like two overloaded methods.
Variables are not polymorphic in Java; they do not override one another.
There is no polymorphism for fields in Java.
Variables decision happens at a compile time so always Base Class variables (not child’s inherited variables) will be accessed.
So whenever upcasting happens always remember
1) Base Class variables will be accessed.
2) Sub Class methods(overridden methods if overriding happened else inherited methods as it is from parent) will be called.
Variables are resolved compile-time, methods run-time. The aRef is of type A, therefore aRef.Intvalue is compile-time resolved to 1.
OverRiding Concept in Java
Functions will override depends on object type and variables will accessed on reference type.
Override Function: In this case suppose a parent and child class both have same name of function with own definition. But which function will execute it depends on object type not on reference type on run time.
For e.g.:
Parent parent=new Child();
parent.behaviour();
Here parent is a reference of Parent class but holds an object of Child Class so that's why Child class function will be called in that case.
Child child=new Child();
child.behaviour();
Here child holds an object of Child Class, so the Child class function will be called.
Parent parent=new Parent();
parent.behaviour();
Here parent holds the object of Parent Class, so the Parent class function will be called.
Override Variable: Java supports overloaded variables. But actually these are two different variables with same name, one in the parent class and one in the child class. And both variables can be either of the same datatype or different.
When you trying to access the variable, it depends on the reference type object, not the object type.
For e.g.:
Parent parent=new Child();
System.out.println(parent.state);
The reference type is Parent so the Parent class variable is accessed, not the Child class variable.
Child child=new Child();
System.out.println(child.state);
Here the reference type is Child, so the Child class variable is accessed not the Parent class variable.
Parent parent=new Parent();
System.out.println(parent.state);
Here the reference type is Parent, so Parent class variable is accessed.
From JLS Java SE 7 Edition §15.11.1:
This lack of dynamic lookup for field accesses allows programs to be run efficiently with straightforward implementations. The power of late binding and overriding is available, but only when instance methods are used.
Answers from Oliver Charlesworth and Marko Topolnik are correct, I would like to elaborate a little bit more on the why part of the question:
In Java class members are accessed according the type of the reference and not the type of the actual object. For the same reason, if you had a someOtherMethodInB() in class B, you wouldn't be able to access it from aRef after aRef = b is run. Identifiers (ie class, variable, etc names) are resolved at compile time and thus the compiler relies on the reference type to do this.
Now in your example, when running System.out.println(aRef.intVal); it prints the value of intVal defined in A because this is the type of the reference you use to access it. The compiler sees that aRef is of type A and that's the intVal it will access. Don't forget that you have both fields in the instances of B. JLS also has an example similar to yours, "15.11.1-1. Static Binding for Field Access" if you want to take a look.
But why do methods behave differently? The answer is that for methods, Java uses late binding. That means that at compile time, it finds the most suitable method to search for during the runtime. The search involves the case of the method being overridden in some class.
I hope this can help:
public class B extends A {
// public int intVal = 2;
public B() {
super();
super.intVal = 2;
}
public void identifyClass() {
System.out.println("I am class B");
}
}
So overriding variable of base class is not possible, but base class variable value can be set (changed) from constructor of inherited class.
This is called variable hiding. When you assign aRef = b; , aRef has two intVal, 1 is named just intVal another is hidden under A.intVal (see debugger screenshot), Because your variable is of type class A , even when you print just intVal java intelligently picks up A.intVal.
Answer 1: One way of accessing child class's intVal is System.out.println((B)aRef.intVal);
Answer 2: Another way of doing it is Java Reflection because when you use reflection java cant intelligently pickup hidden A.intVal based on Class type, it has to pick up the variable name given as string -
import java.lang.reflect.Field;
class A{
public int intVal = 1;
public void identifyClass()
{
System.out.println("I am class A");
}
}
class B extends A
{
public int intVal = 2;
public void identifyClass()
{
System.out.println("I am class B");
}
}
public class Main
{
public static void main(String [] args) throws Exception
{
A a = new A();
B b = new B();
A aRef;
aRef = a;
System.out.println(aRef.intVal);
aRef.identifyClass();
aRef = b;
Field xField = aRef.getClass().getField("intVal");
System.out.println(xField.get(aRef));
aRef.identifyClass();
}
}
Output -
1
I am class A
2
I am class B
Well, I hope u got the answer. If not, you can try seeing in the debug mode. the subclass B has access to both the intVal. They are not polymorphic hence they are not overriden.
If you use B's reference you will get B's intVal. If you use A's reference , you will get A's intVal. It's that simple.
As per the Java specifications, the instance variables are not overridden from a super class by a sub class when it is extended.
Hence the variable in the sub class only can be seen as one sharing the same name.
Also when the constructor of A is called during the instance creation of B the variable (intVal) is initialized and hence the output.
It is because when you assign b to aRef, it is resolved, leading aRef to just be of class A. This means that aRef does not have access to any of class B's fields or methods. If you call for intVal instead by using b.intVal, you will get 2.
Java has a feather of encapsulation means it tightly binds the property and the behavior of an object. so only via a class reference we can call it's behavior to change it's property.
and in inheritance only method overrides so that it can affects only it's property.
As Many users have already pointed out, this is not polymorphism. Polymorphism only applies to methods(functions).
Now as to why the value of the intVal of class A is printed, this happens because as you can see the reference aRef is of type A.
I can see why you are confused by it. By the same procedure you have accessed the overridden methods for ex. the method identifyClass() but the not the variables which directly proves the first line that I have written .
Now in order to access the variable you can do ((Superclass)c).var
Note here that the Superclass can be many levels up for example
A<-B<-C. That is C extends B and B extends A. If you wanted the value of var of A then you could have done ((A)c).var .
EDIT: as one of the users have pointed out this 'trick' does not apply to static methods, because they are static.
I am studying overriding member functions in Java and thought about experimenting with overriding member variables.
So, I defined classes
public class A{
public int intVal = 1;
public void identifyClass()
{
System.out.println("I am class A");
}
}
public class B extends A
{
public int intVal = 2;
public void identifyClass()
{
System.out.println("I am class B");
}
}
public class mainClass
{
public static void main(String [] args)
{
A a = new A();
B b = new B();
A aRef;
aRef = a;
System.out.println(aRef.intVal);
aRef.identifyClass();
aRef = b;
System.out.println(aRef.intVal);
aRef.identifyClass();
}
}
The output is:
1
I am class A
1
I am class B
I am not able to understand why when aRef is set to b intVal is still of class A?
When you make a variable of the same name in a subclass, that's called hiding. The resulting subclass will now have both properties. You can access the one from the superclass with super.var or ((SuperClass)this).var. The variables don't even have to be of the same type; they are just two variables sharing a name, much like two overloaded methods.
Variables are not polymorphic in Java; they do not override one another.
There is no polymorphism for fields in Java.
Variables decision happens at a compile time so always Base Class variables (not child’s inherited variables) will be accessed.
So whenever upcasting happens always remember
1) Base Class variables will be accessed.
2) Sub Class methods(overridden methods if overriding happened else inherited methods as it is from parent) will be called.
Variables are resolved compile-time, methods run-time. The aRef is of type A, therefore aRef.Intvalue is compile-time resolved to 1.
OverRiding Concept in Java
Functions will override depends on object type and variables will accessed on reference type.
Override Function: In this case suppose a parent and child class both have same name of function with own definition. But which function will execute it depends on object type not on reference type on run time.
For e.g.:
Parent parent=new Child();
parent.behaviour();
Here parent is a reference of Parent class but holds an object of Child Class so that's why Child class function will be called in that case.
Child child=new Child();
child.behaviour();
Here child holds an object of Child Class, so the Child class function will be called.
Parent parent=new Parent();
parent.behaviour();
Here parent holds the object of Parent Class, so the Parent class function will be called.
Override Variable: Java supports overloaded variables. But actually these are two different variables with same name, one in the parent class and one in the child class. And both variables can be either of the same datatype or different.
When you trying to access the variable, it depends on the reference type object, not the object type.
For e.g.:
Parent parent=new Child();
System.out.println(parent.state);
The reference type is Parent so the Parent class variable is accessed, not the Child class variable.
Child child=new Child();
System.out.println(child.state);
Here the reference type is Child, so the Child class variable is accessed not the Parent class variable.
Parent parent=new Parent();
System.out.println(parent.state);
Here the reference type is Parent, so Parent class variable is accessed.
From JLS Java SE 7 Edition §15.11.1:
This lack of dynamic lookup for field accesses allows programs to be run efficiently with straightforward implementations. The power of late binding and overriding is available, but only when instance methods are used.
Answers from Oliver Charlesworth and Marko Topolnik are correct, I would like to elaborate a little bit more on the why part of the question:
In Java class members are accessed according the type of the reference and not the type of the actual object. For the same reason, if you had a someOtherMethodInB() in class B, you wouldn't be able to access it from aRef after aRef = b is run. Identifiers (ie class, variable, etc names) are resolved at compile time and thus the compiler relies on the reference type to do this.
Now in your example, when running System.out.println(aRef.intVal); it prints the value of intVal defined in A because this is the type of the reference you use to access it. The compiler sees that aRef is of type A and that's the intVal it will access. Don't forget that you have both fields in the instances of B. JLS also has an example similar to yours, "15.11.1-1. Static Binding for Field Access" if you want to take a look.
But why do methods behave differently? The answer is that for methods, Java uses late binding. That means that at compile time, it finds the most suitable method to search for during the runtime. The search involves the case of the method being overridden in some class.
I hope this can help:
public class B extends A {
// public int intVal = 2;
public B() {
super();
super.intVal = 2;
}
public void identifyClass() {
System.out.println("I am class B");
}
}
So overriding variable of base class is not possible, but base class variable value can be set (changed) from constructor of inherited class.
This is called variable hiding. When you assign aRef = b; , aRef has two intVal, 1 is named just intVal another is hidden under A.intVal (see debugger screenshot), Because your variable is of type class A , even when you print just intVal java intelligently picks up A.intVal.
Answer 1: One way of accessing child class's intVal is System.out.println((B)aRef.intVal);
Answer 2: Another way of doing it is Java Reflection because when you use reflection java cant intelligently pickup hidden A.intVal based on Class type, it has to pick up the variable name given as string -
import java.lang.reflect.Field;
class A{
public int intVal = 1;
public void identifyClass()
{
System.out.println("I am class A");
}
}
class B extends A
{
public int intVal = 2;
public void identifyClass()
{
System.out.println("I am class B");
}
}
public class Main
{
public static void main(String [] args) throws Exception
{
A a = new A();
B b = new B();
A aRef;
aRef = a;
System.out.println(aRef.intVal);
aRef.identifyClass();
aRef = b;
Field xField = aRef.getClass().getField("intVal");
System.out.println(xField.get(aRef));
aRef.identifyClass();
}
}
Output -
1
I am class A
2
I am class B
Well, I hope u got the answer. If not, you can try seeing in the debug mode. the subclass B has access to both the intVal. They are not polymorphic hence they are not overriden.
If you use B's reference you will get B's intVal. If you use A's reference , you will get A's intVal. It's that simple.
As per the Java specifications, the instance variables are not overridden from a super class by a sub class when it is extended.
Hence the variable in the sub class only can be seen as one sharing the same name.
Also when the constructor of A is called during the instance creation of B the variable (intVal) is initialized and hence the output.
It is because when you assign b to aRef, it is resolved, leading aRef to just be of class A. This means that aRef does not have access to any of class B's fields or methods. If you call for intVal instead by using b.intVal, you will get 2.
Java has a feather of encapsulation means it tightly binds the property and the behavior of an object. so only via a class reference we can call it's behavior to change it's property.
and in inheritance only method overrides so that it can affects only it's property.
As Many users have already pointed out, this is not polymorphism. Polymorphism only applies to methods(functions).
Now as to why the value of the intVal of class A is printed, this happens because as you can see the reference aRef is of type A.
I can see why you are confused by it. By the same procedure you have accessed the overridden methods for ex. the method identifyClass() but the not the variables which directly proves the first line that I have written .
Now in order to access the variable you can do ((Superclass)c).var
Note here that the Superclass can be many levels up for example
A<-B<-C. That is C extends B and B extends A. If you wanted the value of var of A then you could have done ((A)c).var .
EDIT: as one of the users have pointed out this 'trick' does not apply to static methods, because they are static.
This question already has answers here:
A Base Class pointer can point to a derived class object. Why is the vice-versa not true?
(13 answers)
Closed 7 years ago.
This is rather basic question. But I can't understand well the concept of inheritance.
Suppose I have two classes, A and B with both have a test() method that returned 1 and 2 respectively, and B inherited A class. In main method I declare the instance as such;
A a1 = new B();
and call the method a1.test(), it will return 2. This is the concept of polymorphism. But when I have a method test2() in just subclass, I can't call the method using the same instance declaration as above. Why is that happen?
I can't call the method using the same instance declaration as above. Why is that happen?
Because the type of the variable is A, and class A does not have a method test2(). The Java compiler only looks at the type of the variable to check if you can call a method, it does not look at the actual object (which is in this case a B).
This is all easier to understand if you use more concrete and meaningful names for your classes, instead of abstract names such as A and B. Let's call them Animal and Bear instead:
class Animal {
}
class Bear extends Animal {
public void growl() { ... }
}
class Cat extends Animal {
public void meow() { ... }
}
Animal a1 = new Bear();
Animal a2 = new Cat();
// Doesn't work, because not every Animal is a Bear, and not all
// animals can growl.
a1.growl();
// You wouldn't expect this to work, because a2 is a Cat.
a2.growl();
Because variable type is A, and class A does not have a method test2():
Rather you can use:
A a1 = new B(); // upcasting
B b1 = (B)a1; // Downcasting a1 to type B
b1.test2(); // now you can call test2 function
Because, the left side of your condition determines which method's you can call, and right side determines which methods will be called. So in this case class A does't have test2() method.
Imagine A = "TV" and B = "HD_TV".
You can say
TV tv = new HD_TV() // HD TV
and
TV tv = new TV() // ordinary TV
because an HD_TV is a TV.
You can say:
tv.show(movie)
It will show what is on TV, but you will get a better picture with the HDTV.
You cannot say:
tv.showHD(hdMovie) // Compiler error !!!
because in declaring tv as TV, you are saying it might not be an HD TV. Even though you can see that in this case it is, the compiler still respects your declaration that it is just a TV and you can only use methods supported for a TV.
That is because you are declaring the instance a1 as an A. Because B inherits A, you can call all the functions declared in A and they might have a different meaning if they are overloaded in B, but you do not have any access to B-only things.
You can see the first A as some kind of a header file, if you are familiar with that. It declares what A contains, without looking at how the functions are implemented or what the default vars are of everything in A. As a direct consequence, you can only access everything that is declared to literally be in A.
The left-hand side - A in this case - is the declared type, and it doesn't know about anything specific to child classes. The right-hand side - ´B´ in this case - is the actual type, and this provides the behaviour.
So, this will work because the declared type B knows about methods available in the class B.
B b1 = new B();
b1.test2();
If it was possible to have a1.test2(), that would mean every class would have to know about every child it has - including those in other libraries, when projects are assembled!
When B inherits A class and the reference of A is created with object of B like A a1 = new B();.
On Compile time java compiler looks for method availability in class A.
So it allows calling method test() but not the test2().
As test() method is available in class A but test2() is not available in class A.
You can type cast the object created like ((B)a1).test2().
This will work.
Here a1 object is of type A. a1 is pointing to an object of type B.
a1 is a reference of type A to an object of type B.
since a1 is of type A it know only test() which is declared in its class definition already. In case you want to access test2 declared in class B you need to type cast the a1 object back to B
like
B b1 = (B)a1
b1.test2() will be accessible.
This happens because you declare A variable and use B class which is an A. The compiler know it's an A but doesn't know it's a B later in the code. It's easier to use real life objects as example.
For example you have:
class Pet() {
method feed();
}
And a
class Dog() extends Pet {
method feed();
method bark()
}
If you have a code in another class:
So if you have code :
Pet dogPet=new Dog();
You know it's a dog here because you create the instance and you can use:
((Dog)dogPet).bark(); or just declare the variable as a dog instead of pet.
But if you have a method in another class:
void someMethod(Pet aPet){
// Here you don't know if the Pet is a dog or not. So you know only that it
//can be fed but you don't know if it barks. Even if a Dog is supplied to the method
}
In a1 = new B(), the actual type of the object created is B but you reference it as its supertype so you can call a method that accepts A (polymorphism).
So if a method is overridden in subclass, a1.test() is executing subclass's test().
In order to execute test2() you have to do that: ((B) a1).test2();
There is a concept called Up casting and Down casting.Up-casting is casting to a supertype, while downcasting is casting to a subtype. Supercasting is always allowed, but subcasting involves a type check and can throw a ClassCastException.,See the Example Code:
class A{
public int test(){
return 1;
}
}
class B extends A{
public int test(){
return 2;
}
public int test2(){
return 3;
}
}
and
A a1 = new B();
a1.test2();//not possible
Here you can't invoke methods of class B.
In the below code, are b and show inherently static?
public class A {
public static class B {
private int b = 0;
public void show() {
System.out.println(b);
}
}
}
No they aren't static. You need to create an instance of B to access them.
The static keyword in your code example means that instances of B can be created without an instance of A.
If B was not static:
Instances would have an implicit reference to an instance of A.
The only way to create them would be to use new B() inside class A, or using syntax like new A().new B().
Methods in B can refer to A.this (the implicit reference to an instance of A).
Methods in B can refer to A.this.someField (using that implicit reference).
Methods in B can call instance (non-static) methods in A.
However, because B is static:
Instances do not have a reference to an instance of A - you don't need an A to create a B.
Instances can be created using new A.B() (or just new B() from within in class A)
Methods in B cannot refer to A.this.
Methods in B cannot access fields in A (unless passed in as a parameter).
Methods in B cannot call instance (non-static) methods in A.
They are not static. They are instance fields in B.
Meaning you need to have an instance of B to get/set them.
B is static in A but that does not make those fields of B static.
You can create many instances of B without any reference to A.
So B is static class in A but the same is not true for B's instance fields.
The static keyword has two meanings that are actually quite different and that can be confusing.
Static on a variable/method means that it exists at the class level, not the instance level. This means that you only have one copy of that variable/method no matter how many instances of the class you create.
Static on an inner class though just means that the class does not depend upon its outer class. In your example you can create a new B() without having an A. If you didn't have the static keyword on the class you could not create a new B() unless it was within an instance of A.
B is a static inner class of A.
Need to instantiate B.
A.B innerObject = new A.B();
innerObject.show();
The identifier static has a specific purpose here that many people don't immediately grasp. I'm going to take your code and change it a bit.
public class A {
private int a;
public A(int a) {
this.a = a;
}
public class B {
public void show() {
System.out.println(a);
}
}
}
Now, what's happening in class B? Because B is a non-static class, it has access to other non-static members in class A. Essentially, it states that every class A object has their own flavor of class B objects, even thought they are functionally the same. For us to get that same behavior if B was a static class:
public class A {
private int a;
public A(int a) {
this.a = a;
}
public int getA() { return a; }
public static class B {
public void show(A a) {
System.out.println(a.getA());
}
}
}
Here, this implies that the flavor of B objects doesn't change depending on which A object created it. The B class is static so that it cannot access non-static members of the A class object that created it and must access those members explicitly from whichever A object it wants to interact with.
In the previous implementation, a B object would seamlessly access fields and non-static methods of the A object that created it.
These are two different behaviors and often it's clear exactly which one fits your objective.