IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Java当中的泛型 -> 正文阅读

[移动开发]Java当中的泛型

背景

在Java推出泛型以前,程序员是可以构建一个元素为Object的集合,该集合是能够存储任意的数据类型对象的,而在使用该集合的过程当中的时候,是需要程序员明确的指定存储每个元素的数据类型,否则是很容易出现ClassCastException异常的。

在这里插入图片描述

而Java中的泛型(generics)是jdk5中引入的一个新特性,泛型提供了编译时类型安全监测的机制,该机制允许我们在编译时就监测到非法的类型数据结构。
泛型的本质就是参数化类型,也就是所操作的数据类型被指定为一个参数。

泛型的优点:它使得类型成为安全的,消除了强制类型的转换

泛型类

class 类名称 <泛型标识> {
private 泛型标识 变量名;
}

理论上泛型标识是可以用任何字母标识的,但当然java当中也肯定有自己的规范,所以常用的泛型标识符:T、E、K、V

调用泛型类的语法格式:

类名<具体的数据类型> 对象名 = new 类名<具体的数据类型>( );
在java1.7以后,后面的< >中的具体数据类型就可以省略不写的
类名<具体的数据类型> 对象名 = new 类名< > ( );

泛型派生子类

子类也是泛型类,子类就要和父类的泛型类型要一致
class ChildGeneric<T> extends Generic<T>
当子类不是泛型类的时候,父类就要明确泛型的数据类型
class ChildGeneric extends Generic<String>

泛型类的接口

interface 接口名称 <泛型标识> {
泛型标识 方法名();
}

在使用泛型接口的时候也要注意到

  1. 要是实现类不是泛型类,接口要明确数据的类型。
  2. 实现类也是泛型类,实现类要和接口的泛型类型是要一致的。

泛型方法:

修饰符 <T,E,…> 返回值类型 方法名(参数列表){
方法体…
}

public与返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。

只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。

<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。

与泛型类的定义一样,此处T是可以任意标识的。

在泛型类当中,我们就可以再单独的定义自己的泛型方法,或者在不是泛型类当中定义泛型方法。
在泛型类当中,泛型方法的泛型是独立于泛型类之外的。

● 成员方法的类型就必须和类的方法是一致的。

● 如果static方法要使用泛型能力,就必须使其成为泛型方法。

● 泛型也是支持可变参数的。

注意事项:

  1. 泛型类,如果没有指定具体的数据类型,那么这个时候,默认的操作数据类型就是Object类。
  2. 泛型的类型参数只能是类类型,不能是基本的数据类型
  3. 泛型类型在逻辑上可以看成是多个不同的类型,但实际上都是相同的类型。
  4. 在泛型里面不能传入基本数据类型,上面也说了,它的默认类型是Object类,所以传入的数据类型也都继承的是Object类。基本数据类型是没有继承Object类型的,所以不能使用。

类型统配符

类型通配符一般都是使用“?”代替具体的类型实参。
所以类型通配符是类型实参,而不是类型形参。

可以接受定义的类型。
在这里插入图片描述

泛型通配符上限
类/接口<? extends 实参类型>
要求该泛型的类型,只能是实参类型,或实参类型的子类类型。
在这里插入图片描述

使用泛型通配符这种方式在方法体内是不能添加元素的。

泛型通配符下限
类/接口<?super 实参类型>
要求该泛型的类型,只能是实参类型,或实参类型的父类类型。
在这里插入图片描述

泛型通配符的下限虽然在方法内可以添加元素,但是它不保证元素数据类型的要求。

泛型擦除

泛型是Java 1.5版本之后才引进的概念,在这之前是玩去没有泛型的,但是,在泛型引入后,它能很好的与之前的代码进行兼容,那是因为,泛型的信息是只存在与代码编译阶段,在进入JVM之前,将与泛型相关的信息会被全部擦除掉,我们就将这个称为类型擦除。

执行下面的代码:

import java.util.ArrayList;

