Java基础系列12: 泛型

本文是作者的读书笔记和心得整理,部分内容来源于网络,如有侵权,请联系作者。

什么是泛型

直接看例子

List arrayList = new ArrayList();
arrayList.add("aaaa");
arrayList.add(100);for(int i = 0; i< arrayList.size();i++){String item = (String)arrayList.get(i);Log.d("泛型测试","item = " + item);
}

这个代码会报错,因为没有给arraylist加泛型,所以无法转换.

注意泛型是会在编译期使用,不会进入到运行期

泛型类的初始化

一个最简单的例子:

//在实例化泛型类时,必须指定T的具体类型
public class Generic<T>{//在类中声明的泛型整个类里面都可以用,除了静态部分,因为泛型是实例化时声明的。//静态区域的代码在编译时就已经确定,只与类相关class A <E>{T t;}//类里面的方法或类中再次声明同名泛型是允许的,并且该泛型会覆盖掉父类的同名泛型Tclass B <T>{T t;}//静态内部类也可以使用泛型,实例化时赋予泛型实际类型static class C <T> {T t;}public static void main(String[] args) {//报错,不能使用T泛型,因为泛型T属于实例不属于类
//        T t = null;}//key这个成员变量的类型为T,T的类型由外部指定private T key;public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定this.key = key;}public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定return key;}
}

一个更加具体的例子:

Generic generic = new Generic("111111");
Generic generic1 = new Generic(4444);
Generic generic2 = new Generic(55.55);
Generic generic3 = new Generic(false);Log.d("泛型测试","key is " + generic.getKey());
Log.d("泛型测试","key is " + generic1.getKey());
Log.d("泛型测试","key is " + generic2.getKey());
Log.d("泛型测试","key is " + generic3.getKey());D/泛型测试: key is 111111
D/泛型测试: key is 4444
D/泛型测试: key is 55.55
D/泛型测试: key is false

需要注意的是,不允许对泛型使用instanceof操作

泛型接口

常常被用于各种类的生产器中

//定义一个泛型接口
public interface Generator<T> {public T next();
}

有两种使用方法:
当实现泛型接口的类,未传入泛型实参时:

/*** 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中* 即:class FruitGenerator<T> implements Generator<T>{* 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class"*/
class FruitGenerator<T> implements Generator<T>{@Overridepublic T next() {return null;}
}

当实现泛型接口的类,传入泛型实参时:

/*** 传入泛型实参时:* 定义一个生产器实现这个接口,虽然我们只创建了一个泛型接口Generator<T>* 但是我们可以为T传入无数个实参,形成无数种类型的Generator接口。* 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型* 即:Generator<T>,public T next();中的的T都要替换成传入的String类型。*/
public class FruitGenerator implements Generator<String> {private String[] fruits = new String[]{"Apple", "Banana", "Pear"};@Overridepublic String next() {Random rand = new Random();return fruits[rand.nextInt(3)];}
}

泛型通配符

public void showKeyValue1(Generic<?> obj);

这里就是一个不确定是什么类型的通配符

泛型方法

如何定义一个类型未知的方法,看下面这个例子:

/*** 泛型方法的基本介绍* @param tClass 传入的泛型实参* @return T 返回值为T类型* 说明:*     1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法,声明T是一个泛型,可以有多个。*     2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。*     3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。*     4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。*/public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,IllegalAccessException{T instance = tClass.newInstance();return instance;}Object obj = genericMethod(Class.forName("com.test.test"));

泛型方法和可变参数

引用自https://how2playlife.com/2019/09/13/13%E6%B3%9B%E5%9E%8B/ , 感觉这个例子非常的好

