2 ctf martin ctf_Martin 于 2017.09.11 13:22 提问

Java类的泛型参数能作为另外一个泛型类的参数传入吗?

最近遇到一个棘手的泛型问题,精简化后,代码如下:

 import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;


public class testMain {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        People people = new People();

        people.doIt("I'm a student!");
    }
}

interface Say {
    void say(String word);
}

class Student implements Say {
    public void print(String say) {
        System.out.println(say);
    }

    @Override
    public void say(String word) {
        print(word);
    }
}

interface ExecutorCallbackHandler<M, P> {
    void execute(M mapper, P param);
}


class DoSomeThing {

    public <M, P> void batchDo(ExecutorCallbackHandler<M, P> executorCallbackHandler, P param) throws IllegalAccessException, InstantiationException {
        Type[] genTypes = executorCallbackHandler.getClass().getGenericInterfaces();
        Type[] params = ((ParameterizedType) genTypes[0]).getActualTypeArguments();
        Class<M> mapperClass = (Class<M>) params[0];
        M mapper = mapperClass.newInstance();
        executorCallbackHandler.execute(mapper, param);
    }
}

class AbstractPeople<M extends Say> {

    private DoSomeThing doSomeThing = new DoSomeThing();

    public void doIt(String param) throws InstantiationException, IllegalAccessException {
        doSomeThing.batchDo(new ExecutorCallbackHandler<M, String>() {
            @Override
            public void execute(M people, String param) {
                people.say(param);
            }
        }, param);
    }
}

class People extends AbstractPeople<Student> {
}

泛型参数Student,经过AbstractPeople.doIt传入DoSomeThing.batchDo,但是解析时,泛型参数M并未解析成Student,导致出现异常。

请问,是什么原因,如何解决

4个回答

ctf_Martin
ctf_Martin   2017.09.11 13:25

调试时,参数M并未按预期转换成Student类型
图片说明

vane11
vane11   2017.09.11 13:47

DoSomeThing在new的时候 没指定泛型

danee1
danee1   2017.09.11 14:12

ExecutorCallbackHandler 这个地方编译器 是不会判断正在执行的类型的,如果想把M当作参数传递,要老老实实的写在形参列表里面。
比如 new ExecutorCallbackHandler 的时候 传进去 一个 Clazz 这样。

ctf_Martin
ctf_Martin ExecutorCallbackHandler是框架的一个接口,没发提供额外的参数
2 个月之前 回复
ctf_Martin
ctf_Martin 能说具体一点吗?
2 个月之前 回复
miaoch
miaoch   2017.09.11 18:48
public class testMain {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        People people = new People();

        people.doIt("I'm a student!");
    }
}

interface Say {
    void say(String word);
}

class Student implements Say {
    public void print(String say) {
        System.out.println(say);
    }

    @Override
    public void say(String word) {
        print(word);
    }
}

interface ExecutorCallbackHandler<M, P> {
    void execute(M mapper, P param);
}


class DoSomeThing {

    /*public <M, P> void batchDo(ExecutorCallbackHandler<M, P> executorCallbackHandler, P param) throws IllegalAccessException, InstantiationException {
        Type[] genTypes = executorCallbackHandler.getClass().getGenericInterfaces();
        Type[] params = ((ParameterizedType) genTypes[0]).getActualTypeArguments();
        Class<M> mapperClass = (Class<M>) params[0];
        M mapper = mapperClass.newInstance();
        executorCallbackHandler.execute(mapper, param);
    }*/
    public <M, P> void batchDo(ExecutorCallbackHandler<M, P> executorCallbackHandler, P param, Class<M> clazz) throws IllegalAccessException, InstantiationException {
        M mapper = (M) clazz.newInstance();
        executorCallbackHandler.execute(mapper, param);
    }
}

class AbstractPeople<M extends Say> {

    private DoSomeThing doSomeThing = new DoSomeThing();
    private Class<M> clazz;
    public AbstractPeople(Class<M> clazz) {
        this.clazz = clazz;
    }

    public void doIt(String param) throws InstantiationException, IllegalAccessException {
        doSomeThing.batchDo(new ExecutorCallbackHandler<M, String>() {
            @Override
            public void execute(M people, String param) {
                people.say(param);
            }
        }, param, clazz);
    }
}

class People extends AbstractPeople<Student> {

    public People() {
        super(Student.class);
    }
}

ctf_Martin
ctf_Martin 多谢!我明白了
2 个月之前 回复
Csdn user default icon
上传中...
上传图片
插入图片