热门标签 | HotTags
当前位置:  开发笔记 > 人工智能 > 正文

Java泛型定义与用法实例详解

这篇文章主要介绍了Java泛型定义与用法,结合实例形式较为详细的分析了Java中泛型的概念、原理、定义、使用方法及相关操作注意事项,需要的朋友可以参考下

本文实例讲述了Java泛型定义与用法。分享给大家供大家参考,具体如下:

1. 泛型的由来

先看如下代码:

import java.util.List;
import java.util.ArrayList;
public class TestGeneric {
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(1);
        list.add("1");
        list.add(new Object());
        System.out.println(list);
        // 取值
        Integer var1 = (Integer) list.get(0);
        String var2 = (String) list.get(1);
        Object var3 = list.get(2);
        System.out.println(var1 + " " + var2 + " " + var3);
    }
}

运行结果:

[1, 1, java.lang.Object@1db9742]
1 1 java.lang.Object@1db9742

这段代码很简单,将整形、字符串、对象放进list集合中,然后逐一取出。可以看出,由于List接口在定义时并不知道元素的类型,因此默认为Object,即任意类型元素进入list集合后都会自动装箱。而取值的过程更为复杂,所有取得的值都是装箱后的Object对象,必须得知道每一个元素的初始类型才能拆箱。一般使用集合的时候,集合的元素往往都是具有共同特征的,比如同属于一类的----那么,如果一开始限定了list集合元素的类型,那么就可避免上述不规范操作。代码如下,

import java.util.List;
import java.util.ArrayList;
public class TestGeneric {
    @SuppressWarnings("unused")
    public static void main(String[] args) {
        List list = new ArrayList();
        // list.add(1);//报错
        // list.add(new Object());//报错
        list.add("1");
        // 取值
        String var1 = list.get(0);// 无需转换
    }
}

如此一来,便有了泛型集合的说法。实际上,查阅List接口的Api会发现,List接口正是泛型接口,它可以接受一个类型参数E,若不传递参数,则默认是Object类型。

2. 泛型类型的继承关系

有如下功能的代码,实现打印任意集合的元素:

import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
public class TestGeneric{
    //打印任意集合元素
    public void print(Collection c){
     System.out.println(c);
    }
    public static void main(String[] args){
     List list=new ArrayList();
     new TestGeneric().print(list);
 }
}

输出:

TestGeneric.java:11: 无法将 TestGeneric 中的 print(java.util.Collection) 应用于 (java.util.List)
   new TestGeneric().print(list);
                    ^
1 错误

很明显,意思就是传递的参数类型不匹配。难道String不是继承自Object的吗?没错,String是继承自Object的,但是ListList是截然不同的两个类型,两者之间没有任何继承关系。那如果真的要实现上面的功能,该如何呢?

2.1 类型通配符

import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
public class TestGeneric {
    // 打印任意集合元素
    public void print(Collection<&#63;> c) {
        System.out.println(c);
    }
    public static void main(String[] args) {
        List list = new ArrayList();
        new TestGeneric().print(list);
    }
}

程序正常执行,这里的?表示一个未知类型,这个未知类型与Object不同,List<&#63;>代表了所有的List<类型>的父类。

2.2 泛型方法

不只有通配符可以解决泛型继承的问题,若将上面的方法定义为泛型方法也具有同样的效果:

import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
public class TestGeneric {
    // 打印任意集合元素
    public  void print(Collection c) {
        System.out.println(c);
    }
    public static void main(String[] args) {
        List list = new ArrayList();
        new TestGeneric().print(list);
    }
}

泛型方法的定义形式如下,

修饰符 返回值 方法名(形参)

其中在修饰符的后面做为类型定义,为方法指明形参中需要用到的T,E类型是来自哪里。既然泛型方法和类型通配符都可以实现泛型中的继承,那么有什么区别?

2.3 泛型方法和通配符的区别

看如下代码:

import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
public class TestGeneric {
    // 打印任意集合元素
    public  void print(Collection c1, Collection c2) {
        System.out.println(c1);
        System.out.println(c2);
    }
    public static void main(String[] args) {
        List list1 = new ArrayList();
        List list2 = new ArrayList();
        new TestGeneric().print(list1, list2);// 传2个father类型
        List list3 = new ArrayList();
        List list4 = new ArrayList();
        new TestGeneric().print(list3, list4);// T为child,E为father
        List list5 = new ArrayList();
        List list6 = new ArrayList();
        new TestGeneric().print(list5, list6);// T为father,E为child,报错
    }
}
class Father {
}
class Child extends Father {
}
class Other {
}

上述泛型方法在定义T,E时已经指明了关系:T是E的子类,所以在传递参数的时候,T要么是E的子类,要么就是E本身,所以在传递关系不小心变为E exends T时,在第三次调用方法时报错了。而如果把上述代码换成?通配符的话,则不具有如此强的限定关系。

总之,泛型方法和?通配符都可以实现未知类型的继承,但是泛型方法主要强调多个未知类型之间的依赖关系。如果只是单纯用作成为一个通用类型的父类这一功能的话,两者都可以实现,反而?通配符较为简洁明了。

2.4 泛型参数上、下限的注意

看如下代码:

