1.泛型
泛型就相当于标签,形式是:<>。
当集合容器类在设计/声明阶段不能确定这个容器到底实例存的是什么类型的对象时,在JDK1.5之前只能把元素类型设计为Object,JDK1.5之后使用泛型来解决。因为这个时候除了元素的类型不确定,其他部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,此时把元素的类型设计成一个参数,这个类型参数叫做泛型。
Collection< E>,List< E>,ArrayList< E>,这个E就是类型参数,即泛型。

2.泛型的引入
在泛型出现之前,List是这样使用的:
public static void add(){
List list = new ArrayList();
list.add(“a”);
list.add(“b”);
list.add(1);//1自动装箱成对象
}
List集合中存储了String和Integer二种类型,在存储时发现没啥问题,但是存储数据肯定是要拿出来使用的,如果对这个集合进行遍历:
Iterator iterator = list.iterator();
while (iterator.hasNext()){
Object obj = iterator.next();
Log.e(TAG,“obj=”+obj);
}
获取集合中的每个元素返回的是Object,如果这个时候想对获取的元素进行操作,比如截取等,会发现最后一个从集合中获取的元素是1,那怎么对字符串进行截取等操作啊,这时候就得要对obj进行类型操作:
if(obj instanceof String){
//截取字符串操作
}
这样每次都要去判断类型,然后做下面的操作,如果obj是String类型,那么obj就要强转成String,如果obj不是String类型,那么强转会造成错误,程序可能直接挂了,这就是为啥出现泛型。因为泛型是出现在编译时期,会避免在运行时候程序因为强转导致程序崩溃。
现在使用泛型对上例代码进行修改:
public static void add(){
List< String> list = new ArrayList< String>();
list.add(“a”);
list.add(“b”);
// list.add(1);会报错
}
会发现集合中存储的是String类型,你存储一个integer进去,编译器就报错了,这就是使用泛型的好处之一。因为把这个List的泛型定义为String类型,相当于给这个List贴了一个String的标签,只有Strinf类型的数据才可以放进去,其他类型放进去就会报错。这样在编译时期就会对类型进行检查,不是泛型对应的类型就不可以添加进这个集合。
所以泛型出现的好处有二点:
①遍历时,避免了强转
②把运行时期改成了在编译时期检查语法

总结一下:
①泛型是在JDK1.5以后才出现的
②泛型其实就是一个<>引起来的参数类型,这个参数类型在使用的时候才会确定具体是哪个类型
③泛型的类型都是引用数据类型,不能是基本数据类型
④List< String> list = new ArrayList< String>();在JDK1.7以后可以写成List< String> list = new ArrayList<>();

3.泛型类
泛型类意思是泛型定义在类上。
格式:public class A< T>

泛型接口就是泛型定义在接口上。与泛型类同理。
public interface IBaseDao< T> {
long insert(T entry);
int update(T entity, T where);
}

(1)泛型类的定义
先看看普通类的定义吧:
public class My class {
}
泛型类就是在普通类的基础上加上<>,<>里面就是参数类型,这个类型现在是不确定的,相当于一个占位,现在能确定的就是这个类型一定是一个引用数据类型,而不是基本数据类型。这里的参数类型可以写任意字母,源码中一般用E。
比如定义一个泛型类:
public class My class< E> {
int age;
String name;
E sex;
public void add(E e) {
}
}
这就是一个泛型类了,泛型类里面的方法或属性也可以使用和泛型类的参数类型一样的类型,这个参数类型E在类初始化的时候才会确定,一旦泛型类的E确定了,它里面的方法和属性里的E也就随之确定了。
下面就可以使用这个泛型类了,对它进行初始化,使用方法分下面两种情况:
①实例化的时候不指定泛型
MyClass mc = new MyClass();
mc.add(“abc”);
mc.add(17);
mc.add(true);
mc.add(new String[]{“a”,“b”,“c”});
可以发现,在实例化泛型类的时候,如果不明确的指定泛型具体类型,那么认为此泛型为Object类型。
②实例化的时候指定泛型——推荐使用
MyClass< String> mc = new MyClass();
mc.add(“abc”);
mc.add(new String[]{“a”,“b”,“c”});
mc.sex = “男”;
因为实例化泛型类的时候,明确指定了泛型的具体类型为String,因此该类里面的方法和属性的类型也就确定了只能是String。

