Java泛型详解-阿里云开发者社区

开发者社区> shy丶gril> 正文

Java泛型详解

简介:
+关注继续查看

一 概念

1.1 为什么需要泛型?

          当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,该对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型。因此,取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现“Java.lang.ClassCastException”异常。使用泛型就可以解决此类问题。

1.2 什么是泛型?

        泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。         

        可以在集合框架(Collection framework)中看到泛型的动机。例如,Map 类允许您向一个 Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象。因为 Map.get() 被定义为返回 Object,所以一般必须将 Map.get() 的结果强制类型转换为期望的类型,如下面的代码所示:

Map m = new HashMap();
m.put("key", "blarg");
String s = (String) m.get("key");

要让程序通过编译,必须将 get() 的结果强制类型转换为 String,并且希望结果真的是一个 String。但是有可能某人已经在该映射中保存了不是 String 的东西,这样的话,上面的代码将会抛出 ClassCastException。

理想情况下,您可能会得出这样一个观点,即 m 是一个 Map,它将 String 键映射到 String 值。这可以让您消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中。这就是泛型所做的工作。

二 定义和使用

2.1 定义

        泛型参数的命名风格为:推荐你用简练的名字作为形式类型参数的名字(如果可能,单个字符)。最好避免小写字母,这使它和其他的普通的形式参数很容易被区分开来。使用T代表类型,无论何时都没有比这更具体的类型来区分它。这经常见于泛型方法。如果有多个类型参数,我们可能使用字母表中T的临近的字母,比如S。如果一个泛型函数在一个泛型类里面出现,最好避免在方法的类型参数和类的类型参数中使用同样的名字来避免混淆。对内部类也是同样。

例:

[java] view plain copy
 print?
  1. <span style="font-size:10px;"> <span style="font-size:12px;">class Notepad<K,V>{       // 此处指定了两个泛型类型    
  2.     private K key ;     // 此变量的类型由外部决定    
  3.     private V value ;   // 此变量的类型由外部决定    
  4.     public K getKey(){    
  5.         return this.key ;    
  6.     }    
  7.     public V getValue(){    
  8.         return this.value ;    
  9.     }    
  10.     public void setKey(K key){    
  11.         this.key = key ;    
  12.     }    
  13.     public void setValue(V value){    
  14.         this.value = value ;    
  15.     }    
  16. };  </span></span>  

2.2 使用方法

2.2.1 通配符(?)与上下界(extends ,super )

        在使用泛型类的时候,既可以指定一个具体的类型,如List<String>就声明了具体的类型是String;也可以用通配符?来表示未知类型,如List<?>就声明了List中包含的元素类型是未知的。 通配符所代表的其实是一组类型,但具体的类型是未知的。List<?>所声明的就是所有类型都是可以的。但是List<?>并不等同于List<Object>。List<Object>实际上确定了List中包含的是Object及其子类,在使用的时候都可以通过Object来进行引用。而List<?>则其中所包含的元素类型是不确定。其中可能包含的是String,也可能是 Integer。如果它包含了String的话,往里面添加Integer类型的元素是错误的。正因为类型未知,就不能通过new ArrayList<?>()的方法来创建一个新的ArrayList对象。因为编译器无法知道具体的类型是什么。但是对于List<?>中的元素确总是可以用Object来引用的,因为虽然类型未知,但肯定是Object及其子类。

例:extends通配符,向上造型一个泛型对象的引用

?extends XX,XX 类是用来限定通配符的上界,XX 类是能匹配的最顶层的类,它只能匹配 XX 类以及 XX 类的子类

[java] view plain copy
 print?
  1. //原始版本  
  2. public void drawAll(List<Shape> shapes) {  
  3.      for (Shapes:shapes)   
  4.          {  
  5.            s.draw(this);  
  6.          }  
  7.     }  
  8. //使用边界通配符的版本  
  9. public void drawAll(List<?exends Shape> shapes) {  
  10.      for (Shapes:shapes)  
  11.          {  
  12.          s.draw(this);  
  13.          }  
  14.     }  

