java泛型——从源头杜绝类型转换异常—基本使用姿势浅析

来源:互联网 发布:ipad比下软件 编辑:程序博客网 时间:2024/05/18 11:25

java泛型——从源头杜绝类型转换异常—基本使用姿势浅析

前言

泛型利用类型参数让代码具有更好的可读性,并且在编译期就对类型进行规范约束,从而从源头解决类型问题

Ps:Java从1.5之后支持泛型

List<String> sList=new ArrayList<>();//最常见的例子 sList.add("str");   sList.add(1); //编译错误  

实现原理

类型擦除

//简单的验证下类型擦除ArrayList<String> aString=new ArrayList<String>();     ArrayList<Integer> aInteger=new ArrayList<Integer>();     System.out.println(aString.getClass()==aInteger.getClass()); //发现结果为true。

在编译期间,所有的泛型信息都会被擦除,List和List类型,在编译后都会变成List类型(原始类型)。Java中的泛型基本上都是在编译器这个层次来实现的,这也是Java的泛型被称为“伪泛型”的原因。

那 什么是“原始类型”呢?

原始类型就是泛型类型擦除了泛型信息后,在字节码中真正的类型。无论何时定义一个泛型类型,相应的原始类型都会被自动提供。原始类型的名字就是删去类型参数后的泛型类型的类名。擦除类型变量,并替换为*限定类型(T为无限定的*类型变量,用Object替换)。

//泛型类型  ,泛型为超类Objectclass Bean<T> {private T value;    }//原始类型  class Bean {private Object value;    }
//泛型类型 , 泛型为数值类型,支持byte,double,float,int,long,shortclass Bean<T extends Number> {private T value;    }//原始类型  class Bean {private Number value;    }

数值类型,点击查看官方解释

泛型使用注意事项

1.不可以在静态变量,静态方法中直接使用

public class Test<T> {          public static T key;   //编译错误,静态存在的时候对象还没有实例化,不知道泛型是什么          public static  T show(T one){ //编译错误              return null;          }     public static <T>T show(T one){//这是正确的,此处使用的泛型T是方法自身的T              return null;          }      }    

2.泛型不能是基本数据类型

比如:没有List,只有List。因为当类型擦除后,List的原始类中的类型变量(T)替换为Object,但Object类型不能存储double值。

基本数据类型:int、short、float、double、long、boolean、byte、char

对应包装类:Integer、Short、Float、Double、Long、Boolean、Byte、Character

String 是引用数据类型

3.泛型类型引用传递

ArrayList<String> aList1=new ArrayList<Object>();//编译错误,要求一致不支持转型,违背设计原则ArrayList<Object> aList1=new ArrayList<String>();//编译错误   

其实这个问题基本不会存在,因为(在java6以上)后面可以直接使用new ArrayList<>(),IDE会直接默认写好

List<String> rawList = new ArrayList();Java 5的javac编译器会产生类型未检查的警告  注意: test.java使用了未检查或称为不安全的操作;这种警告可以使用@SuppressWarnings("unchecked")注解来屏蔽。

4.运行时类型查询

ArrayList<String> arrayList=new ArrayList<>();if( arrayList instanceof ArrayList<String>) //运行报错  //因为类型擦除之后,ArrayList<String>只剩下原始类型,泛型信息String不存在了。  //解决方案if( arrayList instanceof ArrayList<?>)//正确,?为通配符,也即非限定符。

5.限定通配符和非限定通配符

List<? extends T>可以接受任何继承自T的类型的ListList<? super T>可以接受任何T的父类构成的List  //例子  List<? extends Number>可以接受List<Integer>或List<Float>//Byte,Double,Long,Short 几种数值类型

泛型使用场景

1.集合框架/数组

ArrayList<Object> aList1=new ArrayList<>(); 
// 接收可变参数 返回泛型数组public static <T> T[] fun1(T...arg){ return arg ;  }//调用方法Integer i[] = fun1(1,2,3,4,5,6)

2.泛型类 ——对象的引用传递

//进行引用传递的时候泛型必须匹配才可以传递,否则无法传递。class Info<T>{ private T var ; // 定义泛型变量   public void setVar(T var){   this.var = var ;   } }

3.泛型接口

泛型接口很类似泛型类:访问权限 +interface +接口名称 + <泛型标示>{}

// 泛型接口  定义抽象方法,抽象方法的返回值就是泛型类型interface Info<T> {      public T getVar();    }//实现类__方式1   getter/setter方法略class InfoImpl implements Info<String> {    private String mVar;    public InfoImpl(String var) {this.mVar=var;}}//实现类__方式2  getter/setter方法略class InfoImpl2<T> implements Info<T> {     private T mVar;    public InfoImpl2(T var) {this.mVar=var; }}//测试类public class Test {    public static void main(String arsg[]) {        Info i = new InfoImpl("hello world"); // 通过子类实例化对象        System.out.println("方式一内容:" + i.getVar());        Info<String> j = new InfoImpl<String>("soyoungboy");       System.out.println("方式二内容:" + j.getVar());    }}

4.泛型方法(可用在2,3 中也可用在其他位置)

//来个简单案例。泛型方法(对象设置特定属性)    public static <T extends Number> T setValue(T x){            return x;        }   
//T, E or K,V等被广泛认可的类型占位符public V put(K key, V value) {      return cache.put(key, value);  }  

5.泛型嵌套 —— 泛型类的深入使用

//一个普通的泛型类,接收两个泛型变量,省略setter方法class Info<T, V> {    private T var;    private V value;    public Info(T var, V value) {        this.var =var;        this.value =value;    }    public T getVar() {return var;}    public V getValue() { return value;}}//一个嵌套了泛型类的泛型类user,  可能存在一个mannager类也嵌套info泛型类class User<S> {    public S info;    public User(S info) {this.info=info;}    public S getInfo() {return info;}}//测试类public class test {    public static void main(String args[]) {        User<Info<String, Integer>> d = null;        Info<String, Integer> i = null;        i = new Info<String, Integer>("feisher", 29);        d = new User<Info<String, Integer>>(i);        System.out.println("姓名:" + d.getInfo().getVar());        System.out.println("年龄:" + d.getInfo().getValue());    }}
阅读全文
1 0
原创粉丝点击