简体   繁体   中英

Using instanceof and casting with generics

I'm trying to create a function that takes in an instance of a parameterized class with one type parameter T, and then uses reflection to look at fields of its enveloping class, checks if those fields are of type T, and then casts and does something with them if they are. Here's what I have so far:

 private <T> void someFunction(SomeClass<T> instance) throws IllegalAccessException {
            for(Field field : this.getClass().getDeclaredFields()){
                Object obj = field.get(this);
                // TODO: get parameter T from instance and store it in a variable named 'myClass'
                if(myClass.isInstance(obj)){
                    doSomething(instance, myClass.cast(obj))
                }
            }
        }

From what I understand, in order to do this at runtime you need to declare a variable of type Class and store the class of T in there so you can then use the isInstance() and cast() functions, but I am unsure how to properly do this.

Short Story -- Missing Piece

private <T extends SomeClass> void someFunction(SomeClass<T> instance) throws IllegalAccessException {
    for (Field field : this.getClass().getDeclaredFields()) {
        Object obj = field.get(this);

        Class<?> objClass = obj.getClass();
        if (objClass.isInstance(instance))
            doSomething(instance, (T) obj);
    }
  • Where we get and store the Class from the Object, then check that against the instance we want to match with.
  • We use the wildcard ? to signify an unknown Type, which saves us from having to figure out, or specify types.
  • Then we assure the doSomething Method accepts the same generic type argument to allow for similar work
    • Therefore we only need to cast to T

As a Whole, With A Working Example of Animals

(Yes this is a reduction:))

Animal Class as a Base

public abstract class Animal {

    protected Object color;

    protected Animal(Object color) {
        this.color = color;
    }

    protected Animal() {}

}

Various Colors of Animal (To Simplify)

No Color Animal (A Ghost?!)
public class MultiColorAnimal extends Animal {

    // An Array of colors
    public MultiColorAnimal(String... colors) {
        super(colors);
    }

}
A Single Color Animal
public class SingleColorAnimal extends Animal { // A single String of color public SingleColorAnimal(String color) { super(color); } }
A Multi-colored Animal
Viewed a MultiColorAnimal; the tiger
Viewed a SingleColorAnimal; the dolphin

A Zoo With Viewable Animals as Your Enclosing Class

 public class ZooAnimals { public MultiColorAnimal tiger = new MultiColorAnimal("black", "orange"); public SingleColorAnimal dolphin = new SingleColorAnimal("grey"); public <T extends Animal> void viewAnimalIfPresent(Animal<T> animal) throws IllegalAccessException { for (Field field: this.getClass().getDeclaredFields()) { Object obj = field.get(this); Class<?> objClass = obj.getClass(); if (objClass.isInstance(animal)) view(animal, (T) obj, field.getName()); } } private <T extends Animal> void view(Animal<T> animal, T obj, String name) { // TODO - Do something useful with these, but simply log them for now:) System.out.printf("Viewed a %s; the %s%n", obj.getClass().getSimpleName(), name); } }

A Simple Test

ZooAnimals zoo = new ZooAnimals(); @Test public void test() throws IllegalAccessException { zoo.viewAnimalIfPresent(zoo.tiger); zoo.viewAnimalIfPresent(zoo.dolphin); zoo.viewAnimalIfPresent(new NoColorAnimal()); }

Result of Test

The Console Ouput for Test Showing Proper Type Shifting
Viewed a MultiColorAnimal; the tiger Viewed a SingleColorAnimal; the dolphin

Where no field matched a colorless Animal, and therefore nothing was printed.

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