泛型 GenericParadigm
        1.泛型的产生动机
        2.泛型的使用以及通配符
        3.泛型方法的使用
        
        JDK1.5 后的三大主要新特性:泛型,枚举,Annotation
        
        泛型的产生背景

    在 Java SE 5.0 以前操作集合有许多缺点:
      一是从集合取出对象时,需要执行类型转换操作,我们在前面讲过,集合中存储都是以 Object 对象进行存储的,这无疑让我们的操作变得麻烦。
      二是由于没有类型检查,可以向集合添加任意对象,不便于我们对集合的管理,有时候甚至会导致严重的错误。

    泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。
    那么参数化类型怎么理解呢?
      顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

  

假如说现在要求你定义一个表示坐标的类:Point ,在这个类中存放有两个属性:x 坐标和 y 坐标
            但是由于此类设计特殊,现在在实际使用中可能出现有以下三种结构的数据:
                整数:x = 10, y = 10;
                小数:x = 10.0,y = 20.1;
                字符串: x = 东经 100 度,y = 北纬 30 度
            现在发现在 Point 类里面可以保存三种数据类型,而 Point 类中应该只会存在有两个属性:x 和 y
            很明显现在唯一可以想到的一定是 Object 类型,因为满足于如下的转换:
                保存 int:int > 自动装箱为 Integer > 向上转型为 Object
                保存 double:double > 自动装箱为 Double > 向上转型为 Object
                保存 String:String > 向上转型为 Object

  
                
            范例:定义 Point 类

    class Point{
private Object x;
private Object y;
public void setx(){
this.x = x;
}
public void sety(){
this.y = y;
}
public void getx(){
return x;
}
public void gety(){
return y;
}
}

于是下面通过一些重复的操作,分别保存好三个内容
        范例:坐标为整数

    // 第一步:设置坐标数据
Point p = new Point();
p.setx(10);
p.sety(20);
// 第二步:取得坐标数据
int x = (Integer) p.getx();
int y = (Integer)p.gety();
System.out.println("x= " + x + "y = " + y);

范例:坐标为小数

    // 第一步:设置坐标数据
Point p = new Point();
p.setx(10.1);
p.sety(20.0);
// 第二步:取得坐标数据
double x = (Double) p.getx();
double y = (Double)p.gety();
System.out.println("x= " + x + "y = " + y);

范例:坐标为字符串

    // 第一步:设置坐标数据
Point p = new Point();
p.setx("东经 100 度 ");
p.sety("北纬 30 度 ");
// 第二步:取得坐标数据
String x = (String) p.getx();
String y = (String)p.gety();
System.out.println("x= " + x +" "+ "y = " + y);

以上的操作的确是满足了开发要求。但是最严重的问题也就同时产生了,整个代码的实现关键在于利用了 Object 类型
        利用 Object 操作的有点在于可以接收所有的数据类型,但是缺点也就是因为优点造成的: Object 如果要接收数据那么必须进行强制性的向下转型
        
        范例:可能带来的隐患

    // 第一步:设置坐标数据
Point p = new Point();
p.setx(100);
p.sety("北纬 30 度 ");
// 第二步:取得坐标数据
String x = (String) p.getx();
String y = (String)p.gety();
System.out.println("x= " + x +" "+ "y = " + y);

以上的代码本质上讲一定会存在有问题的,但是现在的程序中明显无法发现这些问题
        因为 Object 本身就可以存放 Integer ,但是这个代码是在项目执行的时候出错
            
            Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
                at cn.mysterious.GenericParadigm.main(GenericParadigm.java:29)
                
        所以现在通过分析就可以发现。向下转型这样的操作本身就会存在有安全隐患,而且这种隐患是不能够在编写的时候检查出来的
        传统利用 Object 类来进行处理的操作永远都会有这样的问题
        那么现在既然已经出现了这样的问题,用什么样的方式可以解决此类问题呢?
        唯一的方案,不进行对象的向下转型,但是不转型有又打破了好不容易建立起来的一些优势。所以在这样的背景下产生了泛型技术
        泛型的本质:类中的属性或者方法的参数,在类定义的时候不设置具体的类型,只使用一个标记表示,而在这些类使用的时候才会为其动态的绑定一种数据类型
        
        范例:使用泛型

    class Point<T>{ // T: Type(类型),Param(参数),R:Return
private T x;
private T y;
public void setx(T x){
this.x = x;
}
public void sety(T y){
this.y = y;
}
public T getx(){
return x;
}
public T gety(){
return y;
}
}