(2)泛型类的继承
再定义一个类继承刚刚的泛型类MyClass,分两种情况。如下:
①继承的时候,父类指定泛型
public class SubClass extends MyClass< Integer>{
}
因为这个子类继承泛型类的时候,指定了父类的泛型,因此子类不需要再指定泛型了,可以直接使用。
SubClass sub = new SubClass();
sub.add(19);
②继承的时候,父类不指定泛型
public class SubClass2< E> extends MyClass< E>{
}
因为子类继承的时候,父类没有指定泛型的具体类型,因此子类也要带着< E>。也就是说,如果父类不指定泛型,那么子类也会变成一个泛型类,这个E的类型可以在创建子类对象的时候确定。如下:
SubClass2< String> sub2 = new SubClass2<>();
sub2.add(“girl”);
sub2.sex = “女”;

(3)泛型类注意
①泛型类可以定义多个参数类型
public class TestDemo<A,B,C> {
A age;
B name;
C sex;
public void add(A age, B name, C sex){
}
}
②泛型类的构造器的写法,注意不能在构造方法里写入泛型参数类型,下面的写法是错误的:
public class TestDemo<A,B,C> {
A age;
B name;
C sex;
//构造方法
public TestDemo<A,B,C>(){ //错误写法,报错
}
}
③不同的泛型的引用类型不可以相互赋值
ArrayList< String> list1 = null;
ArrayList< Integer> list2 = null;
list1 = list2;//错误写法
④泛型如果不指定,那么就会被擦除,此时泛型对应的类型就是Object
MyClass mc = new MyClass();
mc.add(“abc”);
mc.add(17);
mc.add(true);
mc.add(new String[]{“a”,“b”,“c”});
⑤泛型类中的静态方法不能使用类的泛型
public class TestDemo<A,B,C> {
A age;
B name;
C sex;
public static int add(A age) { //错误写法,报错
}
}
因为静态方法优先于对象存在,在没有创建对象的时候,静态方法已经被加载到内存里了,但是ABC的类型在创建对象的时候才能确定,由于现在还没有创建对象,那A的类型就还没有确定呢,就导致静态方法里的参数报错了。
⑥不能直接使用E[]的创建
public class TestDemo<A,B,C> {
A age;
B name;
C sex;
public void add(A age) {
A[] ages = new A[10];//错误写法,报错
//可以写成下列方式
A[] ages = (A[])new Object[10];
}
}

4.泛型方法
并不说带有泛型参数的方法就是泛型方法,如下
public class TestDemo< E> {
public void add(E e) {
}
}
这个add方法虽然带有泛型参数,但它并不是泛型方法。
泛型方法要求这个方法的泛型的参数类型和当前类的泛型无关。也就是说,泛型方法对应的那个泛型参数类型和当前所在的这个类是否是泛型类,以及这个类的泛型是啥,都没关系。
public class TestDemo< E> {
public void add(E e) { // 不是泛型方法
}
public < T> void put(T t) { //是泛型方法
}
}
注意:
①泛型方法定义的时候,要在前面加上< T>,因为不加的话,会把T当做一种数据类型,然而代码中没有T类型,就会报错。
那么现在有两个参数类型了E和T,我们知道E的类型是在这个泛型类实例化的时候确定的,那T是在什么时候确定的呢?T的类型是在调用方法的时候才确定的。
TestDemo< String> demo = new TestDemo();
demo.add(“abc”);
demo.put(18);
demo.put(true);
demo.put(“abc”);
②泛型方法可以是静态方法。虽然静态方法优先于对象加载,在没有对象的时候,静态方法就随着类第一次加载的时候加载了,这时候T的类型还没有确定。但是没关系,因为T随着方法的调用才去确定它的类型的。
public class TestDemo< E> {
public static void add(E e) { // 不是泛型方法,不能加static
}
public static < T> void decode(T t) { //是泛型方法,可以加static
}
}

