Java泛型深入

泛型可以作用在类、方法、接口。分别称:泛型类、泛型方法、泛型接口

1. 泛型

泛型:
JDK5引入的新特性,可以在编译阶段约束操作的数据类型,并进行检查
泛型的格式:
<数据类型>
注意:
泛型只能支持引用数据类型,如果要传基本数据类型,需要使用对应的包装类

1.在JDK5之前没有泛型,集合是怎么存储数据的,接下来演示一段代码:

        为集合添加Integer、String、Student三种类型的数据

        此时遍历集合,得到的元素是Object类型,形成多态

        多态的弊端:无法调用子类特有的方法

        因此需要强转成子类,但集合中有三种类型的元素,所以没法强转

//1.创建集合的对象并添加元素
        ArrayList list = new ArrayList();

        list.add(123);
        list.add("abc");
        list.add(new Student("张三", 123));

        //2.迭代器遍历集合中的每一个数据并打印
        /*
        此时打印结果为:
        123
        abc
        Student{name = 张三, age = 123}
         */
        Iterator it = list.iterator();
        while (it.hasNext()){
            //弊端:多态的弊端是不能访问子类的特有功能,例如obj.length(),如果使用强转,Integer会                报错
            Object obj = it.next();
            System.out.println(obj);
        }

package com.hao.generics;

public class Student {
    private String name;
    private int age;


    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}
 

结论:
如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型
此时可以往集合添加任意的数据类型
带来一个坏处:我们在获取集合的元素时,无法使用它的特有行为

此时Java推出了泛型,它可以在添加数据时就把类型进行统一 而且我们在获取类型时,也省得强转了,非常的方便

接下来用泛型创建集合:

ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            String str = it.next();
            int strLength = str.length();
            System.out.println(str + strLength);
        }
 

结论: 泛型的好处: 1.统一数据类型 2.把运行时期的问题提前到了编译时期,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来

扩展知识点:Java中的泛型其实是伪泛型,这个泛型实际上是只在编译时期有效的

理解:

         在java文件中是真正存在泛型的,但编译成class文件时泛型就会消失,这个过程在Java中有一个专业名词叫做泛型的擦除

Java为什么这么设计?

        在jdk5以前,已经有非常多的Java项目,如果直接修改成泛型,以前的所有项目都会出错

泛型的细节:

        1.泛型中不能写基本数据类型

        2.指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型

        3.如果不写泛型,类型默认是Object

2.泛型类

泛型类:

使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
格式:
修饰符 class 类名<类型>{

}

举例:

看以下代码:

定义了一个MyArrayList类,并添加了add和get方法,重写了toString方法

/*
    当我在编写一个类的时候,如果不确定类型,那么这个类就可以定义为泛型类
 */
public class MyArrayList<E> {
    Object[] obj = new Object[10];
    int size;

    /*
        E:表示是不确定的类型。该类型在类名后面已经定义过了
        e:形参的名字,变量名
     */
    public boolean add(E e){
        obj[size] = e;
        size++;
        return true;
    }

    public E get(int index){
        return (E) obj[index];
    }

    @Override
    public String toString() {
        return Arrays.toString(obj);
    }
}

再看以下实现类,此时用泛型类创建了String类型的集合,添加元素并打印了集合

        

public static void main(String[] args) {
        /*
        泛型类:
         */
        MyArrayList<String> list = new MyArrayList<>();

        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        System.out.println(list);
    }

3.泛型方法

使用场景:方法中形参类型不确定时
1.可以使用类名后面定义的泛型<E>——所有方法都能使用
2.在方法申明上定义自己的泛型——只能在本方法中使用

格式:
修饰符 <类型> 返回值类型 方法名(类型 变量名){

}

下面来看一段代码,

/*
    定义一个工具类ListUtil
    类中定义一个静态方法addAll,用来添加多个集合的元素
 */
public class ListUtil {
    private ListUtil(){}

    public static <E> void addAll(ArrayList<E> list, E e1, E e2, E e3, E e4){
        list.add(e1);
        list.add(e2);
        list.add(e3);
        list.add(e4);

    }

    //...可变参数
    public static <E> void addAll2(ArrayList<E> list, E...e){
        for (E element : e) {
            list.add(element);
        }

    }
}

实现类:

public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        ListUtil.addAll(list, "aaa", "bbb", "ccc", "ddd");

        ListUtil.addAll2(list, "1", "b");
        ListUtil.addAll2(list, "12", "c", "is");


        System.out.println(list);
    }

4.泛型接口

使用场景:接口中形参类型不确定时

格式:
修饰符 interface 接口名<类型>{

}

重点:如何使用一个带泛型的接口

方式1:实现类给出具体类型
方式2:实现类延续泛型,创建对象时再确定具体类型

方式1:接下来看一段代码

package com.hao.generics;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

//泛型接口第一种方式
public class MyArrayList2 implements List<String> {
    @Override
    public int size() {
        return 0;
    }

    @Override
    public boolean isEmpty() {
        return false;
    }

    @Override
    public boolean contains(Object o) {
        return false;
    }

    @Override
    public Iterator<String> iterator() {
        return null;
    }

    @Override
    public Object[] toArray() {
        return new Object[0];
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return null;
    }

    @Override
    public boolean add(String s) {
        return false;
    }

    @Override
    public boolean remove(Object o) {
        return false;
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return false;
    }

