如何验证(generic(generic argument))? [英] How to verify the (generic (generic argument))?

查看:310
本文介绍了如何验证(generic(generic argument))?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景(我们真的不需要担心)



这是一个问题,来源于使用继承构建通用树。我打开这个作为一个单独的问题,因为这不仅与一个树问题有关。这是一个泛型和类问题。



问题



为了更好地用代码说明, a Tree 类, SubTree 类和 WrongSubTree class:

  class Tree< TREE extends Tree<?,?& {
}
class SubTree< STREE扩展SubTree<?,?>,DATA& extends Tree }
class WrongSubTree< WSTREE extends Tree<?,?>,DATA& extends Tree< WSTREE,DATA> {
}

在对象创建时,我们想检查泛型参数是否等于对象本身的类:

  Tree< Tree< tree01 = new Tree< Tree<?,?>,String>(); // equals:OK 
Tree< SubTree<?,?>,String> tree02 = new Tree< SubTree<?,?>,String>(); //(!)不等于
SubTree< SubTree<?,?>,String> tree03 = new SubTree< SubTree<?,?>,String>(); // equals:OK
WrongSubTree< Tree<?,?>,String> tree04 = new WrongSubTree< Tree<?,?>,String>(); //(!)不等于

(注意上面的4行没有编译错误



我的试用版



为了做到这一点,我们尝试在构造函数中添加 Class<> 参数:

 类树< TREE扩展树<?,?>,DATA> {
public Tree(Class< TREE> clazz){
System.out.println(this.getClass());
System.out.println(clazz);
System.out.println();
if(this.getClass()!= clazz)
throw new RuntimeException();
}
}
class SubTree< STREE扩展SubTree<?,?>,DATA& extends Tree public SubTree(Class< STREE> clazz){
super(clazz);
}
}
class WrongSubTree< WSTREE extends Tree<?,?>,DATA& extends Tree< WSTREE,DATA> {
public WrongSubTree(Class< WSTREE> clazz){
super(clazz);
}
}



问题



但我不知道如何调用该构造函数:

 树< Tree<?,?>,String& tree01a = new Tree< Tree<?,?>,String>(Tree.class); 
//构造器树< Tree<?,?>,String>(Class< Tree>)未定义

Tree< Tree& tree01b = new Tree< Tree<?,?>,String>(Tree<?,?> .class);
//语法错误,插入Dimensions以完成ArrayType

编译错误。



我想这是因为构造函数 public Tree(Class< TREE> clazz){} 期望类< Tree<?,?>> ,但不是 Class< Tree> 。但是,我们不能做 Tree <?,?> .class



原因是我试图更改类:

  class Tree< TREE extends Tree<?,?& {
public Tree(Class< Tree> clazz){// changed
System.out.println(this.getClass());
System.out.println(clazz);
System.out.println();
if(this.getClass()!= clazz)
throw new RuntimeException();
}
}
Tree< Tree<?,?>,String> tree01a = new Tree< Tree<?,?>,String>(Tree.class);

没有编译错误。



但是,以下引起相同的编译错误:

  class Tree< TREE extends Tree<?,?& ; {
public Tree(Class< Tree<?,?>> clazz){// changed
System.out.println(this.getClass());
System.out.println(clazz);
System.out.println();
if(this.getClass()!= clazz)
throw new RuntimeException();
}
}
Tree< Tree<?,?>,String> tree01a = new Tree< Tree<?,?>,String>(Tree.class);
//构造器树< Tree<?,?>,String>(Class< Tree>)未定义






编辑#1



基于我的评论,我试过这个。希望它有助于一些灵感。

  static class SimpleClass< T& {
private SimpleClass(Object dummy){
// dummy constructor,avoid recursive call of the default constructor
}
SimpleClass(){
SimpleClass< T& own = new SimpleClass< T>(new Object()){};
System.out.println(((ParameterizedType)myself.getClass()。getGenericSuperclass())。getActualTypeArguments()[0]);
//打印T

TypeReference< SimpleClass< T> typeRef = new TypeReference< SimpleClass< T>>(){};
System.out.println(typeRef.getType());
// printsMain.Main $ SimpleClass< T>
}
void func(){
SimpleClass< T> own = new SimpleClass< T>(new Object()){};
System.out.println(((ParameterizedType)myself.getClass()。getGenericSuperclass())。getActualTypeArguments()[0]);
//打印T

TypeReference< SimpleClass< T> typeRef = new TypeReference< SimpleClass< T>>(){};
System.out.println(typeRef.getType());
// printsMain.Main $ SimpleClass< T>
}
}

