泛型
为什么要使用泛型Generic
泛型,JDk1.5新加入的,解决数据类型的安全性问题,其主要原理是在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型.这样在类声明或实例时只要指定好需要的具体的类型即可.
Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常.同时,代码更加简洁、健壮.
Java中的泛型,只在编译阶段有效.
在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入或者离开方法的边界出条件类型检查和类型转换的方法,也就是说,泛型信息不会进入到运行时阶段.
泛型的使用
public class GenericDemo {
public static void main(String[] args) {
A<String> a= new A<>();//在new A的对象指定泛型的类型为String
a.setKey("123");
System.out.println(a.getKey());//123
A<Integer> a1= new A<>();//在new A的对象指定泛型的类型为Integer
a1.setKey(123);
System.out.println(a1.getKey());//123
//同样的类,但是在new对象时泛型指定不同的数据类型,这些对象不能互相赋值
//a = a1;报错,不是同一类型
}
}
/**
* 此次的泛型可以任意的取名,A,B,V
* 一般使用T,意为 type
*/
class A<T>{
private T key;
public T getKey() {
return key;
}
public void setKey(T key) {
this.key = key;
}
}
-
泛型接口
- *未传入泛型实参时,与泛型类的定义相同,在声明类的同时,需将泛型的声明也一起加到类中,
class B1<T> implements IB<T>
,如果不声明泛型,如:class B1 implements IB<T>
,编译器会报错:"Unknown class" - 如果实现接口时指定接口的泛型的具体数据类型,这个类实现接口的所有方法的位置都要泛型替换实际的具体数据类型.
- *未传入泛型实参时,与泛型类的定义相同,在声明类的同时,需将泛型的声明也一起加到类中,
public class GenericDemo02 {
public static void main(String[] args) {
B1<String> b1 = new B1<>();
B2 b2 = new B2();
}
}
interface IB<T>{
T test(T t);
}
/*
*未传入泛型实参时,与泛型类的定义相同,在声明类的同时,需将泛型的声明也一起加到类中
* 如果不声明泛型如:class B1 implements IB<T>,编译器会报错:"Unknown class"
* */
class B1<T> implements IB<T>{
@Override
public T test(T t) {
return null;
}
}
/*
* 如果实现接口时指定接口的泛型的具体数据类型
* 这个类实现接口的所有方法的位置都要泛型替换实际的具体数据类型
*/
class B2 implements IB<String>{
@Override
public String test(String s) {
return null;
}
}
泛型方法
- 方法,也可以被泛型化,不管此时定义在其中的类是不是泛型化的.在泛型方法中可以自定义泛型参数,此时,参数的类型是传入数据的类型.
public class GenericDemo03 {
public static void main(String[] args) {
Cc<Integer> cc = new Cc<>();
cc.test(13,45);
cc.test4(556);
//泛型方法调用之前没有固定的数据类型
//调用时,传入的参数是什么类型,就会把泛型定义成什么类型
}
}
class Cc<E>{
private E age;
//静态的泛型方法
public static <T> void test4(T e){
System.out.println(e);
}
//无返回值的泛型方法
public <T> void test(T e,E age){
if (e == null) {
System.out.println("123");
}else{
System.out.println(age);
System.out.println("哦");
}
return;
}
//有返回值的泛型方法
public <T> T test1(T e){
return e;
}
//可变参数泛型方法
public <T> void test2(T... e){
for (T x:e) {
System.out.println(x);
}
return ;
}
}
泛型通配符
- 不确定集合中的元素具体的数据类型使用?表示所有类型
- 有限制的通配符
-
<? extends Person> (无穷小,Person)
-
只允许泛型为Person和Per送子类的引用调用
-
<? super Person> (Person,无穷大)
-
只允许泛型为Person和Persoon子类的引用调用
-
<? extends Comparable> (Person,无穷大)
-
只允许泛型为实现Comparable接口的实现类的引用调用
-
public class GenericDemo05 {
public static void main(String[] args) {
List<String> name = new ArrayList<String>();
List<Integer> age = new ArrayList<Integer>();
List<Number> number = new ArrayList<Number>();
name.add("icon");
age.add(18);
number.add(314);
getData(name);
getData(age);
getData(number);
//getUperNumber(name);//1在
// 1 处会出现错误,因为 getUperNumber() 方法中的参数已经限定了参数泛型上限为 Number,所以泛型为 String 是不在这个范围之内,所以会报错。
getUperNumber(age);//2
getUperNumber(number);//3
}
public static void getData(List<?> data) {
System.out.println("data :" + data.get(0));
}
public static void getUperNumber(List<? extends Number> data) {
System.out.println("data :" + data.get(0));
}
}