I decided to simulate this example code from Android app:
TextView txt = (TextView) findViewById(R.id.activity_display_message);
findViewById returns View object and then we cast it to a TextView one(TextView is a subclass of View)
It seems I have misunderstood how it works. I was expecting this code to work because C extends B and therefore I should downcast a B object to C.
But I am getting an exception at runtime that I can't cast B to C.
So can anyone explain where I am wrong? And why the Android sample works?
public class A{
public static void main(String[] args){
B b = new B();
b.f();
C c = (C)b;
}
}
class B{
public void f(){
System.out.println("Class B");
}
}
class C extends B{
public void f(){
System.out.println("Class C");
}
}
Cast operation lets you change the static type of your object, which is another way of saying "tell the compiler what you know about the type of the object being cast."
If you have a variable of type B which contains an object of type C, you are allowed to cast that variable to C:
B b = new C();
C c = (C)b; // works fine
This is allowed precisely because b's object is actually a C.
When the object referenced by b is not a C, the compiler will catch your mistake, and throw a cast exception:
B b = new B();
C c = (C)b; // throws class cast exception
The difference between a successful and unsuccessful is decided by the actual type of the object at runtime. The code that works manages to cast a View to TextView because the variable which is statically typed as View actually references a TextView at runtime.
In java, you cannot assign a superclass reference variable to a subclass reference variable without a cast of the subclass type. Examples can find in When is an explicit object reference casting is required?. The compiler is happy when you explict cast the superclass reference to subclass reference, but the compiler does not care what the actual object holded by the reference. Does it actually have a superclass object, or just a superclass reference holding a subclass object? No answer from compile time but it has to answer this quesiton.
You can not just take a parent object and suddenly turn it into a child though. The parent object is not an instance of the subclass. If the actual object holded by the reference is a superclass object, casting it to a subclass reference result in a compile time error.
In your case B is parent class and C is its child.
class SuperClass {
// ...
}
class SubClass extends SuperClass {
// ...
}
public class Program {
public static void main(String[] args) {
// case 1: actual SuperClass object
SuperClass p1 = new SuperClass();
// case 2: SubClass object is referred by a SuperClass reference
SuperClass p2 = new SubClass();
SubClass s1 = (SubClass) p1; //run time error
SubClass s2 = (SubClass) p2; //OK
}
}
In Android findViewByIdreturns instance of View Class. Which is a direct superclass of TextView and other view elements.
So if you want to replicate something like that, then you can do something like this:
class Test {
public static void main(String args[]) {
A a = new A();
C c = (C)a.getViewByid('c');
c.f();
}
}
class A {
public B getViewByid(char c) {
B b = null;
switch (c) {
case 'b':
b = new B();
break;
case 'c':
b = new C();
break;
default:
b = new B();
}
return b;
}
}
class B {
public void f() {
System.out.println("Class B");
}
}
class C extends B {
public void f() {
System.out.println("Class C");
}
}
Related
Can someone explain why the output is 10 and not 20?
Why does the object refers to the value of the parent class instead of the class it is assigned to?
class A {
int i = 10;
}
class B extends A {
int i = 20;
}
public class MainClass {
public static void main(String[] args) {
A a = new B();
System.out.println(a.i);
}
}
The instance you're creating is of type A, so since both variables have the same name, you'll get the superclass' one, if you want B's you should do
B b = new B()
System.out.println(b.i)
You shouldn't use variables of the same name like that in between superclasses and subclasses, gets very confusing and kinda defeats the purpose of inheriting.
In Java, methods are overridden not variables. So variables belong to their owner classes. a is a reference of type A that point to an object of type B but remains of type A.
To call the i of B, you have to cast a to B.
A a = new B();
System.out.println(((B)a).i);
Can someone explain why the output is 10 and not 20?
Since the value of i is defined in the class A and is NOT overridden/re-assigned by the definition of class B as you might just be assuming. Adding a custom constructor could clarify your doubts further of what you might be intending to do:
class A {
int i = 10;
}
class B extends A {
public B() {
this.i = 20;
}
}
A a = new B();
System.out.println(a.i); // would now print 20
Declaring the same variable i in class B would have its own scope and does not inherit from the class A.
Variables can not be overridden in Java as they are resolved at compile-time; You can use super to set its values,
class A {
int i = 10;
}
class B extends A {
int i = 20;
public B() {
super();
super.i = i;
}
}
A a = new B();
System.out.println(a.i); //20
public class A {
public void m1() {
System.out.println("A m1");
}
}
public class B extends A {
public void m1() {
System.out.println("B m1");
}
public void m2() {
System.out.println("B m2");
}
}
public class Result {
public static void main(String[] args) {
// TODO Auto-generated method stub
/*A a = new A();
a.m1();
B b = new B();
b.m1();
b.m2();
*/
A ab = new B();
ab.m1();
}
}
In the above code, I have a Class A and Class B that extends Class A. In class C I am creating the object of class B and it's been assigned to class A. when I try to call ab.m1() it calling the method in class B.but when I try to call ab.m2() i get compile time error. I am not understanding why class B method is called during ab.m1(). can someone help me in understanding the concept much better.thanks in advance.
A ab = new B();
You create a reference of type A and point it to an object of type B. This is valid and legal because B extends A, so an object of type B IS-A type A. That's why, when you call ab.m1(); you're calling the method defined in B. Your object type is B, so it overrides the method defined in A.
However, you can't call ab.m2() because the reference is type A, and knows nothing about new methods defined in B that weren't included in A. The reference only has access to the things defined in A (and anything that it might inherit from its super types, like Object).
B -->A// B is-a A
A ab = new B()//object of B is created and reference variable is type of Super type as A is super class of B
since ab.m1() is type of A class and can be accessible through super variable.
ab.m2() is type of B class and can not be accessed using super type reference, thats where down casting comes into picture.
try:
B a = (B)ab;// down casting
a.m1();
a.m2();
now you call both method of B class.
I have 3 classes A,B and c as follows
A.java
class A
{
protected A(){
System.out.println("A");
}
void show()
{
System.out.println("showA");
}
}
B.java
class B extends A
{
B(){
System.out.println("B");
}
void show()
{
System.out.println("showB");
}
}
C.java
class C extends B
{
C(){
System.out.println("C");
}
void show()
{
System.out.println("showC");
}
public static void main(String... args)
{
A a= (B)new C();
a.show();
}
}
When executed gives the output
D:\java\rmi\Hello>javac C.java
D:\java\rmi\Hello>java C
A
B
C
showC
I know a superclass cannot be casted to a subclass.But in the output why is it executing the C class method (show) when there is a cast to the super class B?
A a= (B)new C();
And if this is right then what is it that is getting casted to B?
I mean here new C() would call the C constructor and hence the respective outputs but
what is the difference between new C().show(); and (B)new C().show(); what is getting casted here?
Casting an object does not change its type.
(B) new C();
will still create an object of type C, no matter what you cast it to. But if you only create a B it will of course only ever be a B which is why C’s constructor is not called when you execute
(C) new B();
The error "B cannot be cast to C at C.main" means that the superclass B is casted by C which is a subclass.(Just read it again and again and you will understand it..)
You can cast in lower element in the hierarchy with the upper element but not vice-verse..
Hope you got it :)
Class B does not extend C, so it has no knowledge of it and connot be casted to C. With java, you can down cast but not upcast.
OK:
A a= (B)new C();
-> C inherits from B, so cast is possible
Not OK
A a= (C)new B();
-> B does not inherit from C, so it cannot be cast to it
see also: Downcasting in Java
Edit:
Please consider to edit your question, as most users tend to correct an error first. (Remove the error and break it down to your original question)
"what is the difference between new C().show(); and (B)new C().show();"
This is called 'polymorphism'. there is no difference between the two calls, as java will always execute the method of the lowest level of the hierarchy.
For example:
class Bird{
public void fly(){
System.out.println("I am flying");
}}
class Duck extends Bird{
public void fly(){
System.out.println("I can not fly");
}}
class Test{
public static void main(String[] args){
Bird[] birds = {new Bird(), new Duck()};
for (Bird b: birds){
b.fly();
}
}
This would output:
I am flying
I cannot fly
When you are creating an object of a class, its superclass objects are created first.
So when you says
A a = (B)new C();
While creating object of C, its superclass objects are first created. So the object of C can be casted to B.
But in the later case while creating the object of B, it would not possible.
Always remember that a subclass object can be casted into superclass, where as a superclass object can not be casted to its subclass, which is done by you in the second case, so it gives you compilation error.
class A is abstract and class B extends class A
now class A reference can hold object of class B,that is
A aObj = new B();
and assume class B has some extra methods....
like
class A
{
public show();
}
class B extends A
{
public show(){}
public method1(){}
private method2(){}
}
now tell me what things variable aObj can access from class B
can it access everything?
aObj only sees the public show() method. If you cast aObj to B, you can then access public method1(). public method2() is only accessible to the implementation of B.
For reference and completeness, here's a list of the possibilities:
A aObj = new B();
aObj.show(); // Works
aObj.method1(); // Error
aObj.method2(); // Error
And with casting to B:
B bObj = (B)aObj; bObj
bObj.show(); // Works
bObj.method1(); // Works
bObj.method2(); // Works inside bObj, but error otherwise
aObj can only use show() as the compiler thinks aObj is of type A, and the only known method of A is show().
If you know that you actually have a B you can cast that object to a B:
if (aObj instanceof B.class) {
B bObj = (B) aObj;
bObj.method1(); //OK
} else {
log.debug("This is an A, but not a B");
}
aObj.show();
I have a Java class B with an inner class C. Some methods of B accept an instance of C as parameter but I only want to accept C instances created by the proper instance of B. Is there a way to do this validation at compile time?
Example
C c1 = new C();
B foo = c1.getB(); // foo was created by instance c1
C c2 = new C();
c2.method(foo); // I want a compiler error here.
My case
Have a class names Map which hold a matrix of instances of the inner class MapArea. The nice thing about this scheme is that I can validate the xPos, and yPos fields at the constructor so no invalid Areas for a given map are built. The map as a method distanceFrom(MapArea startingPos, MapArea toLocation, MapArea... otherLocations) and I was trying to avoid to validate the map area arguments again.
If this is really the behavior you want, method() should really be defined in the inner class.
In other words, instead of:
public class C {
//...
public void method(B b) {
this.x = b.y;
//...
}
//...
public class B {
//...
}
//...
}
It should be:
public class C {
//...
public class B {
//...
public void method() {
C c = this.C;
c.x = this.y;
//...
}
//...
}
//...
}
Of course, this wouldn't solve the problem if, for example, you wanted public void method(B b1, B b2, B b3), where all three instances of B are enclosed by the same instance of C.
A compile error won't work, but you can at least throw an exception:
public class C
{
public static void main (String [] args)
{
C c1 = new C();
B b = c1.getB();
c1.useB(b); //OK
C c2 = new C();
c2.useB(b); //throws IllegalArgumentException
}
public B getB() { return new B(); }
public void useB(B b) {
if(b.getC() != this)
throw new IllegalArgumentException();
//...
}
private class B
{
public C getC() { return C.this; }
//...
}
}
There's no way (AFAIK) of doing this at compile time.
At runtime you can do it by having the outer instance's factory method pass a reference to itself to the inner instance's constructor.
The inner class would need to store that reference, such that the outer class can check whether it created that instance or not:
public class C {
public class B {
private C parent;
private B(C parent) {
this.parent = parent;
}
public C getParent() {
return parent;
}
}
public B getB() {
return new B(this);
}
public void method(B b) {
assert(this == b.getParent());
}
}
Actually, as Kip's concurrent answer shows, B can access C.this to get the parent object so there's no need to store the parent reference. However the method above would be necessary if C wasn't actually an inner class.
If you make the constructor of the inner class (C) private, I believe the enclosing class (B) can still instantiate it while other classes cannot. This ensures that only B and C can instantiate C.
Edit: I've verified that with a small mockup. Make the inner class constructor private, and then only the inner class (C) or the enclosing class (B) can instantiate it.
See http://tns-www.lcs.mit.edu/manuals/java-1.1.1/guide/innerclasses/spec/innerclasses.doc6.html for more. In particular: "Access protection never prevents a class from using any member of another class, as long as one encloses the other, or they are enclosed by a third class.".
There's no compile-time way to guard against instance-specific usage. Your best bet is probably throwing an Exception when the usage in incorrect. Another option you have is to have the parent class to have a Map of instances of the inner class, and to have other classes tell the outer class to operate on the inner class not by the instance but by some other references. This will work with other classes don't need to do anything directly with the inner class.