JAVA泛型的讲解
了解泛型的本质与好处
在java se1.5之前,没有泛型,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式类型的转化,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转化错误的情况下,编译器可能不提示错误,在运行的时候才出席那异常,这是一个隐患。
泛型的本质:
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法中创建,分别称为、泛型类、泛型接口、泛型方法。
泛型的好处:
Java语言引入泛型的好处是简单安全:在编译的时候检查类型安全,并且所有的强制转化都是自动和隐式的,提高代码的重用率。
泛型类:
定义泛型类
泛型类相当于类中一种特殊的类型,这种类型的特点是在实例化该类时可指定为某个具体的实习类型。
声明包含泛型类的格式:
[访问修饰符] class类名<泛型1,泛型2...>
泛型1 泛型成员2;
泛型1 泛型成员2; //... }
声明中的泛型1泛型2等等的泛型符号可以时任意合法的java标识符(Java标识符由数字,字母和下划线(_),美元符号($)或人民币符号(¥)组成。在Java中是区分大小写的,而且还要求首位不能是数字。最重要的是,Java关键字不能当作Java标识符。)。
创建泛型类的实例时,可以使用一对尖括号指定泛型的正在类型。
泛型类实例化时,并不一定要指明泛型对应的实实际类型,此时会使用Object作为默认类型
泛型类的声明示例
这里声明了一个包含泛型T的泛型类,T代表素有可能的类型,而T的实际类型在Start类实例化时指定
package test
public class Snippet<T>{
//这里T称为形式类型参数
private T g;
//g为泛型成员
public void setG(T g){
//set 方法的参数类型为泛型T
this.g = g;
}
public T getG(){
//getG方法的返回类型为泛型T
return g;
}
}
package test;
public class FLL {
public static void main(String arg[]) {
Snippet <Integer> Start1 = new Snippet<Integer>();
Start1.setG(new Integer(10));
//g1的setG方法只能接受Integer类型
Integer a = Start1.getG();
//g1的setG方法只能接受Integer类型数据
System.out.println(a);//结果a=10
}
}
建立类型为泛型类的数组
如果要建立泛型类的数组,需要注意new关键字后面不要加入泛型的实际类型名。
泛型成员不能直接实例化,其实例必需要通过方法的参数传递给泛型成员。
示例:
Genric[] hi;//声明泛型类的数组;
//先对泛型的数组进行初始化
hi = new Generic[8];//不要写成new Generic[5]
//在分别为每一个数组的元素进行初始化 Hi[0]=new Generic();/为第一个数组元素赋值。
限制泛型上限类型(也就是范围)
extends关键字用来指定泛型的上限,在实例化类时,为该泛型只当的实际类型必须是指定类的子类或指定接口的子接口:
Import java.util.List
pblic class ListGeneric<T extends List>{
private T list;
public void setList(T list){
This.list = list;
}
public T getList(){
T return list;
}
}
这里范围是List本身的类型以及子类。
在限定泛型的类型时,无论要限定的是接口或者类,
都要使用extends关键词。
限定泛型上限后的成员可用方法
import java.util.List;一般表示导入的是类文件。
import java staic java.lang.System.out//一般表示的是静 态方法的导入。
限制泛型下限则只能使用本身以及父类类型。
泛型通配符(wildcard)
实例化泛型类是采用默认泛型类型,此时泛型类的实例和其他给定类型的泛型类实例之间存在兼容性,可以直接相互赋值。
泛型默认类型虽然可以做到类型的兼容性,但会失去泛型带来的编译时刻类型检查的优点。
泛型类实例之间的不兼容性会带来使用的不便。
使用泛型通配符(?)声明泛型类的便令可以解决这个问题。
Generic<?> g //g代表了Generic所有可能的实例
通配符也可以用作方法的参数类型的声明,表示该参数可接受对应泛型的任意实例
一旦对象使用通配字符的声明,就无法利用它为类中的泛型成员传入新的实例,这时只能读取其中的泛型成员或者移除泛型成员存储的原有实例。
受限泛型:
设置上限:
声明对象:类名称<? extends 类>对象名
定义类:[访问权限]类名称<泛型标识 extends 类>{}。
设置下限:
声明对象: 类名称<? super 类>对象名
定义类:[访问权限]类名称<泛型标识 extends 类>{}。
泛型方法定义格式:
访问修饰符<泛型列表> 返回类型 方法名(参数列表){ 实现代码 }
任何类或者接口都可以定义泛型方法,而包含泛型方法的类或者接口无需被定义为泛型类或者接口。
静态方法也可以被定义成泛型方法。
泛型接口的声明:
public interface I<T1,T2>{
T1 getT1();
T2 getT2();
//.....
}
实现泛型接口时,类在定义时可以不声明泛型接口中的泛型,此时接口中的泛型也会自动变为Object类型
泛型和枚举
由于枚举类型不能直接实例化,所以枚举的定义不能含有泛型的声明,但枚举中可包含泛型方法的定义.