泛型复习(java)

泛型

为什么用泛型

不用泛型

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 方法");
    }
}



泛型特性

  1. 泛型是 java5 的新特性,属于编译阶段的功能
  2. 让开发者指定集合中存储的数据类型
//这里就表示只能存 String 类型数据,否则编译阶段报错
Arraylist<String> al = new ArrayList<String>();

作用

  1. 类型安全:指定集合中元素类型后,编译器会进行类型检查,如果尝试将类型错误的元素添加到集合中,就会在编译时报错,避免了运行时出现的错误问题
  2. 代码简洁:避免频繁类型转换,因为不用泛型集合就默认返回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){}
}
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值