【学习笔记】Java笔记6:泛型

324 阅读2分钟

1. 介绍

  泛型可以理解为用来修饰数据类型(除了基本类型)的参数。比如一个ArrayList对象,在没有使用使用泛型时可以往里面加任意类型的数据,但这样并不安全,所以可以使用泛型来限制,如ArrayList<String>就是只能往这个集合里面加String类型的数据。

2. 自定义泛型

2.1 泛型类

  假设已定义了Dog和Cat类,都有一个String类型的name字段,那么泛型类可如下定义

public class Person<T> { // 这是一个泛型类,泛型接口的定义也类似
    private String name;
    // 宠物的类型不确定,可能是Dog,可能是Cat,于是使用泛型
    private T pet;

    public T getPet() {
        return pet;
    }

    public void setPet(T pet) {
        this.pet = pet;
    }
}
public class Test {
    public static void main(String[] args) {
        Person<Dog> p = new Person<>();
        p.setPet(new Dog("路卡利欧"));
        System.out.println(p.getPet().getName());
    }
}

2.2 泛型方法

  在方法中包含泛型结构,且其泛型与类的泛型没有任何关系。

public class MyUtil {
    // 这是一个泛型方法,即便它的所属类不是泛型类
    // static后面的<E>起到提示作用,告诉编译器E是泛型,而不是某个具体的类
    public static <E> List<E> copyFromArrayToList(E[] arr) {
        List<E> list = new ArrayList<>();
        for (E e : arr) {
            list.add(e);
        }
        return list;
    }
}

3. 通配符

  定义三个类,Creature类,Person类,Student类。继承关系为:Creature ← Person ← Student

3.1 直接操作List

add()方法get()方法
List<? extends Person>只能添加null可以用Object,Person及其父类来接
List<? super Person>可以添加null,Person及其子类只能用Object来接
public class Test {
    public static void main(String[] args) {
        List<? extends Person> list1 = new ArrayList<>();
//      list1.add(new Creature());         编译不通过
//      list1.add(new Person());           编译不通过
//      list1.add(new Student());          编译不通过
        list1.add(null);

        Object object = list1.get(0);
        Creature creature = list1.get(0);
        Person person = list1.get(0);
//      Student student = list1.get(0);    编译不通过
        
        
        List<? super Person> list2 = new ArrayList<>();
//      list2.add(new Creature());         编译不通过
        list2.add(new Person());
        list2.add(new Student());
        list2.add(null);

        Object object2 = list2.get(0);
//      Creature creature2 = list2.get(0); 编译不通过
//      Person person2 = list2.get(0);     编译不通过
//      Student student2 = list2.get(0);   编译不通过
    }
}

3.2 List作为方法参数

  • List<? extends Person> list 作为方法参数时,可以传 List<Person及其子类>
  • List<? super Person> list 作为方法参数时,可以传 List<Person及其父类>
public class Test {
    public static void main(String[] args) {
        List<Creature> creatureList = new ArrayList<>();
        List<Person> personList = new ArrayList<>();
        List<Student> studentList = new ArrayList<>();

//      testExtends(creatureList); 编译不通过
        testExtends(personList);
        testExtends(studentList);

        testSuper(creatureList);
        testSuper(personList);
//      testSuper(studentList);    编译不通过
    }

    public static void testExtends(List<? extends Person> list) {
    }

    public static void testSuper(List<? super Person> list) {
    }
}

4. 其他知识点

  • 如果类A是类B的父类,那么G<A>和G<B>没有父子关系,如下所示。但A<G>是B<G>的父类。

    public class Test {
        public static void main(String[] args) {
            List<Object> list1 = null;
            List<String> list2 = null;
            // 编译不通过
            // list1 = list2;
        }
    }
    
  • 如果泛型要实现某个接口,要用extends关键字,而不是implements,如下所示

    public class MyUtil {
        public static <E extends Serializable> List<E> copyFromArrayToList(E[] arr) {
            List<E> list = new ArrayList<>();
            for (E e : arr) {
                list.add(e);
            }
            return list;
        }
    }
    

5. 相关链接