程序开发

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

2017-10-17  本文已影响0人  feisher

前言

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

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<Integer>和List<String>类型,在编译后都会变成List类型(原始类型)。Java中的泛型基本上都是在编译器这个层次来实现的,这也是Java的泛型被称为“伪泛型”的原因。

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

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

//泛型类型  ,泛型为超类Object
class Bean<T> {private T value;    }
//原始类型  
class Bean {private Object value;    }
//泛型类型 , 泛型为数值类型,支持byte,double,float,int,long,short
class 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<double>,只有List<Double>。因为当类型擦除后,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的类型的List
List<? 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());
    }
}
上一篇下一篇

猜你喜欢

热点阅读