当前位置: 首页 > news >正文

java泛型使用

  • 泛型的解释

    现在感觉泛型是一个值得学习的地方,就抽出时间来学习和总结一下泛型的使用。

    Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

    泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

    泛型是一种把类型的明确工作推迟到创建对象或者调用方法的时候才去明确的特殊类型。

    注意:类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。

  • 泛型出现的原因

    早期的时候,使用Object来代表任意类型。但是这样在向上转型的是没有问题的,但是在向下转型的时候存在类型转换的问题,这样的程序其实是不安全的。所以Java在JDK5之后提供了泛型来解决这个问题。

    使用泛型的典型例子,是在集合中的泛型使用。

    在使用泛型前,存入集合中的元素可以是任何类型的,当从集合中取出时,所有的元素都是Object类型,需要进行向下的强制类型转换,转换到特定的类型

    泛型的思想就是由程序员指定类型,这样集合就只能容纳该类型的元素。

  • 实例分析

      在JDK1.5之前,Java泛型程序设计是用继承来实现的。因为Object类是所用类的基类,所以只需要维持一个Object类型的引用即可。就比如ArrayList只维护一个Object引用的数组:

public class ArrayList//JDK1.5之前的
{
    public Object get(int i){......}
    public void add(Object o){......}
    ......
    private Object[] elementData;
}
  • 这样会有两个问题:

    1、没有错误检查,可以向数组列表中添加类的对象

    2、在取元素的时候,需要进行强制类型转换。这样,很容易发生错误,比如:

        /**jdk1.5之前的写法,容易出问题*/
        ArrayList arrayList1=new ArrayList();
        arrayList1.add(1);
        arrayList1.add(1L);
        arrayList1.add("asa");
        int i=(Integer) arrayList1.get(1);//因为不知道取出来的值的类型,类型转换的时候容易出错
  • 这里的第一个元素是一个长整型,而你以为是整形,所以在强转的时候发生了错误。

   所以。在JDK1.5之后,加入了泛型来解决类似的问题。例如在ArrayList中使用泛型:

       /** jdk1.5之后加入泛型*/
        ArrayList<String> arrayList2=new ArrayList<String>();  //限定数组列表中的类型
//      arrayList2.add(1); //因为限定了类型,所以不能添加整形
//      arrayList2.add(1L);//因为限定了类型,所以不能添加整长形
        arrayList2.add("asa");//只能添加字符串
        String str=arrayList2.get(0);//因为知道取出来的值的类型,所以不需要进行强制类型转换

  还要明白的是,泛型特性是向前兼容的。尽管 JDK 5.0 的标准类库中的许多类,比如集合框架,都已经泛型化了,但是使用集合类(比如 HashMap 和 ArrayList)的现有代码可以继续不加修改地在 JDK 1.5 中工作。当然,没有利用泛型的现有代码将不会赢得泛型的类型安全的好处。

一、泛型类(注意:一旦在类上声明泛型,在类里面所有非静态成员上都可以使用)

格式:public class 类名<参数类型,...>{} 当然这里<>里面也可以使用多个不同参数类型例如:public class User<T,E>{}  

注意:类型变量使用大写形式,且比较短,这是很常见的。在Java库中,使用变量E表示集合的元素类型,K和V分别表示关键字与值的类型。(需要时还可以用临近的字母U和S)表示“任意类型”。

public class ObjectTool<T>
{
    private T obj;
 
    public void setObj(T obj) {
        this.obj = obj;
    }
 
    public T getObj() {
        return obj;
    }
}
 
 
 public static void main(String[] args) {
        ObjectTool<String> obj = new ObjectTool<>();
        obj.setObj("Hello World.");
        System.out.println(obj.getObj());
    }

泛型方法

格式:public <T> 返回值 方法名(T a){}

public class ObjectTool {
    public <E> void show(E s)
    {
        System.out.println(s);
    }
}
public <E> void show(E s)
    {
        System.out.println(s);
    }
 
 
 
public static void main(String[] args) {
        ObjectTool obj = new ObjectTool();
        obj.show("Hello world.");  
   obj.show(120); }
  • 方法上的泛型和类上的泛型很像,唯一不同的是类型的作用域不同

泛型通配符

<?>:类型通配符一般是使用?代替具体的类型参数。例如 List<?> 在逻辑上是List<String>,List<Integer> 等所有List<具体类型实参>的父类。

//泛型如果明确的写的时候,前后类型必须一致
Collection<Object> c1 = new ArrayList<Object>();
Collection<Object> c2 = new ArrayList<Animal>(); //报错
Collection<Object> c3 = new ArrayList<Dog>(); //报错
 
//?表示任意类型都是可以的
Collection<?> c4 = new ArrayList<Object>();
Collection<?> c5 = new ArrayList<Animal>();
Collection<?> c6 = new ArrayList<Dog>();

<? extends E>:向下限定,只能是E及其子类

Collection<? extends Animal> c1 = new ArrayList<Object>(); //报错
Collection<? extends Animal> c2 = new ArrayList<Animal>();
Collection<? extends Animal> c3 = new ArrayList<Dog>();
Collection<? extends Animal> c4 = new ArrayList<Cat>();

<? super E>:向上限定,只能是E及其父类

