Java基础—泛型

一、概念

1、概念

泛型又称参数化类型,从JDK1.5开始出现,用于解决数据类型的安全性问题。

2、优点

  • 限制所使用的数据类型,避免使用不恰当的数据类型
    在这里插入图片描述

  • 在代码编译之后,泛型会自动帮我们进行类型强转(默认是Object类型),降低手动类型强转可能产生的类型转换异常风险
    在这里插入图片描述

  • 代码重用,减少代码编写的工作量
    在这里插入图片描述

3、特点

  • 如果不指定泛型,那么泛型默认是Object类型
    在这里插入图片描述

  • 泛型不能是基础数据类型,但是可以是基础数据类型的包装类,原因是:泛型默认是Object类型,上面已经解释过了,这里不在赘述~

  • 泛型具体的类型是在编译时确定的,如果我们指定泛型为具体类型,那就使用它。否则使用Object类型
    在这里插入图片描述

  • 泛型使用位置:接口、类、非静态方法(参数、返回值、代码)、非静态成员属性、内部类等等

  • 为什么不能在静态方法或者静态成员属性上使用泛型呢?
    答:静态方法和静态成员变量属于类,无法在编译时确定类型,所以不能使用泛型

  • 如果普通成员变量是数组类型,不可以赋初始值,比如:T[] arr = new T[8],这种写法是不允许的,原因是:参数类型T不能直接实例化

二、使用方法

1、类

代码:

// 解说:目的是演示在类上使用泛型,但是其实也演示了在构造器、方法、成员属性中使用泛型
public class Test {
    public static void main(String[] args) throws Exception {
        // 在类上使用单个泛型
        Cat<String> cat = new Cat<>("小花");
        System.out.println("小猫的名字:" + cat.getT());

        // 在类上使用多个泛型
        Person<String, Integer> person = new Person<>("小明", 180);
        System.out.printf("\n学生姓名:%s,身高:%s厘米", person.getE() , person.getT());
    }
}

// 案例1:在类上使用单个泛型
class Cat<T> {
    T t;

    public Cat(T t) {
        this.t = t;
    }

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

// 案例2:在类上使用多个泛型
class Person<T, E> {
    T t;
    E e;

    public Person(T t, E e) {
        this.t = t;
        this.e = e;
    }

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }

    public E getE() {
        return e;
    }

    public void setE(E e) {
        this.e = e;
    }
}

解释:

泛型其实帮我们限制了数据类型,然后进行了数据的强制类型转换
如果没有泛型,那我们需要自己注意使用的数据类型,并且自己直接强制类型转换,这些工作无趣又繁琐,所以感谢泛型的出现
为证明我在解释中说的第一句话,我将上述示例中的Test.java生成的Test.class进行反编译后,我们看下结果:

解释中第一句话前半截在介绍泛型优点的时候已经提到了,这里解释下这句话的后半截内容

在这里插入图片描述

2、普通成员属性

请看上一节1、类

请注意: 在成员属性中使用的泛型,必须来自于在类上定义的

3、接口

代码:

public class Test {
    public static void main(String[] args) throws Exception {
        Cat<String, String> cat = new Cat<>();
        cat.eat("猫粮");

        Dog dog = new Dog();
        dog.eat("狗粮");
    }
}

// 接口
interface Animal<T, E> {

    E eat();

    void eat(T t);
}

// 类(实现接口的时候指定一样的泛型类型,类后面指定的可以大于等于接口后面携带的)
class Cat<T, E> implements Animal<T, E> {

    @Override
    public E eat() {
        return null;
    }

    @Override
    public void eat(T t) {
        System.out.println("小猫咪吃到猫粮了~");
    }
}

// 类(在继承类的时候指定泛型具体类型)
class Dog implements Animal<String, String> {

    @Override
    public String eat() {
        return "hello world~";
    }

    @Override
    public void eat(String s) {
        System.out.println("小狗吃到狗粮了~");
    }
}

结果:

小猫咪吃到猫粮了~
小狗吃到狗粮了~

4、方法

代码:

public class Test {
    public static void main(String[] args) throws Exception {
        Cat cat = new Cat();
        cat.eat("饼干", "小鱼干");

        Dog<String> dog = new Dog<>();
        dog.eat("狗粮");

        Fox<String> fox = new Fox<>();
        fox.eat("兔子", "小鸡");
    }
}

// 在普通类中使用泛型方法
class Cat {
    public <T, E> T eat(T t, E e) {
        System.out.println("小猫咪吃到猫粮了~");
        return t;
    }
}

// 在泛型类中使用泛型方法,并且在泛型方法中使用泛型类的泛型
class Dog<T> {
    public T eat(T t) {
        System.out.println("小狗吃到狗粮了~");
        return t;
    }
}

// 泛型方法和泛型类一起使用
class Fox<T> {
    public<E> T eat(T t, E e) {
        System.out.println("狐狸吃到兔子了~");
        return t;
    }
}

结果:

小猫咪吃到猫粮了~
小狗吃到狗粮了~
狐狸吃到兔子了~

5、继承和通配符

代码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Test {
    public static void main(String[] args) throws Exception {
        A a = new A();
        a.eat(Arrays.asList("hello", "world"));

        List<Son> sonList = new ArrayList<>();
        a.play(sonList);

        List<Parent> parentList = new ArrayList<>();
        a.run(parentList);
    }
}

// 测试类
class A {
    // 支持所有泛型类型,类似于Object
    void eat(List<?> list) {
        System.out.println("eat方法执行了~");
    }
    
    // 支持范围小于等于Parent类的类,super后面的系统决定了下限
    void play(List<? extends Parent> list) {
        System.out.println("play方法执行了~");
    }

    // 支持范围大于等于Son类的类,super后面的系统决定了下限
    void run(List<? super Son> list) {
        System.out.println("run方法执行了~");
    }
}

// 父类接口和子类接口,用于测试extends和super关键字
class Parent {}

class Son extends Parent {}

结果:

eat方法执行了~
play方法执行了~
run方法执行了~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值