java <T>T和T的区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java <T>T和T的区别相关的知识,希望对你有一定的参考价值。

public class Test<T>
private T t;
public T getT()
return t;


public void setT(T t)
this.t = t;


public T getT2( T t)
return t;



public <T> T getT3(T t)
return t;


public static void main(String[] args)
Test<String> tt = new Test<String>();
tt.setT("123");
System.out.println(tt.getT());
System.out.println(tt.getT2("111"));
System.out.println(tt.getT3("222"));




在这里程序能运行,但是getT2和getT3有区别么?希望能详细解释下之间区别.谢谢

在你这段代码里面是没有区别的,实际上如果是<T>的话,是可以传参数class的,也就是说,如果说你声明Test<T>的对象的时候getT2的返回类型就已经确定了,但是getT3的返回值的类型却可以是你传进来的参数class的类型,也就是说这个方法的返回值的类型可以在你调用方法时候进行设定 参考技术A 泛型可以用"<T>"代表,那么前面的T就是泛型类型,后面的参数T表示的是自定义参数。
解释: “<T>”是泛型的默认值,可以被任意类型所代替,如:
List<String> T= new ArayList<String>();这个就定义了一个String类型的”泛型“集合,那么T(前面的)的类型就是字符串。
List<T> T= new ArayList<T>();
可以赋值给T:T.add("StringBatch");
可以获取到list的值:T.get(0),结果就是”StringBatch“;
这个时候T的类型也是String。也就是说T(前面的)是动态的,可以被任意指定类型。
参考技术B <T> 代表的是泛型 ,意思就是 你 new 的是什么类型传入的就是什么 类型
Test<String> 这里就是你传入的是 String 类型
所以 private T t;的这个T就是 private String t;
getT2 也就是 public String getT2
getT3 因为<T> 代表的就是 String 所以 也是 public String getT3
其实这两个没区别 只是你写法不同罢了追问

我感觉好像是在非泛型类里标识为泛型方法的标识,如果类本身是泛型类,就无需这种写法,可以这么理解么?

追答

可以

参考技术C <T>
是泛型

Java——聊聊<? extends T>和<? super T>的含义及区别

文章目录:

1.简介

2.上界通配符

3.下界通配符

4.简单小总结


1.简介

<? extends T>    <? super T> 是Java泛型中的“通配符(Wildcards)”“边界(Bounds)”的概念。

  • <? extends T>:是指 “上界通配符(Upper Bounds Wildcards)”
  • <? super T>:是指 “下界通配符(Lower Bounds Wildcards)”

为什么要用通配符和边界?

使用泛型的过程中,经常出现一种很别扭的情况。比如我们有Fruit类,和它的派生类Apple类。

class Fruit 
class Apple extends Fruit 

然后有一个最简单的容器:Plate类。盘子里可以放一个泛型的“东西”。我们可以对这个东西做最简单的“放”和“取”的动作:set( )和get( )方法。

class Plate<T> 
    private T item;

    public Plate(T item) 
        this.item = item;
    

    public T getItem() 
        return item;
    

    public void setItem(T item) 
        this.item = item;
    

现在我定义一个“水果盘子”,逻辑上水果盘子当然可以装苹果。

Fruit fruit = new Apple(); //正确
Plate<Fruit> p = new Plate<Apple>(new Apple()); //报错了

但实际上Java编译器不允许这个操作。会报错,“装苹果的盘子”无法转换成“装水果的盘子”。

实际上,编译器脑袋里认定的逻辑是这样的:

  • 苹果 IS-A 水果
  • 装苹果的盘子 NOT-IS-A 装水果的盘子

所以,就算容器里装的东西之间有继承关系,但容器之间是没有继承关系的。所以我们不可以把Plate的引用传递给Plate。

为了让泛型用起来更舒服,Sun公司的那些大牛们就想出了 <? extends T> 和 <? super T> 的办法,来让”水果盘子“和”苹果盘子“之间发生关系。


2.<? extends T>上界通配符

下面代码就是“上界通配符(Upper Bounds Wildcards)”:

Plate<? extends Fruit>

翻译成人话就是:一个能放水果以及一切是水果派生类的盘子。再直白点就是:啥水果都能放的盘子。这和我们人类的逻辑就比较接近了。Plate<? extends Fruit>Plate<Apple>最大的区别就是:Plate<? extends Fruit>Plate<Fruit>以及Plate<Apple>的基类。直接的好处就是,我们可以用“苹果盘子”给“水果盘子”赋值了。

Plate<? extends Fruit> p = new Plate<Apple>(new Apple());

假设,我有下面这样的继承结构:↓↓↓ 