5.泛型类型参数不能使用继承
在不使用泛型的时候,下面这两种情况都是正确的:
Object obj = new Object();
String s = new String();
obj = s; //父类=子类, 正确,向上转型,属于多态的一种形式

Object[] objArr = new Object[10];
String[] strArr = new String[10];
objArr = strArr;//正确,向上转型,属于多态的一种形式

但是在泛型类里,下面这种情况就是错误的:
List< Object> list1 = new ArrayList<>();
List< String> list2 = new ArrayList<>();
list1 = list2;//错误
list1和list2的底层都是一个Object类型数组,泛型只是对编译器进行了限制,所以本质上list1和list2没有继承关系,他俩是并列关系。也就是说即使类型A和类型B存在子类父类关系,当他们用到泛型类的时候,G< A>和G< B>不存在子类父类关系,而是并列关系。

6.泛型通配符使用
假如我现在有一个方法:
public void calculate(List< Object> list){
}
此时还需要一个String和Integer类型的相同的方法:
public void calculate(List< String> list){
}
public void calculate(List< Integer> list){
}
这时候编译器会报错,因为这3个方法的参数都是List,虽然List里的泛型参数不一样,但是在底层看来没区别(泛型只影响了编译器的检查,对底层没影响),所以这3个方法并不是重写,而是重复定义了!
这时候就需要引入通配符了。引入通配符以后,上面3个方法就可以定义为:
public void calculate(List< ?> list){
for(Object obj : list) { //对加了通配符的list进行遍历时可以使用Object,不用?
}
}
使用这个方法的时候再确定?的类型:
calculate(new ArrayList< Integer>());
calculate(new ArrayList< String>());
calculate(new ArrayList< Object>());

可以发现,A和B是子类父类关系的时候,虽然G< A>和G< B>是并列关系,不存在子类父类关系,但是加入通配符以后,G< ?>就变成了G< A>和G< B>的父类。

在给calculate方法加入通配符以后,注意对list的写入和读取操作:
public void calculate(List< ?> list){
//数据的写入操作
list.add(“abc”);//错误写法,报错。因为此时并不确定list的类型,万一调用calculate方法时传入的是ArrayList< Integer>呢?所以这时候不能随意的添加数据。实在想添加,只能添加null
list.add(null);//不报错

//数据的读取操作
Object a = list.get(0);//正确,读取时用Object类型接收即可
}

7.泛型受限
先定义一个父类Person:
public class Person{
}
再定义一个子类Student继承Person:
public class Student extends Person{
}
其实父类Person也有它的父类,就是Object。
现在定义三个集合:
List< Object> a = new ArrayList<>();
List< Person> b = new ArrayList<>();
List< Student> c = new ArrayList<>();
我们知道,此时abc并不存在继承关系,他们是并列关系。
下面开始使用泛型受限:
①泛型的上限
List<? extends Person> list1 = null;
list1 = a; //报错
list1 = b;//正确
list1 = c;//正确
解释:List<? extends Person>是List< Person>的父类,也是List< Person的子类>的父类,因此可以向上转型。
②泛型的下限
List<? super Person> list2 = null;
list2 = a;//正确
list2 = b;//正确
list2 = c;//错误
解释:List<? super Person>是List< Person>的父类,也是List< Person的父类>的父类,因此可以向上转型。

