Java中泛型的理解(一)
2015-10-07 00:22
645 查看
泛型是一种程序设计手段,使用泛型机制编写的程序代码要比那些杂乱地使用Obeject变量,然后再进行强制类型转换的代码具有更好的安全性和可读性
一.为什么要使用泛型程序设计
泛型程序设计(Generic Programming)意味着编写的代码可以被很多不同类型的对象所重用
例:
设计一个可以表示坐标点的类,坐标由x和y组成,表示方法如下:
整数表示:x=10,y=20
字符串表示:x=“东经180度”,y=“北纬210度”
如何设计该类?
分析:建立一个叫做Point的类,类中有x、y两个属性。只是这两个属性有两种数据类型(int,String),要想同时接收这样的两种数据,只能使用Object类,因为Object类可以接收任意数据类型的数据,都会发生向上转型操作:
int-->自动装箱成Integer-->向上转型使用Obeject接收
String-->向上转型使用Object接收
所以我们可以设计出以下程序:
将上面的主方法改为:
虽然实现了,但是上面的程序有一定的问题,假如有人将主方法写为
这时编译不会出现异常,执行时出现类型转换异常,即传统的实现方法会出现操作不当的情况,此时就需要泛型来解决这个问题,这也就是为什么泛型程序设计会具有更高的安全性
二.泛型的用法
1.泛型类
一个泛型类就是具有一个或多个类型变量的类
泛型类定义格式:
泛型对象定义:
类名称<具体类> 对象名称 = new 类名称<具体类>();
p.setVar("Jack")是用来设置内容的,如果设置的内容与指定的泛型类型不一致,则在编译时将出现错误,可以更好的保护数据类型
利用泛型将例子写出来如下:
除此之外在泛型中可以同时指定多个泛型类型:
在泛型类的构造方法中使用泛型
2.泛型方法
泛型方法中可以定义泛型参数,此时参数的类型就是传入数据的类型,定义如下:
[访问权限] <泛型标识> 泛型标识 方法名称(泛型标识 参数名称){}
fun()方法是在普通类中定义的,当然也可以在泛型类中定义。注意:类型变量放在修饰符(public static)后面,返回类型的前面
当调用一个泛型方法时,在方法名前的尖括号里放入具体的类型,如上String str = d.<String>fun("Jack"),但是实际情况下,方法调用中可以省略<String>参数,因为编译器能够推断出所调用方法的参数类型
可以看出,如果在方法中定义了泛型,则可以传递任意数据类型
三.泛型的警告信息及泛型的擦除
在创建泛型类对象时,如果没声明具体泛型类型,编译时会产生安全警告,但是并不会影响执行
我们可以看到创建Point类对象时并没有指定泛型的类型,即Point类并没有指定泛型的类型,则java中为了保证程序依然可以使用,会将T设置成Object类型,说明此时var的类型就是Object,所有的泛型信息将会被擦除,实际上,以上程序相当于如下代码:
此时并不会出现警告,所以说在泛型应用中最好在声明类的时候指定好其内部的数据类型,例如"Point<String>",如果不声明类型,用户在使用中就会出现不安全的警告信息
参考资料:
李兴华java相关视频
java核心技术卷一
一.为什么要使用泛型程序设计
泛型程序设计(Generic Programming)意味着编写的代码可以被很多不同类型的对象所重用
例:
设计一个可以表示坐标点的类,坐标由x和y组成,表示方法如下:
整数表示:x=10,y=20
字符串表示:x=“东经180度”,y=“北纬210度”
如何设计该类?
分析:建立一个叫做Point的类,类中有x、y两个属性。只是这两个属性有两种数据类型(int,String),要想同时接收这样的两种数据,只能使用Object类,因为Object类可以接收任意数据类型的数据,都会发生向上转型操作:
int-->自动装箱成Integer-->向上转型使用Obeject接收
String-->向上转型使用Object接收
所以我们可以设计出以下程序:
class Point{ private Object x; //表示x坐标 private Object y; //表示y坐标 public void setX(Object x){ this.x = x; } public void setY(Object y){ this.y = y; } public Object getX(){ return this.x; } public Object getY(){ return this.y; } } public class GenericDemo01{ public static void main(String[] args){ Point p = new Point(); p.setX(10); //利用自动装箱操作:int-->Integer p.setY(20); int x = (Integer)p.getX(); //取出数据后先变为Integer类型,然后自动拆箱 int y = (Integer)p.getY(); System.out.println("整数表示,x坐标为:"+x); System.out.println("整数表示,y坐标为:"+y); } }
将上面的主方法改为:
public static void main(String[] args){ Point p = new Point(); p.setX("东经180度"); //向上转型:String-->Object p.setY("北纬210度"); String x = (String)p.getX(); //取出数据后强制类型转换变为String类型 String y = (String)p.getY(); System.out.println("字符串表示,x坐标为:"+x); System.out.println("字符串表示,y坐标为:"+y); } }
虽然实现了,但是上面的程序有一定的问题,假如有人将主方法写为
p.setX(10); //向上转型:String-->Object p.setY("北纬210度"); int x = (Integer)p.getX(); //取出数据后强制类型转换变为String类型 int y = (Integer)p.getY();
这时编译不会出现异常,执行时出现类型转换异常,即传统的实现方法会出现操作不当的情况,此时就需要泛型来解决这个问题,这也就是为什么泛型程序设计会具有更高的安全性
二.泛型的用法
1.泛型类
一个泛型类就是具有一个或多个类型变量的类
泛型类定义格式:
class 类名称<泛型类型,泛型类型,...>{} 具体: [访问权限]class 类名称<泛型类型1,泛型类型2,...>{ [访问权限]泛型类型标识 变量名称; [访问权限]泛型类型标识 方法名称(){}; [访问权限]返回值类型声明 方法名称(泛型类型标识 变量名称){}; }
泛型对象定义:
类名称<具体类> 对象名称 = new 类名称<具体类>();
class Point<T>{ private T var; //var的类型由T指定,即:由外部指定 public T getVar(){ //返回值类型由安慰、外部决定 return var; } public void setVar(T var){ //设置类型也由外部决定 this.var = var; } } public class GenericDemo03{ public static void main(String[] args){ Point<String> p = new Point<String>(); p.setVar("Jack"); System.out.println(p.getVar()); } }
p.setVar("Jack")是用来设置内容的,如果设置的内容与指定的泛型类型不一致,则在编译时将出现错误,可以更好的保护数据类型
利用泛型将例子写出来如下:
class Point<T>{ private T x; //表示x坐标 private T y; //表示y坐标 public void setX(T x){ this.x = x; } public void setY(T y){ this.y = y; } public T getX(){ return this.x; } public T getY(){ return this.y; } } public class GenericDemo04{ public static void main(String[] args){ Point<Integer> p = new Point<Integer>(); p.setX(10); //利用自动装箱操作:int-->Integer p.setY(20); //int x = (Integer)p.getX(); //取出数据后先变为Integer类型,然后自动拆箱 //int y = (Integer)p.getY(); int x = p.getX(); int y = p.getY(); System.out.println("整数表示,x坐标为:"+x); System.out.println("整数表示,y坐标为:"+y); } }这里明显看出,程序中了少了类型强制转换的部分,而且更加安全,如果设置的内容不是int类型,则在编译时会报错
除此之外在泛型中可以同时指定多个泛型类型:
class Point<K,V>{ private K key; private V value; public Point(K key,V value){ this.setKey(key); this.setValue(value); } public K getKey(){ return this.key; } public V getValue(){ return this.value; } public void setKey(K key){ this.key = key; } public void setValue(V value){ this.value = value; } public String getInfo(){ return "姓名:"+key+"\t年龄:"+value; } } public class GenericDemo06{ public static void main(String[] args){ Point<String,Integer> p = new Point<String,Integer>("Jack",30); System.out.println(p.getInfo()); } }
在泛型类的构造方法中使用泛型
public Point(T var){} class Point<T>{ private T var; //var的类型由T指定,即:由外部指定 public Point(T var){ this.setVar(var); } public T getVar(){ //返回值类型由安慰、外部决定 return var; } public void setVar(T var){ //设置类型也由外部决定 this.var = var; } } public class GenericDemo05{ public static void main(String[] args){ Point<String> p = new Point<String>("Jack"); System.out.println(p.getVar()); } }
2.泛型方法
泛型方法中可以定义泛型参数,此时参数的类型就是传入数据的类型,定义如下:
[访问权限] <泛型标识> 泛型标识 方法名称(泛型标识 参数名称){}
class Demo{ public static <T> T fun(T t){ return t; } } public class GenericDemo07{ public static void main(String[] args){ Demo d = new Demo(); String str = d.<String>fun("Jack"); int i = d.<Integer>fun(30); System.out.println(str); System.out.println(i); } }
fun()方法是在普通类中定义的,当然也可以在泛型类中定义。注意:类型变量放在修饰符(public static)后面,返回类型的前面
当调用一个泛型方法时,在方法名前的尖括号里放入具体的类型,如上String str = d.<String>fun("Jack"),但是实际情况下,方法调用中可以省略<String>参数,因为编译器能够推断出所调用方法的参数类型
public class GenericDemo07{ public static void main(String[] args){ Demo d = new Demo(); String str = d.fun("Jack"); int i = d.fun(30); System.out.println(str); System.out.println(i); } }
可以看出,如果在方法中定义了泛型,则可以传递任意数据类型
三.泛型的警告信息及泛型的擦除
class Point<T>{ private T var; //var的类型由T指定,即:由外部指定 public Point(T var){ this.setVar(var); } public T getVar(){ //返回值类型由安慰、外部决定 return var; } public void setVar(T var){ //设置类型也由外部决定 this.var = var; } } public class GenericDemo08{ public static void main(String[] args){ Point p = new Point("Jack"); System.out.println(p.getVar()); } }
在创建泛型类对象时,如果没声明具体泛型类型,编译时会产生安全警告,但是并不会影响执行
我们可以看到创建Point类对象时并没有指定泛型的类型,即Point类并没有指定泛型的类型,则java中为了保证程序依然可以使用,会将T设置成Object类型,说明此时var的类型就是Object,所有的泛型信息将会被擦除,实际上,以上程序相当于如下代码:
class Point<T>{ private T var; //var的类型由T指定,即:由外部指定 public Point(T var){ this.setVar(var); } public T getVar(){ //返回值类型由安慰、外部决定 return var; } public void setVar(T var){ //设置类型也由外部决定 this.var = var; } } public class GenericDemo08{ public static void main(String[] args){ Point<Object> p = new Point<Object>("Jack"); System.out.println(p.getVar()); } }
此时并不会出现警告,所以说在泛型应用中最好在声明类的时候指定好其内部的数据类型,例如"Point<String>",如果不声明类型,用户在使用中就会出现不安全的警告信息
参考资料:
李兴华java相关视频
java核心技术卷一
相关文章推荐
- 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局域网聊天系统