views:

80

answers:

4

I have a base Entity class:

public class Entity
{
    abstract int getTypeID();
}

The method int getTypeID() returns a number that is unique to that class:

public class OneEntity extends Entity
{
    int getTypeID()
    {
        return 1; // Actually defined in a constants class
    }
}

Now I want to be able to safely cast it and assign it.

I can do it this way:

public void castTheEntityAndDoSomething(Entity ent)
{
    if (isType(ent, 1)) // this is the 1 from the OneEntity class
    {
        OneEntity oneEnt = (OneEntity)ent;

        // ... and then do something
    }
}

public bool isType(Entity ent, int type)
{
    return ent.getTypeID() == type;
}

But what I'd like to do is combine the cast and the type check in one line.

Something like:

if (OneEntity oneEnt = entityCast(ent, 1))
{
    // use a method specific to the OneEntity class
}

Is this possible? What does the method look like? It would be even better if I could use the subclass name as an argument of the safe casting method.

EDIT:

So I've written this method to avoid the type id etc. etc.

@SuppressWarnings("unchecked")
public static <T extends Entity> T castEntity(Entity ent)
{
    if (ent instanceof T)
    {
        return (T)ent;
    }

    return null;
}

But it has this error:

Cannot perform instanceof check against type parameter T. Use instead its erasure Entity since generic type information will be erased at runtime

What do I need to do to fix this compile error? Is this even going in the right direction?

+2  A: 

In case you have defined this typeId for the sole purpose of casting, then please don't do that and use instanceof operator instead.

Then you just need to do something like this,

if (ent instanceof EntityOne) {
   OneEntity oneEntity = (OneEntity) ent;
   // do whatever
}

Now, taking your example here,

if (Entity oneEnt = entityCast(ent, 1))
{
    // do something with oneEnt
}

Suppose this if statement of yours work and your entityCast() method return OneEntity. Don't you think you are again getting that returned value in type Entity. Hence spoiling the whole purpose.

So, please explain what are you trying to do exactly.

Adeel Ansari
I'm attempting to call a method that is specific to the OneEntity subclass, but only if the if statement returns true.
Brad
@Brad: Then, you are good to go with my former snippet.
Adeel Ansari
@Brad: Tell me, how are you planning to call your `castEntity()` method, that you defined using `Generics`?
Adeel Ansari
+1  A: 

If you implement an interface which defines the methods you want to call on them from the "do something" blocks and implement that inteface in all your derived entiries, your have solved problem by using polymorphism.

rsp
+1  A: 

You might want to rethink your architecture.
First of all maybe you should not have a typeID field in the class.
You should rely on the "power" of inheritance and/or interfaces instead.

// Entity.java
public interface Entity { abstract public void doSomeThing(); }

// EntityType1.java
public class OneEntity extends Entity { 
    @Override
    public void doSomeThing() {
        // do something specific for entity type 1
    }
}

// EntityType2.java
public class TwoEntity extends Entity { 
    @Override
    public void doSomeThing() {
        // do something specific for entity type 2
    }
}

// Main.java
public static void main(String[] args) {
    Entity e1 = new EntityType1();
    Entity e2 = new EntityType2();
    e1.doSomeThing();
    e2.doSomeThing();
}

You should encapsulate the different behavior in the implementation classes.

If you think you have good reasons to detach the behavior from the entities you would better use this same logic in a hierarchy of external processing classes (maybe with a simple factory on top) and use "instanceof" in the factory method.

Manrico Corazzi
+1  A: 

I suppose that you could do this:

OneEntity oneEnt;
if (isType(ent, 1) && (oneEnt = (OneEntity) ent) != null) {
    // ... and then do something
}

... or the equivalent with instanceof instead of your icky isType method ...

Or you could define a method called oneEntityOrNull as follows:

public OneEntity oneEntityOrNull(Entity ent) {
    return ent instanceof OneEntity ? (OneEntity) ent : null;
}

and then

OneEntity oneEnt;
if ((oneEnt = oneEntityOrNull(ent)) != null) {
    // ... and then do something
}

but IMO both of these are a BAD IDEA since the code is harder to understand than the original.

Stephen C