泛型(generics)
他是 JDK5 中引入的一个新特性,泛型提供了编译时类型安全监测机制,该机制允许我们在编译时检测到非法的类型数据结构。本质是参数化类型,也就是说所操作的数据类型被指定为一个参数(type parameter)这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
相较于传统的形参,泛型可以使我们的参数具有更多的类型变化,使代码能够更好的复用。
数据类型的操作更灵活。
- 传统的操作::
public class Box {
String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
可以看出,只能使用固定的String类型。
Box b1 = new Box();
b1.setValue("aaa");
//b1.setValue(100);//不能传入其他类型
String value = b1.getValue();
System.out.println(value);
- 使用泛型:
定义类并使用添加 <T>参数,返回类型、接收类型也使用T。
public class Box<T> {
T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
创建对象及调用:
可在创建对象时指定类型。
//可以使用<>指定String类型
Box<String> b1 = new Box();
b1.setValue("aaa");
String value = b1.getValue();
System.out.println(value);
//可以使用<>指定Integer类型
Box<Integer> b2 = new Box();
b2.setValue(100);
int n = b2.getValue();
System.out.println(n);
- 泛型类与泛型对象:
泛型类就是在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。只有用户使用该类的时候,该类所属的类型才能明确。好处:在定义时不指定具体的数据类型,在使用时再明确使用的具体数据类型。
如果使用泛型类在创建对象时不指定类型(能创建成功、默认Object类型),但有可能运行过程中遇到一些类型异常。
所以建议在使用时就指定类型。
例如以下代码:运行时会存在类型转换异常。
ArrayList list = new ArrayList();
//ArrayList<String> list = new ArrayList();
list.add("abc");
list.add(100);
System.out.println(list);
for (Object o : list) {
String s = (String)o;
System.out.println(s.length());
}
- 泛型方法
泛型方法与泛型类没有任何关系,泛型方法所在的类可以时泛型类,也可以不是泛型类,
泛型方法定义:
[访问权限] <泛型标识> 返回值类型 方法名(泛型标识 参数名)
//定义泛型类
public class MyBox {
//实现:接收什么,打印什么。
public<T> void select(T p){
System.out.println(p);
}
}
//使用泛型
public static void main(String[] args) {
MyBox b = new MyBox();
b.select("1");
b.select(1);
b.select(true);
}
- 泛型接口
实现类方式1:接口实现时直接明确数据类型。
实现类方式2:不指定具体的类型,将实现类也变成一个泛型的类。
public class FanXing {
public static void main(String[] args) {
InterImpl i1 = new InterImpl();
i1.show("hello");
InterImpl2<String> i2 = new InterImpl2();
i2.show("hello");
}
}
//泛型的接口
interface Inter<T>{
public abstract void show(T t);
}
//实现类方式1:接口实现时直接明确数据类型。
class InterImpl implements Inter<String> {
@Override
public void show(String s) {
System.out.println(s);
}
}
//实现类方式2:不指定具体的类型,将实现类也变成一个泛型的类。
class InterImpl2<T> implements Inter<T>{
@Override
public void show(T t) {
System.out.println(t);
}
}
- 类型通配符 ?
数组是可以协变的,即父类和子类可以保持相同形式的变化。
但是集合不能协变,但泛型提供了类型通配符。
public class Wildcard {
//泛型的限定:
//1.上限限定:<? extends 类> 只能是该类或者它的子类
//2.下限限定:<? super 类> 只能是该类或者它的父类
public static void main(String[] args) {
// method1(new ArrayList<A>()); //A、B是C的父类,报错
// method1(new ArrayList<B>());
method1(new ArrayList<C>());
method1(new ArrayList<D>());
method2(new ArrayList<A>());
method2(new ArrayList<B>());
method2(new ArrayList<C>());
// method2(new ArrayList<D>());//D是C的子类,D报错
}
public static void method1(ArrayList<? extends C> list) {
}
public static void method2(ArrayList<? super C> list) {
}
}
class A{
}
class B extends A{
}
class C extends B{
}
class D extends C{
}