Построить общее дерево с наследованием

Я создаю общий класс Tree<T>, который поддерживает наследование поддеревьев. Но я столкнулся с некоторыми проблемами. Не могли бы вы помочь мне?

Описание

Давайте определим класс Tree и класс BlueTree, где BlueTree extends Tree.

Давайте определим класс Leaf и класс RedLeaf, где RedLeaf extends Leaf. Они используются как «данные», содержащиеся в Деревьях.

Tree<Leaf> означает дерево типа Tree, а его "данные" имеют тип Leaf.

Для наследования (это не правильное наследование Java):

  • a Tree<Leaf> can have child of type
    • Tree<Leaf>, Tree<RedLeaf>, BlueTree<Leaf>, and BlueTree<RedLeaf>.

.

  • a Tree<RedLeaf> can have child of type
    • Tree<RedLeaf>, and BlueTree<RedLeaf>,
    • но не Tree<Leaf> или BlueTree<Leaf>.

.

  • a BlueTree<Leaf> can have child of type
    • BlueTree<Leaf>, and BlueTree<RedLeaf>,
    • но не Tree<Leaf> или Tree<RedLeaf>.

.

  • a BlueTree<RedLeaf> can have child of type
    • BlueTree<RedLeaf>,
    • но не Tree<Leaf>, Tree<RedLeaf> или BlueTree<Leaf>.

*Здесь «ребенок» означает ветви/листья Дерева.

(немного сложно, поэтому я разделяю строки.)

Код

(Если у вас есть решение, возможно, вам не нужно читать подробную иллюстрацию моих попыток ниже. Если вы хотите найти решение вместе, мой код может подсказать вам некоторые идеи или запутать их.)

Первая пробная версия: (простая)

// This is the focus of this question, the class signature
public class Tree<T> {
    // some fields, but they are not important in this question
    private Tree<? super T> mParent;
    private T mData;
    private ArrayList<Tree<? extends T>> mChildren;

    // This is the focus of this question, the addChild() method signature
    public void addChild(final Tree<? extends T> subTree) {
        // add the subTree to mChildren
    }
}

Эта структура класса отвечает большинству требований в описании. Кроме того, это позволяет

class BlueTree<T> extends Tree<T> { }
class Leaf { }
class RedLeaf extends Leaf { }

Tree<Leaf> tree_leaf = new Tree<Leaf>();
BlueTree<Leaf> blueTree_leaf = new BlueTree<Leaf>();

blueTree_leaf.addChild(tree_leaf);    // should be forbidden

что нарушает

  • BlueTree<Leaf> не может иметь дочерний элемент типа Tree<Leaf>.

Проблема в том, что в BlueTree<Leaf> его сигнатура метода addChild() по-прежнему

public void addChild(final Tree<? extends Leaf> subTree) {
     // add the subTree to mChildren
}

В идеальном случае сигнатура метода BlueTree<Leaf>.addChild() изменяется (автоматически, при наследовании) на

public void addChild(final BlueTree<? extends Leaf> subTree) {
     // add the subTree to mChildren
}

(Обратите внимание, что этот метод не может переопределить указанный выше метод путем наследования, так как типы параметров различаются.)

Есть обходной путь. Мы можем добавить проверку наследования класса и для этого случая бросить RuntimeException:

public void addChild(final Tree<? extends Leaf> subTree) {
    if (this.getClass().isAssignableFrom(subTree.getClass()))
        throw new RuntimeException("The parameter is of invalid class.");
    // add the subTree to mChildren
}

Но делать это ошибкой времени компиляции гораздо лучше, чем ошибкой времени выполнения. Я хотел бы применить это поведение во время компиляции.

Вторая пробная версия

Проблема в первой пробной структуре заключается в том, что тип параметра Tree в методе addChild() не является параметром универсального типа. Таким образом, он не будет обновляться при наследовании. На этот раз давайте также попробуем сделать его параметром универсального типа.

Во-первых, определите общий класс Tree.

public class Tree<T> {
    private Tree<? super T> mParent;
    private T mData;
    private ArrayList<Tree<? extends T>> mChildren;

    /*package*/ void addChild(final Tree<? extends T> subTree) {
        // add the subTree to mChildren
    }
}

Затем TreeManager, который управляет объектом Tree.

public final class TreeManager<NodeType extends Tree<? super DataType>, DataType> {
    private NodeType mTree;

