Java集合-泛型(Generic)

目录

1、泛型(Generic)

1.1 泛型方法

1.2 泛型类

1.3 泛型接口

1.4 泛型通配符


1、泛型(Generic)

当集合中存储的对象类型不同时,那么会导致程序在运行的时候的转型异常

import java.util.ArrayList;

import java.util.Iterator;

public class Demo5 {

    public static void main(String[] args) {

       ArrayList arr = new ArrayList();

       arr.add(new Tiger("华南虎"));

       arr.add(new Tiger("东北虎"));

       arr.add(new Sheep("喜羊羊"));

       System.out.println(arr);

       Iterator it = arr.iterator();

       while (it.hasNext()) {

           Object next = it.next();

           Tiger t = (Tiger) next;

           t.eat();

       }

    }

}

class Tiger {

    String name;

    public Tiger() {

    }

    public Tiger(String name) {

       this.name = name;

    }

    @Override

    public String toString() {

       return "Tiger@name:" + this.name;

    }

    public void eat() {

       System.out.println(this.name + "吃羊");

    }

}

class Sheep {

    String name;

    public Sheep() {

    }

    public Sheep(String name) {

       this.name = name;

    }

    @Override

    public String toString() {

       return "Sheep@name:" + this.name;

    }

    public void eat() {

       System.out.println(this.name + "吃青草");

    }

}

原因 :发现虽然集合可以存储任意对象,但是如果需要使用对象的特有方法,那么就需要类型转换,如果集合中存入的对象不同,可能引发类型转换异常.

[Tiger@name:华南虎, Tiger@name:东北虎, Sheep@name:喜羊羊]

华南虎吃羊

东北虎吃羊

Exception in thread "main" java.lang.ClassCastException: cn.ittest.gz.map.Sheep cannot be cast to cn.ittest.gz.map.Tiger

    at cn.ittest.gz.map.Demo5.main(Demo5.java:17)

出现问题:

存入的是特定的对象,取出的时候是Object对象,需要强制类型转换,可能诱发类型转换异常.

无法控制存入的是什么类型的对象,取出对象的时候进行强转时可能诱发异常.而且在编译时期无法发现问题.

虽然可以再类型转换的时候通过if语句进行类型检查(instanceof),但是效率较低.(例如吃饭的时候,还需要判断米饭里有没有沙子,吃饭效率低).可以通过给容器加限定的形式规定容器只能存储一种类型的对象.

就像给容器贴标签说明该容器中只能存储什么样类型的对象。

所以在jdk5.0后出现了泛型

泛型应用:

格式

  1. 集合类<类类型>  变量名  = new  集合类<类类型>();

public class Demo5 {

    public static void main(String[] args) {

       // 使用泛型后,规定该集合只能放羊,老虎就进不来了.

       ArrayList<Sheep> arr = new ArrayList<Sheep>();

       arr.add(new Sheep("美羊羊"));

       arr.add(new Sheep("懒洋洋"));

       arr.add(new Sheep("喜羊羊"));

       // 编译失败

       // arr.add(new Tiger("东北虎"));

       System.out.println(arr);

       Iterator<Sheep> it = arr.iterator();

       while (it.hasNext()) {

           // 使用泛型后,不需要强制类型转换了

           Sheep next = it.next();

           next.eat();

       }

    }

}

1. 将运行时的异常提前至编译时发生。

2. 获取元素的时候无需强转类型,就避免了类型转换的异常问题

格式  通过<> 来指定容器中元素的类型.

什么时候使用泛型:当类中操作的引用数据类型不确定的时候,就可以使用泛型类.

JDK5.0之前的Comparable

package java.lang;

public interface Comparable {

    public int compareTo(Object o);

}

JDK5.0之后的Comparable

package java.lang;

public interface Comparable<T> {

    public int compareTo(T o);

}

这里的<T>表示泛型类型,随后可以传入具体的类型来替换它.

细节一

声明好泛型类型之后,集合中只能存放特定类型元素

public class Demo6 {

    public static void main(String[] args) {

       //创建一个存储字符串的list

       ArrayList<String> arr=new ArrayList<String>();

       arr.add("gz");

       arr.add("ittest");

       //存储非字符串编译报错.

       arr.add(1);

    }

}

细节二:

泛型类型必须是引用类型

public class Demo6 {

    public static void main(String[] args) {

       // 泛型类型必须是引用类型,也就是说集合不能存储基本数据类型

       // ArrayList<int> arr2=new ArrayList<int>();

       // 使用基本数据类型的包装类

       ArrayList<Integer> arr2 = new ArrayList<Integer>();

    }

}

