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<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());
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容

  • 泛型是Java 1.5引入的新特性。泛型的本质是参数化类型,这种参数类型可以用在类、变量、接口和方法的创建中,分别...
    何时不晚阅读 3,037评论 0 2
  • 开发人员在使用泛型的时候,很容易根据自己的直觉而犯一些错误。比如一个方法如果接收List作为形式参数,那么如果尝试...
    时待吾阅读 1,055评论 0 3
  • 泛型的好处 使用泛型的好处我觉得有两点:1:类型安全 2:减少类型强转 下面通过一个例子说明: 假设有一个Tes...
    德彪阅读 1,126评论 0 0
  • 前面,由于对泛型擦除的思考,引出了对Java-Type体系的学习。本篇,就让我们继续对“泛型”进行研究: JDK1...
    贾博岩阅读 5,152评论 3 28
  • 文章作者:Tyan博客:noahsnail.com 1. 什么是泛型 Java泛型(Generics)是JDK 5...
    SnailTyan阅读 773评论 0 3