    public TreeManager(Class<NodeType> ClassNodeType) {
        try {
            mTree = ClassNodeType.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void managerAddChild(final NodeType subTree) {
        mTree.addChild(subTree);
        // compile error: The method addChild(Tree<? extends capture#1-of ? super DataType>)
        //                in the type Tree<capture#1-of ? super DataType>
        //                is not applicable for the arguments (NodeType)
    }

    // for testing
    public static void main(String[] args) {
        @SuppressWarnings("unchecked")
        TreeManager<Tree    <Leaf>   , Leaf>    tm_TreeLeaf_Leaf           = new TreeManager<Tree    <Leaf>,    Leaf>   ((Class<Tree    <Leaf>>)    new Tree    <Leaf>   ().getClass());
        TreeManager<Tree    <RedLeaf>, RedLeaf> tm_TreeRedLeaf_RedLeaf     = new TreeManager<Tree    <RedLeaf>, RedLeaf>((Class<Tree    <RedLeaf>>) new Tree    <RedLeaf>().getClass());
        TreeManager<BlueTree<Leaf>   , Leaf>    tm_BlueTreeLeaf_Leaf       = new TreeManager<BlueTree<Leaf>,    Leaf>   ((Class<BlueTree<Leaf>>)    new BlueTree<Leaf>   ().getClass());
        TreeManager<BlueTree<RedLeaf>, RedLeaf> tm_BlueTreeRedLeaf_RedLeaf = new TreeManager<BlueTree<RedLeaf>, RedLeaf>((Class<BlueTree<RedLeaf>>) new BlueTree<RedLeaf>().getClass());

        System.out.println(tm_TreeLeaf_Leaf          .mTree.getClass());    // class Tree
        System.out.println(tm_TreeRedLeaf_RedLeaf    .mTree.getClass());    // class Tree
        System.out.println(tm_BlueTreeLeaf_Leaf      .mTree.getClass());    // class BlueTree
        System.out.println(tm_BlueTreeRedLeaf_RedLeaf.mTree.getClass());    // class BlueTree

        @SuppressWarnings("unchecked")
        TreeManager<Tree    <Leaf>   , RedLeaf> tm_TreeLeaf_RedLeaf     = new TreeManager<Tree    <Leaf>,    RedLeaf>((Class<Tree    <Leaf>>)    new Tree    <Leaf>   ().getClass());
        TreeManager<BlueTree<Leaf>   , RedLeaf> tm_BlueTreeLeaf_RedLeaf = new TreeManager<BlueTree<Leaf>,    RedLeaf>((Class<BlueTree<Leaf>>)    new BlueTree<Leaf>   ().getClass());

        System.out.println(tm_TreeLeaf_RedLeaf       .mTree.getClass());    // class Tree
        System.out.println(tm_BlueTreeLeaf_RedLeaf   .mTree.getClass());    // class BlueTree

        // the following two have compile errors, which is good and expected.
        TreeManager<Tree    <RedLeaf>, Leaf>    tm_TreeRedLeaf_Leaf     = new TreeManager<Tree    <RedLeaf>, Leaf>   ((Class<Tree    <RedLeaf>>) new Tree    <RedLeaf>().getClass());
        TreeManager<BlueTree<RedLeaf>, Leaf>    tm_BlueTreeRedLeaf_Leaf = new TreeManager<BlueTree<RedLeaf>, Leaf>   ((Class<BlueTree<RedLeaf>>) new BlueTree<RedLeaf>().getClass());
    }
}

TreeManager инициализируется без проблем; хотя очереди немного длинные. Он также соответствует правилам в описании.

Однако возникает ошибка компиляции при вызове Tree.addChild() внутри TreeManager, как показано выше.

Третья пробная версия

Чтобы исправить ошибку компиляции во втором испытании, я попытался изменить сигнатуру класса (на еще более длинную). Теперь mTree.addChild(subTree); компилируется без проблем.

// T is not used in the class. T is act as a reference in the signature only
public class TreeManager3<T, NodeType extends Tree<T>, DataType extends T> {
    private NodeType mTree;

    public TreeManager3(Class<NodeType> ClassNodeType) {
        try {
            mTree = ClassNodeType.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void managerAddChild(final NodeType subTree) {
        mTree.addChild(subTree);    // compile-error is gone
    }
}

И я протестировал его с очень похожим кодом, что и во втором испытании. Создает без проблем, как и второй триал. (Только еще дольше.)

(Можно пропустить приведенный ниже блок кода, так как он просто логически повторяется.)

public static void main(String[] args) {
    @SuppressWarnings("unchecked")
    TreeManager3<Leaf   , Tree    <Leaf>   , Leaf>    tm_TreeLeaf_Leaf           = new TreeManager3<Leaf   , Tree    <Leaf>,    Leaf>   ((Class<Tree    <Leaf>>)    new Tree    <Leaf>   ().getClass());
    TreeManager3<RedLeaf, Tree    <RedLeaf>, RedLeaf> tm_TreeRedLeaf_RedLeaf     = new TreeManager3<RedLeaf, Tree    <RedLeaf>, RedLeaf>((Class<Tree    <RedLeaf>>) new Tree    <RedLeaf>().getClass());
    TreeManager3<Leaf   , BlueTree<Leaf>   , Leaf>    tm_BlueTreeLeaf_Leaf       = new TreeManager3<Leaf   , BlueTree<Leaf>,    Leaf>   ((Class<BlueTree<Leaf>>)    new BlueTree<Leaf>   ().getClass());
    TreeManager3<RedLeaf, BlueTree<RedLeaf>, RedLeaf> tm_BlueTreeRedLeaf_RedLeaf = new TreeManager3<RedLeaf, BlueTree<RedLeaf>, RedLeaf>((Class<BlueTree<RedLeaf>>) new BlueTree<RedLeaf>().getClass());

    System.out.println(tm_TreeLeaf_Leaf          .mTree.getClass());    // class Tree
    System.out.println(tm_TreeRedLeaf_RedLeaf    .mTree.getClass());    // class Tree
    System.out.println(tm_BlueTreeLeaf_Leaf      .mTree.getClass());    // class BlueTree
    System.out.println(tm_BlueTreeRedLeaf_RedLeaf.mTree.getClass());    // class BlueTree

    @SuppressWarnings("unchecked")
    TreeManager3<Leaf   , Tree    <Leaf>   , RedLeaf> tm_TreeLeaf_RedLeaf     = new TreeManager3<Leaf   , Tree    <Leaf>,    RedLeaf>((Class<Tree    <Leaf>>)    new Tree    <Leaf>   ().getClass());
    TreeManager3<Leaf   , BlueTree<Leaf>   , RedLeaf> tm_BlueTreeLeaf_RedLeaf = new TreeManager3<Leaf   , BlueTree<Leaf>,    RedLeaf>((Class<BlueTree<Leaf>>)    new BlueTree<Leaf>   ().getClass());

    System.out.println(tm_TreeLeaf_RedLeaf       .mTree.getClass());    // class Tree
    System.out.println(tm_BlueTreeLeaf_RedLeaf   .mTree.getClass());    // class BlueTree

    // the following two have compile errors, which is good and expected.
    TreeManager3<RedLeaf, Tree    <RedLeaf>, Leaf>    tm_TreeRedLeaf_Leaf     = new TreeManager3<RedLeaf, Tree    <RedLeaf>, Leaf>   ((Class<Tree    <RedLeaf>>) new Tree    <RedLeaf>().getClass());
    TreeManager3<RedLeaf, BlueTree<RedLeaf>, Leaf>    tm_BlueTreeRedLeaf_Leaf = new TreeManager3<RedLeaf, BlueTree<RedLeaf>, Leaf>   ((Class<BlueTree<RedLeaf>>) new BlueTree<RedLeaf>().getClass());
}

Однако возникает проблема, когда я пытаюсь позвонить TreeManager3.managerAddChild().

tm_TreeLeaf_Leaf.managerAddChild(new Tree<Leaf>());
tm_TreeLeaf_Leaf.managerAddChild(new Tree<RedLeaf>());      // compile error: managerAddChild(Tree<RedLeaf>) cannot cast to managerAddChild(Tree<Leaf>)
tm_TreeLeaf_Leaf.managerAddChild(new BlueTree<Leaf>());
tm_TreeLeaf_Leaf.managerAddChild(new BlueTree<RedLeaf>());  // compile error: managerAddChild(BlueTree<RedLeaf>) cannot cast to managerAddChild(BlueTree<Leaf>)

Это понятно. TreeManager3.managerAddChild(NodeType) означает TreeManager3.managerAddChild(Tree<T>), и в типе параметра нет подстановочного знака Tree<? extends T>, как Tree.addChild(final Tree<? extends T> subTree) в первом испытании.

Умоляю тебя о помощи...

У меня уже закончились идеи. Я шел в неправильном направлении, чтобы решить эту проблему? Я потратил много времени на написание этого вопроса и изо всех сил старался сделать его более читабельным, понятным и понятным. Я должен извиниться, что он все еще очень длинный и многословный. Но не могли бы вы помочь, если знаете, как это сделать, или, пожалуйста, дайте мне какие-нибудь идеи, которые у вас есть? Каждый ваш вклад высоко ценится. Большое спасибо!


Изменить № 1 (для комментария ниже)

Основываясь на первой пробной версии, разрешить изменение mChildren только с помощью addChild() (и других методов с проверкой isAssignableFrom()), так что даже разрешение пользователям наследования Tree и переопределение addChild() не нарушит целостность Дерева.

/developer/util/Tree.java

package developer.util;

import java.util.ArrayList;

public class Tree<T> {

    private Tree<? super T> mParent;
    private final ArrayList<Tree<? extends T>> mChildren = new ArrayList<Tree<? extends T>>();

    public int getChildCount() { return mChildren.size(); }
    public Tree<? extends T> getLastChild() { return mChildren.get(getChildCount()-1); }

    public void addChild(final Tree<? extends T> subTree) {
        if (this.getClass().isAssignableFrom(subTree.getClass()) == false)
            throw new RuntimeException("The child (subTree) must be a sub-class of this Tree.");

        subTree.mParent = this;
        mChildren.add(subTree);
    }
}

/user/pkg/BinaryTree.java

package user.pkg;

import developer.util.Tree;

public class BinaryTree<T> extends Tree<T> {
    @Override
    public void addChild(final Tree<? extends T> subTree) {
        if (getChildCount() < 2) {
            super.addChild(subTree);
        }
    }
}

/Main.java

import user.pkg.BinaryTree;
import developer.util.Tree;

public class Main {

    public static void main(String[] args) {
        Tree<Integer> treeOfInt = new Tree<Integer>();
        BinaryTree<Integer> btreeOfInt = new BinaryTree<Integer>();

        treeOfInt.addChild(btreeOfInt);
        System.out.println(treeOfInt.getLastChild().getClass());
        // class user.pkg.BinaryTree

        try {
            btreeOfInt.addChild(treeOfInt);
        } catch (Exception e) {
            System.out.println(e);
            // java.lang.RuntimeException: The child (subTree) must be a sub-class of this Tree.
        }

        System.out.println("done.");
    }
}

Что вы думаете?


person midnite    schedule 23.08.2013    source источник
comment
Вы считали своим объектом Tree‹TREE‹LEAF›,LEAF›? так что в этом случае у вас также будет тип вашего дерева   -  person user902383    schedule 23.08.2013
comment
Спасибо за ваш ответ!! Я должен попробовать это, как только я вернусь домой. Если бы это работало, было бы так здорово! И простой, красивый и аккуратный способ :-)   -  person midnite    schedule 23.08.2013
comment
@ user902383, еще раз спасибо. Я только что попробовал в своем затмении. public class Tree<Tree<T>, T> { } не компилируется, к сожалению.   -  person midnite    schedule 23.08.2013
comment
попробуй public class Tree<TREE extends Tree<?,?>,LEAF extends Leaf> { }   -  person user902383    schedule 23.08.2013
comment
@user902383 user902383, действительно большое СПАСИБО!!! я думаю, ваш ответ работает! На данный момент я проверил, что он работает, как и ожидалось, для конструктора по умолчанию, присваивания (другой тип просто не может быть назначен, как и ожидалось), метода addChild() и метода setParent(). Я не могу дождаться, чтобы скоро построить весь класс Tree! Для справки я использовал подписи class Tree2<TREE extends Tree2<?,?>, LEAF> { }, class BlueTree2<BT extends BlueTree2<?,?>,L> extends Tree2<BT,L> { }, Tree2<? super TREE, ? super LEAF> mParent; и void addChild(Tree2<? extends TREE, ? extends LEAF> subTree) {}.   -  person midnite    schedule 23.08.2013
comment
нет проблем, дай мне крикнуть, если у тебя будут еще проблемы с этим   -  person user902383    schedule 24.08.2013
comment
Уважаемый @user902383, если class Tree<TREE extends Tree<?,?>, DATA> {} и у него есть подклассы BigBlueTree extends BlueTree extends Tree. При создании объекта можно фактически выполнить Tree<BigBlueTree<?,?>, String> tree = new Tree<BigBlueTree<?,?>, String>();, что сделает BigBlueTree аргументом типа Tree<> и (может) вызвать ошибки в методах. Как убедиться, что пользователи передают именно Tree в аргументе типа Tree<>?   -  person midnite    schedule 31.08.2013
comment
(продолжение) Концептуально было бы неплохо, если бы мы могли class Tree<TREE equals Tree<?,?>, DATA> {} (но equals не является правильным ключевым словом). я пробовал class Tree<TREE extends Tree<TREE,?>, DATA> {}, но не могу (или не знаю как) создать объект из этого класса. Большое спасибо!!   -  person midnite    schedule 31.08.2013
comment
это какая-то причина, по которой вы делаете Tree<BigBlueTree<?,?>, String> tree вместо BigBlueTree<BigBlueTree<?,?>, String> tree?   -  person user902383    schedule 02.09.2013
comment
@ user902383, я имею в виду, что пользователь может создать объект неправильно, вот так. Если бы можно было принудительно применить и предотвратить неправильное создание пользователем этого, было бы неплохо. я думаю о двух решениях: (1) передать Class<TREE> в конструктор для проверки (но это усложнит конструктор) или (2) разрешить модифицировать только сам узел и дочерние узлы в общедоступном API, сделать все методы о родитель, как и attachParent() частный, я думаю такой, что мы можем обеспечить целостность структуры древовидной иерархии.   -  person midnite    schedule 02.09.2013
comment
я не думаю, что есть простой способ получить универсальные типы, поэтому, к сожалению, передача Tree.class в конструктор может быть правильным путем. во-вторых, как я понимаю, под пользователем вы подразумеваете программиста, и вы разрабатываете библиотеку. в этом случае, я думаю, вы можете предположить, что он знает, что делает.   -  person user902383    schedule 02.09.2013
comment
@ user902383, спасибо за ответ. Да, это библиотека. Да, пользователь = программист. Итак, вы думаете, что достаточно просто добавить руководство по использованию в описание класса?   -  person midnite    schedule 02.09.2013
comment
да, используйте javadoc, которого должно быть достаточно, если это будет реальной проблемой, вы можете добавить параметр класса в свой класс и использовать статическую фабрику для создания объектов. но, как я уже сказал, я не вижу в этом реальной проблемы   -  person user902383    schedule 02.09.2013
comment
Уважаемый пользователь @user902383, Спасибо за вашу помощь. Немного подумав, я решил добавить параметр Class<> в конструктор для проверки. Но при этом остается проблема. я поставил это в отдельный вопрос. Не могли бы вы взглянуть? stackoverflow.com/questions/18581788   -  person midnite    schedule 03.09.2013
comment
Уважаемый пользователь @user902383, еще раз большое спасибо за помощь. Почему я думаю, что мы должны применять проверку по коду, потому что структура Tree<Tree<?,?>, DATA> очень хрупкая, как при определении подклассов, так и при создании объектов. Не говоря уже о том, что пользователи могут неправильно использовать или взломать его, даже мне сложно сделать неправильный синтаксис (точно так же, как ответ Пола< /а> сказал). я собираюсь вернуться к моей самой первой пробной версии с проверкой isAssignableFrom(). Как вы думаете, это хорошая идея?   -  person midnite    schedule 04.09.2013
comment
У меня такое ощущение, что вы пытаетесь получить идеальное решение, забывая об этом, вы не можете получить идеальное решение в несовершенном мире. В вашем решении из First Trial вы по-прежнему можете переопределить метод addChild, чтобы избежать проверки. Просто быстрый вопрос, хотите ли вы разрешить пользователям создавать свои собственные деревья? если да, ваше решение может запретить им создавать дерево, которое принимает любое дерево, но не синее. Если вы не хотите, чтобы они позволяли создавать собственные деревья, возможно, вам следует рассмотреть шаблон строителя?   -  person user902383    schedule 05.09.2013
comment
@ user902383, Спасибо за ответ! Да, я хотел бы сделать свой класс максимально надежным. И да, я хотел бы позволить пользователям создавать подклассы и создавать свои собственные деревья. я думаю, что мы можем сделать mChildren приватным, поэтому подклассы должны вызывать через super.addChild() при добавлении дочернего элемента. Я думаю, что это может привести к проверке. Пожалуйста, взгляните на мои добавленные коды выше. Спасибо.   -  person midnite    schedule 05.09.2013
comment
выглядит красиво и, кажется, работает, лично мне не очень нравится делать такие проверки во время выполнения. Я также думаю, что хорошей идеей будет проверить, добавлено ли дерево, которое вы добавляете, еще где-то не добавлено, поэтому, возможно, ваше дерево должно иметь метод getParent, который будет установлен только при их добавлении, поэтому дерево   -  person user902383    schedule 06.09.2013


Ответы (3)


Как я понимаю, идеального решения этой проблемы не существует. Это в основном из-за стирания типа. В статье Удаление универсальных методов объясняется, что ваша addChild(final Tree<? extends Leaf> subTree) функция станет функция addChild(final Tree subTree). Таким образом, даже если бы вы каким-то образом могли получить общий параметр <TreeType extends Tree<? extends Leaf>> addChild(final TreeType subTree) (недопустимый синтаксис!), он был бы стерт до addChild(final Tree subTree) во время компиляции. Тем не менее, добавление вашего теста времени выполнения будет работать, поэтому сделанное вами редактирование будет работать.

person blalasaadri    schedule 21.10.2013

Я думаю, что вам нужно следующее

class Tree<LT extends Leaf>{
//have your generic add/delete/traverse methods here.
}

class BlueTree<LT extends Leaf> extends Tree<LT>{
//have your blue tree specific add/delete/traverse methods here.
}

class Leaf {
//have basic data members here
}
class BlueLeaf extends Leaf{
//have blue leaf specific data members here
}
person Keshava    schedule 28.07.2014

вы пробовали такой код?

package trees;                                                                                                          

import java.util.ArrayList;                                                                                             

public class Trees {                                                                                                    

    public static void main(String... args) {                                                                           
        Tree<Leaf, Tree<? extends Leaf, ?>> tree_leaf = new Tree<>();                                                   
        BlueTree<Leaf, BlueTree<? extends Leaf, ?>> blueTree_leaf = new BlueTree<>();                                   
        Tree<RedLeaf, Tree<? extends RedLeaf, ?>> tree_redLeaf = new Tree<>();                                          
        BlueTree<RedLeaf, BlueTree<? extends RedLeaf, ?>> blueTree_redLeaf = new BlueTree<>();                          
        //1                                                                                                             
        tree_leaf.addChild(tree_leaf);                                                                                  
        tree_leaf.addChild(tree_redLeaf);                                                                               
        tree_leaf.addChild(blueTree_leaf);                                                                              
        tree_leaf.addChild(blueTree_redLeaf);                                                                           
        //2                                                                                                             
        tree_redLeaf.addChild(tree_redLeaf);                                                                            
        tree_redLeaf.addChild(blueTree_redLeaf);                                                                        
        tree_redLeaf.addChild(tree_leaf);//compile error                                                                
        tree_redLeaf.addChild(blueTree_leaf);//compile error                                                            
        //3                                                                                                             
        blueTree_leaf.addChild(blueTree_leaf);                                                                          
        blueTree_leaf.addChild(blueTree_redLeaf);                                                                       
        blueTree_leaf.addChild(tree_leaf);//compile error                                                               
        blueTree_leaf.addChild(tree_redLeaf);//compile error                                                            
        //4                                                                                                             
        blueTree_redLeaf.addChild(blueTree_redLeaf);                                                                    
        blueTree_redLeaf.addChild(tree_leaf);//compile error                                                            
        blueTree_redLeaf.addChild(tree_redLeaf);//compile error                                                         
        blueTree_redLeaf.addChild(blueTree_leaf);//compile error                                                        

    }                                                                                                                   
}                                                                                                                       

class Tree<Data ,Children extends Tree<? extends Data, ?>> {                                                            

    //important in this question                                                                                        
    private Tree<? super Data, ? super Children> mParent;                                                               
    private Data mData;                                                                                                 
    private ArrayList<Children> mChildren;                                                                              

    // This is the focus of this question, the addChild() method signature                                              
    public void addChild(final Children subTree) {                                                                      
        // add the subTree to mChildren                                                                                 
    }                                                                                                                   

}                                                                                                                       


class BlueTree<Data, Children extends BlueTree<? extends Data, ?>> extends Tree<Data, Children> {                       
}                                                                                                                       

class Leaf {                                                                                                            
}                                                                                                                       

class RedLeaf extends Leaf {                                                                                            
}                                                                                                                       
person Alexander Kudrevatykh    schedule 12.09.2014