import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
public class TestGeneric {
    // 复制集合并返回原始集合的最后一个元素
    public  T copy(Collection des, Collection<&#63; extends T> src) {
        T lastElement = null;
        for (T t : src) {
            lastElement = t;
            des.add(t);
        }
        return lastElement;
    }
    public static void main(String[] args) {
        List des = new ArrayList();
        List src = new ArrayList();
        src.add(new Integer(1));
        Integer lastElement = new TestGeneric().copy(des, src);//
        System.out.println(lastElement.getClass());
    }
}

输出:

TestGeneric.java:18: 不兼容的类型
找到: java.lang.Number
需要: java.lang.Integer
Integer lastElement= new TestGeneric().copy(des,src);//
                                              ^
1 错误

当调用完copy方法后,系统比对发现T类型为Number,&#63;类型为Integer。所以函数返回的T类型是Number了,所以根本不兼容Integer。要修改上面的代码,有俩个办法,

方法1:

改为

Number lastElement=new TestGeneric().copy(des,src);

分析代码可以得出,?为T的子类,在方法中T=lastElement这句表现为多态,虽然返回的是T类型,但是多态的表现为?类型,即Interger类型,调用lastElement.getClass()也可发现返回的是java.lang.Integer类型,说明此处编译类型为T类型,实际运行类型为?类型。这就好比如下多态转换,

Father f=new Child();
Child c=f;//此处一定报错,类型不兼容

虽然f的多态表现为子类Child,但是上面一句连语法检测都过不了。这也就是为什么上面Integer不能兼容Number的原因了。

方法2:

改为

public  T copy(Collection<&#63; super T> des,Collection src)

这样一来,?类型变为了父类,T类型变为了子类,于是在方法中返回的T类型对象,即lastElement就不具有多态性了。泛型中的上下限是很有学问的,每次看源码时都会琢磨很久,但还是会在浩瀚的接口+泛型的设计中昏迷,这种设计真的完全是为了突出面向对象的特性,以后慢慢琢磨吧。

从这也再次可以看出?通配符在处理具有依赖关系的泛型方法中,显得过于灵活而会导致一些潜在的隐患。

更多关于java算法相关内容感兴趣的读者可查看本站专题:《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》

希望本文所述对大家java程序设计有所帮助。


推荐阅读
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • “你永远都不知道明天和‘公司的意外’哪个先来。”疫情期间,这是我们最战战兢兢的心情。但是显然,有些人体会不了。这份行业数据,让笔者“柠檬” ... [详细]
  • 生成对抗式网络GAN及其衍生CGAN、DCGAN、WGAN、LSGAN、BEGAN介绍
    一、GAN原理介绍学习GAN的第一篇论文当然由是IanGoodfellow于2014年发表的GenerativeAdversarialNetworks(论文下载链接arxiv:[h ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 无线认证设置故障排除方法及注意事项
    本文介绍了解决无线认证设置故障的方法和注意事项,包括检查无线路由器工作状态、关闭手机休眠状态下的网络设置、重启路由器、更改认证类型、恢复出厂设置和手机网络设置等。通过这些方法,可以解决无线认证设置可能出现的问题,确保无线网络正常连接和上网。同时,还提供了一些注意事项,以便用户在进行无线认证设置时能够正确操作。 ... [详细]
  • 本文介绍了游戏开发中的人工智能技术,包括定性行为和非定性行为的分类。定性行为是指特定且可预测的行为,而非定性行为则具有一定程度的不确定性。其中,追逐算法是定性行为的具体实例。 ... [详细]
  • JavaScript设计模式之策略模式(Strategy Pattern)的优势及应用
    本文介绍了JavaScript设计模式之策略模式(Strategy Pattern)的定义和优势,策略模式可以避免代码中的多重判断条件,体现了开放-封闭原则。同时,策略模式的应用可以使系统的算法重复利用,避免复制粘贴。然而,策略模式也会增加策略类的数量,违反最少知识原则,需要了解各种策略类才能更好地应用于业务中。本文还以员工年终奖的计算为例,说明了策略模式的应用场景和实现方式。 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • 本文详细介绍了相机防抖的设置方法和使用技巧,包括索尼防抖设置、VR和Stabilizer档位的选择、机身菜单设置等。同时解释了相机防抖的原理,包括电子防抖和光学防抖的区别,以及它们对画质细节的影响。此外,还提到了一些运动相机的防抖方法,如大疆的Osmo Action的Rock Steady技术。通过本文,你将更好地理解相机防抖的重要性和使用技巧,提高拍摄体验。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 无损压缩算法专题——LZSS算法实现
    本文介绍了基于无损压缩算法专题的LZSS算法实现。通过Python和C两种语言的代码实现了对任意文件的压缩和解压功能。详细介绍了LZSS算法的原理和实现过程,以及代码中的注释。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • JVM 学习总结(三)——对象存活判定算法的两种实现
    本文介绍了垃圾收集器在回收堆内存前确定对象存活的两种算法:引用计数算法和可达性分析算法。引用计数算法通过计数器判定对象是否存活,虽然简单高效,但无法解决循环引用的问题;可达性分析算法通过判断对象是否可达来确定存活对象,是主流的Java虚拟机内存管理算法。 ... [详细]
  • 本文介绍了数模国赛的报名参加方法,包括学校报名和自己报名的途径。同时给出了建模竞赛的建议,重在历练的同时掌握方法以及弥补自己的短板。此外,还分享了论文的结构和模型求解部分的注意事项,包括数学命题的表述规范和计算方法的原理等。 ... [详细]
author-avatar
伤恋ZY_162
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有