Question about Java polymorphism and casting - java

I have a class C. Class E extends it.
E e = new E();
C c = new C();
Why is
e = (E) c;
Upon further review: though numeric conversions have the same syntax as casting objects, some confusion arose. At any event, the above does not give a compilation, but rather a runtime error - so a class can be casted to subclass in some instances (otherwise the code would not compile). Any examples that anyone can give where the above works?
And also:
K extends M
K k = new K();
((M) k).getClass() gives K. Why is that? It was casted to the more general M!
Suppose I have a doIt() method implemented in both M and K. executing
((M) k).doIt();
gives M's or K's doIt()?
Thanks!

Consider a real-world example:
public class Dog extends Animal
All dogs are animals, but not all animals are dogs. Hence...
public class Cat extends Animal
Casting an Animal to a Dog can only be done if the Animal in question is indeed a Dog. Otherwise it would force the Universe to infer properties unique to a dog (wagging tail, barking, etc.) onto an Animal. That Animal might well be a Cat with properties unique to it (purring, rigorous regime of self-cleaning, etc.). If the cast is not possible then a ClassCastException is thrown at runtime.
Nobody wants a dog that purrs.
((M) k).getClass() gives K. Why is that? It was casted to the more general M!
You've casted k to M, but all classes have a getClass() method. k's class is always K, regardless of whather you cast its reference to M or not. If you cast a Dog to an Animal and ask it what animal it is it'll still answer that it's a dog.
In fact, casting to a superclass is redundant. A Dog already is an Animal and it has all the methods of an Animal as well as its own. Many Code Analysis tools such as FindBugs will notify you of redundant casts so you can remove them.
Suppose I have a doIt() method implemented in both M and K. executing
((M) k).doIt();
gives M's or K's doIt()?
K's doIt() for the same reasons as above. The cast operates on the reference; it doesn't transform an object to a different type.
Can you give an example of when casting (Dog doggy = (Dog) myAnimal) makes sense?
Sure can. Imagine a method that receives a list of animals for processing. All the dogs need to be taken for a walk, and all the cats need to be played with using a bird-shaped toy. To do this we call the takeForWalk() method that only exists on Dog, or the play() method which only exists on Cat.
public void amuseAnimals( List<Animal> animals ) {
for ( Animal animal : animals ) {
if ( animal instanceof Dog ) {
Dog doggy = (Dog)animal;
doggy.takeForWalk( new WalkingRoute() );
} else if ( animal instanceof Cat ) {
Cat puss = (Cat)animal;
puss.play( new BirdShapedToy() );
}
}
}

You can't cast objects in Java.
You can cast references in Java.
Casting a reference doesn't change anything about the object it refers to. It only produces a reference of a different type pointing to the same object as the initial reference.
Casting primitive values is different from casting references. In this case the values do change.

Just because E extends C, C doesn't become an E... E on the other hand is a C
Edit: To expand Mark's comment below... Just because every woman is a human, not all humans are women. All humans share the "human interface" with legs, hands, faces, etc. Women extends it with functionality that returns good feelings when you provide diamonds and gold.
The int => double conversion is not even related as it is not a class cast but a conversion telling the compiler to store whatever is in x in y (which happens to be a double).
((M) k).getClass() gives K.
because k is still a K even if you cast it to an M or an Object (or something else it happens to be).
Edit: I think the confusion here is because you consider k to "become" an M when you cast it, it doesn't. You are just treating it as an M.
If you ask someone who is a "dog owner" what kind of breed it is he will not return "It's a dog", the reason is simply that the getBreedName() method is likely to have been overridden in the subclass LabradorOwner to return "Labrador". It is the same with getClass(), it will return the class of the implementation. It will not be an M but a K that happens to be an M as well just because K extends M.