Collection<? super Animal> c1 = new ArrayList<Object>();
Collection<? super Animal> c2 = new ArrayList<Animal>();
Collection<? super Animal> c3 = new ArrayList<Dog>(); //报错
Collection<? super Animal> c4 = new ArrayList<Cat>(); //报错

四、继承泛型类别

父类:

public class Parent<T1,T2>
{
    private T1 foo1;
    private T2 foo2;
    
    public T1 getFoo1()
    {
        return foo1;
    }
    public void setFoo1(T1 foo1)
    {
        this.foo1 = foo1;
    }
    public T2 getFoo2()
    {
        return foo2;
    }
    public void setFoo2(T2 foo2)
    {
        this.foo2 = foo2;
    }    

}

子类:

public class Child<T1, T2, T3> extends Parent<T1, T2>
{
    private T3 foo3;

    public T3 getFoo3()
    {
        return foo3;
    }

    public void setFoo3(T3 foo3)
    {
        this.foo3 = foo3;
    }
    
}

五、实现泛型接口

泛型接口

public interface ParentInterface<T1,T2>
{
    public void setFoo1(T1 foo1);
    public void setFoo2(T2 foo2);
    public T1 getFoo1();
    public T2 getFoo2();

}

子类实现泛型接口:

public class ChildClass<T1,T2> implements ParentInterface<T1, T2>
{
    private T1 foo1;
    private T2 foo2;
    
    @Override
    public void setFoo1(T1 foo1)
    {
        this.foo1 = foo1;
        
    }
    @Override
    public void setFoo2(T2 foo2)
    {
        this.foo2 = foo2;
    }
    @Override
    public T1 getFoo1()
    {
        return this.foo1;
    }
    @Override
    public T2 getFoo2()
    {
        return this.foo2;
    }

}

还可以在实现接口的时候定义类型:

interface Show<T,U>{
    void show(T t,U u);
}
 
class ShowTest implements Show<String,Date>{
    @Override
    public void show(String str,Date date) {
        System.out.println(str);
        System.out.println(date);
    }
}

测试一下:

public static void main(String[] args) throws ClassNotFoundException {
        ShowTest showTest=new ShowTest();
        showTest.show("Hello",new Date());
    }

 

  • 不允许使用泛型的地方

  a) 不能是静态的类型
public class GenericsExample<T>
{
   private static T member; //This is not allowed
}
  b)不能创建T的实例
public class GenericsExample<T>
{
   public GenericsExample(){
      new T();
   }
}
  c)在声明时不能和原生类型一起使用 
final List<int> ids = new ArrayList<>();    //不允许
final List<Integer> ids = new ArrayList<>(); //允许
  d) 不能创建泛型的异常类
// 引起编译错误
public class GenericException<T> extends Exception {}

 

 

转载于:https://www.cnblogs.com/ya-qiang/p/9327918.html

相关文章:

  • 【RocksDB】TransactionDB源码分析
  • 原生JS动态加载JS、CSS文件及代码脚本
  • 2-快速填充单元格
  • Linux学习笔记之文件系统
  • 所谓死锁
  • Linux下函数调用堆栈帧的详细解释【转】
  • Array.some()方法
  • python浏览器自动化测试库【2018/7/22-更新】
  • 工作踩坑系列——https访问遇到“已阻止载入混合活动内容”
  • 剥开比原看代码12:比原是如何通过/create-account-receiver创建地址的?
  • ubuntu 出错 /etc/sudoers is world writable
  • J2ee分布式架构 dubbo + springmvc + mybatis + ehcache + redis 技术介绍
  • RabbitMQ系列(五)使用Docker部署RabbitMQ集群
  • 小程序获取用户头像大图 小程序获取用户头像模糊的问题 小程序自定义转发头像模糊 小程序自定义转发分享大图...
  • mysql---表操作之创建表
  • 2019年如何成为全栈工程师?
  • Angular4 模板式表单用法以及验证
  • CEF与代理
  • Java知识点总结(JavaIO-打印流)
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • select2 取值 遍历 设置默认值
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 漂亮刷新控件-iOS
  • 前端攻城师
  • 再谈express与koa的对比
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • 阿里云API、SDK和CLI应用实践方案
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • #100天计划# 2013年9月29日
  • #我与Java虚拟机的故事#连载05:Java虚拟机的修炼之道
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • ( 10 )MySQL中的外键
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (C语言)strcpy与strcpy详解,与模拟实现
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (pytorch进阶之路)扩散概率模型
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (四) 虚拟摄像头vivi体验
  • (算法)Travel Information Center
  • ../depcomp: line 571: exec: g++: not found
  • .net core 6 集成和使用 mongodb
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • .net专家(张羿专栏)
  • @angular/cli项目构建--Dynamic.Form
  • @CacheInvalidate(name = “xxx“, key = “#results.![a+b]“,multi = true)是什么意思
  • @kafkalistener消费不到消息_消息队列对战之RabbitMq 大战 kafka
  • @SuppressWarnings(unchecked)代码的作用
  • [20171102]视图v$session中process字段含义
  • [Android Pro] android 混淆文件project.properties和proguard-project.txt
  • [BUG]Datax写入数据到psql报不能序列化特殊字符
  • [BUUCTF]-PWN:wustctf2020_number_game解析(补码,整数漏洞)
  • [C#]winform制作圆形进度条好用的圆环圆形进度条控件和使用方法