I am facing some problems about inheritance in Java.
I can't understand why the following two programs have those outputs!
Could anyone help me? :)
1)
public class A {
int foo() {
return 1;
}
}
public class B extends A {
int foo() {
return 2;
}
}
public class C extends B {
int bar(A a) {
return a.foo();
}
}
C x = new C();
System.out.println(x.bar(x));
// OUTPUT:2
2)
public class A {
int e=1;
}
public class B extends A {
int e=2;
}
public class C extends B {
int bar(A a){
return a.e;
}
}
C x= new C();
System.out.println(x.bar(x));
// OUTPUT:1
In both cases, you're passing in an object of type C into the print function. The bar function asks for an object of type A, but it's still acceptable for you to pass in an object of type C since it is a subclass of A. So first of all, it's important to keep in mind that a.foo() and a.e are being called on a C object.
So what is happening in both cases is that it's searching for the lowest attribute or method in the list. Here is a very simplified version of what Java is doing in part 1:
Hey, you've passed in an object of type C to the bar method! Now let's call its foo method.
Whoops! C doesn't have a foo method! Let's take the next step up to the B class to see if it has a foo method.
Yay! B has a foo method, so let's call it. No need to work our way up to the A class because we've already found what we need in B.
It's all about understanding that the parameter was downcast from A to C. The exact same sort of logic is used in part 2. It notices that an object of type C was passed in, so it gets the e attribute from object B since its the lowest class in the hierarchy that contains that attribute.
Hopefully that answers your question!
Related
I am thinking about this java oop problem . I don't exactly know exactly what is really happening there . Can someone make me understand ?
abstract class A {
public int proc (A p){
return 98;
}
}
class B extends A {
public int proc(A p) {
return 17;
}
}
class C extends A {
public int proc (C p) {
return 65;
}
}
public class HelloWorld{
public static void main(String []args){
C x = new C(); // here x is C type and is an instance of C ?
A y=new B(); // here y is A type and is an instance of B?
C z=new C(); // here z is C type and is an instance of C ?
System.out.println(y.proc(x)+z.proc(x)); /* y is A type so it is looking for proc function in A ,but doesn't return 98
, z is C type and it is looking for proc function in C and return 65 .*/
}
}
Can someone tell me how should I tackle theese instances ?
Y is an A but contains a reference to a B so when we call y.proc it is the proc in B that is called, and returns 17, not 98.
You need to look at the instance that is created and not the type of variable.
In Java, you can create base class objects which hold the child classes objects except for abstract classes.
A is an abstract class, you cannot instantiate it, but you can assign an object of the child class to it which holds the child class object's features.
You can think, we are assigning the reference of B to y which has a type of A.
System.out.println(y.proc(x));
The code above will print 17, which is the return value of the proc in class B returns.
Whenever you call the methods of y, the compiler will give you class B's methods automatically.
So, you are creating an instance of class B in the memory and assigning it to y which points to the same memory location.
For that reason, you can use the methods of class B.
Same goes for z as well.
Let's say I have the following interface and classes defined:
public interface I { void a(); }
public class A implements I {
public void a() { System.out.println("A"); }
}
public class B implements I {
public void a() { System.out.println("B"); }
public void b() { System.out.println("C"); }
}
And then I run the following code:
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
I i;
i = a;
i.a(); // prints "A"
i = b;
i.a(); // prints "B"
i.b(); // 1st problem: i can't seem to find method b. Why?
b = i; // 2nd problem: b can't be assigned to i although i references an object of class B?
b = (B)i; // why does this work fine...
a = (A)i; // 3rd problem: ...but this here doesn't?
}
}
So here are my questions:
First Problem
Why can't i.b() be called?
i points to the same object as b, an object of class B which does have a method b.
So why does i.a() call the right method (the one that prints out "B") but i.b() doesn't resolve at all?
Does the fact that i was declared as being of type I (an interface) have anything to do with that? Does this mean that in an assignment X x = new Y() where Y extends X, one can only ever call methods on x that are already declared in X, and not just specific to Y?
Second Problem
Why can't b be assigned to i although i references an object of class B? b and i already reference the same object, don't they? So why does it cause an error if I try to assign b to i - the end result of which should be identical to the state of the program before that assignment, unless I'm missing something significant.
Third Problem
Why can I cast i to type B now although I couldn't assign b to i earlier, and why doesn't casting i to A work?
I'm assuming my confusion is somehow rooted in an unclear distinction between the reference variables and the objects they're referencing, as well as the differences between the types of these variables and objects. I just can't quite explain these occurrences - and in particular the first problem confuses me a lot.
For the first problem:
You can use the interface reference to call only the methods it declares
For the second problem:
You can use interface reference to invoke methods in the classes that implement the interface. However, there is no use to assign interface reference to a class reference since interface reference doesn't have any methods that can be invoked.
for the third problem:
You have assigned previously
i=b
and hence
b=(B)i
works fine.
However,
a=(A)i
wouldn't work because i stores b and not a
First of all, learn Java (and/or OO (object oriented)) programming...
Variable i is a reference to an object instance that implements interface I. Method b() was not declared in interface I, thus it is not visible through i.b().
To be able to call it, i needs to be casted, EG: ((B) i).b()
Variable b is a reference to an object that is an instance of class B, and cannot be assigned to any reference that itself is not declared as an instance of B.
Again, a cast needed, EG: b = (B) i
Class B is not a child of class A. They both implement interface I, but A is not parent of B.
It's not a problem at all but It's behavior of inheritance and polymorphism.
Please note that when you
I i = new A();
Left hand side (I) will tells compiler which all methods it can call using that reference.
Right hand side (A) will tells the runtime which method should execute using that method call
So in your case
1 Problem
you can not call b() since b() is not there in inteface I
2 Problem
you are casting interface to object b and then calling b() so its working fine.
At university we were given a Java program and tasked with understanding how the output comes to be the way it is. The program is the following:
interface A {
public void f(A x);
}
interface AA extends A {
public void f(B x);
}
class B implements A {
public void f (A x) {System.out.println("1");}
public void f (B x) {System.out.println("2");}
public void f (C x) {System.out.println("3");}
}
class C implements A,AA {
public void f(A x) {System.out.println("4");}
public void f(B x) {System.out.println("5");}
public void f(C x) {System.out.println("6");}
}
public class Task7 {
public static void main(String[] args) {
B b = new B(); C c = new C();
A ac = c; A ab = b;
AA aac = c;
b.f(b); c.f(c);
ac.f(b); ab.f(b);
aac.f(b); aac.f(c);
}
}
The output is "264154". I don't really understand how the last 4 numbers can be explained. can anybody help?
EDIT: To explain what is my problem a little bit further:
´b.f(b)´ obviously will print out 2 because you are giving a B reference to a B object, and ´c.f(c)´ will print 6 for the same reason.
´ab.f(b)´ will call ´b.f(b)´ because its dynamic type is B. Now, I don't understand why the argument ´b´, which before has been seen by the same class as a ´B´, is now understood as an ´A´, so that "1" gets printed instead of "2". And the same goes for the other method calls, I just don't understand why the same argument with the same underlying object is interpreted differently
Polymorphism applied to the object on the left of the . only. The compiler determines which method signature to call at compile time, regardless of the value passed.
e.g.
B b = new B();
b.f((A) null);
b.f((B) null);
b.f((C) null);
prints 123 as only the type of the reference known at compile time matters.
Similarly, when invoking a static method, only the type of reference matters if you use a reference.
Thread t = null;
t.yield(); // call Thread.yield() so no NullPointerException.
I just don't understand why the same argument with the same underlying object is interpreted differently
The method signature is determined at compile time based on the reference type.
Another way of looking at it is that polymorphism only applied for overridden methods, not overloaded methods.
First of all you have to really understand polymorphism.
I'm not going to explain why the first two values are printed out, but I consider interesting knowing why the other ones have those outputs.
So, let's check the third one: ac.f(b); ac is an instance of A: A ac = c; and c is an instance of C: C c = new C();. Therefore, A ac = new C(); which means that ac can only use functions inside C class and among those functions it can only call the ones written inside A interface: public void f(A x) {System.out.println("4");} (The compiler doesn't care about the type of object in the parameters section)
Other example: ab.f(b); that's the fourth number you're getting in the output. ab is an instance of A: A ab = b and b is an instance of B: B b = new B();. Thus, A ab = new B();. Which implies that ab can call all functions declared inside B and inside A that's why: public void f (A x) {System.out.println("1");}.(Remember they must be declared in both sections, not just in one).
public class A {
private String superStr;
public String getSuperStr() {
return superStr;
}
public void setSuperStr(String superStr) {
this.superStr = superStr;
}
}
public class B extends A {
private String subStr;
public String getSubStr() {
return subStr;
}
public void setSubStr(String subStr) {
this.subStr = subStr;
}
}
And I expect result likes below
public static void main(String[] args) {
A a = fuc();
B b = new B();
b = (B) a;
b.setSubStr("subStr");
System.out.println(a.getSuperStr() + b.getSubStr());
}
private static A fuc() {
A a = new A();
a.setSuperStr("super");
return a;
}
but java.lang.ClassCastException is ocuured.
How can I cast this?
I want use subclass variable and super class variable.
thank you
How can I cast this?
You can't. You can only cast when the object in question has an "is a" relationship with the type. In your case, you have an A object (the one from fn), which is not a B. (All B objects are As, because B extends A, but not all A objects are Bs.)
Consider: Let's call B Bird and A Animal: A Bird is an Animal, but not all Animals are Birds. So we can treat all Birds as Animals, but we cannot treat all Animals as Birds. When you're using a variable of a given type to refer to an object, you're treating the object as being of that type (e.g., B b = (B)a tries to treat the Animal a as a Bird).
Side note: There's no point to the indicated part of the code:
B b = new B();
// ^^^^^^^^^^
b = (B) a;
Since the very next line assigns to b (well, it would if it would compile), there's no purpose served by doing new B() and assigning that to b just beforehand. (Unless the B constructor has side-effects, which is generally a Bad Idea™.)
Casting a particular object to another types does not magically convert it into an instance of that class (or at least not in Java); Therefore, the object referenced by variable a does not e.g. have the field subStr to use despite that the object referenced by b after executing B b = new B(); does.
The others have already explained why you can't do that. I'm here to give you a simple alternative. Your B class could have a constructor that had an A as argument and you would simply wrap that A so you could "transform" it to a B. Using that your code would look way more clean, it would actually work and you were following a good design pattern. For more information check the Decorator Pattern
The question might be a very basic one. I am new to Java so please bear with me.
My code:
class A
{
int b=10;
A()
{
this.b=7;
}
int f()
{
return b;
}
}
class B extends A{ int b; }
class Test
{
public static void main(String[] args)
{
A a=new B();
System.out.println(a.f());
}
}
Why is the output 7? Doesn't class B get its own instance variable b?
It would but the function f can only see the version of b that is in A. Thus the function returns 7.
If you were to copy the function f into the class B you would see the member b of the class B being returned.
As Hiding instance variables of a class explains, Java variables are not polymorphic. The 2 b variables are 2 different variables as you would expect, but when you call the function A.f it can only see the one b variable that A has. So it returns A.b and NOT B.b.
So to answer your question, class B DOES get its own instance variable b, and it is completely independant of A.b but you currently have no way to access it so you cannot see its value.
Your type reference is A:
A a = new B();
Thus instance fields/static fields and static methods will be provided from A, as long as concerned method (in your case f()) isn't overriden by B.
In other languages, as Scala, variables can be redefined in subclasses and targeted even from a supertype reference.