细节三: 使用泛型后取出元素不需要类型转换.

public class Demo6 {

    public static void main(String[] args) {

       ArrayList<String> arr = new ArrayList<String>();

       arr.add("gzittest");

       arr.add("cdittest");

       arr.add("bjittest");

       //使用泛型后取出元素不需要类型转换.

       String str=arr.get(0);

       System.out.println();

    }

}

1.1 泛型方法

需求:写一个函数,调用者传递什么类型的变量,该函数就返回什么类型的变量?

实现一:

由于无法确定具体传递什么类型的数据.那么方法的形参就定义为Object类型.返回值也就是Object类型.但是使用该函数时需要强制类型转换.

private Object getDate(Object obj) {

       return obj;

}

当不进行强制类型转换能否写出该功能?

目前所学的知识无法解决该问题

就需要使用泛型类解决

使用的泛型的自定义来解决以上问题。

泛型: 就是将类型当作变量处理。规范泛型的定义一般是一个大写的任意字母。

1. 函数上的泛型定义

         当函数中使用了一个不明确的数据类型,那么在函数上就可以进行泛型的定义。

        public <泛型的声明> 返回值类型  函数名( 泛型 变量名  ){

        }

public static void main(String[] args) {

       int[] arr = { 1, 2, 3, 4, 5 };

       new Demo6().getData(5);

    }

    public <T> T getData(T data) {

       return data;

    }

细节:

使用泛型方法前需要进行泛型声明,使用一对尖括号 <泛型>,声明的位置在static后返回值类型前。

当一个类中有多个函数声明了泛型,那么该泛型的声明可以声明在类上。

1.2 泛型类

格式

2. 类上的泛型声明

         修饰符 class 类名<泛型>{

         }

import java.util.Arrays;

public class Demo6<T> {

    public static void main(String[] args) {

       // 使用泛型类,创建对象的时候需要指定具体的类型

       new Demo6<Integer>().getData(5);

    }

    public T getData(T data) {

       return data;

    }

    // 反序任意类型数组

    public void reverse(T[] arr) {

       int start = 0;

       int end = arr.length - 1;

       for (int i = 0; i < arr.length; i++) {

           if (start < end) {

              T temp = arr[start];

              arr[start] = arr[end];

              arr[end] = temp;

           }

       }

}

在泛型类中定义一个静态方法

public class Demo6<T> {

   public static void main(String[] args) {

      System.out.println(getData2(100));

   }

   public T getData(T data) {

      return data;

   }

   //静态方法

   public static T getData2(T data) {

      return data;

   }

}

注意:静态方法不可以使用类中定义的泛型

因为类中的泛型需要在对象初始化时指定具体的类型,而静态优先于对象存在。那么类中的静态方法就需要单独进行泛型声明,声明泛型一定要写在static后,返回值类型之前

泛型类细节:

1、创建对象的时候要指定泛型的具体类型

2、创建对象时可以不指定泛型的具体类型(和创建集合对象一眼)。默认是Object,例如我们使用集合存储元素的时候没有使用泛型就是那么参数的类型就是Object

3、类上面声明的泛型只能应用于非静态成员函数,如果静态函数需要使用泛型,那么

需要在函数上独立声明。

4、如果建立对象后指定了泛型的具体类型,那么该对象操作方法时,这些方法只能操作一种数据类型。

5、所以既可以在类上的泛型声明,也可以在同时在该类的方法中声明泛型。

泛型练习:

定义泛型成员

public class Demo7 {

    public static void main(String[] args) {

       Father<String> f = new Father<String>("jack");

       System.out.println(f.getT());

       Father<Integer> f2 = new Father<Integer>(20);

       System.out.println(f2.getT());

    }

}

class Father<T> {

    private T t;

    public Father() {

    }

    public Father(T t) {

       super();

       this.t = t;

    }

    public T getT() {

       return t;

    }

    public void setT(T t) {

       this.t = t;

    }

}

如果Father类有子类,子类该如何实现

public class Demo7 {

    public static void main(String[] args) {

       Father<String> f = new Father<String>("jack");

       System.out.println(f.getT());

       Father<Integer> f2 = new Father<Integer>(20);

       System.out.println(f2.getT());

    }

}

class Father<T> {

    private T t;

    public Father() {

    }

    public Father(T t) {

       super();

       this.t = t;

    }

    public T getT() {

       return t;

    }

    public void setT(T t) {

       this.t = t;

    }

}

//子类指定了具体的类型

class Son extends Father<String>{

}

//子类也需要使用泛型

class Son3<T> extends Father<T>{

}

//错误写法,父类上定义有泛型需要进行处理

class Son2 extends Father<T>{

}

1.3 泛型接口

public class Demo8 {