public static void main(String [] args){
SimpleClass< String> simpleObj = new SimpleClass< String>();
simpleObj.func();

SimpleClass< String> outsideSimpleClass = new SimpleClass< String>(){};
System.out.println((ParameterizedType)outsideSimpleClass.getClass()。getGenericSuperclass())。getActualTypeArguments()[0]);
//打印class java.lang.String
}



我们仍然不能获取class java.lang.String里面 SimpleClass


更重要的是,如果我们使用类型参数< T> 另一个类实例化一个对象,无法从中获取类型参数:

  static class AnotherClass< T> {
private AnotherClass(Object dummy){}
}
static class SimpleClass< T> {
SimpleClass(){
AnotherClass< T> another = new AnotherClass< T>(new Object()){};
System.out.println(((ParameterizedType)another.getClass()。getGenericSuperclass())。getActualTypeArguments()[0]);
//打印T

TypeReference< AnotherClass< T> anotherTypeRef = new TypeReference< AnotherClass< T>>(){};
System.out.println(anotherTypeRef.getType());
// printsMain.Main $ AnotherClass< T>
}
void func(){
AnotherClass< T> another = new AnotherClass< T>(new Object()){};
System.out.println(((ParameterizedType)another.getClass()。getGenericSuperclass())。getActualTypeArguments()[0]);
//打印T

TypeReference< AnotherClass< T> anotherTypeRef = new TypeReference< AnotherClass< T>>(){};
System.out.println(anotherTypeRef.getType());
// printsMain.Main $ AnotherClass< T>
}
}

注意,这意味着<$ c的类型参数$ c> AnotherClass 不能在 SimpleClass 中显示,它是类本身之外的一个地方! >

根据我的理解,我们只能使用匿名子类& getGenericSuperclass()在一个实际上已经知道答案的地方。如 main(),这里是 class java.lang.String 真的定义为Type参数。



(IMO,如果这个技巧的能力受到限制,它根本不是非常有用。)

解决方案

请查看 TypeTools 。示例:

 列表< String> stringList = new ArrayList< String>(){}; 
Class<?> stringType = TypeResolver.resolveRawArgument(List.class,stringList.getClass());
assert stringType == String.class;


