java泛型(一)--泛型的简单介绍以及常用情况
2015-11-08 22:32
489 查看
一.泛型的基本概念
泛型是JavaSE5引入的一个新概念,实现了参数化类型的概念,并且使代码可以应用于多种类型。
在日常编写程序时,我们都会很注重“泛化”,像多态其实就是一种类型的泛化,将子类的对象赋给父类的引用获得更好的泛化特性,将方法的参数类型设置为父类以获得泛化特性等等...... 同样,为类声明出接口,而后对接口进行操作同样也可以获得很好的泛化特性。但是上述的方法都有一定的局限性,那就是继承与实现。继承引起了类与类之间的强耦合关系,实现接口又可能会实现一些不需要的接口。我们想去实现代码能应用于一个“不具体的类型”,而不是具体的类与接口。泛型的出现很好的帮我们实现了这一点!
二.泛型的简单使用
1.泛型与容器类的联合使用
考虑一种情况,我们需要实现一个自己的容器类,这个类仅仅持有一个对象的引用(假设持有的对象是字符串),在JavaSE5之前,我们可以编写出如下代码:
与上述代码类似,在JavaSE5以前的集合类就是用Object的数组来储存数据,每次我们向里面添加什么对象都不予以限制,在返回时需要程序员手动通过强制转换来还原对象。问题在于编译器无法得到对象的实际类型,如果我传入了一个String对象,而在返回时将其返回成Integer的话,运行期的虚拟机就会很不客气的抛出一个ClassCastException,就像这样:
而泛型的作用就是将异常转移到编译器,下面是添加了泛型后的程序:
2.泛型实现元组
很多时候我们希望retrue可以返回多个对象,在这种情况下一般就是创建一个类,让它持有需要返回的对象。考虑这样一种情况,我们需要返回非常多组(假设每组中有两个对象)数据,我们就需要为这些对象创建很多的类。有了泛型,我们就能很好的解决这个问题。
需要返回数据时我们只需要返回一个元组即可。
三.泛型的定义规则
1.泛型类的定义
在前面实现了MyHolder类,现在我们将其定义为泛型类:
仅仅需要在类名后面加上<T>即可,而后可以在类中使用T,不过只能将其作为一种类型参数来使用,而不能当做是一个真正的类。具体原因会在下面的文章中介绍。
2.泛型接口的定义
<span style="font-size:18px;color:#000000;">public interface GenericInterface<T>{
public T get();
}</span>可以看到和类的定义方式基本相同。
3.泛型方法的定义
public class GenericMethod {
public static <T> void f(T x){
}
public <T> void g(T x){
}
}泛型方法的定义比较特殊,它不需要将泛型作用在整个类上。是否拥有泛型方法,与其所在的类是否是泛型没有关系。在Thingking in java一书中给出了指导原则:如果泛型方法可以取代对整个类进行泛化时,就应该只使用泛型方法。对于静态的(static)方法,其无法访问泛型类的类型参数(T),所以如果要在static方法中使用类型参数,那么就必须要使用泛型方法。
针对泛型方法的类型参数推断
在使用泛型类时,如果我们需要创建一个对象,就需要制定类型参数的值,像这样:
ArrayList<String> list = new ArrayList<String>();
new ArrayList<String>()中的类型参数String是没有意义的(在JavaSE7中已经可以使用<>不写参数来创建对象了),在使用泛型方法的时候,我们可以不用写明参数类型,编译器会自动为我们找出类型,示例中使用的方法为上面实现的GenericMethod.class:
f("123");
f(1);
f(1.0);编译器自动为我们找出了类型,我们可以和调用正常的方法一样调用f().
下一篇文章中将详细说明泛型的擦除,边界,通配符等一些问题。
泛型是JavaSE5引入的一个新概念,实现了参数化类型的概念,并且使代码可以应用于多种类型。
在日常编写程序时,我们都会很注重“泛化”,像多态其实就是一种类型的泛化,将子类的对象赋给父类的引用获得更好的泛化特性,将方法的参数类型设置为父类以获得泛化特性等等...... 同样,为类声明出接口,而后对接口进行操作同样也可以获得很好的泛化特性。但是上述的方法都有一定的局限性,那就是继承与实现。继承引起了类与类之间的强耦合关系,实现接口又可能会实现一些不需要的接口。我们想去实现代码能应用于一个“不具体的类型”,而不是具体的类与接口。泛型的出现很好的帮我们实现了这一点!
二.泛型的简单使用
1.泛型与容器类的联合使用
考虑一种情况,我们需要实现一个自己的容器类,这个类仅仅持有一个对象的引用(假设持有的对象是字符串),在JavaSE5之前,我们可以编写出如下代码:
package com.fsc.generic; public class MyHolder { private String s; public MyHolder(String s){ this.s = s; } public String getS() { return s; } public void setS(String s) { this.s = s; } }代码很简单,也实现了持有一个对象。但是如果除了需要持有字符串外还要持有其他类呢?难道要再写一个MyHolder2类么?在泛型出现以前我们可以编写如下代码:
package com.fsc.generic; public class MyHolder { private Object obj; public MyHolder(Object obj){ this.obj = obj; } public Object getObj() { return obj; } public void setObj(String obj) { this.obj = obj; } }来看一下使用的情况:
MyHolder holderForString = new MyHolder("A String"); String s = (String) holderForString.getObj();需要对返回的数据进行强制转换,并且很容易出现问题,若我们将返回值转化为Integer,那么在运行期就会出现ClassCastException。
与上述代码类似,在JavaSE5以前的集合类就是用Object的数组来储存数据,每次我们向里面添加什么对象都不予以限制,在返回时需要程序员手动通过强制转换来还原对象。问题在于编译器无法得到对象的实际类型,如果我传入了一个String对象,而在返回时将其返回成Integer的话,运行期的虚拟机就会很不客气的抛出一个ClassCastException,就像这样:
ArrayList list = new ArrayList(); list.add("123"); list.add(1); Integer i = (Integer) list.get(0);
而泛型的作用就是将异常转移到编译器,下面是添加了泛型后的程序:
ArrayList<String> list = new ArrayList<String>(); list.add("123"); //list.add(1); 不允许向集合添加非String类型的对象 String s = list.get(0);编译器阻止了我们添加不正确的对象,也不需要我们手动进行转型,极大的避免了上述情形的发生。
2.泛型实现元组
很多时候我们希望retrue可以返回多个对象,在这种情况下一般就是创建一个类,让它持有需要返回的对象。考虑这样一种情况,我们需要返回非常多组(假设每组中有两个对象)数据,我们就需要为这些对象创建很多的类。有了泛型,我们就能很好的解决这个问题。
public class TwoTuple<A,B> { public final A first; public final B second; public TwoTuple(A first, B second){ this.first = first; this.second = second; } @Override public String toString() { return "first: "+ first+" second: "+second; } }
需要返回数据时我们只需要返回一个元组即可。
三.泛型的定义规则
1.泛型类的定义
在前面实现了MyHolder类,现在我们将其定义为泛型类:
package com.fsc.generic; public class MyHolder<T> { private T t; public MyHolder(T t){ this.t = t; } public T getT() { return t; } public void setT(T t) { this.t = t; } }
仅仅需要在类名后面加上<T>即可,而后可以在类中使用T,不过只能将其作为一种类型参数来使用,而不能当做是一个真正的类。具体原因会在下面的文章中介绍。
2.泛型接口的定义
<span style="font-size:18px;color:#000000;">public interface GenericInterface<T>{
public T get();
}</span>可以看到和类的定义方式基本相同。
3.泛型方法的定义
public class GenericMethod {
public static <T> void f(T x){
}
public <T> void g(T x){
}
}泛型方法的定义比较特殊,它不需要将泛型作用在整个类上。是否拥有泛型方法,与其所在的类是否是泛型没有关系。在Thingking in java一书中给出了指导原则:如果泛型方法可以取代对整个类进行泛化时,就应该只使用泛型方法。对于静态的(static)方法,其无法访问泛型类的类型参数(T),所以如果要在static方法中使用类型参数,那么就必须要使用泛型方法。
针对泛型方法的类型参数推断
在使用泛型类时,如果我们需要创建一个对象,就需要制定类型参数的值,像这样:
ArrayList<String> list = new ArrayList<String>();
new ArrayList<String>()中的类型参数String是没有意义的(在JavaSE7中已经可以使用<>不写参数来创建对象了),在使用泛型方法的时候,我们可以不用写明参数类型,编译器会自动为我们找出类型,示例中使用的方法为上面实现的GenericMethod.class:
f("123");
f(1);
f(1.0);编译器自动为我们找出了类型,我们可以和调用正常的方法一样调用f().
下一篇文章中将详细说明泛型的擦除,边界,通配符等一些问题。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统