Java 里的泛型简介.
2014-06-08 23:37
405 查看
我们在JDK中有时回见到1个类or接口后面跟这1个尖括号.
例如:
我们一开始大概知道K,V 大概就是Key和Value的意思, 键值对嘛, 但是不知道这个特性对编程的影响.
其实这个设计Java的泛型问题. 把本文看完就明白了.
一. Java里泛型的定义
在数据结构中, 泛型(generic)这个词代表一种编程思想.
它的意思就是: 不论存储结构如何差异, 都可以令其具有看起来一样的操作方法.
例如 ArrayList 和 LinkList 这两个容器, 它们在内存内的存储结构是完全不同的.
但是它们的操作方法基本上是一样的.
都具有相同的,add() 方法, remove()方法, size()方法等等.
这就是泛型的编程思想.
但是在Java里不能直接操作内存, Java里泛型是另一种定义:
java里泛型用于限制传入容器和接口的数据类型.
会见到下面的字眼
java.util
类 ArrayList<E>
ArrayList后面有个尖括号, 里面一个大写E.
其实E代表的是Element的意思, 它告诉我们, ArrayList可以用泛型来限制放入容器里的对象类型.
2.1 假如不使用泛型
假如我们不适用泛型
代码是这样写的:
上面的代码中, arr这个容器添加了两个Student对象, 1个integer对象(自动装箱),1个String对象.
但是编译失败
原因在于这行代码:
在JDK API中, get()方法是这样定义的:
返回此列表中指定位置上的元素。
其实上面的定义告诉我们, 可以使用泛型来决定get()方法的返回值类型, 但是如果不使用泛型, 返回的类型是object.
上面用1个Student的引用st 来接收1个Object类型对象, 所以会编译失败.
所以我们需要强制转换, 将出错的代码改为:
这样就编译通过了.
但是编译信息有两句warning:
它告诉我们这样是不安全的, 因为没有使用泛型, arr容器内还可能有其它的类型的对象.
一旦我把上面的get方法里的参数从1改成2, 则会发生转会失败, 抛出异常..
例如:
修改后的代码如下:
上面的 get()方法已经不需要强制转换了.
值得注意的是, 当使用了泛型以后, 上面的arr容器就不能再放入除Student对象之外的其他类型元素. 否则会报错!
ava.lang
类型参数:
然后再看看Comparable里面最重要的方法:
里面都有1个T, 意思也是可以利用泛型来指定传入Comparable接口里方法的参数类型:
例子:
例如上面的例子
类Student 实现了Comparable接口, 重写comparaTo时的参数必须是对象Object
内容里还必须强制转会:
这样写虽然看起来ok, 但是实际上也不安全
因为这样写, Student对象调用compareTo方法时就能放入各种类型的参数.
编译时是无错的,但是执行时就有可能转换失败了.
只需要在接口名后面加上<参数类名>就ok
修改后的例子:
上面修改后, 重写的compareTo方法参数就应该指定为Student类.
而且不能将其他类型对象作为参数调用, 否则编译出错.
1.避免强制转换的代码
2.限制传入容器的对象类型 和 接口方法参数的类型
3.避免了编译通过, 但是因为强制转换失败而执行出错的情况. 令java程序更加安全健壮.
例如:
java.util.HashMap<K,V>
我们一开始大概知道K,V 大概就是Key和Value的意思, 键值对嘛, 但是不知道这个特性对编程的影响.
其实这个设计Java的泛型问题. 把本文看完就明白了.
一. Java里泛型的定义
在数据结构中, 泛型(generic)这个词代表一种编程思想.它的意思就是: 不论存储结构如何差异, 都可以令其具有看起来一样的操作方法.
例如 ArrayList 和 LinkList 这两个容器, 它们在内存内的存储结构是完全不同的.
但是它们的操作方法基本上是一样的.
都具有相同的,add() 方法, remove()方法, size()方法等等.
这就是泛型的编程思想.
但是在Java里不能直接操作内存, Java里泛型是另一种定义:
java里泛型用于限制传入容器和接口的数据类型.
二. 容器里的泛型.
我们打开Java JDK API, 查看ArrayList这个类会见到下面的字眼
java.util
类 ArrayList<E>
ArrayList后面有个尖括号, 里面一个大写E.
其实E代表的是Element的意思, 它告诉我们, ArrayList可以用泛型来限制放入容器里的对象类型.
2.1 假如不使用泛型
假如我们不适用泛型代码是这样写的:
import java.util.ArrayList; class Student{ int id; private String name; public Student(int id, String name){ this.id = id; this.name = name; } public String toString(){ return this.id + ": " + this.name; } } public class ArrayList1{ public static void main(String args[]){ ArrayList arr = new ArrayList(); arr.add(new Student(1,"Jack")); arr.add(new Student(2,"Bill")); arr.add(1); arr.add("Jack"); Student st = arr.get(1); System.out.println(st); } }
上面的代码中, arr这个容器添加了两个Student对象, 1个integer对象(自动装箱),1个String对象.
但是编译失败
原因在于这行代码:
Student st = arr.get(1);
在JDK API中, get()方法是这样定义的:
get
public E get(int index)
返回此列表中指定位置上的元素。
其实上面的定义告诉我们, 可以使用泛型来决定get()方法的返回值类型, 但是如果不使用泛型, 返回的类型是object.
上面用1个Student的引用st 来接收1个Object类型对象, 所以会编译失败.
所以我们需要强制转换, 将出错的代码改为:
Student st = (Student)arr.get(1);
这样就编译通过了.
但是编译信息有两句warning:
Note: ArrayList1.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details.
它告诉我们这样是不安全的, 因为没有使用泛型, arr容器内还可能有其它的类型的对象.
一旦我把上面的get方法里的参数从1改成2, 则会发生转会失败, 抛出异常..
2.2 使用泛型:
我们可以在定义1个容器时使用泛型, 方法很简单, 就是在容器类名后面加上尖括号,后面写上你要放入的对象类名.例如:
Arraylist<Student> arr = new ArrayList<Student>();
修改后的代码如下:
import java.util.ArrayList;
class Student{
int id;
private String name;
public Student(int id, String name){
this.id = id;
this.name = name;
}
public String toString(){
return this.id + ": " + this.name;
}
}
public class ArrayList2{
public static void main(String args[]){
ArrayList<Student> arr = new ArrayList<Student>();
arr.add(new Student(1,"Jack"));
arr.add(new Student(2,"Bill"));
//arr.add(1);
//arr.add("Jack");
Student st = arr.get(1);//Student st = (Student)arr.get(1);
System.out.println(st);
}
}
上面的 get()方法已经不需要强制转换了.
值得注意的是, 当使用了泛型以后, 上面的arr容器就不能再放入除Student对象之外的其他类型元素. 否则会报错!
三. 接口里的泛型.
我地再一次打开JDKAPI, 看看Comparable接口的定义:ava.lang
接口 Comparable<T>
类型参数:T- 可以与此对象进行比较的那些对象的类型
然后再看看Comparable里面最重要的方法:
int | compareTo(T o) 比较此对象与指定对象的顺序。 |
3.1 假如不使用泛型:
如果不使用泛型, 那么使用实现了Comparable接口的对象里的comparaTo方法里就能接受各种类型的对象, 必须使用强制转会:例子:
import java.lang.Comparable; class Student implements Comparable{ int id; private String name; public Student(int id, String name){ this.id = id; this.name = name; } public String toString(){ return this.id + ": " + this.name; } public int compareTo(Object o){ Student st = (Student)o; return this.id - st.id; } } public class Comparable1{ public static void main(String args[]){ Student jack = new Student(1,"Jack"); Student bill= new Student(2,"Bill"); System.out.println(bill.compareTo(jack)); } }
例如上面的例子
类Student 实现了Comparable接口, 重写comparaTo时的参数必须是对象Object
内容里还必须强制转会:
Student st = (Student)o;
这样写虽然看起来ok, 但是实际上也不安全
因为这样写, Student对象调用compareTo方法时就能放入各种类型的参数.
编译时是无错的,但是执行时就有可能转换失败了.
3.2 假如使用泛型.
接口使用泛型的方法也很简单:只需要在接口名后面加上<参数类名>就ok
修改后的例子:
import java.lang.Comparable; class Student implements Comparable<Student>{ int id; private String name; public Student(int id, String name){ this.id = id; this.name = name; } public String toString(){ return this.id + ": " + this.name; } public int compareTo(Student s){ return this.id - s.id; } } public class Comparable2{ public static void main(String args[]){ Student jack = new Student(1,"Jack"); Student bill= new Student(2,"Bill"); System.out.println(bill.compareTo(jack)); //System.out.println(bill.compareTo("jack")); compile error } }
上面修改后, 重写的compareTo方法参数就应该指定为Student类.
而且不能将其他类型对象作为参数调用, 否则编译出错.
四. 使用泛型的意义
通过上面的例子, 我们可以得出使用java泛型 有如下好处:1.避免强制转换的代码
2.限制传入容器的对象类型 和 接口方法参数的类型
3.避免了编译通过, 但是因为强制转换失败而执行出错的情况. 令java程序更加安全健壮.
相关文章推荐
- java泛型简介
- Java基础之集合框架类及泛型简介
- JAVA学习笔记35——泛型1:泛型的简介以及使用
- java高级特性——泛型简介
- Java 泛型 简介
- Java中的泛型简介
- 2015第22周六Java反射、泛型、容器简介
- Java泛型01 : 泛型简介、泛型由来、入门示例和其他说明
- Java,泛型,Generic java,JDK1.5beta,简约主义的朋友还是敌人
- Java Map 集合类简介
- 基于Java的全文索引引擎Lucene简介
- Anders Hejlsberg谈C#、Java和C++中的泛型
- Java Map 集合类简介
- Anders Hejlsberg谈C#、Java和C++中的泛型
- Java Map 集合类简介
- 诊断 Java 代码:轻松掌握 Java 泛型
- 掌握 Java 泛型类型(二)
- 掌握 Java 泛型类型(四)
- JavaWebStudio系列开发工具Visaul Struts版本简介
- Java更新XML的四种常用方法简介