    @Override
    public boolean addAll(Collection<? extends String> c) {
        return false;
    }

    @Override
    public boolean addAll(int index, Collection<? extends String> c) {
        return false;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return false;
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return false;
    }

    @Override
    public void clear() {

    }

    @Override
    public String get(int index) {
        return null;
    }

    @Override
    public String set(int index, String element) {
        return null;
    }

    @Override
    public void add(int index, String element) {

    }

    @Override
    public String remove(int index) {
        return null;
    }

    @Override
    public int indexOf(Object o) {
        return 0;
    }

    @Override
    public int lastIndexOf(Object o) {
        return 0;
    }

    @Override
    public ListIterator<String> listIterator() {
        return null;
    }

    @Override
    public ListIterator<String> listIterator(int index) {
        return null;
    }

    @Override
    public List<String> subList(int fromIndex, int toIndex) {
        return null;
    }
}

方式2:

package com.hao.generics;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

//泛型接口第二种使用方式
public class MyArrayList3<E> implements List<E> {
    @Override
    public int size() {
        return 0;
    }

    @Override
    public boolean isEmpty() {
        return false;
    }

    @Override
    public boolean contains(Object o) {
        return false;
    }

    @Override
    public Iterator<E> iterator() {
        return null;
    }

    @Override
    public Object[] toArray() {
        return new Object[0];
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return null;
    }

    @Override
    public boolean add(E e) {
        return false;
    }

    @Override
    public boolean remove(Object o) {
        return false;
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return false;
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        return false;
    }

    @Override
    public boolean addAll(int index, Collection<? extends E> c) {
        return false;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return false;
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return false;
    }

    @Override
    public void clear() {

    }

    @Override
    public E get(int index) {
        return null;
    }

    @Override
    public E set(int index, E element) {
        return null;
    }

    @Override
    public void add(int index, E element) {

    }

    @Override
    public E remove(int index) {
        return null;
    }

    @Override
    public int indexOf(Object o) {
        return 0;
    }

    @Override
    public int lastIndexOf(Object o) {
        return 0;
    }

    @Override
    public ListIterator<E> listIterator() {
        return null;
    }

    @Override
    public ListIterator<E> listIterator(int index) {
        return null;
    }

    @Override
    public List<E> subList(int fromIndex, int toIndex) {
        return null;
    }
}

实现:

package com.hao.generics;


public class GenericsDepthDemo4 {
    /*
        泛型接口的俩种使用方式:
            1:实现类给出具体类型
            2:实现类延续泛型,创建对象时再确定具体类型
     */

    public static void main(String[] args) {
        //第一种
        MyArrayList2 list1 = new MyArrayList2();
        list1.add("abc");

        //第二种
        MyArrayList3<String > list2 = new MyArrayList3();
        list2.add("def");
    }

}

5.泛型的继承和通配符

泛型不具备继承性,但是数据具备继承性

请看下述代码:

package com.hao.generics;

import java.util.ArrayList;

public class GenericsDepthDemo5 {
    public static void main(String[] args) {
        /*
        泛型不具备继承性,但是数据具备继承性
         */

        //创建集合对象
        ArrayList<Ye> list1 = new ArrayList<>();
        ArrayList<Fu> list2 = new ArrayList<>();
        ArrayList<Zi> list3 = new ArrayList<>();

        //调用method方法
        method(list1);
        method(list2);
    }

    public static void method(ArrayList<Ye> list){

    }
}

class Ye{}
class Fu extends Ye{}
class Zi extends Fu{}

 此时会报该异常,因为泛型是不具备继承性的

E:\gitee_clone\hao_learn\learn\gather\src\com\hao\generics\GenericsDepthDemo5.java:18:16
java: 不兼容的类型: java.util.ArrayList<com.hao.generics.Fu>无法转换为java.util.ArrayList<com.hao.generics.Ye>

来看下一段代码:此时method方法就只能传递Ye、Fu、Zi类对象

应用场景:

1.如果我们定义类、方法、接口时,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口

2.如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以使用通配符

package com.hao.generics;

import java.lang.reflect.Method;
import java.util.ArrayList;

public class GenericsDepthDemo6 {
    public static void main(String[] args) {
        /*
            需求:
                定义一个方法,形参是一个集合,但是集合中的数据类型不确定
         */
        //创建集合对象
        ArrayList<Ye> list1 = new ArrayList<>();
        ArrayList<Fu> list2 = new ArrayList<>();
        ArrayList<Zi> list3 = new ArrayList<>();

        method(list1);
        method(list2);
        method(list3);
        method(Student2);
    }


    /*
    此时,泛型里面写的是什么类型,那么只能传递什么类型的数据
    弊端:
        利用泛型方法有一个小弊端,此时它可以接收任意的数据类型
        例如:Ye、Fu、Zi、Student以及各种其他类

    希望:本方法虽然不确定类型,但是以后我希望只能传递Ye、Fu、Zi
        此时我们就可以使用泛型的通配符
            ?也表示不确定的类型
            它可以进行类型的限定
            ? extends E:表示可以传递E或者E所有的子类类型
            ? super E:表示可以传递E或者E所有的父类类型
     */
    public static <E> void method(ArrayList<? extends Ye> list){

    }
}

class Ye{}
class Fu extends Ye{}
class Zi extends Fu{}
class Student2{}

以上就是泛型的深入讲解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值