class Food 

class Fruit extends Food 
class Meat extends Food 

class Apple extends Fruit 
class Banana extends Fruit 
class Beef extends Meat 
class Pork extends Meat 

class RedApple extends Apple 
class GreenApple extends Apple 

此时,上面的 <? extends Fruit> 就表示下图的红色部分。

class MainTest1 
    public static void main(String[] args) 
        Plate<? extends Fruit> plate = new Plate<>(new Apple());
        //不能存入任何元素
//        plate.setItem(new Fruit());
//        plate.setItem(new Apple());

        //读取出来的东西只能存放在Fruit或它的基类里
        Fruit fruit = plate.getItem();
        Food food = plate.getItem();
        Object obj = plate.getItem();
        //Apple apple = plate.getItem(); //报错
    

但是呢,在上界通配符中存在着一定的缺陷:不能往里存,只能往外取。

<? extends Fruit>会使往盘子里放东西的set()方法失效。但取东西get( )方法还有效。比如下面例子里两个set()方法,插入Apple和Fruit都报错。

  • setItem() : 编译器只知道元素类型是 Fruit 或 Fruit 的子类,所以有可能是 Fruit、Apple、Banana、RedApple、GreenApple中的某一个类型,那么当我们向其中添加元素时,编译器并不知道具体是哪一个 (派生) 类。所以这种操作是不允许的。
  • getItem() : 即使编译器不知道此时类、集合中的元素是 Fruit、Apple、Banana、RedApple、GreenApple 中的哪一个,但是能够确定的是这些元素都是由 Fruit 派生出来的,所以上面的代码中 getItem 方法是可以用 Fruit、Fruit的父类Food、总类Object 接收。

3.<? super T>下界通配符

下面代码就是“下界通配符(Upper Bounds Wildcards)”:

Plate<? super Fruit>

表达的就是相反的概念:一个能放Fruit以及一切是Fruit基类的盘子。Plate<? super Fruit>Plate<Fruit>的基类,但不是Plate<Apple>的基类。对应刚才那个例子,Plate<? super Fruit>覆盖下图中红色的区域。 

Plate<? super Fruit> plate = new Plate<>(new Fruit());

假设,我有下面这样的继承结构:↓↓↓ 

class Food 

class Fruit extends Food 
class Meat extends Food 

class Apple extends Fruit 
class Banana extends Fruit 
class Beef extends Meat 
class Pork extends Meat 

class RedApple extends Apple 
class GreenApple extends Apple 

此时,上面的 <? superFruit> 就表示下图的蓝色部分。

class MainTest2 
    public static void main(String[] args) 
        Plate<? super Fruit> plate = new Plate<>(new Fruit());
        //存入元素正常
        plate.setItem(new Fruit());
        plate.setItem(new Apple());
        //读取出来的东西只能存放在Object类中
        //Apple apple = plate.getItem();
        //Fruit fruit = plate.getItem();
        Object obj = plate.getItem();
    

但是呢,在下界通配符中存在着一定的缺陷:下界<? super T>可以往里存,但往外取只能放在Object对象里。

使用下界<? super Fruit>会使从盘子里取东西的get()方法部分失效,只能存放到Object对象里。set( )方法正常。

  • setItem() : 编译器只知道元素类型是 Fruit 或者 Fruit 的基类或父类,所以有可能是 Fruit、Food、Object 其中的一个类型。编译器知道类型的下界是 Fruit ,根据类型向上兼容的特性,所以可以添加的元素是 Fruit 以及 Fruit 的派生类。
  • getItem() : 既然编译器不确定集合类型是 Fruit 或者 Fruit 的基类或父类中的哪一种,可能是Fruit,可能是Food,那么返回类型只能是它们的共同父类 Object。但是这里可以通过强制类型转换成相应的Fruit的子类。

4.简单小总结

最后看一下什么是PECS(Producer Extends Consumer Super)原则,已经很好理解了:

  • <? extends C> 适合大量做获取操作的情景。
  • <? super C> 适合大量做添加操作的情景。

特点:<? extends C> 的 add() 被限制,<? super C> 的 get() 被限制。

以上是关于java <T>T和T的区别的主要内容,如果未能解决你的问题,请参考以下文章

“E”、“T”和“”有啥区别?对于 Java 泛型?

java 泛型 ? 和 T的区别

java中Class<T>类型和不写<T>的区别

java中Collection方法里面的Object[] toArray() 和 <T> T[] toArray(T[] a)有啥区别吗?

Java——聊聊<? extends T>和<? super T>的含义及区别

Java——聊聊<? extends T>和<? super T>的含义及区别