简体   繁体   中英

checking type of reference in generics java

I am currently building a game in java(turn based RPG) and am facing a problem in inventory UI. Perhaps my problem is well known or has a simple solution, but having never had any training, I will still ask the question.

While displaying the inventory after selecting an item I check if that item implements the SpecificItemWorker interface , that is, acts on a specific GameObject that has to be passed in to its takeAction() method. While selecting that object which has to be passed, I display all the possible candidate objects for the user to select. For example, suppose the user selects a UpgradeParchment that acts on any object that implements Upgradable interface. Here, I initiate a ItemSelector that displays all the items in the inventory that implements Upgradable . However with a different class , the interface that the object needs to implement in order to be a possible candidate will differ.(Note that some objects act on the game environment rather than on a specific object, but we are not considering that case here.).Now instead of hard-coding the possible interfaces in a switch case statement , i want it to be dynamic.I tried to use generics, but it does not allow to check if an object is an instanceof of the Type parameter. The following code gives a compile error:

package ui;

import objects.Collectable;

public class ItemSelector<T> {
    public void test(Collectable ob) {
        if (ob instanceof T) {// compile error
            // do work
        }
    }
}

Does anyone know how this can be achieved?Thanks for any help.

Looking for a speedy reply, Thanks.

EDIT : The parameter in the testAction() method will be of type Collectable as in my inventory class, there is only a list of Collectable objects.Similarly, in my test method , I have updated the types.Although it is a minor change, sorry for any inconvenience. Collectable is also an interface.

Due to runtime type erasure, you need to provide what's called a type token to the class:

public class ItemSelector<T> {
    private final Class<T> clazz;
    public ItemSelector(Class<T> clazz) {
        this.clazz = clazz;
    }

    public void test(GameObject ob) {
        if (clazz.isInstance(ob)) {// use token to check type
            // do work
        }
    }
}

This requires a class object to be passed to the constructor, usually by passing a class literal, eg MyClass.class

There is a way to check the type with class.getTypeName().

I assume the SpecificItemWorker is a game object as shown in the code.

package stackoverflow.question39718130;

public class SpecificItemWorker extends GameObject {
}

package stackoverflow.question39718130;

public class ItemSelector<T> {

    private T t;

    public ItemSelector(final T t) {
        this.t = t;
    }

    public T getT() {
        return t;
    }

    public void test(final GameObject ob) {
        /*if (ob instanceof T) {// compile error
            // do work
        }*/

        if (t.getClass().getTypeName() == ob.getClass().getTypeName()) {
            System.out.println("Grab item.");
        } else {
            System.err.println("No item found.");
        }
    }
}

There is a test example to pass the GameObject .

package stackoverflow.question39718130;

public class GameObjectTest {

    public static void main(final String[] args) {
        specificItemWorkerTest();
    }

    public static void specificItemWorkerTest() {
        final GameObject specificItemWorker = new SpecificItemWorker();

        final ItemSelector<GameObject> selector = new ItemSelector<>(specificItemWorker);
        selector.test(specificItemWorker);
    }
}

I hope I understood you right with the SpecificItemWorker . Please let me know if this fits to your solution.

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