泛型
为什么用泛型
不用泛型
public class User {
public static void main(String[] args) {
//创建 arraylist 集合
Collection arraylist = new ArrayList();
//把 Person 对象假如 arraylist
Person p = new Person();
arraylist.add(p);
//用迭代器遍历调用 test 方法
Iterator it = arraylist.iterator();
while (it.hasNext()) {
Object o = it.next();
//这里非常麻烦,要向下转型,所以我们可以用泛型
if (o instanceof Person) {
Person temp = (Person) o;
temp.test();
}
}
}
}
class Person {
public void test() {
System.out.println("调用 test 方法");
}
}
使用泛型
public class User {
public static void main(String[] args) {
//创建 arraylist 集合
Collection<Person> arraylist = new ArrayList<>();
//把 Person 对象假如 arraylist
Person p = new Person();
arraylist.add(p);
//用迭代器遍历调用 test 方法
Iterator<Person> it = arraylist.iterator();
while (it.hasNext()) {
//这里用了泛型所以代码更简便了,也不用向下转型了,并且编译会进行类型检查,更安全了
Person temp = it.next();
temp.test();
}
}
}
class Person {
public void test() {
System.out.println("调用 test 方法");
}
}
泛型特性
- 泛型是 java5 的新特性,属于编译阶段的功能
- 让开发者指定集合中存储的数据类型
//这里就表示只能存 String 类型数据,否则编译阶段报错
Arraylist<String> al = new ArrayList<String>();
作用:
- 类型安全:指定集合中元素类型后,编译器会进行类型检查,如果尝试将类型错误的元素添加到集合中,就会在编译时报错,避免了运行时出现的错误问题
- 代码简洁:避免频繁类型转换,因为不用泛型集合就默认返回Object
钻石表达式:
java7 的新特性
//后面<>里的 String 可以省略
Arraylist<string> a1 = new ArrayList();
泛型的擦出和补偿
擦除
- 泛型提高安全性,是编译阶段的技术,专门给编译器用的,加载类的时候,会把泛型擦除掉,擦成 Object 类型
- 擦除的本质是让 JDK1.4之前的 和 JDK1.5 能兼容同一个类加载器,1.5擦除后为 Object 和 1.4 之前就兼容了
补偿
- 擦除为 Object 类型,所以添加的元素就被转化为 Object 类型,同时取出的元素也默认为 Object 类型
- 这里有一个默认的操作:他帮你自动把 Object 强转成对应的类型,不用强转
自定义泛型
在类上自定义泛型
public class User {
public static void main(String[] args) {
//下面Person类所有 T 都替换为 String
Person<String> p = new Person<>("张三");
}
}
//如果多个泛型就用 逗号 隔开
class Person<T1> {
private T name;
public Person(T name){
this.name = name
}
public T getName() {
return name;
}
public void setName(T name) {
this.name = name;
}
}
这个 T 是自定义的 名字可以随意取
在方法上使用泛型
class Person<R> {
//这个 T 和 T 对应属于泛型方法,R 和 r 对应属于泛型类
public <T> void method(T t, R r)
}
在类上定义的泛型,静态方法中无法使用,如果在静态方法中使用泛型则需要在返回值类型前进行泛型声明
class Person<T1> {
public staic void setName(T name) {
this.name = name;
}
}
因为如果静态方法能使用,你用类名.方法 (Person.setName),直接调用,定义不了泛型直接寄了
如果要在静态上用泛型,就要使用自定义泛型方法
class Person {
//提前定义好 T1
//这个 T 是属于这个方法的泛型
public staic <T> void setName(T name) {
this.name = name;
}
}
在接口上定义泛型
接口继承时定义泛型
interface IA extends IUsb<String, Double> {
}
//当我们去实现IA接口时,因为IA在继承IUsu 接口时,指定了U 为String R为Double
//,在实现IUsu接口的方法时,使用String替换U, 是Double替换R
class AA implements IA {
@Override
public Double get(String s) {
return null;
}
@Override
public void hi(Double aDouble) {
}
@Override
public void run(Double r1, Double r2, String u1, String u2) {
}
}
interface IUsb<U, R> {
int n = 10;
//U name; 不能这样使用
//普通方法中,可以使用接口泛型
R get(U u);
void hi(R r);
void run(R r1, R r2, U u1, U u2);
//在jdk8 中,可以在接口中,使用默认方法, 也是可以使用泛型
default R method(U u) {
return null;
}
}
实现接口时定义泛型
//实现接口时,直接指定泛型接口的类型
//给U 指定Integer 给 R 指定了 Float
//所以,当我们实现IUsb方法时,会使用Integer替换U, 使用Float替换R
class BB implements IUsb<Integer, Float> {
@Override
public Float get(Integer integer) {
return null;
}
@Override
public void hi(Float aFloat) {
}
@Override
public void run(Float r1, Float r2, Integer u1, Integer u2) {
}
}
interface IUsb<U, R> {
int n = 10;
//U name; 不能这样使用
//普通方法中,可以使用接口泛型
R get(U u);
void hi(R r);
void run(R r1, R r2, U u1, U u2);
//在jdk8 中,可以在接口中,使用默认方法, 也是可以使用泛型
default R method(U u) {
return null;
}
}
没有指定接口
//没有指定类型,默认为Object
//建议直接写成 IUsb<Object,Object>
class CC implements IUsb { //等价 class CC implements IUsb<Object,Object> {
@Override
public Object get(Object o) {
return null;
}
@Override
public void hi(Object o) {
}
@Override
public void run(Object r1, Object r2, Object u1, Object u2) {
}
}
interface IUsb<U, R> {
int n = 10;
//U name; 不能这样使用
//普通方法中,可以使用接口泛型
R get(U u);
void hi(R r);
void run(R r1, R r2, U u1, U u2);
//在jdk8 中,可以在接口中,使用默认方法, 也是可以使用泛型
default R method(U u) {
return null;
}
}
简单来说就是在 继承接口,或实现接口时指定泛型
接口中,静态成员也不能使用泛型 (接口中)
类型通配符
泛型不具备继承性
也就是 如果你是 Number 那就是 Number 不能是它的 子类
比如集合定义好了泛型,你不确定存声明类型,直接 ArrayList<?>
- 无限定通配符:<?>:可以为任意引用数据类型
- 上限通配符:<? extends Numbers>:必须为 Numbers 或者它的子类
- 下限通配符:<? super Numbers>:必须为 Numbers 或者它的父类
public class User {
public static void main(String[] args) {
//啥类型都可以
User.test(new ArrayList<String>());
User.test(new ArrayList<Double>());
//只能是 Number 和 Number 的子类
User.test2(new ArrayList<Double>());
//只能是 Double 和 Double 的父类
User.test3(new ArrayList<Number>());
}
public static void test(ArrayList<?> list){}
public static void test2(ArrayList<? extends Number> list){}
public static void test3(ArrayList<? super Double> list){}
}