实际上这里面就告诉使用者,此时的 Poit 类中的属性类型无法确定,必须在类实例化对象的时候动态的绑定
        
        范例:使用泛型实例化类对象

    // 第一步:设置坐标数据
Point<String> p = new Point();
p.setx("东经 100 度");
p.sety("北纬 30 度 ");
// 第二步:取得坐标数据
String x = p.getx();
String y = p.gety();
System.out.println("x= " + x +" "+ "y = " + y);

此时没有出现所谓的向上转型或者向下转型,并且操作的类型都是动态分配的
            
            如果在应用了泛型技术的类使用的时候没有设置泛型类型,JDK 默认也不会认为它出现了语法错误,也能够正常的执行
            同时使用 Object 作为默认类型
            
            如果泛型保存的死基本数据类型,则必须使用包装类处理
            
    通配符:“?”
        现在有如下泛型类

    class Message<T>{
private T info;
public void setInfo(T info) {
this.info = info;
}
public T getInfo() {
return info;
}
}

首先类的对象一定是可以发生引用传递操作的,所以以上的代码可以进行对象的引用传递
            
        范例:编写代码

    public class GenericParadigm {

        public static void main(String[] args) {
Message<String> msg = new Message<String>();
fun(msg);
System.out.println(msg.getInfo());
}
public static void fun(Message<String> temp){
temp.setInfo("hello");
}
}

但是泛型类型可以改变,所以现在将以上使用的泛型类型由 String 变为 Integer ,
            这个时候 fun() 方法将不能正常的使用,并且由于重载是受到类型而不是泛型类型的限制,那么也无法通过重载解决此问题
            可是这样的问题怎么解决呢?那么现在就必须有一种类型可以接收全部的泛型种类,有人说:方法里面不用泛型声明了
            
        范例:不用泛型,则用 Object 描述

    public class GenericParadigm {

        public static void main(String[] args) {
Message<String> msg = new Message<String>();
fun(msg);
System.out.println(msg.getInfo());
}
public static void fun(Message temp){
temp.setInfo("hello");
}
}

这个时候需要有一种标记,这种标记要满足如下要求
            可以用于泛型上,这样可以避免安全警告
            这个标记使用之后,允许接收任何内容,但是不能修改里面的数据
        为此在泛型中提供有一个重要的通配符“?”
        
        范例:使用通配符描述

    public class GenericParadigm {

        public static void main(String[] args) {
Message<String> msg = new Message<String>();
msg.setInfo("......");
fun(msg); }
public static void fun(Message<?> temp){
System.out.println(temp.getInfo());
}
}

但是在此时通配符的基础上又扩展了两个子通配符组合
            ? extends 类:设置泛型的上限,此设置可以在类或者方法参数中
                “? extends Number ”:表示可以使用的泛型只能够是 Nunber 或者是 Number 的子类
            ? super 类:设置泛型的下限 ,可以设置在方法参数中
                “? super String ”:表示只能够设置 String 或者是其父类 Object
                
        范例:设置泛型的上限

package cn.mysterious;

class Message<T extends Number >{
private T info;
public void setInfo(T info) {
this.info = info;
}
public T getInfo() {
return info;
}
} public class GenericParadigm { public static void main(String[] args) {
Message<Integer> msg = new Message<Integer>();
msg.setInfo(1010);
fun(msg); }
public static void fun(Message<? extends Number> temp){
System.out.println(temp.getInfo());
}
}

