Doubts about object Casting
I am helping a friend from first year to prepare his exam on Java. The teacher asked them to create a method that can cast a Musicians to a Poets.
No one knew how to do it. After thinking a good while, I came to the conclusion that it is impossible to do that(ClassCastException), because the fact that Musician and Poet Share an Interface is not enough to cast them to the other.
I think that would be possible only, if they were in the same开发者_开发问答 inheritance chain.
Now I have three questions:
- Am I right?
- If I am right, what is what the professor wanted from them to do? I really doubt that he would ask for such a thing.
- If I am wrong, could you write code that can cast a Musician into a Poet?
- You are right
- Trick question?
- No, at least, not without a
ClassCastException
.
You could try:
Musician musician = new Musician();
Artist artist = musician;
Poet poet = (Poet)artist;
But of course, that code won't actually work at runtime.
You are right. Given your inheritance structure, you cannot cast a Musician
to a Poet
.
The only thing you could do is create a facade object that is a Poet
and forwards relevant method invocations to an associated Musician
.
Can Musician and Poet each be an interface? If so it's possible to have a class that implements both and could be cast from a Musician to a Poet and vice versa.
public interface Musician {
void sing();
}
public interface Poet {
void read();
}
public class Common implements Musician, Poet {
public void sing() {
//sing
}
public void read() {
//read
}
}
public Musician convert(Poet poet) {
if(poet instancof Musician) {
return (Musician) poet;
else {
throw new IllegalArgumentException("Not a musician");
}
}
public void test() {
Common rapper = new Common();
Musician singer = convert(rapper);
}
static Poet musicianToPoet(String fileName) {
Poet p = new Poet();
p.readArtist(fileName); // this method is defined in the interface
return p;
}
static Poet musicianToPoet(Musician musician) {
String filename = "/some/file/name.txt";
musician.saveArtist(filename);
return musicianToPoet(filename);
}
Just to throw ideas around... can you use the java.lang.reflect.Proxy class?
Edited..
Actually you don't need the Proxy as I mentioned. Using ideas I borrow from dynamic sub-classing, you can achieve your goal of convert musician to poet. Basically what you do is you have to create a class that extends Poet, takes in a Musician in constructor. Then in the sub class you can override each of Poet's method to "map" Poet's method to Musician's method.
I have written all stuff in one class, which is not a good programming style, but it's just easier to do on SO ;-)
public class Caster {
public static void main(String[] args){
Musician m = new Musician();
Caster caster = new Caster();
Poet p = caster.cast(m);
System.out.println(p.getPoetryGenre());
}
public Poet cast(Musician m){
Poet p = new PoetWannabe(m);
return p;
}
private class PoetWannabe extends Poet{
private Musician musicianInDisguise;
public PoetWannabe(Musician m){
this.musicianInDisguise = m;
}
@Override
public String getPoetryGenre() {
return musicianInDisguise.getMusicGenre();
}
@Override
public void setPoetryGenre(String g) {
musicianInDisguise.setMusicGenre(g);
}
/*override more methods as you wish*/
}
}
public Musician getMusician(Poet p) {
Artist a = p;
return (Musician)a;
}
Yes, this will explode with a ClassCastException. But, at least from a language level, it SEEMS like it can be done. But the runtime will prevent it at runtime.
You are correct, Musician and Poet are different classes that share the same base implementation. The only thing that you could reliably do is cast IArtist<->Artist<->Musician, or IArtist<->Artist<->Poet
With the class diagram you have there. NO, you cannot cast a Musician to a Poet. Are you sure the prof isn't asking you/your friend to redesign the class tree?
精彩评论