搜索
首页Javajava教程如何使用Java泛型方法

如何使用Java泛型方法

May 01, 2023 pm 02:16 PM
java

泛型方法

一般定义如下,即方法的前面加了个

public class FTest {
	public <T> List<T> f(T t){...};
}

三种泛型参数推断方式:

1、直接在f()前面加确定泛型

fTest.<Integer>f(xxx)

2、通过输入参数确定, 下面这个推断为Integer

int number = 0;
fTest.f(number)

3、可通过 返回值 确定

List<Integer> list = fTest.f(xxx);

Q: 下面这段代码哪里有问题? 是toString()那里吗?

public class A<T> {
	public static void  test(T t){
  		System.out.println(t.toString());  
  }
}

A:test是static方法, 因此无法感知A实例里的T
需要改成
public static void test(T t)

toString()那里没问题,toString就是Object的方法。

泛型参数和类型消除

Q: 泛型参数T在运行时,会变成什么?
A: 统一变成Object且不包含任何类型信息。

Q: 泛型参数T可以可以使用instanceof做比较吗?

class A<T> {
   void f(Object arg)
   if(arg instanceof T) {
	  ...
   }
}

A: 不能,编译器会报错。

Q: 泛型参数T可以进行new T()或者new T[]操作吗?
A: 不能,编译器会报错。

如何使用Java泛型方法

Q: 能调用泛型参数对象里的方法吗?

T.f();

A: 只能调用Object的方法。

Q: 可以用T做强制转化吗?

T t = (T)object;

A: 能运行, 但不会真正发生转型, 编译时会触发waring警告。

新建泛型对象时的问题

先假定有2个类, 基类Parent 和子类Child

class Parent{}
class Child extends Parent{}

回答以下问题:
Q:下面这句话有问题吗?

List<Parent> list = new ArrayList<Child>()

A:有问题,编译就错误了。 List和ArrayList并不存在父子类的关系

Q:

List<? extends Parent> list = new ArrayList<Child>();

这个list有什么特点?

A:这个list可以调用A a = list.get(), 但是不能list.add(new Parent())

  • 原因:
    list.get()所做的操作是在返回时, 把内部的 强转成Parent, 是合理的,任何Parent的子类都可以转成Parent
    list.add(new Parent())所做的操作是在输入时, 把外部的A转成内部的, 这是不合理的,因为我们不知道这个Parent对象可以转成哪个Parent的子类。

Q:

List<? super Child> list = new ArrayList<Parent>();

这个list有什么特点?
下面谁会报错

list.add(new Child())
list.add(new Parent())
Parent a= list.get();
Child b = list.get()

A:截图如下:

如何使用Java泛型方法

  • Child c = list.get() 或者Parent p = list.get()所做的操作是在返回时, 把内部的 强转成外部的Parent或者child, 是不合理的, 因为编译器觉得child的父类 不一定 能转成parent或者child,所以禁止了这种行为( 比如parent的父类是object, 但object不一定就能转成parent或者child)。*list.add(new Child())所做的操作是在输入时, 把外部的child或者parent转成内部的, 这是合理的,因为child和parent一定能转成child的父类。

Q:

List<?> list = new ArrayList<A>();

这个list有什么特点?

A:get和add都不行,只能做remove等无返回值无输入A的操作。
PS: 注意,不是说不能调用get或add方法, 而是调用get或add时,不能使用A这个对象去操作。
即无法做add(A) 或者 A a = get(0)
但是可以做add(object) 或者Object o = get(0)
因为?可以转为Object, 但是无法转为A。

Q:下面这个代码会报错吗?

   List<Fruit> fruitList = new ArrayList<>();
   fruitList.add(new Fruit());
   List<Apple> appleList = new ArrayList<>();
   appleList.add(new Apple());
   fruitList.addAll(appleList);
   System.out.println(fruitList);

A:不会报错。会正常打印结果。

如何使用Java泛型方法

PECS原则
注意PECS原则和上面的区别!
上面之前提到的? extend或者? supert, 都是在声明对象的时候用的。
而PECS原则是用于泛型对象的方法输入参数!

假设有一个类定义如下:

public static class MyList<T> {
    List<T> list = new ArrayList<>();

    // 把输入参数塞给自己,类似于生产操作
    public void pushList(List<T> t) {
        list.addAll(t);
    }

    // 把自己的内容塞给输入参数,类似于让输入参数做消费。
    public void pollList(List<T> t) {
         t.addAll(list);
    }
}

则T就是泛型参数。

Q:下面代码能正常运行吗?

MyList<Number> myList = new MyList<>();

List<Integer> intList = new ArrayList<>();
myList.pushList(intList);

List<Object> objectList = new ArrayList<>();
myList.pollList(objectList);

A:不能正常运行, pushList和pollList都会报错

因为编译器检查后,认为 List和List不是一个东西!

Q: 如果上文要支持pushList,应该怎么修改pushList方法的定义?
A:改成这样:

// 把输入参数塞给自己,类似于生产操作
public void pushList(List<? extends T> t) {
    list.addAll(t);
}

即编译器认为,List 和List是一个东西,允许!

Q: 如果要支持pollList,怎么修改定义?
A:

// 把自己的内容塞给输入参数,类似于让输入参数做消费。
public void pollList(List<? super T> t) {
    t.addAll(list);
}

因为是把自己的东西塞给输入参数, 而想要能塞进去,必须保证自己这个T,是输入参数的子类,反过来说,输入参数必须是T的父类,所以用super
于是编译器认为,List 和List是一个东西,允许!

PECS原则出自Effective Java, 注意只是一个编程建议而已!

  • 如果有一个类A,泛型参数为T

  • 如果他一般只用于接收输入容器List后,塞入自己内部的T容器, 则类A就叫生产者, 因此输入参数最好定义为最好, 以便能接收任何T子类的容器。

  • 如果他一般只用于接收输入容器后List, 把自己内部的T元素塞给它, 那么这个类A就叫消费者, 输入参数最好定义为\ 最好, 以便自己的T元素能塞给任何T元素的父类容器。

以上是如何使用Java泛型方法的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:亿速云。如有侵权,请联系admin@php.cn删除

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境