范例:设置泛型的下限

package cn.mysterious;

class Message<T >{
private T info;
public void setInfo(T info) {
this.info = info;
}
public T getInfo() {
return info;
}
} public class GenericParadigm { public static void main(String[] args) {
Message<String> msg = new Message<String>();
msg.setInfo("1111");
fun(msg); }
public static void fun(Message<? super String> temp){
System.out.println(temp.getInfo());
}
}

以后如果在看文档的时候会出现许多这样的标记,要求能看懂
            
    泛型接口(重点)
        在接口上使用泛型就是泛型接口

             // 接口:Ixxx,抽象类:Abstractxxx,普通类:直接写
interface IMessage<T >{
public void print(T t); // 此方法上使用了泛型
}

此时实现了泛型接口,但是对于泛型接口的子类有两种实现模式
            一:在子类继续使用泛型声明

    package cn.mysterious;
// 接口:Ixxx,抽象类:Abstractxxx,普通类:直接写
interface IMessage<T >{
public void print(T t); // 此方法上使用了泛型
}
class Message<P> implements IMessage<P>{
public void print(P t) {
// TODO Auto-generated method stub
System.out.println(t);
}
}
public class GenericParadigm { public static void main(String[] args) {
IMessage<String> msg = new Message<String>();
msg.print("ssssss");
}
}

二:在子类定义时不使用泛型,直接为父类接口设置好泛型类型

    package cn.mysterious;
// 接口:Ixxx,抽象类:Abstractxxx,普通类:直接写
interface IMessage<T >{
public void print(T t); // 此方法上使用了泛型
}
class MessageImpl implements IMessage<String>{
public void print(String t) {
// TODO Auto-generated method stub
System.out.println(t);
}
}
public class GenericParadigm { public static void main(String[] args) {
IMessage<String> msg = new MessageImpl();
msg.print("ssssss");
}
}

后续学习的时候一定会出现泛型接口的使用,要清楚它的两种实现模式
            
    泛型方法
        如果在一个方法上使用了泛型,那么这个方法就称为泛型方法
        泛型方法不一定非要定义在泛型声明的类中,也可能就是一个方法定义为泛型方法
        
        范例:泛型方法

    package cn.mysterious;

    public class GenericParadigm {

        public static void main(String[] args) {
Integer num[] = fun(1,2,3); // 泛型操作
for (Integer integer : num) {
System.out.println(integer);
}
}
public static <T> T[] fun(T ...arg ){ // 声明并使用泛型
return arg;
}
}

从现实来讲泛型方法能看懂就行了
            
    总结
        1.泛型解决的问题:对象向下转型所带来的安全隐患
        2.本质思想:类的属性或方法的参数都是可以由用户在使用的动态设置好的
        3.通配符:?,? extends 类,? super 类

