Java笔记 —— 泛型

本文详细介绍了Java中的泛型概念,包括泛型的引入、好处、格式及使用,如在集合中确保数据类型安全,减少类型转换。此外,还讲解了泛型的高级用法,如通配符、泛型类、泛型方法和泛型接口的实现。通过示例代码展示了如何在实际编程中应用泛型,以提高代码的可读性和安全性。
摘要由CSDN通过智能技术生成

泛型的引入

List集合中是可以加入不同类型的元素的,比如下面这样

public class demo1 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("hello");
        list.add("java");
        list.add(12);

        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            Object obj = iterator.next();
            String s = (String)obj;
            System.out.println(s);
        }
    }
}

这段代码在编译的过程中是没有报错的,但是一旦运行就会报 ClassCastException: 类型转换异常的错误
在这里插入图片描述
究其原因,是因为list集合中既有String类型的元素,又有Integer类型的元素
这样会在编译和操作集合的过程造成很多麻烦,这时候就会希望集合也能跟数组一样,可以在一开始就要求只能加入某一种类型的元素

这样在添加元素的时候,只能添加定义好的类型的元素
这样的技术就叫做泛型
一般来说,泛型主要用于集合中

泛型:把明确数据类型的工作提前到编译时期,在创建对象的时候明确。

这种操作有点像把类型当作参数进行传递,所以泛型还有另外一种叫法:参数化类型。

格式:<数据类型>

注意:这里的数据类型只能是引用数据类型

使用泛型的好处:
  1. 将运行时期的问题提前到编译时期
  2. 避免了强制类型转化
  3. 优化了代码程序,消除不必要的警告内容
public class demo1 {
    public static void main(String[] args) {
        //使用了泛型的集合
        List<String> list1 = new ArrayList<>();
        //ArrayList后面的<>里面的String可以省略,原来为new ArrayList<String>();
        list1.add("java");
        list1.add("hive");
        list1.add("flume");
        //Iterator后面也需要加上泛型
        Iterator<String> it = list1.iterator();
        while(it.hasNext()){
            //避免了强制类型转换
            String s = it.next();
            System.out.println(s);
        }
    }
}

当传入的参数是一个类的时候

public class demo2 {
    public static void main(String[] args) {
        List<Student> list = new ArrayList<>();
        list.add(new Student("zhang",12));
        list.add(new Student("zhao",15));
        list.add(new Student("zhou",18));

        Iterator<Student> iterator = list.iterator();
        while(iterator.hasNext()){
            Student s = iterator.next();
            System.out.println(s.getName()+"---"+s.getAge());
        }

    }
}

其实我们在api中查阅相关内容的时候,就应该已经见过泛型的相关用法了

在这里插入图片描述
这里的就是泛型的表现

为什么这里的<>里面是一个E,而不是明确的String,Integer等引用数据类型呢?

因为这里的E仅仅表示的是一种参数类型,这个参数类型是一个变量,可以指代任意一种引用数据类型,具体是哪种根据实际使用的时候传入的数据类型。

而这个既然是变量,只要符合变量的命名规则就是可以的,为了有辨识度,通常使用E或者T来作为括号里面的内容

泛型的高级用法:(通配符)

泛型通配符< ? > —— 任意类型,如果没有明确,那么就是Object以及任意的Java类了
< ? extends E> —— 向下限定,E,与E同级的类及其子类
< ? super E> —— 向上限定,E,与E同级的类及其父类

public class demo3 {
    public static void main(String[] args) {
        ArrayList<?> arrayList = new ArrayList<>();
        //泛型通配符<?>
        //表示任意类型,可以是Object以及任意的Java类
        ArrayList<?> objects1 = new ArrayList<Object>();
        ArrayList<?> objects2 = new ArrayList<Animal>();
        ArrayList<?> objects3 = new ArrayList<Dog>();

        //<? extends E> 向下限定,E及其子类
        ArrayList<? extends Animal> list1 = new ArrayList<Animal>();
        ArrayList<? extends Animal> list2 = new ArrayList<Dog>();
        ArrayList<? extends Animal> list3 = new ArrayList<Cat>();

        //<? super E> 向上限定,E及其父类
        ArrayList<? super Animal> list11 = new ArrayList<Animal>();
        ArrayList<? super Animal> list22 = new ArrayList<Object>();
        //错误写法ArrayList<? super Animal> list33 = new ArrayList<Dog>();
    }
}

