如果你已经知道大部分答案,请原谅我:很难在你的水平上做出假设。
问题的原因是类型擦除,如您所知。为了摆脱类型擦除,Guice使用了一个具体祖先的技巧,如下所示:
class Trick<T> {
    T t;
}
public class GenericTest {
    public static void main(String[] args) {
        Trick<Set<String>> trick = new Trick<Set<String>>() {
        };
        // Prints "class org.acm.afilippov.GenericTest$1"
        System.out.println(trick.getClass());
        // Prints "org.acm.afilippov.Trick<java.util.Set<java.lang.String>>"
        System.out.println(trick.getClass().getGenericSuperclass());
    }
}
关键是,当您创建一个扩展泛型超类并显式指定类型参数的类时,您通常需要编写接受该非常特定类型的metods,并且这些方法的签名无法擦除。在这种情况下,我们在FAQ中讨论没有问题,但编译器无论如何都会保存类型信息:您的类的用户需要知道确切的类型才能使用这些方法。
现在,您的版本没有从 继承的具体类,它只有 - 这就是它全部失败的地方。TypeLiteral<Set<YourSpecificType>>TypeLiteral<Set<T>>
改变我的小例子,那就是:
public class GenericTest {
    public static void main(String[] args) {
        tryMe(String.class);
    }
    private static <T> void tryMe(Class<T> clazz) {
        Trick<Set<T>> trick = new Trick<Set<T>>() {
        };
        // Prints "class org.acm.afilippov.GenericTest$1"
        System.out.println(trick.getClass());
        // Prints "org.acm.afilippov.Trick<java.util.Set<T>>"
        System.out.println(trick.getClass().getGenericSuperclass());
    }
}
正如你所看到的,我们不再是具体的:它仍然有一个类型参数,它的具体值,在这里,在编译过程中丢失了。GenericTest$1String
您当然可以避免这种情况,但为了做到这一点,您需要创建一个具有用于继承的特定类型参数的类 , 以便Guice能够计算出细节。等一下,我会试着举个例子。
更新:事实证明这是一个很长的位。因此,这里有一个更新的版本:
public class GenericTest {
    public static void main(String[] args) throws Exception {
        tryMe(String.class);
    }
    private static <T> void tryMe(Class<T> clazz) throws IllegalAccessException, InstantiationException {
        Class c = loadClass("org.acm.afilippov.ASMTrick", generateClass(clazz));
        Trick<Set<T>> trick = (Trick<Set<T>>) c.newInstance();
        // Prints "class org.acm.afilippov.ASMTrick"
        System.out.println(trick.getClass());
        // Prints "org.acm.afilippov.Trick<java.util.Set<java.lang.String>>"
        System.out.println(trick.getClass().getGenericSuperclass());
    }
    private static byte[] generateClass(Class<?> element) {
        ClassWriter cw = new ClassWriter(0);
        MethodVisitor mv;
        cw.visit(V1_6, ACC_FINAL + ACC_SUPER, "org/acm/afilippov/ASMTrick",
                "Lorg/acm/afilippov/Trick<Ljava/util/Set<L" + element.getName().replaceAll("\\.", "/") + ";>;>;",
                "org/acm/afilippov/Trick", null);
        {
            mv = cw.visitMethod(0, "<init>", "()V", null, null);
            mv.visitCode();
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "org/acm/afilippov/Trick", "<init>", "()V");
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        cw.visitEnd();
        return cw.toByteArray();
    }
    private static Class loadClass(String className, byte[] b) {
        //override classDefine (as it is protected) and define the class.
        Class clazz = null;
        try {
            ClassLoader loader = ClassLoader.getSystemClassLoader();
            Class cls = Class.forName("java.lang.ClassLoader");
            java.lang.reflect.Method method =
                    cls.getDeclaredMethod("defineClass", new Class[]{String.class, byte[].class, int.class, int.class});
            // protected method invocaton
            method.setAccessible(true);
            try {
                Object[] args = new Object[]{className, b, new Integer(0), new Integer(b.length)};
                clazz = (Class) method.invoke(loader, args);
            } finally {
                method.setAccessible(false);
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
        return clazz;
    }
}
如您所见,类型信息现在已保留。我相信没有使用这种方法,因为即使对于这个草案来说,它也太痛苦了。