Android 泛型★★★★★相关推荐

  1. IT知识免费学习视频地址大全

    Jquery2.0实战 http://edu.ibeifeng.com/view-index-id-318.html 使用SSH框架技术开发学籍管理系 统-Hibernate 部分 http://ed ...

  2. Android/Java中使用Protobuf的Any类型实现泛型解析

    上一篇博客中只讲解到了简单的使用protobuf,还不会的可以先去看一下[Android项目使用Protobuf教程(结合Retrofit+RxJava及HttpURLConnection使用)],有 ...

  3. android 生成泛型对象,java android解析多层含有泛型对象的json数据获取不到泛型类型解析失败解决办法...

    ####问题描述 * java 解析多层含有泛型对象的json数据获取不到泛型类型 * 如果将泛型改成实际的类型就能正常解析 * 如果不改成实际的类型泛型数据被解析成com.google.gson.i ...

  4. android 无线接口 泛收,Android下的Java之interface接口泛型 动态获取泛型的类型

    Android的泛型有多坑? 先来看看该问题的场景 将String转换成具体对象时,需要进行的关键点就是获取到对象的类型 // 这里定义了一个泛型R,那运行时如何获取到这个类型呢? // 第一眼看上去 ...

  5. android 移除泛型中元素_最新(2020)Android高级面试知识点干货分享(二)

    最新Android高级面试知识点干货分享(一) *转载请说明出处*! 四.Java集合(List.Set.Queue.Map) Java集合体系是一个树状,如果按照类似OSI网络模型来看的话,整个Ja ...

  6. android 移除泛型中元素_Android 代码混淆 混淆方案

    欢迎关注专栏:里面定期分享Android和Flutter架构技术知识点及解析,还会不断更新的BATJ面试专题,欢迎大家前来探讨交流,如有好的文章也欢迎投稿. Flutter跨平台开发终极之选​zhua ...

  7. 泛型在Android中的应用

    引言 Android应用中经常会碰到对JSON的解析,但解析一串比较长的JSON时候往往会比较耗时,那么耗时就采用异步解决. 但程序中有很多bean啊,要怎样解决该类适合全部的bean呢? 那就用到泛 ...

  8. 重学Android基础系列篇(二):泛型

    前言 本系列文章主要是汇总了一下大佬们的技术文章,属于Android基础部分,作为一名合格的安卓开发工程师,咱们肯定要熟练掌握java和android,本期就来说说这些~ [非商业用途,如有侵权,请告 ...

  9. Android MVP(四)运用反射配置泛型 Model

    博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载.本文由博主 威威喵 原创,请多支持与指教. 本文首发于此   博主:威威喵  |  博客主页:https://blog.csdn.net/ ...

最新文章

  1. VDI序曲十七 RDVH虚拟主机中开启RemoteFX的硬件配置要求
  2. Microsoft Visual Studio 2008 快捷键
  3. Mac10.9 Mavericks 输入法切换快捷键
  4. .htaccess的基本作用及相关语法介绍
  5. 为什么要学python-为什么要学 Python?
  6. Alexa与小娜结盟,智能语音助手该呼朋引伴还是独自前行?
  7. python自学笔记_Python 自学笔记
  8. SpringMVC框架、Spring boot框架、SSM區別
  9. Android WebView使用基础
  10. 中移动酝酿改革数据业务分成模式:SP与CP分开
  11. 【原创】ourphp一处SQL注射
  12. 《数字图像处理》实验二
  13. vulnhub--ALFA: 1
  14. 量子计算机和量子纠缠的关系,科普:什么是量子纠缠和量子计算?
  15. 计算机电路板工作原理,电磁炉万能电路板工作原理(图)
  16. Oracle 技能强化 Part 9 范围查询
  17. 人工智能 —— 语义网络表示法
  18. 这样的牛皮凉席清水席要慎买!!!
  19. 从移动应用创作者到产品总监—专访微软MVP邹建峰
  20. 微信小程序刷新(重载)当前页面的方法,超简单~

热门文章

  1. 3 x 10的python表达式_python3.x 正则表达式的应用
  2. Kafka Eagle 2.0.6 安装
  3. 基于javaweb的图书馆图书管理借阅书籍管理系统(java+ssm+jsp+html+mysql)
  4. Spring Boot项目集成AWS SDK连接到AWS S3,实现上传下载功能
  5. 四大CPU体系结构ARM、X86/Atom、MIPS、PowerPC
  6. 多因素多水平实验的设计方法
  7. 嵌入式 STM32 红外遥控
  8. 基于ANSYS Workbench的表面裂纹计算
  9. vue2 对接网易im初始化操作
  10. 用代码和想象力拥抱一个物联网时代