什么是泛型
泛型是Java SE 1.5的新特性,Java语言引入泛型的好处是安全简单,并且以提高代码的重用性。在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的。
package gernrictiry;
import java.util.HashMap;
class container{
HashMap hp;
public container(){
hp = new HashMap();
}
public HashMap createMap(String name,String desc){
hp.put(name, desc);
return hp;
}
}
public class Demo1 {
public static void main(String[] args) {
container con = new container();
HashMap hp;
con.createMap("小马","老师");
hp = con.createMap("小王","经理");
System.out.println(hp);
}
}
看下边的例子,创建容器类构建一个HashMap集合存储人的姓名和描述信息,定义它的key-value类型为均为String,这会没有一点问题,倘若此时想要的是一个人的姓名和ID号码,可以ID的类型是整型,其他的都不变,依然使用上边的结构,此时就需要把上边的代码重新拷贝一份修改类型即可,大家想一想这样是不是很麻烦。但是有了泛型后这些都变的很容易了,因为泛型的一大优点就是代码的重用性高,从而提高效率。修改后如下:
- import java.util.HashMap;
class container<T,F>{
HashMap<T, F> hp;
public container(){
hp = new HashMap<T, F>();
}
public HashMap<T, F> createMap(T name,F desc){
hp.put(name, desc);
return hp;
}
}
public class Demo1 {
public static void main(String[] args) {
container<String, Integer> con = new container<String, Integer>();
HashMap<String, Integer> hp1;
con.createMap("小马",111);
hp1 = con.createMap("小王",222);
System.out.println(hp1);
HashMap<String, String> hp2;
container<String, String> cn = new container<String, String>();
cn.createMap("张三", "经理");
hp2 = cn.createMap("李四", "门卫");
System.out.println(hp2);
}
}
若没有泛型就必须从定义一个container类,或者使用Object类进行再强制类型转换(显式的强制类型转换)。总体来说,泛型可以极大的减少代码的冗余。
泛型使用
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
泛型格式(采用尖括号)
"< T >"表示泛型类型,在使用中可以传入具体的类型来替换它,或者使用自定义类型替换。对于这两种使用有下边几个需要注意的地方:
- 声明好泛型类型之后,集合中只能存放泛型类型元素
- 自定义泛型: 自定义泛型就是一个数据类型的占位符或者是一个数据类型的变量。自定义泛型有一定的通用性,在不确定类型是可以使用自定义泛型来定义,提高程序的可重用性。
- 泛型类型必须是引用类型
在泛型中不能使用基本数据类型,如果需要使用基本数据类型,那么就使用基本数据类型对应的包装类型。
byte----> Byte
short---> Short
int----> Integer
long----> Long
double ----> Double
float -----> Float
boolean----->Boolean
char-------> Character- 使用泛型后取出元素不需要类型转换,都是隐式的完成转换。
泛型方法
方法上自定义泛型格式如下:
修饰符 <声明自定义的泛型>返回值类型 函数名(使用自定义泛型 ...){
}
简单的代码示例:
public class Demo1{
public static void main(String[] args) {
Demo1 demo = new Demo1();
System.out.println(demo.desc(111));
}
public <T>T desc(T t){
return t;
}
}
对于desc方法定义时其返回值和参数都使用了自定义泛型,只需要在具体调用该方法时指定具体的类型即可。非常具有通用性。
方法泛型注意的事项:
1. 在方法上自定义泛型,这个自定义泛型的具体数据类型是在调用该 方法的时候传入实参时确定具体的数据类型的。
2. 自定义泛型只要符合标识符 的命名规则即可, 但是自定义泛型我们一般都习惯使用一个大写字母表示。 T Type E Element
泛型类
泛型类的定义格式:
class 类名<声明自定义泛型>{
}
测试代码
package gernrictiry;
class Animal<T>{
private T attribute;
Animal(T attribute){
this.attribute=attribute;
}
public T get_attribute(){
return attribute;
}
}
public class Demo2 {
public static void main(String[] args) {
String name="猫";
Animal<String> animal1 = new Animal<String>(name);
System.out.println(animal1.get_attribute());
Integer id=10;
Animal<Integer> animal2 = new Animal<Integer>(id);
System.out.println(animal2.get_attribute());
}
}
泛型类要注意的事项:
1. 在类上自定义泛型的具体数据类型是在使用该类的时候创建对象时候确定的。
2. 如果一个类在类上已经声明了自定义泛型,如果使用该类创建对象 的时候没有指定 泛型的具体数据类型,那么默认为Object类型
3.在类上自定义泛型不能作用于静态的方法,如果静态的方法需要使用自定义泛型,那么需要在方法上自己声明使用。
泛型接口
泛型接口的定义格式:
interface 接口名<声明自定义泛型>{
}
当实现一个接口的时候,不明确目前要操作的数据类型是什么,要等待创建接口实现类对象的时候才能指定泛型的具体数据类型。
测试代码:
package gernrictiry;
interface desc<T> {
public T get();
}
//定义了泛型接口,在Pp类实现接口的时候指定具体类型
class Pp implements desc<String> {
private String name;
Pp(String name){
this.name=name;
}
public String get(){
return name;
}
}
public class Demo3{
public static void main(String[] args) {
Pp pp =new Pp("小花");
System.out.println(pp.get());
}
}
泛型接口要注意的事项:
1. 接口上自定义的泛型的具体数据类型是在实现一个接口的时候指定 的。
2. 在接口上自定义的泛型如果在实现接口的时候没有指定具体的数据类型,那么默认为Object类型。