    public static void main(String[] args) {

       MyInter<String> my = new MyInter<String>();

       my.print("泛型");

       MyInter2 my2 = new MyInter2();

       my.print("只能传字符串");

    }

}

interface Inter<T> {

    void print(T t);

}

// 实现不知为何类型时可以这样定义

class MyInter<T> implements Inter<T> {

    public void print(T t) {

       System.out.println("myprint:" + t);

    }

}

//使用接口时明确具体类型。

class MyInter2 implements Inter<String> {

    @Override

    public void print(String t) {

       System.out.println("myprint:" + t);

    }

}

1.4 泛型通配符

需求:

定义一个方法,接收一个集合对象(该集合有泛型),并打印出集合中的所有元素。

例如集合对象如下格式:

Collection<Person> coll = new ArrayList<Person>();

       coll.add(new Person("jack", 20));

        coll.add(new Person("rose", 18));

       Collection<Object> coll2 = new ArrayList<Object>();

       coll2.add(new Object());

       coll2.add(new Object());

       coll2.add(new Object());

       Collection<String> coll3 = new ArrayList<String>();

       coll3.add("abc");

       coll3.add("ddd");

       coll3.add("eee");

分析,集合对象中的元素的类型是变化的,方法的形参的那么泛型类型就只能定义为Object类型.

import java.util.ArrayList;

import java.util.Collection;

import java.util.HashSet;

import java.util.Iterator;

public class Demo9 {

    public static void main(String[] args) {

        ArrayList<Object> arr = new ArrayList<Object>();

       arr.add(new Object());

       arr.add("String");

       print(arr);

      

       //将集合的泛型设置类String类型,是Object子类

       HashSet<String> hs = new HashSet<String>();

       hs.add("hello");

       hs.add("jack");

       //由于print方法接收的集合进行了元素限定,只接受限定为Object类型的集合,编译不通过

       //print(hs);

    }

    public static void print(Collection<Object> coll) {

       Iterator<Object> it = coll.iterator();

       while (it.hasNext()) {

           Object next = it.next();

           System.out.println(next);

       }

    }

}

但是,由于print方法接收的集合进行了元素限定,只接受限定为Object类型的集合,编译不通过该问题如何解决?

可以把方法的形参的泛型去掉,那么方法中就把集合中的元素当做Object类型处理.

也可以使用使用泛型通配符

public class Demo9 {

    public static void main(String[] args) {

       ArrayList<Object> arr = new ArrayList<Object>();

       arr.add(new Object());

       arr.add("String");

       print(arr);

        // 将集合的泛型设置类String类型,是Object子类

       HashSet<String> hs = new HashSet<String>();

       hs.add("hello");

       hs.add("jack");

       // 使用泛型通配符,编译通过。

       print(hs);

    }

    public static void print(Collection<?> coll) {

       Iterator<?> it = coll.iterator();

       while (it.hasNext()) {

           Object next = it.next();

           System.out.println(next);

       }

    }

}

上述就使用了泛型通配符

通配符:?

public void show(List<?> list){

}

可以对类型进行限定范围。

?extends E: 接收E类型或者E的子类型。

? super E: 接收E类型或者E的父类型。

限定泛型通配符的边界

限定通配符的上边界:

extends

接收Number 类型或者Number的子类型

正确:Vector<? extends Number> x = new Vector<Integer>();

错误:Vector<? extends Number> x = new Vector<String>();

限定通配符的下边界

super

接收Integer 或者Integer的父类型

正确:Vector<? super Integer> x = new Vector<Number>();

错误:Vector<? super Integer> x = new Vector<Byte>();

总结:

JDK5中的泛型允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定

注意:泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。

泛型的基本术语,以ArrayList<E>为例:<>念着typeof

ArrayList<E>中的E称为类型参数变量

ArrayList<Integer>中的Integer称为实际类型参数

整个称为ArrayList<E>泛型类型

整个ArrayList<Integer>称为参数化的类型ParameterizedType

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/624986.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Samtec应用分享 | 汽车应用中的视觉系统

【前言】 视觉系统在未来的汽车设计中扮演着关键的角色。 在过去&#xff0c;一直是由驾驶员掌握和应对道路上的危险&#xff0c;但现代车辆在保障驾驶安全方面发挥着前所未有的作用。 视觉系统&#xff0c;无论是可见光摄像头还是先进的探测系统&#xff0c;如激光雷达&…

rk3588 安卓调试

rknn装上了android系统&#xff0c;用type-c usb连接上电脑&#xff0c;设备管理器发现了rk3588&#xff0c;但是Android Studio没有发现设备 后来怀疑是驱动没有安装&#xff0c;我用的驱动下载地址&#xff1a; 瑞芯微Rockchip驱动安装助手(适用于RK3308 RK3399等) Mcuzone…

ARP代理

10.1.0.1/8 和10.2.0.1/8是在同一个网段 10.1.0.2/16 和10.2.0.2/16 不在同一个网段 10.1.0.1/8 和10.1.0.2/16 是可以ping通的 包发出来了&#xff0c;报文有发出来&#xff0c;目的地址是广播包 广播请求&#xff0c;发到路由器的接口G 0/0/0 target不是本接口&#xff0…

pytorch Neural Networks学习笔记

&#xff08;1&#xff09;输入图像&#xff0c;13232&#xff0c;通道数1&#xff0c;高32&#xff0c;宽32 &#xff08;2&#xff09;卷积层1&#xff0c;滤波器的shape为6155&#xff0c;滤波器个数6&#xff0c;通道数1&#xff0c;高5&#xff0c;宽5。卷积层1的输出为62…

springboot整合dubbo实现RPC服务远程调用

一、dubbo简介 1.什么是dubbo Apache Dubbo是一款微服务开发框架&#xff0c;他提供了RPC通信与微服务治理两大关键能力。有着远程发现与通信的能力&#xff0c;可以实现服务注册、负载均衡、流量调度等服务治理诉求。 2.dubbo基本工作原理 Contaniner:容器Provider&#xf…

Spring Boot 处理过滤器(filter )中抛出的异常

前言&#xff1a; 在改造老项目登录功能的时候&#xff0c;使用了过滤器对 token 进行有效性验证&#xff0c;验证通过继续进行业务请求&#xff0c;验证不通过则抛出校验异常。 过程&#xff1a; 技术方案拟定后&#xff0c;就着手开始改造&#xff0c;一切都很顺畅&#x…

机器学习-11-基于多模态特征融合的图像文本检索

总结 本系列是机器学习课程的系列课程&#xff0c;主要介绍机器学习中图像文本检索技术。此技术把自然语言处理和图像处理进行了融合。 参考 2024年&#xff08;第12届&#xff09;“泰迪杯”数据挖掘挑战赛 图像特征提取&#xff08;VGG和Resnet特征提取卷积过程详解&…

【ARFoundation自学01】搭建AR框架,检测平面点击位置克隆物体

Unity开发ARFoundation相关应用首先安装ARFoundation包 然后设置XR 1.基础AR场景框架搭建 2.一个基本的点击克隆物体到识别的平面脚本 挂在XROrigin上 脚本AppController 脚本说明书 ## 业务逻辑 AppController 脚本旨在实现一个基本的 AR 应用程序功能&#xff1a;用户通过…

Redis的Stream 和 实现队列的方式【List、SortedSet、发布订阅、Stream、Java】

Redis队列与Stream、Redis 6多线程详解 Redis队列与StreamStream总述常用操作命令生产端消费端单消费者消费组消息消费 Redis队列几种实现的总结基于List的 LPUSHBRPOP 的实现基于Sorted-Set的实现PUB/SUB&#xff0c;订阅/发布模式基于Stream类型的实现与Java的集成 消息队列问…

MaxCompute 近实时增全量处理一体化新架构和使用场景介绍

随着当前数据处理业务场景日趋复杂&#xff0c;对于大数据处理平台基础架构的能力要求也越来越高&#xff0c;既要求数据湖的大存储能力&#xff0c;也要求具备海量数据高效批处理能力&#xff0c;同时还可能对延时敏感的近实时链路有强需求&#xff0c;本文主要介基于 MaxComp…

复习回顾ES6基础篇(一小时学会es6)

基本语法 多行注释 /* 这里的所有内容 都是注释。 */单行注释 // 这是一条注释。变量定义 var x "" //定义范围变量 let y "" //定义局部变量 const z "" //定义常量运算符 变量类型 流程语句 if (condition) {/* 条件为真时运行的代…

02_Fixture定位,Caliper卡尺工具,几何学工具

Fixture定位工具 需求: 测量工件的尺寸 使用Caliper(卡尺)工具 这个时候需要借助Fixture工具 VisionPro中的图像空间 “” 图像的当前空间&#xff0c;即CogImage中的“SelectedSpaceName”表示的名字空间 “#” 像素空间&#xff0c;即坐标原点为图片左上角的坐标空间&am…