public class Demo04 {
    public static void main(String[] args) {
        ArrayList<Integer> integers = new ArrayList<>();
        ArrayList<String> strings = new ArrayList<>();
        System.out.println("integers的类型为:" + integers.getClass().getSimpleName());
        System.out.println("strings的类型为:" + strings.getClass().getSimpleName());
        System.out.println(integers.getClass() == strings.getClass());
    }
}

在这里插入图片描述

我们得到的结果就是它们的本质还都是一个类型,并且它们的getClass也都是相等的。

尽管创建的时候,给的类型是不一样的,但是到底层最实质上的来讲,又都一样,这就是泛型擦除。

无限制类型擦除:
在这里插入图片描述

在编译的时候,都是将泛型转换为Object类型进行编译的。

import java.lang.reflect.Field;

public class Demo07 {
    public static void main(String[] args) {
        Demo06<Integer> demo = new Demo06<>();

        //利用反射获取demo对象里面的字节码文件的Class类对象。
        Class<? extends Demo06> aClass = demo.getClass();
        //获取所有的成员变量
        Field[] declaredField = aClass.getDeclaredFields();
        //打印成员变量中的所有名称和类型
        for (Field field : declaredField) {
        	System.out.println(field.getName() + ":" + field.getType());
            System.out.println(field.getName() + ":" + field.getType().getSimpleName());
        }
    }
}
public class Demo06<T> {
    private T key;

    public T getKey() {
        return key;
    }

    public void setKey(T key) {
        this.key = key;
    }
}

在这里插入图片描述

有限制的类型擦除:
当出现上限的时候,我们就在编译的时候,就将数据类型转换为它的上限类型。
在这里插入图片描述

在这里插入图片描述

在这里泛型方法也是同样的道理:
在这里插入图片描述

桥接方法
主要用于实现接口方面。
保持接口和类的实现关系。
在这里插入图片描述

在这里要注意到 在编译后的文件里面是有两个Info方法的。
在这里插入图片描述

泛型数组

泛型数组在创建的时候是声明带泛型的数组引用,但是不能直接创建带泛型的数组对象。
在这里插入图片描述

所以我在创建的时候,可以这样操作。

ArrayList[] arr = new ArrayList[5];
ArrayList<String>[] strArr = arr;

接着来看,我们对这样创建的集合数组添加并读取元素的代码:

在编译器是没有报错的

import java.util.ArrayList;

public class Demo09 {
    public static void main(String[] args) {
        ArrayList[] arr = new ArrayList[5];
        ArrayList<String>[] strArr = arr;

        ArrayList<Integer> intArr = new ArrayList<>();
        intArr.add(123);
        arr[0] = intArr;

        String s = strArr[0].get(0);
        System.out.println(s);
    }
}

执行这个代码,显然报错,报错指出,类型转换的异常。
在这里插入图片描述

因为我们创建的数组元素时一个Integer类型,但是数组的类型是String类型,在类型转换这里,显然是很不合理的。

所以我们在创建的时候,要注意一个小的细节,在创建的时候,应该直接赋给集合数组。

ArrayList<String>[] strArr = new ArrayList[5];

在这里插入图片描述

然后我们将代码稍作修改:

import java.util.ArrayList;

public class Demo09 {
    public static void main(String[] args) {
        ArrayList<String>[] strArr = new ArrayList[5];

        ArrayList<String> arr = new ArrayList<>();
        arr.add("123");
        strArr[0] = arr;

        String s = strArr[0].get(0);
        System.out.println(s);
    }
}

就得到了我们想要的结果:
在这里插入图片描述

在创建泛型数组的时候,我们也可以根据java.lang.reflect.Array中的newInstance(Class< T>,int)来创建T[ ]数组

直接创建是显然不能创建的。

import java.lang.reflect.Array;

public class Fruit<T> {
    private T[] arr;

    public Fruit(Class<T> tClass , int length){
        arr = (T[]) Array.newInstance(tClass,length);
    }
}

创建这个泛型类保存数组:

        Fruit<String> fruits = new Fruit<>(String.class, 3);

后面括号传入的是数据类型的class,和数组长度。

演示个例子:
在这里插入图片描述

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-06-01 15:22:00  更:2022-06-01 15:22:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 0:58:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码