the int/double is unrelated; that is a conversion, not a cast - there is no relationship between int and double.
Re the question; a type's object is fixed at creation. An object that is a C is not (and can never be) an E. However, you can treat an E as a C, since inheritance represents "is a". For example:
E e = new E();
C c = e;
Here we still only have one object - simply that the c variable thinks of it as a C, so won't expose methods specific to E (even though the object is an E).
If we then add:
E secondE = (E) c;
This is a type check; again, we haven't changed the object, but to put c into an E variable requires us to prove to the compiler/runtime that it really is an E. We didn't need this in the first example as it can already prove that any E is also a C.
Likewise, with the getClass() - all the cast does is change how the compiler thinks of the object; you haven't changes the object itself. It is still a K.
You need to separate variables from objects. The cast is talking about the variables; they don't change the object.

To add to Frederik's answer, casting an object to something doesn't change it's type. Also, object's can only be cast to a type it already is (the compiler just doesn't know at that point)
That's why impossible casts will never be accepted:
Integer i = (Integer) new String();
will not compile, because the compiler knows it can't be possible.

((M) k).getClass() gives K. Why is that? It was casted to the more general M!
A useful analogy (that I got from Bill Venners' site artima.com) that may help clear the confusion is that the difference between classes and objects is like the difference between an architect's blueprint and the actual house that is built. The blueprint exists on paper and is a concept, while the house exists in real life. You can have more than one house built to the same blueprint.
How is that relevant to this question? Let's say there's a McMansion blueprint and a McMansionWithHeatedPool blueprint. A McMansionWithHeatedPool is an extension of a McMansion with a heated pool.
Now, if you see a real McMansionWithHeatedPool, for that object:
Conceptually (i.e., if you look at the architect's blueprints), you would see that a McMansionWithHeatedPool is clearly also a McMansion. Hence the upcast is allowed. (For the same reason, a McMansion object cannot be type cast into a McMansionWithHeatedPool : no heated pool!)
((McMansion) k).getClass() gives McMansionWithHeatedPool because k is still a McMansionWithHeatedPool. The type cast is on the expression, not on the object.

"If the compiler treats it as an M, it should execute M's methods."
The compiler treats the reference as M. The instance that the reference points to is of type K, not M. You can't cast the reference and assume that means the instance will suddenly change behavior. What the compiler does is make sure that the method you invoke on the specified reference exists. It does not have anything to do with which implementation is invoked, only that an implementation does exist.

For the first question, you cannot cast a superclass to a subclass because a subclass adds members that the superclass doesn't have. How is the compiler supposed to know what values to put there when it's casting? Basically, an E is a C, but a C is not an E.
getClass() gets the type of the object in memory. Casting to M simply hides the fact that it's a K, it doesn't change the underlying object.

Casting an object does not change the object to the object being cast, but allows another class reference that is related to it by inheritance to refer to the object.
For example C extends E. And they both have a method myName();. If you say
E e = new C();
e.myName();
you are calling C myName() method and if you also say
E e = new E();
C c = (C)e;
you just told the compiler that it should allow you refer to E with C reference type.

Related

How to cast two classes of the same abstract class back and forth

public abstract class Animal {
}
public class Dog implements Animal{
}
public class Cat implements Animal{
}
public static void main(String[] args){
Dog dog = new Dog();
Cat cat = new Cat();
}
If I have the above structure is there a way to cast an instance of Cat to Dog and vice versa?
No. You misunderstand the cast operator. It is used for three utterly unrelated tasks. You probably know that 5 + 2 is 7, but "hey" + "bye" is "heybye". The + operator is used for 2 utterly unrelated tasks. The cast operator is no different.
Hence it's best to reserve the name 'cast' for the actual syntactical construct of (SomeType) someExpr, i.e. use that term very rarely, and instead use the names for the 3 completely unrelated things you can do with it:
Primitive conversion
You get this 'mode' when the thing in the parens is a primitive, and, specifically, a numeric primitive: char, int, long, double, float, short, or byte. That's the whole list - these types are hardcoded in java, you can't make your own primitives, there will never be different primitive types than this1.
In this mode, actual conversion occurs:
double y = 5.5;
int x = (int) y;
The above converts, and this is the only usage of the cast operator that does so.
Type assertion
This mode occurs when you stick a non-primitive type in the parentheses, and applies only to the reified part (the non-generics part, so not anything in the <> part of the type).
What does this is, if everything works out, nothing. It doesn't do anything at all. It is incapable of converting anything.
Specifically, it will inject the following code:
Check if the expression is actually an instance of the type in the parentheses.
2a. If it is, then do absolutely nothing, but for the purposes of parsing your code and knowing what to do, the expression (String) whatever is of type String, even if whatever is not.
2b. If it is not, then throw a ClassCastException on the spot.
That's all it can ever do. So, if it's not throwing an exception, it does nothing.
Type coercion / generics voodoo magic
I'm including this one for completeness: You shouldn't ever be using this particular mode of cast until you're way, way more advanced in java, and none of this is even going to make sense until you know quite a bit of java. If this sounds like gobbledygook to you, that's fine. Just ignore it, it's not important.
For the non-reified stuff in the parentheses (the stuff in the <>), it really really does absolutely nothing. It cannot possibly throw anything, it literally boils down to zero bytecode. It just tells javac to stop whining. It's you telling the compiler: Yes, I know, you cannot guarantee that any of this code makes sense. Shut up, I know what I am doing.
Example:
List<String> listOfStrings = new ArrayList<String>();
listOfStrings.add("Test");
List raw = listOfStrings;
List<Integer> numbers = (List<Integer>) raw;
The above compiles (but with warnings, because this is crazy code that makes no sense), and runs, and doesn't even throw an exception. Even though you now have a variable of type List<Integer> which contains a not-integer. If you interact with this list, ClassCastExceptions will start occurring even though you aren't even writing any casts.
Dogs and Cats
You're doing the second mode: Type assertion. An instance of Dog is not an instance of Cat, therefore:
Dog dog = new Dog();
Cat c = (Cat) dog;
will fail. It will in fact fail with a compile-time error because the compiler knows it'll never work. You can 'fix' that:
Animal a = new Dog();
Cat c = (Cat) a;
Now it will compile, but it'll throw a ClassCastException on the second line.
What does Animal a = new Dog() even mean?
Non-primitives in java are always references. It is impossible in java to have a variable that has a dog in it. I know Dog dog = new Dog() sure looks like you have a variable named dog whose value is a dog, but, it is not. It is a reference to a dog. Dogs are far too weird and large, variables are very simple things. All variables are like postit notes: They have a fixed, small amount of space. For int and boolean and the like, the number fits right on the postit note, but for all the non-primitives, you don't put the dog literally on the note. You write the location of the dog on the note. Dog dog = new Dog() is just syntax sugar for:
Dog dog; // make a new postit note
new Dog(); // make a dog object
dog = what we just made; // scribble the dog's location on the note
Now Animal a = new Dog() makes sense: Animal a; and Dog dog are both just postit notes. It's just the a postit note here is restricted: It can be blank (a = null), or it can hold the location of an animal. You can write the location of a cat on there, or of a dog, or of a donkey, or of a unicorn. But you can't write the location of a house on it. The dog note can only hold the location of a dog (or be blank).
Hence, the location of a dog can be written on either note.
Cat c = (Cat) animal;
means:
Make a new postit note, name it c, and restrict it so that it can only hold the location of a cat, or b e blank.
Take the postit note named animal. Follow it and check if the animal it leads you to is, in fact, a cat. If it is NOT, throw a ClassCastException.
but if it is, take the location of that cat and scribble it on the postit titled 'c'.
That's a sensible thing to do.
[1] For the purposes of primitive conversion, the future language update known as Project Valhalla is unlikely to change this, even though it will more or less introduce the concept of letting you write your own primitives.

Understanding Multiple Casting in Java

Skip to the last sentence if you want to read the question right away.
Suppose we have an Interface and three classes:
interface I{}
class A implements I{}
class B extends A {}
And the following declarations:
A a = new A();
B b = new B();
Now, there's the classic way of casting which allows me to cast a reference of type A (the parent class) to an object of type B (the child class) like this:
a = b; //here a is no longer pointing at object A, and is now pointing at the same object b is pointing at.
b = (B) a; // the casting is now accepted by the compiler and during runtime as well.
Here where lies the problem though. Every time I see a line of code with multiple casting, I fail to read it (literally) and, as a result, I can't understand what it means.
For instance, let's say we have this line of code:
a = (B)(I)b;
How would you read this one? a is a reference to an object of type A, and it is being assigned the value of an object of type B (first cast from the left). But wait a minute, there's also another cast (I) preceding b. So what do we have here? Is it an interface being cast as a (B) object? or is it a b being cast as an interface which is also being cast as a (B)?
I tried to break it down to avoid confusion:
I temp = (I) b;// first line
a = (B) temp;// second line
So, first, since b is an I (because it extends A which implements I), "first line" is accepted by the compiler and during runtime.
"Second line" though, we have a reference to an object A being assigned a value of type B. At first glance, there's nothing wrong with it. But then I realized I is not an A nor is it a B, and even though the cast in "second line" can dupe the compiler into believing it's an object of type B, it shouldn't be accepted at runtime.
So the main question that I would like an answer to is how do I interpret the following line:
a = (B)(I)b;
Reality or The answer you don't want
The real problem here is that a careless goofball wrote crappy code.
The real solution is; either don't write crappy code or fix the code.
Lets keep being a goofball or The answer you seem to want
There are two types of casting in java; up-casting and down-casting.
Up-casting is when you cast an object of type A to be an instance of interface I; you are casting "up" the inheritance tree.
For example:
A aObject = new A();
I iObject = (I)aObject; // Up casting.
The benefit of up-casting is that the compiler is able to determine, at compile time, if the cast is legal.
Down-casting is when you cast an object of type I to be an object of type A; you are casting "down" the inheritance tree.
For example:
A aObject;
I iObject = new A();
aObject = (A)iObject;
The compiler does not know, at compile time, if down-casting will succeed.
Because of this, a down-cast may throw an exception at runtime.
Your confusing code: a = (B)(I)b; is an example of both up-casting (safe) and down-casting (not safe).
As a bonus, the casting is in no way required.
It is always safe to assign a B object directly to an A reference because the B class extends the A class.
Addressing: "careless goofball" seems like strong language.
It is not strong language, it is the nicest way to describe the cause your situation.
In truth, somebody who writes code like that should be terminated (optionally, get them hired by one of your competitors).
Based on the Java language grammar, the statement
a = (B)(I)b;
might be better visualized like this:
a =
// outer CastExpression
(B)(
// with its UnaryExpression being another CastExpression
(I)(b)
);
That is, it casts b to I, then casts that to B, then assigns that to an A variable.
However, it doesn't look like either of these casts are necessary. If b is an instance of B, it is also an instance of A and I.
a = (B)(I)b;
Cast b to I, and then cast it to B. Presumably since you can't cast b to B directly.
Now there aren't really good situations to use this, since casting even a single time should be avoided if possible. However if you want something like
String s = (String) myHashMap;
to compile, you need to upcast to prevent the compiler from disallowing an obviously illegal cast:
String s = (String) (Object) myHashMap;
Naturally if your myHashMap isn't null, this will cause a runtime ClassCastException, but unlike the earlier example it will compile.
Maybe you don't get the point that, even if cast to I or A, b remains an Object of type B, it doesn't loose its nature. Think of casting a way to say to java 'see my object as an object of type I'. Then if type B it is also of type A.
So the instruction tells java 'use my object as it is of type I and immediatly after use it as type B, which, by declaration, is also of type A. So no compile or runtime errors.
Then we can see.that it looks also mostly unuseful and ugly..

Upcasting in Java for non primitive types

Let us consider we have two classes A and B. B is a sub class for A because B extends A. If We create an instance of A Class and assign that in to a A type will contains all the properties of A. Similarly when I create an Instance of B and assign it to B type will get all the properties of B along with properties of A because it is inheriting from A. According to above lines instance of A contains properties a few as compared to properties contains to instance B. That means Instance of B is Bigger than Instance of A as casting should be explicit when narrowing implicit when widening. According to my theory Instance of B is bigger we are trying to store it in A type we need conversion.
A a1=new (A)B();
The above conversion is taking place implicitly. But my question is how it is implicit, Instance of B is bigger we are trying to convert that to small type which is A. How this is possible???
Answer me with examples thank you in advance.
You are thinking in terms of object size, but in Java, non primitive types are never contained, only referred to. Thus, your code is casting the result of new B(), which is of type "reference to B", to type " reference to A". Since all references are the same size, no data is lost in the cast.
So, I really don't understand your question. I just think you are confused about what happens to the class B members when a upcast to his super class is made. In that case, you ended up with a instance of A wich means that Object type is A and non of B stored data will remain.
In Java, with
B b = new B();
A a = b;
one defines references b and a. Under the hood, references are implemented with pointers, and thus, all references are the same size. Of course, an instance of a B might indeed require more memory than an instance of A (I take it, this is what you mean by "bigger").
By the way, in C++ this is not the case.
B b();
does define an object, not a reference, and therefore
A a = b;
in C++ is indeed not allowed.
Think about this:
class Animal{
public void eat(){}
}
class Monkey extends Animal{
public void climbTree(){}
}
I can now do this:
Animal someAnimal = new Monkey(); //This is ok. (Create a Monkey and identify is as an Animal)
someAnimal.eat(); //This is ok too. (All Animal objects can eat)
someAnimal.climbTree(); //Not ok. Java sees someAnimal as a general Animal, not a Monkey yet.
From the above example, someAnimal is a Monkey object which is stored within a variable of higher hierarchy (Animal).
The object itself is perceived as the a more general class (The Animal class) and I don't think an implicit casting is done here since all Monkeys are already Animals (but not the other way round).
Explicit casting can be done when you want to let the compiler knows that the object actually belongs to a more specific class. For example:
((Monkey)someAnimal).climbTree(); //This is ok. Inform Java someAnimal is actually a Monkey which knows how to climb.
Example :
Class Employee {
private String name;
private double Salary;
//getter & setter
//mutators to increase salary etc;
}
class Manager extends Employee {
private double bonus;
//inherits methods from superclass
// sub class specific methods
}
Employee e = new Manager(); //is fine as manager is also an Employee...
The prefixes super and sub come from the language of sets used in theoretical computer science and mathematics. The set of all employees contains the set of all managers, and thus is said to be a superset of the set of managers. Or, to put it another way, the set of all managers is a subset of the set of all employees.
~ From core java series
hope this helps...
The cast isn't actually implicit like you're saying. What is actually happening is this:
B b1 = new B();
A a1 = (A)b;
The (A) is an explicit cast, what's more important is to stop considering the size of things in the sense that the size of B is different from the size of A. This can be an implicit assignment because B IS-A A, so using A as an interface for B is completely safe, because we know that B has at least the same members as defined by A.
So the perfectly safe (and not erroneous) method of doing this is simple:
A a1 = new B();
Done!

Java: Casting to an Interface and Inheritance

I've been trying to understand casting in Java and how it affects the references. I've come up on this particular example:
public interface A1{
public void foo();
};
public class A2{
public void bar();
public static void main( String[] args )
{
A2 a = new B();
A1 c = (A1)a;
c.foo();
}
};
public class B extends A2 implements A1{
public void foo(){ System.out.println("This is B"); }
}
It prints "This is B", but i'm not sure why. This is how I understand this currently: a is a reference to an object of type A2, but during runtime, it points to a heap object which has the properties of B, but a only "sees" the properties of A2. But the types are already determined during compilation, so the cast tries to cast A2 to A1, which it can't do. Obviously I'm wrong, but I can't figure out why. Any help will be appreciated.
Casting conceptually has two components,
At runtime the JVM ensures that the object is of that type, and
will error with a ClassCastException if it is not
At compile time, it tells the compiler to allow use of the methods/fields of
that class. Note that if the object turns out to not be of that type at runtime, then it will error at runtime.
What casting does not do, is change the type of the actual object at runtime.
In your example you called new B(); that means after casting a reference from B to A1, then the object is still an instance of B. Given that foo() is declared on A1, and B extends foo then the compiler is happy (it passes 2 above). At runtime the JVM will scan B looking for the method of foo, it checks B before A1 because the object was created as type B. It did not change its type since new was called.
Casting checks are always made at runtime (see caveat in next paragraph), your reference points to an object of type B, therefore when you get to the casting bit, the VM will see a reference to an object of B, which can be safely cast. Note that casting doesn't actually change the object, it just ensures that the rest of the code calls methods which are available in the original object.
The caveat is that if it can be seen at compile time that the cast is definitely NOT possible, you do get a compile error.
String foo = "x";
Integer i = (Integer)foo; //throws a compile time error because `String` is final and `Integer` isn't its supertype.
But:
Object foo = "x";
Integer i = (Integer)foo; //this will only throw a runtime exception because from the compiler's point of view, `foo` may or may not be an integer.
The type of the variable that holds the reference has nothing to do with what the method implementations resolve to. In Java, all methods are implicitly virtual, meaning that they get looked up by the actual type of the object (instead of the type of the referring variable) every time. Since c actually points to an instance of B, it's B.foo() that gets called.
Note that this doesn't necessarily hold true for all languages - in C#, for example, methods are only virtual if you explicitly declare them as such and so i its default behavior would match what you were thinking. Java, however, is always virtual.
Reference comes into picture only during compile time or in case of static methods or behaviors.
When you are creating an object, method or behavior will depend on the whose object you have created rather than whose reference you have used.This is called polymorphism.
For example lets take an example of real life entities ---
When you rent a house, you ask a broker to find a house for you, which is your reference.but the person whom house belong, the land-lord is the actual object whom you are requesting. so it is the land-lord who gives you house on rent and not the broker.

Java - Object Type Casting and Inheritance

I have superclass A, which is extended by subclasses B1 and B2. Then, I have five subclasses (C1, C2, C3, C4, C5) that extend either B1 or B2.
I am trying to make an array containing one of each of these five subclasses.
These objects are all instantiated as instances of type A.
ClassA[] objects = new ClassA[5];
I attempt to reassign each of the objects to one of the subclasses:
objects[0] = new ClassC1;
objects[1] = new ClassC2; // etc...
At this point, any methods that existed in Class A work fine, but methods defined in B1/B2 or the other subclasses are not found:
objects[0].MethodFromC1(); // returns a "symbol not found" error
The instanceof keyword indicates that objects[0] is an instance of classes A, B1/B2, and C1.
What can I do to maintain my array of class objects (to loop through and perform operations), while getting my code to recognize the methods of the subclasses?
If you are doing a lot of instanceof and conditional logic based on class, you are completely missing out on the benefits of an object-oriented language. Just stick to C.
You should have some method do(), for example, that is abstract in ClassA but implemented in ClassB and ClassC. Then you iterate over the array and call do() on every object in there. The polymorphic call will result in the right do()'s being called.
Hope that helps.
Elements in the objects array don't know anything about ClassC1 since they're only guaranteed to be members of ClassA.
For instance, if you have a class hierarchy of Animal and subclass Cat and its subclass Lion, you're trying to call the Animal.maimSafarigoer() method. Animals in general don't know anything about safarigoers, only Lions know how to do that.
Use the instanceof operator to check if you're operating on a particular subtype.
(Sorry for the gruesome analogy. :-) )
You're trying to implement variants in Java. This subject has long been one of the things I hate the most about this language.
http://jazzjuice.blogspot.com/2010/10/6-things-i-hate-about-java-or-scala-is.html
I have listed about 8 suboptimal ways to do variants there.
You can use the instanceof keyword in the if statement and cast the object to the desired type. For example,
for (ClassA obj : objects) {
// do something common...
if (obj instanceof ClassC1) {
ClassC1 c1Obj = (ClassC1) obj;
c1Obj.MethodFromC1();
}
}

Categories