例:?super通配符,向下造型一个泛型对象的引用
? super XX,XX 类是用来限定通配符的下界,XX 类是能匹配的最底层的类,它只能匹配 XX 类及子类。

[java] view plain copy
 print?
  1. List<Shape> shapes = new ArrayList<Shape>();  
  2. List<? super Cicle> cicleSupers = shapes;  
  3. cicleSupers.add(new Cicle()); //OK, subclass of Cicle also OK  
  4. cicleSupers.add(new Shape());//Error  


2.2.2 泛型接口

[java] view plain copy
 print?
  1. <span style="font-size:12px;">   interface Info<T>{        // 在接口上定义泛型    
  2.        public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型    
  3.    }    
  4.    class InfoImpl<T> implements Info<T>{   // 定义泛型接口的子类    
  5.        private T var ;             // 定义属性    
  6.        public InfoImpl(T var){     // 通过构造方法设置属性内容    
  7.            this.setVar(var) ;      
  8.        }    
  9.        public void setVar(T var){    
  10.            this.var = var ;    
  11.        }    
  12.        public T getVar(){    
  13.            return this.var ;    
  14.        }    
  15.    };    
  16.    public class GenericsDemo24{    
  17.        public static void main(String arsg[]){    
  18.            Info<String> i = null;        // 声明接口对象    
  19.            i = new InfoImpl<String>("汤姆") ;  // 通过子类实例化对象    
  20.            System.out.println("内容:" + i.getVar()) ;    
  21.        }    
  22.    };    
  23.    ----------------------------------------------------------    
  24.    interface Info<T>{        // 在接口上定义泛型    
  25.        public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型    
  26.    }    
  27.    class InfoImpl implements Info<String>{   // 定义泛型接口的子类    
  28.        private String var ;                // 定义属性    
  29.        public InfoImpl(String var){        // 通过构造方法设置属性内容    
  30.            this.setVar(var) ;      
  31.        }    
  32.        public void setVar(String var){    
  33.            this.var = var ;    
  34.        }    
  35.        public String getVar(){    
  36.            return this.var ;    
  37.        }    
  38.    };    
  39.    public class GenericsDemo25{    
  40.        public static void main(String arsg[]){    
  41.            Info i = null;      // 声明接口对象    
  42.            i = new InfoImpl("汤姆") ;    // 通过子类实例化对象    
  43.            System.out.println("内容:" + i.getVar()) ;    
  44.        }    
  45.    };  </span>  

2.2.3 泛型数组

[java] view plain copy
 print?
  1. public class GenericsDemo30{    
  2.     public static void main(String args[]){    
  3.         Integer i[] = fun1(1,2,3,4,5,6) ;   // 返回泛型数组    
  4.         fun2(i) ;    
  5.     }    
  6.     public static <T> T[] fun1(T...arg){  // 接收可变参数    
  7.         return arg ;            // 返回泛型数组    
  8.     }    
  9.     public static <T> void fun2(T param[]){   // 输出    
  10.         System.out.print("接收泛型数组:") ;    
  11.         for(T t:param){    
  12.             System.out.print(t + "、") ;    
  13.         }    
  14.     }    
  15. };    


转载:http://blog.csdn.net/chaoyu168/article/details/49360529

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
3140 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
4550 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
5761 0
windows server 2008阿里云ECS服务器安全设置
最近我们Sinesafe安全公司在为客户使用阿里云ecs服务器做安全的过程中,发现服务器基础安全性都没有做。为了为站长们提供更加有效的安全基础解决方案,我们Sinesafe将对阿里云服务器win2008 系统进行基础安全部署实战过程! 比较重要的几部分 1.
5500 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
2197 0
如何设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云安全组设置详细图文教程(收藏起来) 阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程。阿里云会要求客户设置安全组,如果不设置,阿里云会指定默认的安全组。那么,这个安全组是什么呢?顾名思义,就是为了服务器安全设置的。安全组其实就是一个虚拟的防火墙,可以让用户从端口、IP的维度来筛选对应服务器的访问者,从而形成一个云上的安全域。
4007 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
1144 0
+关注
1878
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载