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
Related
I have three classes: A, AA and Top. A and AA extend Top.
Why is it that this won't compile:
A a = new A();
AA aa = (AA)a;
but this will:
float f = 4.3f;
int i = (int) f;
Class A and class AA are on the same hierarchy, but they are side by side, so they can not be cast as one another.
Lets say class A was defined as so:
public class A extends Top{
public A() {
}
public void foo(int i) {
System.out.println(i);
}
}
And that class AA was defined as so:
public class AA extends Top {
public AA() {
}
public void bar(String s) {
}
}
Now lets theoretically imagine what would actually happen if you tried to cast an A to an AA and it worked:
A a = new A();
(AA) aa = (AA) a;
Since aa has a static type of AA, Java would let you write code like this:
aa.bar("hi!");
Because the AA class has a bar method, BUT aa has a dynamic type of A, which means that the actual object that the variable aa refers to does not have a method called bar("hi!").
(The static type of an object tells you what methods you can call on it and the dynamic type tells you what methods it actually has.)
So Java would tell aa to do bar("hi!") but aa wouldn't know what to do, because aa does not have the bar method defined.
You may create cast method in the class you want to cast. Here I have cast type into type A by using a.cast(B b) method.
public class A {
public int i;
public A cast(B b){
A a = new A();
a.i=b.i;
return a ;
}
}
public class B {
public int i=10;
}
public class Tester {
public static void main(String[] args) {
B b = new B();
A a= new A();
a=a.cast(b);
System.out.println(a.i);
}
}
Java is a strong-type programming language, which means to define every variable, you need to specify its type, and for each variable, it can only hold a value belongs to the same type. For primitive types Java also defines the rules how different types can be casted to each other, there's Widening Primitive Conversion(no info loss) and Narrowing Primitive Conversion(info may loss), you can find more details at the official Java docs. So the reason you can do int i = (int) f; is that the conversion rule is defined in Java Spec and Java compiler allows you to do so. You can't do int a = (int) true if you tried, because there's no such a rule to convert boolean type to int.
Type casting rules for reference types are also simple, the compiler only allow you to do type casting A a = (A) b when it thinks the type of b maybe A or some sub-type of A in the type hierarchy, take a look at the following code:
Object b = c;
A a = (A) b;
compiler only knows that b is type Object but has no idea of its specific type, because Object is the root of Java type hierarchy, so the real type of b maybe any type, like type A, so the compiler will allow you to do so. If b actually is not a A, the error can only be found at runtime, when a ClassCastException will be thrown.
On the other hand, the compiler will prevent you to do A a = (A) b when it clearly knows that b is not type A:
class A {}
class B {}
If you have the above definition of type A and B, then compiler has enough information that an instance B is absolutely not type A, so it will give you a compile error of Inconvertible types when you try to do A a = (A) new B(). And this is one of big benefits to use a strong-type programming language: to guarantee type safety (at compile time for Java).
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!
Upcasting is allowed in Java, however downcasting gives a compile error.
The compile error can be removed by adding a cast but would anyway break at the runtime.
In this case why Java allows downcasting if it cannot be executed at the runtime?
Is there any practical use for this concept?
public class demo {
public static void main(String a[]) {
B b = (B) new A(); // compiles with the cast,
// but runtime exception - java.lang.ClassCastException
}
}
class A {
public void draw() {
System.out.println("1");
}
public void draw1() {
System.out.println("2");
}
}
class B extends A {
public void draw() {
System.out.println("3");
}
public void draw2() {
System.out.println("4");
}
}
Downcasting is allowed when there is a possibility that it succeeds at run time:
Object o = getSomeObject(),
String s = (String) o; // this is allowed because o could reference a String
In some cases this will not succeed:
Object o = new Object();
String s = (String) o; // this will fail at runtime, because o doesn't reference a String
When a cast (such as this last one) fails at runtime a ClassCastException will be thrown.
In other cases it will work:
Object o = "a String";
String s = (String) o; // this will work, since o references a String
Note that some casts will be disallowed at compile time, because they will never succeed at all:
Integer i = getSomeInteger();
String s = (String) i; // the compiler will not allow this, since i can never reference a String.
Using your example, you could do:
public void doit(A a) {
if(a instanceof B) {
// needs to cast to B to access draw2 which isn't present in A
// note that this is probably not a good OO-design, but that would
// be out-of-scope for this discussion :)
((B)a).draw2();
}
a.draw();
}
I believe this applies to all statically typed languages:
String s = "some string";
Object o = s; // ok
String x = o; // gives compile-time error, o is not neccessarily a string
String x = (String)o; // ok compile-time, but might give a runtime exception if o is not infact a String
The typecast effectively says: assume this is a reference to the cast class and use it as such. Now, lets say o is really an Integer, assuming this is a String makes no sense and will give unexpected results, thus there needs to be a runtime check and an exception to notify the runtime environment that something is wrong.
In practical use, you can write code working on a more general class, but cast it to a subclass if you know what subclass it is and need to treat it as such. A typical example is overriding Object.equals(). Assume we have a class for Car:
#Override
boolean equals(Object o) {
if(!(o instanceof Car)) return false;
Car other = (Car)o;
// compare this to other and return
}
We can all see that the code you provided won't work at run time. That's because we know that the expression new A() can never be an object of type B.
But that's not how the compiler sees it. By the time the compiler is checking whether the cast is allowed, it just sees this:
variable_of_type_B = (B)expression_of_type_A;
And as others have demonstrated, that sort of cast is perfectly legal. The expression on the right could very well evaluate to an object of type B. The compiler sees that A and B have a subtype relation, so with the "expression" view of the code, the cast might work.
The compiler does not consider the special case when it knows exactly what object type expression_of_type_A will really have. It just sees the static type as A and considers the dynamic type could be A or any descendant of A, including B.
In this case why Java allows downcasting if it cannot be executed at the runtime?
I believe this is because there is no way for the compiler to know at compile-time if the cast will succeed or not. For your example, it's simple to see that the cast will fail, but there are other times where it is not so clear.
For instance, imagine that types B, C, and D all extend type A, and then a method public A getSomeA() returns an instance of either B, C or D depending on a randomly generated number. The compiler cannot know which exact run-time type will be returned by this method, so if you later cast the results to B, there is no way to know if the cast will succeed (or fail). Therefore the compiler has to assume casts will succeed.
# Original Poster - see inline comments.
public class demo
{
public static void main(String a[])
{
B b = (B) new A(); // compiles with the cast, but runtime exception - java.lang.ClassCastException
//- A subclass variable cannot hold a reference to a superclass variable. so, the above statement will not work.
//For downcast, what you need is a superclass ref containing a subclass object.
A superClassRef = new B();//just for the sake of illustration
B subClassRef = (B)superClassRef; // Valid downcast.
}
}
class A
{
public void draw()
{
System.out.println("1");
}
public void draw1()
{
System.out.println("2");
}
}
class B extends A
{
public void draw()
{
System.out.println("3");
}
public void draw2()
{
System.out.println("4");
}
}
Downcast works in the case when we are dealing with an upcasted object.
Upcasting:
int intValue = 10;
Object objValue = (Object) intvalue;
So now this objValue variable can always be downcasted to int because the object which was cast is an Integer,
int oldIntValue = (Integer) objValue;
// can be done
but because objValue is an Object it cannot be cast to String because int cannot be cast to String.
Downcasting is very useful in the following code snippet I use this all the time. Thus proving that downcasting is useful.
private static String printAll(LinkedList c)
{
Object arr[]=c.toArray();
String list_string="";
for(int i=0;i<c.size();i++)
{
String mn=(String)arr[i];
list_string+=(mn);
}
return list_string;
}
I store String in the Linked List.
When I retrieve the elements of Linked List, Objects are returned. To access the elements as Strings(or any other Class Objects), downcasting helps me.
Java allows us to compile downcast code trusting us that we are doing the wrong thing.
Still if humans make a mistake, it is caught at runtime.
Consider the below example
public class ClastingDemo {
/**
* #param args
*/
public static void main(String[] args) {
AOne obj = new Bone();
((Bone) obj).method2();
}
}
class AOne {
public void method1() {
System.out.println("this is superclass");
}
}
class Bone extends AOne {
public void method2() {
System.out.println("this is subclass");
}
}
here we create the object of subclass Bone and assigned it to super class AOne reference and now superclass reference does not know
about the method method2 in the subclass i.e Bone during compile time.therefore we need to downcast this reference of superclass to subclass reference so as the resultant reference can know about the presence of methods in the subclass i.e Bone
To do downcasting in Java, and avoid run-time exceptions, take a reference of the following code:
if (animal instanceof Dog) {
Dog dogObject = (Dog) animal;
}
Here, Animal is the parent class and Dog is the child class.
instanceof is a keyword that is used for checking if a reference variable is containing a given type of object reference or not.
Downcasting transformation of objects is not possible.
Only
DownCasting1 _downCasting1 = (DownCasting1)((DownCasting2)downCasting1);
is posible
class DownCasting0 {
public int qwe() {
System.out.println("DownCasting0");
return -0;
}
}
class DownCasting1 extends DownCasting0 {
public int qwe1() {
System.out.println("DownCasting1");
return -1;
}
}
class DownCasting2 extends DownCasting1 {
public int qwe2() {
System.out.println("DownCasting2");
return -2;
}
}
public class DownCasting {
public static void main(String[] args) {
try {
DownCasting0 downCasting0 = new DownCasting0();
DownCasting1 downCasting1 = new DownCasting1();
DownCasting2 downCasting2 = new DownCasting2();
DownCasting0 a1 = (DownCasting0) downCasting2;
a1.qwe(); //good
System.out.println(downCasting0 instanceof DownCasting2); //false
System.out.println(downCasting1 instanceof DownCasting2); //false
System.out.println(downCasting0 instanceof DownCasting1); //false
DownCasting2 _downCasting1= (DownCasting2)downCasting1; //good
DownCasting1 __downCasting1 = (DownCasting1)_downCasting1; //good
DownCasting2 a3 = (DownCasting2) downCasting0; // java.lang.ClassCastException
if(downCasting0 instanceof DownCasting2){ //false
DownCasting2 a2 = (DownCasting2) downCasting0;
a2.qwe(); //error
}
byte b1 = 127;
short b2 =32_767;
int b3 = 2_147_483_647;
// long _b4 = 9_223_372_036_854_775_807; //int large number max 2_147_483_647
long b4 = 9_223_372_036_854_775_807L;
// float _b5 = 3.4e+038; //double default
float b5 = 3.4e+038F; //Sufficient for storing 6 to 7 decimal digits
double b6 = 1.7e+038;
double b7 = 1.7e+038D; //Sufficient for storing 15 decimal digits
long c1 = b3;
int c2 = (int)b4;
//int 4 bytes Stores whole numbers from -2_147_483_648 to 2_147_483_647
//float 4 bytes Stores fractional numbers from 3.4e−038 to 3.4e+038. Sufficient for storing 6 to 7 decimal digits
float c3 = b3; //logic error
double c4 = b4; //logic error
} catch (Throwable e) {
e.printStackTrace();
}
}
}
I will tell you why this happened. First of all you have to understand how JVM supports when we assign parent class into the child class using downcasting, because of reference . For example consider in the following code.
A is the super type any class that extends from it and can store the reference B class.
A a =new B();
When you assign a reference variable into the child class jvm will understand that since A can store the reference of B class that is why you can do it.
B b=(B)b;
The reason which is called compile time error and why you couldn't directly assign Parent class into the Child class because there is not any extends relationship. Note that casting only occurring with the key which is called extends, that is why you receive the compile time error.
Another reason which is called ClassCastException by the runtime because of jvm it directly accept the rule which is okay I accept that it is true but jvm after that will understand that by the runtime it is not store any referance of Child class when code was writing by the programmer who write coding in the syntax .
So, I have this:
public class A {
public int a = 0;
public void m(){
System.out.println("A"+a);
}
}
And this:
public class B extends A {
public int a = 5 ;
public void m (){
System.out.println("B"+a);
}
public static void main(String[] args) {
A oa = new A();
B ob = new B();
A oab = ob;
oa.m();
ob.m();
oab.m();
System.out.println("AA"+oa.a);
System.out.println("BB"+ob.a);
System.out.println("AB"+oab.a);
}
}
Output:
A0
B5
B5
AA0
BB5
AB0
I don't understand why oab.m(); output is B5 instead of A0. Can someone explain this to me?
That's the whole point of polymorphism. The concrete type of oab is B (since the object was created with new B()). So the method B.m() is called.
Look at the Animal example in http://en.wikipedia.org/wiki/Polymorphism_%28computer_science%29 to understand why it's useful. When you have an animal, and this animal is a Cat, you expect it to say "Meow!" when you make it talk.
B ob = new B();
A oab = ob;
Similar as
A oab=new B();
I don't understand why oab.m(); output is B5 instead of A0
Because you creating object of B and referencing it to A so m() is being inherited and that's why B's version of m()is being called.
A oa = new A();
B ob = new B();
A oab = ob;
From the code above ob is an instance of class B. It can be stored in a variable of class A as A extends B. But as the stored Object instance is of B and hence it is not aware of A's m() function.
Hence the out put is B5
In inheritance actual method invocation depends on the type of the actual object and not on the type of the reference.
B ob = new B();
A oab = ob;
Here oab is a reference variable of type A but it is pointing to object of type B i.e. ob so at runtime oab.m() will invoke overridden m() method from class B
In Java there is something like late binding (polymorphism). It means that code of method is not linked while compilation time (early binding), but while runtime. While invoking oab.m(); JVM is checking actual type (class) of object from aob reference (in your case B) and based on that info invoking code of method from that class. That is why oab.m(); returns B5.
You also need to know that late binding works only for methods, not fields. For fields value will be determined by reference type, so oab.a will return 0 not 5.
Imagine you had the following:
public class C extends A {
public int a = 7 ;
public void m (){
System.out.println("C"+a);
}
Now if you had this in your Main method...
C oc = new C();
A oac = oc;
oac.m();
...you would want that last call to output the stuff that is specific for the class C.
The point is that B is an A, and C is an A, but each of them have more specific versions of the values that an A contains, and when you ask for those data, the specific versions of them should be returned.
Now you can do this:
// Get an instance of B or C, but you don't
// care which - could be either:
A someVersionOfA = getAnInstanceOfA();
// This works no matter if you've got an instance
// of B or C, but the result should vary accordingly:
someVersionOfA.m();
As someone else mentioned, think of A as "Animal", B as "cat", and C as "Dog". If m() means "Make some noise", then calling m() should result in "Meow" or "Woof!" depending on on the instance getAnInstanceOfA() returned.
You have just copied the internal address of B to A one, and replacing it.
B inherit from A, so no compilation problem.
Finally, the reference to A is destroyed, it is now a copy of reference to B
Please tell me why i am getting ClassCastException in this case
I have type casted , the source of B class to A as shown below , but why i am still getting ClassCastException here .
public class A extends B
{
}
public class B {
public String getData() {
return "B";
}
}
public class Main {
public static void main(String args[]) {
A a = new A();
B b = new B();
a = (A) b;
System.out.println(a.getData());
}
}
It becomes more obvious if we play with different classnames:
public class Car extends SomethingWithWheels {} // was A extends B
public class SomethingWithWheels {} // was B
public class Train extends SomethingWithWheels {} // aahh, some C extends B
Now, lets cast again:
SomethingWithWheels somethingWithWheels = getItFromSomewhere();
Car car = (Car) somethingWithWheels;
The compiler has to complain, because somethingWithWheels (B) could be a Train instance (C), which can't be cast to Car (A).
You can't cast a base class to derived class. You can do the other way round though.
Because your instance "b" is not of type A (B does not extend A), so when you cast "b" to A it fails.
The opposite would work (casting an instance of type A to type B)
Because an instance of B is not an instance of A. It's really that simple.
If you create an instance of A, it's also a B - because that's what the subclassing means. However, if you create an instance of B, that is not an A, and can't be assigned/cast as such.
The only time you can cast is if the run-time class of an object is compatible with the type you're trying to cast to. You can't change the class of an existing object - which is what I think you might be trying to do here - only tell the compiler "look, I know it's really something more specific".
So as a counter-example, the following would work:
public static void main(String args[]) {
B b = new A();
A a = (A) b;
System.out.println(a.getData());
}
In this case, the variable b is declared to hold a reference to a B. It turns out that you populate it with an instance of A, but for the rest of the program the compiler isn't allowed to assume that b is an A, because it's not guaranteed. Since you know it's an A in your specific case, you insert the cast, which causes a run-time check that the object actually is an A. This succeeds, and from that point on you can call methods specific to A on your a variable.
In this case however there is no reason at all to do any casting - there are no extra methods available on the subclass that you'd need to call, and no methods which only take an A but not a B. Even if A overrode getData to do something different, you would still get this behaviour if invoking through a B reference.
You are downcasting and you try to cast a supertype to a subtype, thats why it does well during compilation but fails at runtime with ClassCastException.
You can call:
System.out.println(a.getData());
after removing the line where you try to cast the types