泛型基础------(1)

来源:互联网 发布:淘宝店人气 编辑:程序博客网 时间:2024/06/15 02:30

1,泛型的产生意义;

2,泛型的基本使用;

3,泛型的警告信息以及泛型的擦除;

1,为什么要使用泛型?

泛型是在jdk1.5出现的, generic;为什么要使用泛型,对于这个问题,先看一个场景。

问题:

这里写图片描述

分析:

一看到这样的需求,首先就要考虑到,必须建立一个坐标点的类——Point,此类中有两个属性分别表示x坐标和y坐标,但是x和y中所保存的额数据类型会有3种(int,float,String),而要想使用一个类型就可以同时接收这三种数据类型,现在看起来似乎只能使用object,因为object类可以接收所有数据类型的数据,都会自动发生向上转型操作,这样三种数据类型将按照以下的方式进行转换:

这里写图片描述
这里写图片描述

Point的坐标是整形int类型:

class Point{    private Object x ;      // 表示X坐标    private Object y ;      // 表示Y坐标    public void setX(Object x){        this.x = x ;    }    public void setY(Object y){        this.y = y ;    }    public Object getX(){        return this.x ;    }    public Object getY(){        return this.y ;    }};public class GenericsDemo01{    public static void main(String args[]){        Point p = new Point() ; // 声明一个Point的对象        p.setX(10) ;        // 利用自动装箱操作:int --> Integer --> Object        p.setY(20) ;        // 利用自动装箱操作:int --> Integer --> Object        int x = (Integer)p.getX() ; // 取出数据先变为Integer,之后自动拆箱        int y = (Integer)p.getY() ; // 取出数据先变为Integer,之后自动拆箱        System.out.println("整数表示,X坐标为:" + x) ;        System.out.println("整数表示,Y坐标为:" + y) ;    }};

Point的坐标是浮点型float类型:

class Point{    private Object x ;      // 表示X坐标    private Object y ;      // 表示Y坐标    public void setX(Object x){        this.x = x ;    }    public void setY(Object y){        this.y = y ;    }    public Object getX(){        return this.x ;    }    public Object getY(){        return this.y ;    }};public class GenericsDemo02{    public static void main(String args[]){        Point p = new Point() ; // 声明一个Point的对象        p.setX(10.5f) ;     // 利用自动装箱操作:float --> Float --> Object        p.setY(20.6f) ;     // 利用自动装箱操作:float --> Float --> Object        float x = (Float)p.getX() ; // 取出数据先变为Integer,之后自动拆箱        float y = (Float)p.getY() ; // 取出数据先变为Integer,之后自动拆箱        System.out.println("小数表示,X坐标为:" + x) ;        System.out.println("小数表示,Y坐标为:" + y) ;    }};

Point的坐标是字符串String类型:

class Point{    private Object x ;      // 表示X坐标    private Object y ;      // 表示Y坐标    public void setX(Object x){        this.x = x ;    }    public void setY(Object y){        this.y = y ;    }    public Object getX(){        return this.x ;    }    public Object getY(){        return this.y ;    }};public class GenericsDemo03{    public static void main(String args[]){        Point p = new Point() ; // 声明一个Point的对象        p.setX("东经180度") ;      // String --> Object        p.setY("北纬210度") ;      // String --> Object        String x = (String)p.getX() ;   // 取出数据先变为Integer,之后自动拆箱        String y = (String)p.getY() ;   // 取出数据先变为Integer,之后自动拆箱        System.out.println("字符串表示,X坐标为:" + x) ;        System.out.println("字符串表示,Y坐标为:" + y) ;    }};

看起来似乎,并没有问题,似乎解决了需求,解决了3种数据类型的设置和获取,但是,真的是这样么?

上面的解决方案只是给出了这个点的两个坐标的数据类型相同的情况,比如X,Y坐标都是int或者都是float或者String,两个坐标的数据类型相同;如果这个Point,X坐标是int,Y是String或者float,一个点的两个坐标的数据类型不同了呢?通过Object方式还能解决问题么?

class Point{    private Object x ;      // 表示X坐标    private Object y ;      // 表示Y坐标    public void setX(Object x){        this.x = x ;    }    public void setY(Object y){        this.y = y ;    }    public Object getX(){        return this.x ;    }    public Object getY(){        return this.y ;    }};public class GenericsDemo04{    public static void main(String args[]){        Point p = new Point() ; // 声明一个Point的对象        p.setX(10) ;            // 利用自动装箱操作:int --> Integer --> Object        p.setY("北纬210度") ;      // String --> Object        int x = (Integer)p.getX() ; // 取出数据先变为Integer,之后自动拆箱        int y = (Integer)p.getY() ; // 取出数据先变为Integer,之后自动拆箱        System.out.println("整数表示,X坐标为:" + x) ;        System.out.println("整数表示,Y坐标为:" + y) ;    }};

对于这样的操作,编译的时候,是不会报错的,在执行的时候,会报错的。
这里写图片描述

很明显,类型转换异常了,出现了操作不当的情况了,那这个问题怎么解决呢???

其实Java中为了解决这样的问题,出现了泛型的技术。

2,什么是泛型?

上面的程序的问题,就是因为数据类型不统一而造成的,也就是说,是因为数据安全性的问题,传入的数据类型没有经过验证,没有经过类型验证,直接就传入了,并进行了转换操作,从而导致了程序的异常。

泛型可以解决数据类型的安全性问题,主要原理是在类声明的时候,通过一个标识(比如T)表示类中某个属性的类型或者是某一个方法的返回值以及参数类型。这样在类声明或实例化的时候只要制定好需要的类型即可

泛型的概念,听着似乎还是云里雾里的,简单的说就是,首先:是在类的声明的时候,其次:通过一个标识表示某个参数的类型,这个参数可以是指属性,可以是方法返回值等。

这里写图片描述

类的旁边尖括号里指定了泛型,也就是一个标识,比如T,最常用的就是这个字符是type的意思,外部在使用这个类的时候,需要指定一个具体的类型,这个具体的类型,由外部指定的,

比如:

class Demo<T>{}使用Demo<String> d=new Demo<String>();在jdk1.7以后,可以这样写:Demo d=new Demo<String>();

泛型的作用:在代码编译阶段就对数据结构进行验证,保证数据类型的安全性,这个安全性其实就是数据类型的统一,数据类型的合法性,不至于需要一个int却传入一个String的情况发生在传入数据的时候就进行验证如果需求int,那么在传入的时候通过泛型验证必须是int类型,否则不允许传入;,数据类型的 安全性的保证就是通过泛型验证,验证传入的数据是否符合该泛型或者返回值是否符合该泛型来保证的;

3,泛型的声明

声明泛型

class Point<T>{     // 此处可以随便写标识符号,T是type的简称    private T var ; // var的类型由T指定,即:由外部指定    public T getVar(){  // 返回值的类型由外部决定        return var ;    }    public void setVar(T var){  // 设置的类型也由外部决定        this.var = var ;    }};

在泛型的指定中是无法指定基本数据类型的,必须设置成一个类,这样在设一个数字的时候就必须使用包装类,jdk1.5以后提供了自动装箱,自动拆箱,操作也是非常方便。

此时泛型T是String类型,由外部使用的时候指定的,

class Point<T>{     // 此处可以随便写标识符号,T是type的简称    private T var ; // var的类型由T指定,即:由外部指定    public T getVar(){  // 返回值的类型由外部决定        return var ;    }    public void setVar(T var){  // 设置的类型也由外部决定        this.var = var ;    }};public class GenericsDemo06{    public static void main(String args[]){        Point<String> p = new Point<String>() ; // 里面的var类型为String类型        p.setVar("MLDN") ;      // 设置字符串        System.out.println(p.getVar().length()) ;   // 取得字符串的长度    }};

如果泛型是integer,但是设置内容给一个String,肯定会报错的
现在此处这个泛型T,相当于Integer,可以用它来替换,

class Point<T>{     // 此处可以随便写标识符号,T是type的简称    private T var ; // var的类型由T指定,即:由外部指定    public T getVar(){  // 返回值的类型由外部决定        return var ;    }    public void setVar(T var){  // 设置的类型也由外部决定        this.var = var ;    }};public class GenericsDemo07{    public static void main(String args[]){        Point<Integer> p = new Point<Integer>() ;   // 里面的var类型为String类型        p.setVar("MLDN") ;      // 设置字符串    }};

这里写图片描述

通过泛型,可以很好的保护数据类型的安全性。

对与之前的,数据类型不统一导致的问题,这里就可以通过泛型来进行验证

class Point<T>{    private T x ;       // 表示X坐标    private T y ;       // 表示Y坐标    public void setX(T x){        this.x = x ;    }    public void setY(T y){        this.y = y ;    }    public T getX(){        return this.x ;    }    public T getY(){        return this.y ;    }};public class GenericsPoint{    public static void main(String args[]){        Point<Integer> p = new Point<Integer>() ;        p.setX(10) ;        // 利用自动装箱操作:int --> Integer        p.setY("北纬210度") ;      // 利用自动装箱操作:int --> Integer        int x = p.getX() ;  // 自动拆箱        int y = p.getY() ;  // 自动拆箱        System.out.println("整数表示,X坐标为:" + x) ;        System.out.println("整数表示,Y坐标为:" + y) ;    }};

和使用Object方式的相比,省去了类型的强转,而且在编译器的时候就进行验证了数据类型,如果不是泛型要求的数据类型,则在程序编译的时候就会出现错误,可以保证数据类型的安全性。

4,泛型也可以在构造方法中使用

构造方法可以为类中的属性初始化,那么如果类中的属性通过泛型指定,而又需要通过构造设置属性内容的时候,那么构造方法的定义与以前并无不同,不需要像声明类那样指定泛型。
这里写图片描述

class Point<T>{     // 此处可以随便写标识符号,T是type的简称    private T var ; // var的类型由T指定,即:由外部指定    public Point(T var){        // 通过构造方法设置内容        this.var = var ;    }    public T getVar(){  // 返回值的类型由外部决定        return var ;    }    public void setVar(T var){  // 设置的类型也由外部决定        this.var = var ;    }};public class GenericsDemo08{    public static void main(String args[]){        Point<String> p = new Point<String>("MLDN") ;   // 里面的var类型为String类型        System.out.println("内容:" + p.getVar()) ;    }};

这里写图片描述

5,同时使用多个泛型

class Notepad<K,V>{     // 此处指定了两个泛型类型    private K key ;     // 此变量的类型由外部决定    private V value ;   // 此变量的类型由外部决定    public K getKey(){        return this.key ;    }    public V getValue(){        return this.value ;    }    public void setKey(K key){        this.key = key ;    }    public void setValue(V value){        this.value = value ;    }};public class GenericsDemo09{    public static void main(String args[]){        Notepad<String,Integer> t = null ;      // 定义两个泛型类型的对象        t = new Notepad<String,Integer>() ;     // 里面的key为String,value为Integer        t.setKey("李兴华") ;       // 设置第一个内容        t.setValue(30) ;            // 设置第二个内容        System.out.print("姓名;" + t.getKey()) ;      // 取得信息        System.out.print(",年龄;" + t.getValue()) ;       // 取得信息    }};

这里写图片描述

6,泛型的安全警告

在泛型应用中,最好在声明类的对象的时候指定好其内部的数据类型。比如:Info info=null;

使用中没有指定泛型会如何呢?

class Info<T>{    private T var ;    public T getVar(){        return this.var ;    }    public void setVar(T var){        this.var = var ;    }    public String toString(){       // 覆写Object类中的toString()方法        return this.var.toString() ;    }};public class GenericsDemo10{    public static void main(String args[]){        Info i = new Info() ;       // 警告,没有指定泛型类型        i.setVar("MLDN") ;          // 设置字符串        System.out.println("内容:" + i.getVar()) ;    }};

此时只是在编译期间产生了警告,但是程序依然可以执行。
这里写图片描述

在Java中为了保证程序依然可以使用,会将T设置成Object类型,这样一来,就可以接收任意的数据类型。也就是说,var的类型就是Object,所有的泛型信息将会被擦除,以上的程序就相当于下面的程序:

class Info<T>{    private T var ;    public T getVar(){        return this.var ;    }    public void setVar(T var){        this.var = var ;    }    public String toString(){       // 覆写Object类中的toString()方法        return this.var.toString() ;    }};public class GenericsDemo11{    public static void main(String args[]){        Info<Object> i = new Info<Object>() ;       // 指定Object为泛型类型        i.setVar("MLDN") ;          // 设置字符串        System.out.println("内容:" + i.getVar()) ;    }};

这里写图片描述
这样的话,就是没有警告的,因为声明了泛型,虽然是object,但是也是声明的时候指定了。所以不会有警告。

在泛型的引用中,最好在声明类的时候指定好其内部的数据类型,例如Info,但是也可以不指定类型,这样一来用户在使用这样的类时,就会出现不安全的警告信息。

这里写图片描述

总结:

1,泛型产生,是为了保证数据类型的安全性。
2,泛型的使用,是由外部指定具体的操作类型。

原创粉丝点击