泛型类

泛型类:把泛型定义在类上面

package test.GenericDemo;

//这里的T是一个参数,可以指代任意的引用数据类型
//这个类的setObj方法可以传入String,Integer等多种数据类型
public class genericDemo1<T> {
    private T obj;

    public void setObj(T obj){
        this.obj = obj;
    }

    public T getObj(){
        return obj;
    }

}

写一个类来使用泛型类

package test.GenericDemo;

public class genericTest1 {
    public static void main(String[] args) {
        //虽然我们定义了一个泛型类,但是也可以不去使用它
        genericDemo1 g1 = new genericDemo1();
        //此时g1可以传入任意的参数
        g1.setObj("hello");
        System.out.println(g1.getObj());  //hello
        g1.setObj(20);
        System.out.println(g1.getObj());  //20

        /*
            虽然上面都成功的打印出了结果,但实际上,这里的hello与20都是 Object 类型
            尝试一下下面这条语句
            String s= g1.getObj();
            如果这样写就会报错,错误原因是Object无法转换为String类型
            因此如果我们只需要String类型的话,就需要使用泛型来定义
         */

        genericDemo1<String> g2 = new genericDemo1<>();
        g2.setObj("hello");
        String s = g2.getObj();
        System.out.println(s); //hello,结果正确
        
    }
}

泛型方法

泛型方法:将泛型定义方法上
格式:public <泛型类型> 返回类型 方法名(泛型类型 变量名)
先来看看如果不使用泛型,写一个传入多种数据类型的方法是什么样子

public class genericDemo2 {
    public void show(String s){
        System.out.println(s);
    }

    public void show(Integer i){
        System.out.println(i);
    }

    public void show(Boolean b){
        System.out.println(b);
    }
}

写一个类来测试

public class genericTest2 {
    public static void main(String[] args) {
        genericDemo2 g1 = new genericDemo2();
        g1.show("hello"); //hello
        g1.show(12); //12
        g1.show(true); /true
    }
}

结果是正确的,但如果我们每需要传入一种数据类型,就需要写一个对应的方法,这样未免太过麻烦

这时候就用到泛型方法了
格式:public <泛型类型> 返回类型 方法名(泛型类型 变量名)

package test.GenericDemo;
//泛型方法
public class genericDemo2 {
    public <T> void show(T t){
        System.out.println(t);
    }
}

写一个测试类

package test.GenericDemo;

public class genericTest2 {
    public static void main(String[] args) {
        genericDemo2 g2 = new genericDemo2();
        g2.show("hello"); //hello
        g2.show(12); //12
        g2.show(12.23); //12.23
        g2.show(true); //true
    }
}

同样可以打印这些对应的结果,但是省却了很多代码

泛型接口

把泛型定义在接口上
格式:public interface 接口名<泛型类型1…>

接口

public interface genericDemo3<T> {
    public abstract void show(T t);
}

实现接口的类

public class genericImpl<T> implements genericDemo3<T> {
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}

具体的测试类

package test.GenericDemo;

public class genericTest3 {
    public static void main(String[] args) {
        genericImpl<String> g1 = new genericImpl();
        g1.show("hello");  //hello

        genericImpl<Integer> g2 = new genericImpl<>();
        g2.show(12);  //12
    }
}

实例
选择学生中年龄大于30岁的学生对象

package lambdaDemo;

public interface filterInterface<Student> {
    public boolean judge(Student s);
}

这里的类名filterStudentByAge后面不能加上< Student >,加上就会报错

package lambdaDemo;

//这里的类名后面不能加上<>,加上就会报错
public class filterStudentByAge implements filterInterface<Student> {
    public boolean judge(Student s) {
        return s.getAge() > 30;
    }
}

    public List<Student> filterStudent(List<Student> list, filterInterface<Student> f){
        List<Student> list1 = new ArrayList<Student>();
        for(Student s : list){
            if(f.judge(s)){
                list1.add(s);
            }
        }
        return list1;
    }

    @Test
    public void show2(){
        List<Student> list2 = filterStudent(list,new filterStudentByAge());
        for(Student s : list2){
            System.out.println(s);
        }
    }

直接用测试方法测试
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一纸春秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值