public class 泛型和可变参数 {@Testpublic void test () {printMsg("dasd",1,"dasd",2.0,false);print("dasdas","dasdas", "aa");}//普通可变参数只能适配一种类型public void print(String ... args) {for(String t : args){System.out.println(t);}}//泛型的可变参数可以匹配所有类型的参数。。有点无敌public <T> void printMsg( T... args){for(T t : args){System.out.println(t);}}//打印结果://dasd//1//dasd//2.0//false}

注意静态方法要使用泛型的时候必须二次声明.

public class StaticGenerator<T> {......../*** 如果在类中定义使用泛型的静态方法,需要添加额外的泛型声明(将这个方法定义成泛型方法)* 即使静态方法要使用泛型类中已经声明过的泛型也不可以。* 如:public static void show(T t){..},此时编译器会提示错误信息:"StaticGenerator cannot be refrenced from static context"*/public static <T> void show(T t){}
}

泛型的上下界

比如只有Number的子类或者是Integer的父类才能传入.

public class 泛型通配符与边界 {public void showKeyValue(Generic<Number> obj){System.out.println("key value is " + obj.getKey());}@Testpublic void main() {Generic<Integer> gInteger = new Generic<Integer>(123);Generic<Number> gNumber = new Generic<Number>(456);showKeyValue(gNumber);//泛型中的子类也无法作为父类引用传入
//        showKeyValue(gInteger);}//直接使用?通配符可以接受任何类型作为泛型传入public void showKeyValueYeah(Generic<?> obj) {System.out.println(obj);}//只能传入number的子类或者numberpublic void showKeyValue1(Generic<? extends Number> obj){System.out.println(obj);}//只能传入Integer的父类或者Integerpublic void showKeyValue2(Generic<? super Integer> obj){System.out.println(obj);}@Testpublic void testup () {//这一行代码编译器会提示错误,因为String类型并不是Number类型的子类//showKeyValue1(generic1);Generic<String> generic1 = new Generic<String>("11111");Generic<Integer> generic2 = new Generic<Integer>(2222);Generic<Float> generic3 = new Generic<Float>(2.4f);Generic<Double> generic4 = new Generic<Double>(2.56);showKeyValue1(generic2);showKeyValue1(generic3);showKeyValue1(generic4);}@Testpublic void testdown () {Generic<String> generic1 = new Generic<String>("11111");Generic<Integer> generic2 = new Generic<Integer>(2222);Generic<Number> generic3 = new Generic<Number>(2);
//        showKeyValue2(generic1);本行报错,因为String并不是Integer的父类showKeyValue2(generic2);showKeyValue2(generic3);}
}

Java基础系列12: 泛型相关推荐

  1. 夯实Java基础系列9:深入理解Class类和Object类

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  2. 夯实Java基础系列14:深入理解Java枚举类

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  3. 夯实Java基础系列17:一文搞懂Java多线程使用方式、实现原理以及常见面试题

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  4. java基础系列十七(时间日期转换)

    目录 一.概述 二.基础知识 2.1 时区 2.2 格林威治时间 2.3 时间戳 三.Date/Calendar/SimpleDateFormat 3.1 Date 3.2 Calendar 3.3 ...

  5. 夯实Java基础系列15:Java注解简介和最佳实践

    Java注解简介 注解如同标签 Java 注解概述 什么是注解? 注解的用处 注解的原理 元注解 JDK里的注解 注解处理器实战 不同类型的注解 类注解 方法注解 参数注解 变量注解 Java注解相关 ...

  6. 夯实Java基础系列19:一文搞懂Java集合类框架,以及常见面试题

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  7. 夯实Java基础系列23:深入理解Java继承、封装、多态的底层实现原理

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  8. 夯实Java基础系列20:从IDE的实现原理聊起,谈谈那些年我们用过的Java命令

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  9. 夯实Java基础系列1:Java面向对象三大特性(基础篇)

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

最新文章

  1. 缓存架构设计细节二三事
  2. 【转贴】Lua 5.0 参考手册
  3. Android App应用包增量升级(one)
  4. Bailian4130 踩方格【组合+打表】
  5. 智课雅思词汇---十五、前缀co-com-con-col-cor-是什么意思
  6. h2 不能访问localhost_Spring 配置的 H2 控制台 frameOptions 导致无法访问
  7. 打太极不协调的二三事
  8. 得力计算机怎么用二进制,如何将得力计算器 DL-1529 调到保留两位小数点?
  9. CentOS7安装lepus
  10. 邮票的制作(1.主要画笔工具2.钢笔工具)
  11. centos查看版本(centos查看版本号)
  12. java:Cassandra入门与实战——上
  13. 【夏目鬼鬼分享】StringBoot整合RabbitMQ,使用Direct、Fanout、Topic三种模式
  14. 傅里叶级数展开和傅里叶变换(一)
  15. 计算机视觉领域稍微容易中的期刊系列(二)1
  16. win10 xp共享文件夹互访问题解决
  17. matlab语言学习笔记(一)
  18. BQ40Z80 SMBUS通讯不上
  19. 64位Windows 7 中最好的杀毒软件!
  20. 希尔瓦娜斯服务器位置,魔兽世界9.1希尔瓦娜斯战斗信息与场景一览[多图]

热门文章

  1. 什么是 “内卷化效应” ?
  2. 《灵飞经》3·印神无双 第十三章 剑奕星斗 1
  3. 试炼之路(起)——0407
  4. 阿里云asp主机 后台登录一直提示验证码错误_Lazada官方最全开店指南首发!云开店之入驻篇,快速入驻只需四步...
  5. 计算机无法找到组件c0000135,电脑开机显示无法找到组件的原因
  6. Glide加载https图片
  7. 最受消费者欢迎的美国十大保健品品牌
  8. 【​观察】5G时代,运营商需要怎样的数据中心?
  9. js刷新当前页面的方法
  10. Python二手车价格预测(一)—— 数据处理