菜鸡的Java笔记 第三十三 - java 泛型的更多相关文章

  1. 菜鸡的Java笔记 第三十七 - java 线程与进程

    线程与进程        线程与进程的区别                最早的的时候DOS 系统有一个特点:只要电脑有病毒,那么电脑就死机了,是因为传统的DOS 系统属于单进程的操作系统       ...

  2. 菜鸡的Java笔记 第三十 - java 异常的捕获及处理

    异常的捕获及处理        1.异常的产生分析以及所带来的影响        2.异常的处理的基本格式        3.异常的处理流程        4.异常的处理模式        5.自定义 ...

  3. Java从零开始学三十三(JAVA IO- File类)

    一.简述 在整个io包中,唯一表示与文件本身有关的类就是File类.使用File类可以进行创建或删除文件等常用操作.要想使用File类,则首先要观察File类的构造方法,此类的常用构造方法如下所示: ...

  4. “全栈2019”Java多线程第三十三章:await与signal/signalAll

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  5. 菜鸡的Java笔记 第三十六 - java 函数式编程

    StudyLambda    Lambda 指的是函数式编程,现在最为流行的编程模式为面向对象,很多的开发者并不认可面向对象,所以很多的开发者宁愿继续使用 C 语言进行开发,也不愿意使用java,c+ ...

  6. Java开发笔记(三十三)字符包装类型

    正如整型int有对应的包装整型Integer那样,字符型char也有对应的包装字符型Character.初始化字符包装变量也有三种方式,分别是:直接用等号赋值.调用包装类型的valueOf方法.使用关 ...

  7. 菜鸡的Java笔记 第二十八 - java 包的定义

    包的主要作用以及定义    包的导入操作    系统常见的开发包    jar 程序命令        包的定义        在任何的操作系统之中都有一个统一的共识:同一个目录下不能够存在有相同的文 ...

  8. Dynamic CRM 2013学习笔记(三十三)自定义审批流4 - 规则节点 -有分支的流程处理

    上次介绍过节点的基本配置<Dynamic CRM 2013学习笔记(三十二)自定义审批流3 - 节点及实体配置>,这次介绍下规则节点,因为有时流程里会有一些分支.合并,这时就要用到规则节点 ...

  9. Java笔记(三)异常

    异常 一.概念 一)为什么会有Java异常机制 在没有Java异常机制的情况下,唯一的退出机制就是返回值,判断是否异常的方法就是 返回值.方法根据是否异常返回不同的返回值,调用者根据不同的返回值进行判 ...

随机推荐

  1. 小米路由器4a千兆版刷openwrt

    现在网上搜小米路由器4a千兆版刷机的都是刷的padavan的,很少能找到openwrt的刷机教程. 首先刷openwrt系统的时候要先刷入引导程序breed,网上有一篇帖子写的很详细(https:// ...

  2. Java中的原子操作

    Java中的原子操作 原子性:指该操作不能再继续划分为更小的操作. Java中的原子操作包括: 除long和double之外的基本类型的赋值操作 所有引用reference的赋值操作 java.con ...

  3. firewalld dbus接口使用指南

    firewalld,一个基于动态区的iptables/nftables守护程序,自2009年左右开始开发,最新版本 - 防火墙0.6.3 - 发布于2018年10月11日.主要的开发人员是托马斯·沃纳 ...

  4. 5.2 MySQL备份工具

    物理备份: 冷备份:cp tar 逻辑备份: mysqldump mysqldump:是MySQL的客户端命令,通过mysql协议连接至mysql服务器进行备份 -A, --all-databases ...

  5. C++ 与 Visual Studio 2019 和 WSL(二)

    终端 A more integrated terminal experience | Visual Studio Blog (microsoft.com) Say hello to the new V ...

  6. 10-1 Python 学习笔记

    1. 项目 在文本编辑器中新建一个文件,写几句话来总结一下你至此学到的 Python 知识,其中每一行都以"In Python you can"打头. 将这个文件命名为learni ...

  7. 第四代富士X100F操作学习

    前言 本文为自己通过B站的UP主[阿布垃机手册]整理.原视频地址:[阿布垃机手册][布瞎BB]富士 X100F 相机外部按键 拍人像自己的设置 [X100F相机光圈大小支持F2到F16+Auto]光圈 ...

  8. [Java]Sevlet

    0 前言 对于Java程序员而言,Web服务器(如Tomcat)是后端开发绕不过去的坎.简单来看,浏览器发送HTTP请求给服务器,服务器处理后发送HTTP响应给浏览器. Web服务器负责对请求进行处理 ...

  9. 阿里大神favoorr提供的书单

     Thoughtwoks中国的推荐书单 <http://www.douban.com/doulist/2012097/ >新浪微博-秦迪 <http://blog.2baxb.me/ ...

  10. the Agiles Scrum Meeting 2

    会议时间:2020.4.10 21:00 1.每个人的工作 今天已完成的工作 yjy:debug:班级创建了个人项目不能访问班级:教师窗口的前端bug. issues:Bug:教师创建博客时显示项目为 ...