Background (that we don't really need to worry about)

This is a question derived from Build A Generic Tree With Inheritance . I open this one as a separate question because this is not only related to a Tree problem. This is more a Generic and Class problem instead.

Question

To be better illustrated by codes, we have a Tree class, a SubTree class, and a WrongSubTree class:

class Tree<TREE extends Tree<?,?>, DATA> {
}
class SubTree<STREE extends SubTree<?,?>, DATA> extends Tree<STREE, DATA> {
}
class WrongSubTree<WSTREE extends Tree<?,?>, DATA> extends Tree<WSTREE, DATA> {
}

While object creation, we would like to check if the generic argument equals to the class of the object itself:

Tree<Tree<?,?>, String> tree01 = new Tree<Tree<?,?>, String>();                 // equals : OK
Tree<SubTree<?,?>, String> tree02 = new Tree<SubTree<?,?>, String>();           // (!) not equals
SubTree<SubTree<?,?>, String> tree03 = new SubTree<SubTree<?,?>, String>();     // equals : OK
WrongSubTree<Tree<?,?>, String> tree04 = new WrongSubTree<Tree<?,?>, String>(); // (!) not equals

(Note that the 4 lines above have no compile errors and no runtime exceptions, for now.)

My trial

To do so, we try to add a Class<> parameter in the constructors:

class Tree<TREE extends Tree<?,?>, DATA> {
    public Tree(Class<TREE> clazz) {
        System.out.println(this.getClass());
        System.out.println(clazz);
        System.out.println();
        if (this.getClass() != clazz)
            throw new RuntimeException();
    }
}
class SubTree<STREE extends SubTree<?,?>, DATA> extends Tree<STREE, DATA> {
    public SubTree(Class<STREE> clazz) {
        super(clazz);
    }
}
class WrongSubTree<WSTREE extends Tree<?,?>, DATA> extends Tree<WSTREE, DATA> {
    public WrongSubTree(Class<WSTREE> clazz) {
        super(clazz);
    }
}

(The above class definitions are valid java codes.)

Problem

But i don't know how to call that constructor:

Tree<Tree<?,?>, String> tree01a = new Tree<Tree<?,?>, String>(Tree.class);
// The constructor Tree<Tree<?,?>,String>(Class<Tree>) is undefined

Tree<Tree<?,?>, String> tree01b = new Tree<Tree<?,?>, String>(Tree<?,?>.class);
// Syntax error, insert "Dimensions" to complete ArrayType

Both 2 lines above cause compile-errors.

i guess it is because the constructor public Tree(Class<TREE> clazz) {} is expecting Class<Tree<?,?>>, but not Class<Tree>. However, we cannot do Tree<?,?>.class.

The reason is i tried to change the class to:

class Tree<TREE extends Tree<?,?>, DATA> {
    public Tree(Class<Tree> clazz) {            // changed
        System.out.println(this.getClass());
        System.out.println(clazz);
        System.out.println();
        if (this.getClass() != clazz)
            throw new RuntimeException();
    }
}
Tree<Tree<?,?>, String> tree01a = new Tree<Tree<?,?>, String>(Tree.class);

There is no compile-error.

However, the following causes the same compile-error:

class Tree<TREE extends Tree<?,?>, DATA> {
    public Tree(Class<Tree<?,?>> clazz) {       // changed
        System.out.println(this.getClass());
        System.out.println(clazz);
        System.out.println();
        if (this.getClass() != clazz)
            throw new RuntimeException();
    }
}
Tree<Tree<?,?>, String> tree01a = new Tree<Tree<?,?>, String>(Tree.class);
// The constructor Tree<Tree<?,?>,String>(Class<Tree>) is undefined


Edit #1

Based on my comment below, i tried this one. Hope it helps for some inspirations.

static class SimpleClass<T> {
    private SimpleClass(Object dummy) {
        // dummy constructor, avoid recursive call of the default constructor
    }
    SimpleClass() {
        SimpleClass<T> myself = new SimpleClass<T>(new Object()) {};
        System.out.println(((ParameterizedType) myself.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
        // prints "T"

        TypeReference<SimpleClass<T>> typeRef = new TypeReference<SimpleClass<T>>() {};
        System.out.println(typeRef.getType());
        // prints "Main.Main$SimpleClass<T>"
    }
    void func() {
        SimpleClass<T> myself = new SimpleClass<T>(new Object()) {};
        System.out.println(((ParameterizedType) myself.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
        // prints "T"

        TypeReference<SimpleClass<T>> typeRef = new TypeReference<SimpleClass<T>>() {};
        System.out.println(typeRef.getType());
        // prints "Main.Main$SimpleClass<T>"
    }
}

public static void main(String[] args) {
    SimpleClass<String> simpleObj = new SimpleClass<String>();
    simpleObj.func();

    SimpleClass<String> outsideSimpleClass = new SimpleClass<String>(){};
    System.out.println(((ParameterizedType) outsideSimpleClass.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
    // prints "class java.lang.String"
}

Note we still cannot get "class java.lang.String" inside SimpleClass.

More importantly, if we use the Type Argument <T> to instantiate an object from another class, we still cannot get the type parameter from it:

static class AnotherClass<T> {
    private AnotherClass(Object dummy) {}
}
static class SimpleClass<T> {
    SimpleClass() {
        AnotherClass<T> another = new AnotherClass<T>(new Object()) {};
        System.out.println(((ParameterizedType) another.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
        // prints "T"

        TypeReference<AnotherClass<T>> anotherTypeRef = new TypeReference<AnotherClass<T>>() {};
        System.out.println(anotherTypeRef.getType());
        // prints "Main.Main$AnotherClass<T>"
    }
    void func() {
        AnotherClass<T> another = new AnotherClass<T>(new Object()) {};
        System.out.println(((ParameterizedType) another.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
        // prints "T"

        TypeReference<AnotherClass<T>> anotherTypeRef = new TypeReference<AnotherClass<T>>() {};
        System.out.println(anotherTypeRef.getType());
        // prints "Main.Main$AnotherClass<T>"
    }
}

Note that this means the Type Argument of AnotherClass cannot be revealed in SimpleClass, where it is a place outside the class itself!

To my understanding, we can only use the anonymous sub-class & getGenericSuperclass() trick at a place where it actually already know the answer. Such as in main(), here is the place where class java.lang.String is really defined as the Type Argument.

(IMO, if the ability of this trick is so restricted, it is not really useful at all.)

解决方案

Check out TypeTools for this. Example:

List<String> stringList = new ArrayList<String>() {};
Class<?> stringType = TypeResolver.resolveRawArgument(List.class, stringList.getClass());
assert stringType == String.class;

这篇关于如何验证(generic(generic argument))?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