To my understanding, the following code should print a as per my knowledge of run time polymorphism.
However, when I run the following code it is printing b:
Per JLS 8.4.8.1, B1.m1 does not override A1.m1, and so when A1.m1 is
invoked, B1.m1 should not be selected
package a;
public interface I1 {
public Object m1();
}
public class A1 {
Object m1() {
return "a";
}
}
public class C1 extends b.B1 implements I1 {
public static void main(String[] args) {
a.A1 a = new a.C1();
System.out.println(a.m1());
}
}
package b;
public class B1 extends a.A1 {
public String m1() {
return "b";
}
}
Can some one help me understand this behavior.
After adding the packages, the question is much more difficult. I've tried this, and I changed your main program to
public class C1 extends b.B1 implements I1 {
public static void main(String[] args) {
a.A1 a = new a.C1();
System.out.println(a.m1());
a.A1 b = new b.B1();
System.out.println(b.m1());
}
}
(I actually used different package names to avoid conflicts with the variable names. So my code looks a bit different from the above.)
I've confirmed that this prints "b" and "a". That is, if I create a new B1, its m1 method does not override the one in A1. Thus if I print b.m1(), since b is of type A1, polymorphism doesn't kick in, and the method declared in A1 is called. So what's going on with C1?
C1 inherits the m1 method from B1. But even though the m1 method in B1 doesn't override the one in A1, the m1 method in C1, which it inherits from B1, actually does override the one in A1. I think it has to do with this clause in 8.4.8.1:
mA is declared with package access in the same package as C, and either C declares mC or mA is a member of the direct superclass of C.
Here C is your C1 class. mC is the m1 that's inherited from B1. In this case, "C declares mC" is false, because C1 doesn't declare m1, it inherits it. However, I believe "mA is a member of the direct superclass of C" is true. As I understand it, B1 has all the members that A1 has. B1 declares its own m1, and since it's not overriding, it's a new m1 that causes the m1 it inherits from A1 to be hidden. But even though it's hidden, it's still a member. Thus the condition that mA is a member of the direct superclass of C (which is B1) is satisfied, and thus all the conditions of 8.4.8.1 are satisfied and thus the inherited m1 in C1 overrides the one in A1.
The expected output is indeed b.
When you declare your object a as being of the type A1, that class defines only the interface of the methods. It defines that m1 returns a String, but the implementation of that method is defined by the Class used to build the object, which is Test1. And Test1 extends B1, which overrides the method m1, so that is the implementation of m1 used for your object.
The output of that call m1() must be indeed the B1's.
EDIT: This answer was written for the first version of the question. OP changed a lot of the code, but the root of the explanation is still the same.
The following line A1 a = new Test1(); simply means build a Test1 instance and store it in a A1 box.
So the instance will be a Test1, but you will only have access to the method/variable of A1, but every overriden method in Test1 will be accessed.
This is polymorpish.
By reading the JLS about 8.4.8.1. Overriding (by Instance Methods) about the accesor
An instance method mC declared in or inherited by class C, overrides from C another method mA declared in class A, iff all of the following are true:
A is a superclass of C.
The signature of mC is a subsignature (§8.4.2) of the signature of mA.
mA is public.
You can find more information about the access modifiers in 8.4.8.3. Requirements in Overriding and Hiding
The access modifier (§6.6) of an overriding or hiding method must provide at least as much access as the overridden or hidden method, as follows:
If the overridden or hidden method is public, then the overriding or hiding method must be public; otherwise, a compile-time error occurs.
If the overridden or hidden method is protected, then the overriding or hiding method must be protected or public; otherwise, a compile-time error occurs.
If the overridden or hidden method has package access, then the overriding or hiding method must not be private; otherwise, a compile-time error occurs.
EDIT :
Now, with your package added.
Having C1 to implement m1 (because of the interface), you are hiding the method of A1 with the implementation you find in B1, this method is indeed a valid definition for the interface contract.
You can see you are not overriding the method (you can't call super.m1 or even add #Override on the B1.m1. But the call a.m1() is valid as it is define in the class itself.
You are Overriding. Include the #Override annotation and you can see that. As long as your class extending can override the parent class method, you can increase the access, but not decrease the access.
If you tried to make B#m1 private, then somebody could just cast to an A and use the method.
Conversely, if you make A#m1 private, then B cannot override it and you can end up with an object having two methods with the same signature.
static class A{
private String get(){
return "a";
}
}
static class B extends A{
public String get(){
return "b";
}
}
public static void main (String[] args) throws java.lang.Exception
{
A b = new B();
System.out.println(b.get());
System.out.println(((B)b).get());
// your code goes here
}
This will output:
a
b
All comments and answers are mostly correct. They explain things in term of language mechanisms. I think, instead, that to realise the real meaning of inheritance and polymorphism and how to use them, you have to take a more conceptual approach.
First of all inheritance is a relationship between two things and the relationship is of the type “is a”. In other words when you write the statement class C1 extends B1 you mean C1 is a B1.
Of course this won’t work with A1, B1 and C1. Let me change them in something more real. For example:
A1 = Animal
B1 = Feline
C1 = Cat and C2 = Lion (polymorphism)
At this point you will have class Cat extends Feline, and you can conceptually read it as: Cat is a Feline. I suggest to challenge your inheritance formal correctness using the “is a” test. If it doesn't work, it is better to reconsider or rethink the inheritance.
Your resulting code will be like the following:
public interface IAnimal {
public Object saySome();
}
public class Animal {
Object saySome() {
return "I am an animal";
}
}
public class Feline extends Animal {
public String saySome() {
return "I am a feline";
}
public class Cat extends Feline implements IAnimal {
Object saySome() {
return "meow";
}
}
public class Lion extends Feline implements IAnimal {
Object saySome() {
return "roar";
}
}
class Aplication {
public static void main(String[] args) {
Animal anAnimal = new Cat();
Animal anotherAnimal = new Lion();
System.out.println(anAnimal.saySome());
System.out.println(anotherAnimal.saySome());
}
}
And clearly the output will be
meow
roar
I hope this will help.
You have an interface I1, which is implemented by A1
Class B1 extends A1
Class C1 extends B1 (and therefore implicitly extends A1).
So an instance of C1 is also of type B1, A1 & I1, however it remains an instance of C1 regardless of whether you assign it to one of the other types.
If you have:
I1 instance = new C1();
String value = instance.m1();
The first m1 method going up the inheritance tree from the real type (C1) will be called, which will be in B1 and return "b".
Related
I have three classes.
Class A
public class A {
}
Class B
public class B extends A {
public void hello(){
System.out.println("hello");
}
}
Class C
public class C extends B {
}
Class Test
public class Test {
public static void main(String[] args) {
A a = new C();
a.hello(); // The method hello() is undefined for type A
}
}
The code above will not compile because it reports an error that reads "The method hello() is undefined for type A"
My question is, since "a" is a C object, why doesn't a.hello() use the hello() method in the parent class of B?
If I add a hello method to A class, only then does the code above use the hello() from B class, but why do I have to add hello() to A class in order to use the method from B class?
A is a top level class in your hierarchy. It sees only those methods that are defined within it. Methods defined by its subclasses are not accessible to A. Sure, you can assign C to variable A, and then you can use it wherever A can be used, but now C will be limited to methods that A has.
It makes sense when you think about it. When you define a type (A), you expect it to behave according to your definition (which does not include anything about C fields and methods). You do not expect it to suddenly have everything that subclasses might have defined (e.g., imagine situation where a hundred people extended your class in various ways - top class would become incredibly bloated and broad).
That is why subclasses extend parent classes - they add additional functionality that is not (and probably should not be) defined in its parent. However, the parent itself has no awareness of the additional functionality and cannot use it. Each class can only use what it has defined or its parent(s) has defined. Hence, when you assign C to the parent's type, you will only get those methods that A is aware of (but with C's implementation).
Consider:
public class Animal {
public void walk() {
System.out.println("Walking");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println("Woof");
}
#Override
public void walk() {
System.out.println("Doggy walk");
}
public static void main(String[] args) {
Dog dog = new Dog();
Animal animal = new Animal();
Animal animalDog = new Dog();
dog.walk(); // "Doggy walk"
dog.bark(); // "Woof"
animal.walk(); // "Walking"
animal.bark(); // Error: bark() is not defined in the Animal class
animalDog.walk(); // "Doggy walk"
animalDog.bark(); // Error: Animal class has no bark()
}
}
Since we assigned Dog to Animal type, it can only use methods that are defined in Animal class. But note that the behavior will be the one that you defined in Dog class for the same method.
If you must use the method and for some reason you have not assigned it to a type that has the method, you should cast it accordingly, e.g.:
((Dog) animalDog).bark(); // "Woof"
I think you're a bit confused on how polymorphism works. You're saying "a" is a "c" object, which is a misleading assumption that many beginners make. So here's an example to illustrate what's happening:
Say you have an "Animal" class, which is extended by a separate "Dog" class, because a Dog is an Animal. So we can write:
Animal someAnimal = new Dog();
The above statement can be rewritten as:
Dog someDog = new Dog();
Animal someAnimal = someDog;
which shows that a Dog object can be stored as an Animal object. Why? Because a Dog is an Animal. You can't do
Dog someDog = new Animal();
because an Animal is not [necessarily] a Dog.
This points back to your original assertion. Your "a" is not a "c" object because you never wrote something like:
C a = new A(); // sidenote : this will give you error, as you are saying the analogous Animal is a Dog
As a result, your superclass (which is "A") can not access methods from the subclass (which in this case is "B") because superclasses don't inherit from subclasses (it's the other way round).
It's all about variable types. You are instantiating C class, but treat result object as A. Interface of A class does not contain 'hello' method, that's why you can't use it in your example.
To solve the problem you should either add your method to A or update type of the variable to B.
When you declare a variable as having the type of the superclass, you can only access (public) methods and member variables of the superclass through that variable.
In your question A is a parent class of B ,B is the parent class of C
(i.e. A->B->C) and you create the object of C class through A . So, according to your program firstly it try to find the hello() method in A class because it is a super parent class of C, which is not defined hello() method that's why it shows an error.
When you define a as an A type object (A a = new C();), it only has access to the members and methods of type A. To do what you want, either define hello() on type A or define a as an object of type B (B a = new C();). This is because the compiler is keeping track of which methods it has available. If, for some reason, you don't actually have access to the instantiation but you need to access something from B but it's handed to you as an A object, then you can cast it:
if (a instanceof B) (B a).hello();
else throw new Exception();
In method overriding you should have same method in super class.In this scenario most super class is A
I am facing a confusion. please look into the below java code.
public interface Interface {
public void draw();
}
public class A {
public void draw()
{
System.out.println("Draw in A");
}
}
public class B extends A implements Interface {
#Override
public void draw()
{
System.out.println("Draw in B");
}
}
public class Main {
public static void main(String [] args)
{
Interface i = new B();
i.draw();
A a = new B();
a.draw();
B b = new B();
b.draw();
}
}
For all I am getting the same output ("Draw in B"). Could you please tell me which draw() is getting invoked (Interface / Parent class)?
Java performs late binding, meaning it is the method of the instance that gets invoked, not the method corresponding to the type.
A a = new B();
^ ^
type instance
In this case, you create only B instances (new B()), so the method of B gets invoked each time, irrespective of your assigning this instance to a variable of type A.
See also: dynamic dispatch
As you might have guessed, it is the draw() method in class B that is getting invoked. This is because even though you have declared the varialbles i, a, and b as being able to reference different type, you choose to assign instances of type B to all of them. In other words, when draw is invoked what matters is the runtime type of the object (the one created by new B()), and not how the variable is declared.
The method which is invoked depends on the Object created. So, the method of the RHS (B) is invoked always.
every time you create instance of B class, and its method is being invoked
In a simple words it is because of new B(). it doesnt matter what type it is, when you instantiating from B, all methods from B(and it's parents if B not implementing them.) will be invoked.
I have a following code bellow and i don't understand why the output of this code is: "high high". In my mind the output must be: "Low Out"
public class A{
private String runNow(){
return "High";
}
static class B extends A{
public String runNow(){
return "Low";
}
}
public static void main(String args[]){
A[] a=new B[]{new B(),new C()};
for(A aa:a)
System.out.print(aa.runNow()+" ");
}
}
class C extends A.B{
public String runNow(){
return "Out";
}
}
Since runNow() method in class A is private, it's not overridden at all. So, the output is as expected.
Try adding #Override annotation over the method in class B, and you'll see a compiler error.
private methods cannot be overriden. The rules are described in the Java Language Specification 8.4.8.1. Overriding (by Instance Methods)
An instance method m1, declared in class C, overrides another instance
method m2, declared in class A iff all of the following are true:
C is a subclass of A.
The signature of m1 is a subsignature (§8.4.2) of the signature of m2.
Either:
m2 is public, protected, or declared with default access in the same
package as C, or
m1 overrides a method m3 (m3 distinct from m1, m3 distinct from m2),
such that m3 overrides m2.
When you declare a runNow() method in B and in C, you are simply creating a new method. Try to add #Override to them for kicks. You will get a compiler error
The method runNow() of type A.B must override or implement a supertype
method
In your for loop
for(A aa:a)
System.out.print(aa.runNow()+" ");
you are calling runNow() on variables declared as type A and since you are in the A class you have access to them. There's no polymorphism involved here.
I have a question and below is my code.
class A
{
int i=10;
public void m1() {
System.out.println("I am in class A");
}
}
class B extends A
{
public void m1() {
System.out.println("I am in class B");
}
}
class main2 extends A
{
public static void main(String...a) {
A a1= new B();
a1.m1();
}
}
Now my question; it's OK to get the variable "i" of the parent class A, but the method that I am getting is also of class A. Is it getting class B's method, as it overrides class A's method?
In Java, any derived class object can be assigned to a base class variable. For instance, if you have a class named A from which you derived the class B, you can do this:
A a1 = new B();
The variable on the left is type A, but the object on the right is type B. As long as the variable on the left is a base class of B, you are allowed to do that. Being able to do assignments like that sets up what is called “polymorphic behavior”: if the B class has a method that is the same as a method in the A class, then the version of the method in the B class will be called. For instance, if both classes define a method called m1(), and you do this:
a1.m1();
the version of m1() in the B class will be called. Even though you are using an A variable type to call the method m1(), the version of m1() in the A class won’t be executed. Instead, it is the version of m1() in the B class that will be executed. The type of the object that is assigned to the A variable determines the method that is called.
So, when the compiler scans the program and sees a statement like this:
a1.m1();
it knows that a1 is of type A, but the compiler also knows that a1 can be a reference to any class derived from A. Therefore, the compiler doesn’t know what version of m1() that statement is calling. It’s not until the assignment:
A a1 = new B();
is executed that the version of m1() is determined. Since the assignment doesn’t occur until runtime, it’s not until runtime that the correct version of m1() is known. That is known as “dynamic binding” or “late binding”: it’s not until your program performs some operation at runtime that the correct version of a method can be determined. In Java, most uses of inheritance involve dynamic binding.
Yes, it calls the B implementation of m1. When you run this code, it prints
I am in class B
just as expected. (Note that you don't actually use i in any of the code you posted, so I'm not sure what the first part was about...)
Yes it will invoke B's version of method, Since the object is of class B
Suppose that we have next situation:
Parent class A:
class A{
public A(){}
public doSomething(){
System.out.println(this.getClass());
}
}
with a child class B:
class B extends A{
public B(){}
public void doSomething(){
super.doSomething();
System.out.println(this.getClass());
}
}
and Main class:
class Main{
public static void main(String[] args){
A ab=new B();
ab.doSomething();
}
}
When I execute this code result is
B
B
Why does this, referenced in superclass A, returns B as a class when the reference is of type A?
It doesn't matter what the reference is, it's the instantiated object's class that counts. The object that you're creating is of type B, therefore this.getClass() is always going to return B.
Despite the fact that you are calling the doSomething() method of A, the this during that call is a B, and so the getClass() method is called on B not on A. Basically the this will always be a B whether you are using a method from superclass A, a method from B, or from A's superclass Object (the parent class of all Java classes).
this doesn't do anything for you in this situtaion. Calling this.getClass() is no different than just calling getClass();
So, A calls getClass(), which will return B if you are dealing with an instance of B that extends A.
Think of it in terms of runtime vs static types:
Animal a = new Cat();
The static type (in this case written on the left hand side) of variable a is Animal (you couldn't pass a into a method that required a Cat without a downcast) but the runtime type of the object pointed to by a is Cat.
a.getClass() exposes the runtime type (if it helps think of it as the most specific subtype).
Interestingly in Java overloaded methods are resolved at compile-time (without looking at the runtime type). So given then following two methods:
foo(Cat c);
foo(Animal animal)
Calling foo(a) would call the latter. To 'fix' this the visitor pattern can be used to dispatch based on the runtime type (double dispatch).
The output of program is correct.
When in Main class ab.doSomething(); line get executed doSomething() method of class B will be called then super.doSomething(); line will call doSomething() method of class A. As this keyword indicates reference of current object(ab is the object of class B see A ab=new B(); as constructor is of class B),i.e.System.out.println(this.getClass()); line in class A will print B only.
Again control will come back to System.out.println(this.getClass());in class B, So again B will get print.
In birdeye view only object of class B has created. That is why we are getting B B in output.