如果默认情况下接受子类对象,为什么要在泛型中使用有界类型参数?

时间:2016-07-16 15:39:58

标签: java generics bounded-types

我在泛型(JAVA)中使用有界类型参数。

class First<T extends Use>{
    T s;
    First(T s){
        this.s=s;
    }
    void setS(T s){
        this.s=s;
    }
    void getS(){
        System.out.println(s);
    }
}

class UseChild extends Use{
    public String toString(){
        return "I am UseChild";
    }
}

class Use{
    public String toString(){
        return "I am Use";
    }
    public static void main(String[] args){
        First <Use> f1 = new First <Use> (new Use());
        f1.getS();
        f1.setS(new UseChild());
        f1.getS();
    }
}

输出是:

I am Use
I am UseChild

直到现在好了。我以为我可以将子类对象传递给setS(),因为“T extends Use”在Type-parameter中,否则我不能。

但如果我使用不带extends关键字的type-parameter,则输出相同:

class First<T>
{
//Same code as above
}

我怀疑是: 如果我可以将子类对象传递给没有extends关键字的setS(),那么extends关键字有什么特别之处?

3 个答案:

答案 0 :(得分:1)

假设Use定义了一种新方法(而不是覆盖toString):

class Use {
    ...
    public void printMe() { // Some nonsensical method for demonstration
        System.out.println("printing Use");
    }
}

此绑定允许您从First类调用此方法:

class First<T extends Use> {
    T s;
    ...
    public void getS() {
        s.printMe(); // not possible without the bound.
    }
}

您使用First的方式,根本不需要泛型。使用Use类型而不是T可以使用相同的内容:

class First {
    Use s;
    First(Use s) {
        this.s = s;
    }
    void setS(Use s) { 
        this.s = s;
    }
    void getS() {
        System.out.println(s);
    }
}

输出结果相同。

答案 1 :(得分:0)

此处Use充当限制。它指定您只能传递Use类型或扩展类型<T>的对象。

更改为<T extends Object>相当于First<T> - 换句话说,您将能够传递任何对象。

不同之处在于LinkedList您可以传递任何对象,例如JFrameFirst<T extends Use>。使用Use,您只能传递Use类型的对象或类型为Use的对象。

如果类型First具有您希望类<T extends Use>使用的某些方法,那么这种方法非常有用。在这种情况下,您需要指定First,以便Use了解FactoryInterface类的方法和属性。

答案 2 :(得分:0)

任何泛型类的Type-parameter(T)都接受type-argument和类型为argument的子类。我们可以在setS()中传递UseChild的对象,即使使用Use as type-argument创建了First类的对象。因为UseChild是Use的子类。因此,以下陈述完全有效:

First<Use>f = new First<Use>(new Use());
f.setS(newUseChild());

有界和无界类型之间的差异并不像问题中所述。下面讨论实际差异:

如果我们不使用有界类型,则T扩展Object,s成为对象类型的引用变量。

class Use
{
        public String toString()
        {
                return "I am Use";
        }
        public void call()
        {
                System.out.println("I am call of Use");
        }
        public static void main(String[] args)
        {
                First <Use> f1 = new First <Use> (new Use());
                f1.getS();
        }
}

让我们检查第一课的各个领域:

import java.lang.reflect.*;
class First<T>
{
        T s;
        First(T s)
        {
                this.s=s;
        }
        void setS(T s)
        {
                this.s=s;
        }
        void getS()
        {
                Field[] flds = this.getClass().getDeclaredFields();
                for(Field f:flds)
                {
                        String name = f.getName();
                        String type = f.getType().getName();
                        int i = f.getModifiers();
                        String modifier = Modifier.toString(i);
                        System.out.println("Name = "+name+" type= "+type);
                }
                System.out.println(s.getClass().getName());
        }
   }

输出是:

Name = s type= java.lang.Object
Use

所以T扩展了java.lang.Object。 s是java.lang.Object类型的引用变量。我们不能使用变量s调用Use特定方法。

让我们检查类的各个字段First With bound type:

import java.lang.reflect.*;
class First<T extends Use>
{
        T s;
        First(T s)
        {
                this.s=s;
        }
        void setS(T s)
        {
                this.s=s;
        }
        void getS()
        {
                Field[] flds = this.getClass().getDeclaredFields();
                for(Field f:flds)
                {
                        String name = f.getName();
                        String type = f.getType().getName();
                        int i = f.getModifiers();
                        String modifier = Modifier.toString(i);
                        System.out.println("Name = "+name+" type= "+type);
                }
                System.out.println(s.getClass().getName());
        }
   }

输出是:

Name = s type= Use
Use

所以现在T扩展了Use,而不是java.lang.Object。 s是Use类型的引用变量。正如@jorn vernee所说,我们现在可以调用First中的Use特定方法。