简体   繁体   中英

Java: Returning an extended class given it's name

In the following code I am returning a class that extends the type of Entity given the name of the class (it then corrects it so that Class.forName can find it properly).

How can I modify this so that I can still return a class that extends Entity without using @SuppressWarnings("unchecked") ?

I tired a few variations using T and just ? but couldn't come up with an answer.

@SuppressWarnings("unchecked")
public static Class<? extends Entity> getProjectile(String name) {
    if (name.equalsIgnoreCase("ARROW"))
        name = "Arrow";
    else if (name.equalsIgnoreCase("ENDERPEARL"))
        name = "EnderPearl";
    else if (name.equalsIgnoreCase("EXPERIENCEORB"))
        name = "ExperienceOrb";
    else if (name.equalsIgnoreCase("FIREBALL"))
        name = "Fireball";
    else if (name.equalsIgnoreCase("FIREWORK"))
        name = "Firework";
    else if (name.equalsIgnoreCase("SMALLFIREBALL"))
        name = "SmallFireball";
    else if (name.equalsIgnoreCase("SNOWBALL"))
        name = "Snowball";
    else
        name = "Egg";

    try {
        return (Class<? extends Entity>) Class.forName("org.bukkit.entity." + name);
    } catch (ClassNotFoundException e) {
        return Egg.class;
    }
}

You can't. Class.forName(String) is declared as returning a reference of type Class<?> which you then have to cast if you want it to conform to Class<? extends Entity> Class<? extends Entity> This cast is unsafe so the compiler warns you.

The alternative is to have the actual Class objects in the if-else block instead of the names.

If you can access the class at compile time you can just return, say org.bukkit.entity.Egg.class instead of calling forName . If you can't you're stuck with the annotation.

Compiler can't guess whether class extends Entity just by looking at possible values for Class.forName(...) call.

You can use a Class aClass variable instead of String name for storing answer to avoid warning:

public static Class<? extends Entity> getProjectile(String name) {
    Class<? extends Entity> ans;

        if (name.equalsIgnoreCase("ARROW"))
            ans = Arrow.class;
        else if (name.equalsIgnoreCase("ENDERPEARL"))
            ans = EnderPearl.class;
        else if (name.equalsIgnoreCase("EXPERIENCEORB"))
            ans = ExperienceOrb.class;
        else if (name.equalsIgnoreCase("FIREBALL"))
            ans = Fireball.class;
        else if (name.equalsIgnoreCase("FIREWORK"))
            ans = Firework.class;
        else if (name.equalsIgnoreCase("SMALLFIREBALL"))
            ans = SmallFireball.class;
        else if (name.equalsIgnoreCase("SNOWBALL"))
            ans = Snowball.class;
        else
            ans = Egg.class;

        return ans;
    }

Answer to your question: Class.forname isn't very 'safe' code, so you'll get compile messages. I'd say stick with what you have, as it works.

A few remarks: rather than that massive if block to determine the entity child's name, use the following code instead.

name = name.toLowerCase();
name = name.substring(0,1).toUpperCase() + name.substring(1);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM