Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/393.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 通用类型x通用参数:建筑a";“非常通用”;结构 目标_Java_Generics_Methods_Arraylist_Generic Programming - Fatal编程技术网

Java 通用类型x通用参数:建筑a";“非常通用”;结构 目标

Java 通用类型x通用参数:建筑a";“非常通用”;结构 目标,java,generics,methods,arraylist,generic-programming,Java,Generics,Methods,Arraylist,Generic Programming,例如,我们有一个树类,类型为T:即树 我们想让这个树类能够容纳 树(当然) 子树其中子树扩展了树 树其中SubT扩展了T,以及 子树其中子树扩展树和子树扩展T “Hold”表示接受某个子类,并根据请求分别返回某个子类的对象 例如,原始的ArrayList具有以下属性: private static class Leaf { } private static class RedLeaf extends Leaf { } @Test public final void test() { Ar

例如,我们有一个
类,类型为
T
:即

我们想让这个
类能够容纳

  • (当然)
  • 子树
    其中
    子树扩展了树
  • 其中
    SubT扩展了T
    ,以及
  • 子树
    其中
    子树扩展树
    子树扩展T
  • “Hold”表示接受某个子类,并根据请求分别返回某个子类的对象

    例如,原始的
    ArrayList
    具有以下属性:

    private static class Leaf {
    }
    private static class RedLeaf extends Leaf {
    }
    @Test
    public final void test() {
        ArrayList<Leaf> al = new ArrayList<Leaf>();
        al.add(new Leaf());
        System.out.println(al.get(al.size()-1).getClass());     // class Leaf
        al.add(new RedLeaf());
        System.out.println(al.get(al.size()-1).getClass());     // class RedLeaf
    }
    
    为什么这是一场灾难?考虑树中的某个节点,我们希望找到下一个兄弟。 事实上,我们可以在插入元素时进行快速修复:

    private static class Leaf {
        Leaf() { super(); }
        Leaf(Leaf leaf) { super(); }
    }
    private static class RedLeaf extends Leaf {
        RedLeaf() { super(); }
        RedLeaf(RedLeaf redLeaf) { super(redLeaf); }
    }
    @Test
    public final void test() {
        ArrayList<Leaf> al = new ArrayList<Leaf>();
        Leaf leaf = new Leaf();
        RedLeaf redLeaf = new RedLeaf();
        al.add(new Leaf(leaf));
        al.add(new RedLeaf(redLeaf));
        al.add(new Leaf(leaf));
        System.out.println(al.indexOf(al.get( 0 )));    // 0
        System.out.println(al.indexOf(al.get( 1 )));    // 1
        System.out.println(al.indexOf(al.get( 2 )));    // 2 <-- nice :-)
    }
    
    我们有这个
    addChild
    方法,没有问题:

    public void addChild(final Tree<T> subTree) {
        getChildren().add(new Tree<T>(this, subTree));  // copy the tree & set parent attach to this
    }
    
    在概念上,我们希望将
    addChild
    方法修改为:

    (但是下面的代码有编译错误,如注释所示。)

    返回基类,
    。下面是
    addChild
    存储对象的方式

    public Tree<T> addChildren(final Tree<? extends T>... subTrees) {
        if (subTrees == null)               // called addChildren((Tree<T>) null)
            addChild((Tree<T>) null);           // add null to children
        else
            for (final Tree<? extends T> subTree : subTrees)      // empty parameter goes here != null array
                addChild(subTree);
        return this;
    }
    public Tree<T> addChild(final Tree<? extends T> subTree) {
        if (subTree == null)            // for addChild((Tree<T>) null)
            getChildren().add(null);        // add null to children
        else {                          // else
            getChildren().add(              // copy (constructor) the tree & set parent attach to this
                    Reflection.<Tree<T>>invokeConstructor(subTree, new ParameterTypeAndArg(subTree.getClass(), subTree))
                    .setParent(this));
        }
        return this;
    }
    

    public Tree addChildren(final Tree首先,您将此操作复杂化了。您真正需要做的是:

    public void add(final Tree<? extends T> subTree) {
    
    如果
    Leaf
    A
    并且
    子树是
    ,则
    添加(最终子树)
    不匹配

    因此,从概念上讲,您实际上希望:

    public <Leaf extends T, SubTree extends Tree<Leaf>> void add(final SubTree<Leaf> subTree) {
    
    然而,现在你有一个更大的问题,这是一个经典的问题,在这里的许多其他地方都有答案:

    tr = new SubTree();
    

    由于类型擦除,您无法实例化泛型类型的对象。您必须在某个位置指定子树的
    ,然后使用
    .newInstance()

    对其进行实例化。您可以向我们显示更多代码吗?构造函数等是什么?
    public void add(最终树)“编译器错误”节看起来像Scala中的Scala=D,我们可以编写使用泛型类型参数的函数。谢谢!回答得非常好,有很好的解释!我有几个问题。如果我使用
    你不能单独从泛型类型实例化对象。句号。你必须有对象的
    类可用。然后你可以使用
    Class、 newInstance()
    使用默认构造函数实例化该类型的对象,也可以使用
    Class.getConstructor(…)
    获取特定的非默认构造函数。是否要复制值或存储引用或其他内容完全取决于您的应用程序要求。如果需要复制,则必须复制。如果不需要复制,则不必复制。执行需要执行的操作。:)此外,您永远不需要将
    子树
    显式强制转换为
    。您可以始终将
    子树
    存储在一个变量中,该变量可以容纳
    ,而无需任何显式强制转换,因为
    子树
    扩展了
    。您需要显式强制转换相反的内容(除非你知道
    是一个
    子树
    ),否则该转换可能会失败。无论如何,
    Class.newInstance()
    的返回类型是
    T
    。请看。非常感谢!!根据你的回答和解释,我学到了很多,并构建了一个非常通用的树,它可以接受和保持(而不是重新创建超级类)子树、树、子树的节点。我使用默认构造函数来确保所有子类定义一个副本构造函数。这样,在插入时,我可以安全地使用反射来调用子类的副本构造函数。代码发布在上面。请随意更正我。我希望它也能帮助其他人:-)
    /** Default constructor. **/
    public Tree() {     // All sub-classes instantiation must invoke this default constructor
        super();                // here is a good place to ensure every sub-class has a copy constructor
        if (Reflection.hasCopyConstructor(this) == false)
            throw new CopyConstructorRequiredException(this.getClass());
    }
    class Reflection {
        public static boolean hasCopyConstructor(final Object object) {
            return hasCopyConstructor(object.getClass());
        }
        public static boolean hasCopyConstructor(final Class<?> clazz) {
            try {
                clazz.getDeclaredConstructor(clazz);
                return true;
            } catch (SecurityException e) {
                e.printStackTrace();
                return false;
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
                return false;
            }
        }
    }
    
    private Tree(final Tree<? extends T> copyFrom) {
        super();
        if (copyFrom != null) {
            this.setData(copyFrom.getData());
            for (final Tree<? extends T> child : copyFrom.getChildren()) {
                this.addChildren(child);    // addChildren() handles null well
            }
        }
    }
    
    private static class BlueTree<T> extends Tree<T> {
        private BlueTree(final BlueTree<T> blueTree) { super(blueTree); }
    }
    
    public Tree<T> addChildren(final Tree<? extends T>... subTrees) {
        if (subTrees == null)               // called addChildren((Tree<T>) null)
            addChild((Tree<T>) null);           // add null to children
        else
            for (final Tree<? extends T> subTree : subTrees)      // empty parameter goes here != null array
                addChild(subTree);
        return this;
    }
    public Tree<T> addChild(final Tree<? extends T> subTree) {
        if (subTree == null)            // for addChild((Tree<T>) null)
            getChildren().add(null);        // add null to children
        else {                          // else
            getChildren().add(              // copy (constructor) the tree & set parent attach to this
                    Reflection.<Tree<T>>invokeConstructor(subTree, new ParameterTypeAndArg(subTree.getClass(), subTree))
                    .setParent(this));
        }
        return this;
    }
    
    public void add(final Tree<? extends T> subTree) {
    
    public class Base { }
    public class A extends Base { }
    public class B extends Base { }
    
    public <Leaf extends T, SubTree extends Tree<Leaf>> void add(final SubTree<Leaf> subTree) {
    
    public <Leaf extends T, SubTree extends Tree<Leaf>> void add(final SubTree subTree) {
    
    {
        Tree<Object> x = new Tree<Object>();
        MyTree<Integer> y = new MyTree<Integer>();
        Tree<Integer> z = new Tree<Integer>();
    
        x.add(y);
        y.add(x); // not valid, as Tree<Object> does not extend Tree<Integer>  
        y.add(z); // fine, as Tree<Integer> matches
    }
    
    public static class MyTree<T> extends Tree<T> {     
    }
    
    SubTree tr = ...;
    
    tr = new SubTree();