25.泛型

news2024/7/6 18:26:24

泛型

    • 1.泛型
      • 1.1 概述
      • 1.2 代码示例
    • 2. 泛型类
      • 2.1 概述
      • 2.2 代码示例
    • 3. 泛型方法
      • 3.1 概述
      • 3.2 代码示例
    • 4. 泛型接口
      • 4.1 概述
      • 4.2 代码示例
    • 5. 泛型特点
      • 5.1 概述
      • 5.2 代码示例
    • 6. 泛型通配符
      • 6.1 概述
      • 6.2 代码示例
    • 7. 综合案例
    • 8. 注意事项

1.泛型

泛型是Java编程语言的一项重要功能,它允许开发人员在定义类、接口和方法时使用类型参数。使用泛型可以实现类型的参数化,使代码更加灵活和可重用。

1.1 概述

问题】没有泛型的时候,集合如何存储数据?

结论:如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型的,此时可以往集合里添加任意的数据类型(带来一个坏处:我们在获取数据的时候,无法使用它的特有方法),因此产生了泛型,可以在添加数据的时候对数据进行统一,而且在获取数据的时候,也省的强转了。

使用泛型带来了以下几个优势:

  1. 类型安全性:通过使用泛型,编译器可以在编译时检查代码中的数据类型错误,并提供编译时类型安全性。这意味着在编译时就可以检测到类型不匹配的错误,而不是在运行时出现问题。

  2. 代码重用:使用泛型可以编写更为通用的代码,可适用于多种数据类型。这样可以减少代码的冗余,并增加代码的可重用性和维护性。

  3. 更强的类型检查和自动转换:使用泛型可以在编译时进行更强的类型检查,并自动执行类型转换,避免了手动的类型转换。

泛型的好处

  1. 统一数据类型

  2. 把运行时期的问题提前到了编译时期,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确认下来。

泛型的细节

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

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

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

1.2 代码示例

  • 代码示例

    package text.text02;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    
    /*
    泛型:
    没有泛型的时候,集合如何存储数据
    结论:如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型的,此时可以往集合里添加任意的数据类型(带来一个坏处:我们在获取数据的时候,无法使用它的特有方法),因此产生了泛型,可以在添加数据的时候对数据进行统一,而且在获取数据的时候,也省的强转了。
    
    泛型的好处:
        1.统一数据类型
        2.把运行时期的问题提前到了编译时期,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确认下来。
    
    泛型的细节:
        1.泛型中不能有基本数据类型
        2.指定泛型的具体类型后,传递数据时,可以传入该类类型或者子类类型
        3.如果不写泛型,类型默认是Object
     */
    public class text30 {
        public static void main(String[] args) {
            //没有用泛型的方法
            System.out.print("没有用泛型的方法:");
            method1();
    
            System.out.println();
    
            //有用泛型的方法
            System.out.print("有用泛型的方法:");
            method2();
        }
    
        //没有用泛型的方法
        public static void method1() {
            //创建集合对象并添加元素
            ArrayList list = new ArrayList();
            list.add(123);//添加Integer类型
            list.add("aaa");//添加字符串类型
            list.add(true);//添加布尔类型
    
            //通过迭代器遍历集合
            Iterator it = list.iterator();
            while (it.hasNext()) {
                //多态的弊端是不能访问子类的特有方法
                //我们没有给集合指定类型,默认认为所有的数据类型都是Object类型的
                Object o = it.next();
                //o.length(); 采用字符串中Length()方法获取字符串的长度报错 (可以采用强转,但是集合里面有别的类型的,强转比较麻烦)
                System.out.print(o + "  ");        //没有用泛型的方法:123  aaa  true
            }
        }
    
        //有用泛型的方法
        public static void method2() {
            //创建集合并添加元素
            ArrayList<String> list = new ArrayList<>(); //泛型<String>表明该集合只能存入String类型的数据
            list.add("aaa");
            list.add("bbb");
            list.add("ccc");
            list.add("ddd");
    
            //遍历集合并输出数据
            Iterator<String> it = list.iterator();
            while (it.hasNext()) {
                String str = it.next();
                System.out.print(str + "  ");         //有用泛型的方法:aaa  bbb  ccc  ddd
            }
        }
    
    }
    
    
  • 输出结果
    在这里插入图片描述

2. 泛型类

泛型类是使用泛型参数的类。通过在类名后使用尖括号<>包围的类型参数,可以定义泛型类。这样的泛型类可以在类的任何位置使用类型参数作为参数类型或返回类型。

2.1 概述

泛型类:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类

格式:

	    修饰符 class 类名 <类型> {
	
	    }

举例:

public class ArrayList<E>{  //创建该对象时,E就确定了类型
	    //此处E可以理解为变量,但是不是用来记录数据的,而是记录数据的类型。
	
	        }

2.2 代码示例

要求:自己创建一个带有泛型的ArrayList集合(当在编写一个类的时候,如果不能确认类型,那么这个类可以定义为泛型类)

  • 代码示例

    package text.text02;
    
    import java.util.Arrays;
    
    /*
    泛型类:
        当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
    
    格式:
        修饰符 class 类名 <类型> {
    
        }
    
    要求:自己创建一个带有泛型的ArrayList集合(当在编写一个类的时候,如果不能确认类型,那么这个类可以定义为泛型类)
     */
    public class text31 {
        public static void main(String[] args) {
            //创建MyArrayList的集合对象并添加数据
            MyArrayList<String> list = new MyArrayList<>();
            list.add("aaa");
            list.add("ddd");
            list.add("ccc");
            System.out.println(list);      //[aaa, ddd, ccc, null, null, null, null, null, null, null]
    
            //获取索引为1的元素
            String str = list.get(1);
            System.out.println("索引为1的元素:" + str);          //索引为1的元素:ddd
        }
    }
    
    class MyArrayList<E> {
        //创建一个长度为10的数组
        Object[] arr = new Object[10];
        //定义变量记录存储数据的长度,初始化为0
        int size;
    
        /*
        E:表示是不确定的类型,该类型在类名后面已经定义过了
        e:形参的名字,变量名
         */
        //添加数据的方法
        public boolean add(E e) {
            arr[size] = e;
            size++;
            return true;
        }
    
        //获取数据的方法
        public E get(int index) {
            return (E) arr[index];
        }
    
        //重写toString方法
        @Override
        public String toString() {
            return Arrays.toString(arr);
        }
    }
    
  • 输出结果
    在这里插入图片描述

3. 泛型方法

泛型方法是在方法定义中使用泛型参数的方法。通过在方法名前使用尖括号<>包围的类型参数,可以定义泛型方法。这样的泛型方法可以在方法的参数类型、返回类型或方法体中使用类型参数。

3.1 概述

泛型方法:

  1. 使用类名后面定义的类型(所有的方法都能使用)

  2. 在方法申明上定义自己的泛型(只有本方法能用)

格式:

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

例如:

public <T> void add(T t){
	    //此处T可以理解为变量,但是不是用来记录数据的,而是记录数据的类型。
	
}

3.2 代码示例

要求:定义一个工具类:ListUtil,类中定义一个静态方法addAll,用来将多个元素添加进集合。

  • 代码示例

    package text.text02;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    
    /*
    泛型方法:
        1.使用类名后面定义的类型(所有的方法都能使用)
        2.在方法申明上定义自己的泛型(只有本方法能用)
    
    格式:
        修饰符 <类型> 返回值类型 方法名 (类型  变量名){
    
        }
    
    要求:定义一个工具类:ListUtil,类中定义一个静态方法addAll,用来将多个元素添加进集合。
     */
    public class text32 {
        public static void main(String[] args) {
            //创建集合对象
            ArrayList<String> list = new ArrayList<>();
    
            //调用addAll方法
            ListUtil.addAll(list, "aaa", "bbb", "ccc", "ddd", "eee", "fff");
    
            System.out.println(list);         //[aaa, bbb, ccc, ddd, eee, fff]
        }
    
    }
    
    //工具类:ListUtil
    class ListUtil {
        //私有化构造方法
        private ListUtil() {
        }
    
        //在方法申明上定义自己的泛型(只有本方法能用) 
        public static <T> void addAll(ArrayList<T> list, T t1, T t2, T t3, T t4, T t5, T t6) {   //添加多个元素:T... t(底层是一个可变数组))
            list.add(t1);
            list.add(t2);
            list.add(t3);
            list.add(t4);
            list.add(t5);
            list.add(t6);
        }
    }
    
    
  • 输出结果
    在这里插入图片描述

4. 泛型接口

泛型接口是在接口定义中使用泛型参数的接口。通过在接口名称后面使用尖括号<>包围的类型参数,可以定义泛型接口。这样的泛型接口可以在接口的方法参数类型、返回类型或方法体中使用类型参数。

4.1 概述

泛型接口:
定义一个接口时,数据类型不确定时,就可以定义带有泛型的接口。

格式:

修饰符 interface 接口名 <类型>{
	
	    }

例如:

 public interface  List<E>{
	    //此处E可以理解为变量,但是不是用来记录数据的,而是记录数据的类型。
	
 }

泛型接口的使用方法:

  • 方法1:实现类给出具体的类型

  • 方法2:实现类延续泛型,创建对象时再确定

4.2 代码示例

  • 代码示例

    package text.text02;
    
    import java.util.*;
    
    /*
    泛型接口:
        定义一个接口时,数据类型不确定时,就可以定义带有泛型的接口。
    
    格式:修饰符 interface 接口名 <类型>{
    
        }
    
    泛型接口的使用方法:
    方法1:实现类给出具体的类型
    方法2:实现类延续泛型,创建对象时再确定
     */
    public class text33 {
        public static void main(String[] args) {
            //方法1:实现类给出具体的类型,创建对象时不用确认数据类型
            MyArrayList1 list1 = new MyArrayList1();
            list1.add("aaa");
            list1.add("bbb");
            list1.add("ccc");
            //list1.add(123);由于在实现类中确认的是字符串类型的,因此添加Integer类型的会报错
            System.out.print("方法1:实现类给出具体的类型,创建对象时不用确认数据类型:");
            for (int i = 0; i < list1.size(); i++) {
                System.out.print(list1.get(i) + "  ");           //aaa  bbb  ccc
            }
    
            System.out.println();
    
            //方法2:实现类延续泛型,创建对象时再确定
            MyArrayList2<String> list2 = new MyArrayList2<>();
            list2.add("ddd");
            list2.add("eee");
            list2.add("fff");
            //list2.add(123);由于在创建对象时确定了是字符串类型的,因此添加Integer类型的会报错
            System.out.print("方法2:实现类延续泛型,创建对象时再确定:");
            for (int i = 0; i < list2.size(); i++) {
                System.out.print(list2.get(i) + "  ");           //ddd  eee  fff
            }
        }
    }
    
    //方法1:实现类给出具体的类型
    class MyArrayList1 implements List<String> {     //List是一个Java已经定义好的为泛型的接口 :public interface List<E> extends Collection<E>
        Object[] arr = new Object[10];
        int size;
    
        @Override
        public int size() {
            return size;
        }
    
        @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) {
            arr[size] = s;
            size++;
            return true;
        }
    
        @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 (String) arr[index];
        }
    
        @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:实现类延续泛型,创建对象时再确定
    class MyArrayList2<E> implements List<E> {
        Object[] arr = new Object[10];
        int size;
    
        @Override
        public int size() {
            return size;
        }
    
        @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 s) {
            arr[size] = s;
            size++;
            return true;
        }
    
        @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 (E) arr[index];
        }
    
        @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;
        }     //List是一个Java已经定义好的为泛型的接口 :public interface List<E> extends Collection<E>
    
    }
    
  • 输出结果
    在这里插入图片描述

5. 泛型特点

5.1 概述

泛型是一种参数化类型的机制,它在编程语言中引入了类型参数,使得代码可以更加通用和类型安全。

泛型不具备继承关系,但是数据可以继承

5.2 代码示例

package text.text02;

import java.util.ArrayList;

/*
泛型不具备继承关系,但是数据可以继承
*/
public class text34 {
    public static void main(String[] args) {

    }

    //泛型不具备继承关系,但是数据可以继承
    public static void method1() {
        //创建集合对象
        ArrayList<Ye1> list1 = new ArrayList<>();
        ArrayList<Fu1> list2 = new ArrayList<>();
        ArrayList<Zi1> list3 = new ArrayList<>();

        //泛型不具备继承关系
        //调用method2方法,将创建的集合对象作为参数传进去
        method2(list1);
        //method2(list2);代码报错,说明泛型不具备继承关系
        //method2(list3);代码报错,说明泛型不具备继承关系

        //泛型数据可以继承
        list1.add(new Ye1());
        list1.add(new Fu1());
        list1.add(new Zi1());
    }

    //定义一个方法,只能接受Fu类类型的数据
    public static void method2(ArrayList<Ye1> list) {

    }
}


//定义一个继承关系:Ye1 Fu1 Zi1
class Ye1 {
}

class Fu1 extends Ye1 {
}

class Zi1 extends Fu1 {
}

6. 泛型通配符

泛型通配符(Wildcard)是 Java 泛型中的一个特性,用于在泛型类、接口和方法中表示一种未知类型。它使用问号(?)来表示。通配符允许你使用不具体的类型参数,从而增加代码的灵活性和通用性。

6.1 概述

泛型的通配符:? (限定类型的范围)

  • ? extends E : 表示可以传递E或者E的子类类型

上界通配符:使用上界通配符? extends 类型表示未知类型是给定类型的子类型或本身。它限制了类型的上界,表示类型必须是某个具体类型或其子类型。通常用于限制方法的参数类型或方法的返回类型。

  • ? super E :表示可以传递E或者E的父类类型

下界通配符:使用下界通配符? super 类型表示未知类型是给定类型的父类型或本身。它限制了类型的下界,表示类型必须是某个具体类型或其父类型。通常用于限制方法的参数类型。

泛型通配符的主要特点:

  • 灵活性:通配符允许你使用一种未知的类型,从而使得代码可以处理不同的类型参数。

  • 通用性:通配符可以适用于任何类型,使得代码更加通用和可重用。

  • 安全性:泛型通配符提供了类型安全性,编译器会检查通配符使用的合法性,并在编译时发出警告或错误。

应用场景:

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

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

6.2 代码示例

需求:定义一个方法,形参是一个集合,但是集合中的数据类型不能确定

package text.text02;
/*
泛型的通配符:?  (限定类型的范围)
    ? extends E : 表示可以传递E或者E的子类类型
    ? super E :表示可以传递E或者E的父类类型

 */

import java.util.ArrayList;

public class text35 {
    public static void main(String[] args) {
        //创建集合并调用method系列方法
        ArrayList<Ye2> list1 = new ArrayList<>();
        ArrayList<Fu2> list2 = new ArrayList<>();
        ArrayList<Zi2> list3 = new ArrayList<>();
        ArrayList<Student> list4 = new ArrayList<>();

        //利用泛型方法有个弊端,此时method1方法可以接受任意的数据类型
        method1(list1);
        method1(list2);
        method1(list3);
        method1(list4);   //list4是学生类型的,没有继承关系,但是依旧可以调用method1方法


        //利用泛型通配符的方式一:? extends E : 表示可以传递E或者E的子类类型
        method2(list1);
        method2(list2);
        method2(list3);
        //method2(list4);代码报错,因为list4是学生类型的,没有继承关系,因此不能调用method2方法

        //利用泛型通配符的方式二:? super E :表示可以传递E或者E的父类类型
        method3(list1);
        method3(list2);
        method3(list3);
        //method3(list4);代码报错,因为list4是学生类型的,没有继承关系,因此不能调用method3方法
    }

    //可以利用泛型方法的方式,但是利用泛型方法有个弊端,此时method1方法可以接受任意的数据类型
    public static <E> void method1(ArrayList<E> list) {

    }

    //利用泛型通配符的方式
    //? extends E : 表示可以传递E或者E的子类类型
    //? super E :表示可以传递E或者E的父类类型
    public static void method2(ArrayList<? extends Ye2> list) {  //说明该方法只能传递Ye2数据类型的或者继承Ye2数据类型的list对象

    }

    public static void method3(ArrayList<? super Zi2> list) {  //说明该方法只能传递Zi2数据类型的或者Zi2数据类型的父类的list对象

    }
}

//定义一个继承关系:Ye2 Fu2 Zi2
class Ye2 {
}

class Fu2 extends Ye2 {
}

class Zi2 extends Fu2 {
}

//再定义一个没有继承结构的学生类
class Student {
}

7. 综合案例

  • 需求:

      定义一个继承结构:
                                        动物
         					    |                 |
                                 猫                狗
                          |           |        |        |
                       波斯猫        狸花猫     泰迪    哈士奇
    
     属性:名字,年龄
     行为:吃东西
          方法体打印:一只叫做XXX的,X岁的波斯猫,正在吃小饼干
          方法体打印:一只叫做XXX的,X岁的狸花猫,正在吃鱼
          方法体打印:一只叫做XXX的,X岁的泰迪,正在吃骨头,边吃边蹭
          方法体打印:一只叫做XXX的,X岁的哈士奇,正在吃骨头,边吃边拆家
    
     测试类中定义一个方法,用来饲养动物
     public static void keepPet(ArrayList<???> list){
      //遍历集合,调用动物的eat方法
     }
    
     要求1:该方法能养所有品种的猫,但是不能养狗
     要求2:该方法能养所有品种的狗,但是不能养猫
     要求3:该方法能养所有品种的动物,但是不能传递其他类型
    
  • 代码实现:

    • 组父类:Animal类
    package code.code36;
    
    public abstract class Animal {
        private String name;
        private int age;
    
        public Animal() {
        }
    
        public Animal(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 "Animal{name = " + name + ", age = " + age + "}";
        }
    
        public abstract  void eat();
    }
    
    
    • 父类:Cat类
    package code.code36;
    
    public abstract class Cat extends Animal {
    
        public Cat() {
        }
    
        public Cat(String name, int age) {
            super(name, age);
        }
    
    }
    
    
    • 父类:Dog类
    package code.code36;
    
    public abstract class Dog extends Animal {
    
        public Dog() {
        }
    
        public Dog(String name, int age) {
            super(name, age);
        }
    
    }
    
    
    • 子类:波斯猫类
    package code.code36;
    
    //波斯猫
    public class PersianCat extends Cat {
        public PersianCat() {
        }
    
        public PersianCat(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void eat() {
            System.out.println("一只叫做" + this.getName() + "的," + this.getAge() + "岁的波斯猫,正在吃小饼干");
        }
    }
    
    
    • 子类:狸花猫类
     package code.code36;
    
    //狸花猫
    public class LiHuaCat extends Cat {
        public LiHuaCat() {
        }
    
        public LiHuaCat(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void eat() {
            System.out.println("一只叫做" + this.getName() + "的," + this.getAge() + "岁的狸花猫,正在吃鱼");
        }
    
    }
    
    
    • 子类:哈士奇类
    package code.code36;
    
    //哈士奇
    public class HaShiQi extends Dog {
        public HaShiQi() {
        }
    
        public HaShiQi(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void eat() {
            System.out.println("一只叫做" + this.getName() + "的," + this.getAge() + "岁的哈士奇,正在吃骨头,边吃边拆家");
        }
    }
    
    
    • 子类:泰迪类
    package code.code36;
    
    //泰迪
    public class TaiDi extends Dog {
        public TaiDi() {
        }
    
        public TaiDi(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void eat() {
            System.out.println("一只叫做" + this.getName() + "的," + this.getAge() + "岁的泰迪,正在吃骨头,边吃边蹭");
        }
    
    }
    
    
    • 测试类:
    package code.code36;
    
    import java.util.ArrayList;
    
    public class CodeText36 {
       public static <E> void main(String[] args) {
           //创建动物的集合对象,并将动物对象添加进集合
           ArrayList<PersianCat> list1 = new ArrayList<>();
           ArrayList<LiHuaCat> list2 = new ArrayList<>();
           ArrayList<TaiDi> list3 = new ArrayList<>();
           ArrayList<HaShiQi> list4 = new ArrayList<>();
    
           list1.add(new PersianCat("波斯", 2));
           list2.add(new LiHuaCat("狸花", 3));
           list3.add(new TaiDi("泰迪", 4));
           list4.add(new HaShiQi("二哈", 5));
    
           //要求1:该方法能养所有品种的猫,但是不能养狗
           System.out.println("要求1:该方法能养所有品种的猫,但是不能养狗:");
           keepPet1(list1);         //一只叫做波斯的,2岁的波斯猫,正在吃小饼干
           keepPet1(list2);         //一只叫做狸花的,3岁的狸花猫,正在吃鱼
    
           System.out.println("===============================");
    
           //要求2:该方法能养所有品种的狗,但是不能养猫
           System.out.println("要求2:该方法能养所有品种的狗,但是不能养猫:");
           keepPet2(list3);         //一只叫做泰迪的,4岁的泰迪,正在吃骨头,边吃边蹭
           keepPet2(list4);         //一只叫做二哈的,5岁的哈士奇,正在吃骨头,边吃边拆家
    
           System.out.println("===============================");
    
           //要求3:该方法能养所有品种的动物,但是不能传递其他类型
           System.out.println("要求3:该方法能养所有品种的动物,但是不能传递其他类型:");
           keepPet3(list1);        //一只叫做波斯的,2岁的波斯猫,正在吃小饼干
           keepPet3(list2);        //一只叫做狸花的,3岁的狸花猫,正在吃鱼
           keepPet3(list3);        //一只叫做泰迪的,4岁的泰迪,正在吃骨头,边吃边蹭
           keepPet3(list4);        //一只叫做二哈的,5岁的哈士奇,正在吃骨头,边吃边拆家
       }
    
       //要求1:该方法能养所有品种的猫,但是不能养狗
       public static void keepPet1(ArrayList<? extends Cat> list) {
           //遍历集合,调用动物的eat方法
           for (Cat cat : list) {
               cat.eat();
           }
       }
    
       //要求2:该方法能养所有品种的狗,但是不能养猫
       public static void keepPet2(ArrayList<? extends Dog> list) {
           //遍历集合,调用动物的eat方法
           for (Dog dog : list) {
               dog.eat();
           }
       }
    
       //要求3:该方法能养所有品种的动物,但是不能传递其他类型
       public static void keepPet3(ArrayList<? extends Animal> list) {
           //遍历集合,调用动物的eat方法
           for (Animal animal : list) {
               animal.eat();
           }
       }
    }
    
    
    • 输出结果:
      在这里插入图片描述

8. 注意事项

  1. 参数化类型不能使用基本数据类型

泛型的类型参数只能是引用类型,不能是基本数据类型。如果需要使用基本数据类型,可以使用对应的包装类(如Integer代替int)。

  1. 无法创建具体的泛型类型的实例

不能直接使用泛型类型来创建对象,例如List<String> list = new List<String>();是错误的。可以使用原始类型(如List)或通配符来创建对象,例如List<?> list = new ArrayList<>();是正确的。

  1. 泛型类型的类型参数在运行时被擦除

泛型在编译时进行类型检查,但在运行时会被擦除为原始类型。这意味着在运行时无法获得泛型类型的具体参数类型。例如,对于List<String>List<Integer>,在运行时它们都被视为List<Object>

  1. 泛型数组的创建受限

无法直接创建带有泛型类型参数的数组,例如List<String>[] array = new List<String>[10];是错误的。可以使用通配符或原始类型数组,例如List<?>[] array = new List<?>[10];是正确的。

  1. 不能使用基本类型作为类型参数

泛型类型参数不能是基本类型,只能是引用类型。如果需要使用基本类型作为类型参数,可以使用对应的包装类。

  1. 泛型类型的类型参数不能是基本类型的数组

泛型类型的类型参数不能是基本类型的数组,例如List<int[]>是错误的。

  1. 类型擦除可能导致运行时异常

由于泛型的类型参数在运行时被擦除,可能会导致在运行时出现类型相关的异常。因此,在使用泛型时要格外小心,并进行必要的类型检查和转换。

  1. 通配符的使用限制

使用通配符时,不能使用null以外的具体值,只能用于方法声明、参数传递和通配符类型的赋值操作。

  1. 泛型类型的兼容性

泛型类型在类型参数相同的情况下才具有兼容性。例如,List<String>List<Integer>不是兼容类型。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1428610.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis核心技术与实战【学习笔记】 - 15.Redis 缓存的淘汰策略

前言 Redis 缓存使用内存来保存数据&#xff0c;避免业务应用直接从数据库读取数据&#xff0c;可以提升应用的访问速度。但是&#xff0c;我们又没有办法做到把所有的数据都放入缓存&#xff0c;因为这样做的性价比不高&#xff0c;而且缓存也存不下数据库中的所有数据。 例…

《Pandas 简易速速上手小册》第8章:Pandas 高级数据分析技巧(2024 最新版)

文章目录 8.1 使用 apply 和 map 函数8.1.1 基础知识8.1.2 重点案例&#xff1a;客户数据清洗和转换8.1.3 拓展案例一&#xff1a;产品评分调整8.1.4 拓展案例二&#xff1a;地址格式化 8.2 性能优化技巧8.2.1 基础知识8.2.2 重点案例&#xff1a;大型销售数据分析8.2.3 拓展案…

Echarts+Vue 首页大屏静态示例Demo 第三版

效果图: 源码: <template><div class="content bg" style="height: 100vh;overflow-y: auto" :class="{ fullscreen-container: isFullScreen }"><div class="reaDiv" style="height: 10vh"><div…

【华为】GRE VPN 实验配置

【华为】GRE VPN 实验配置 前言报文格式 实验需求配置思路配置拓扑GRE配置步骤R1基础配置GRE 配置 ISP_R2基础配置 R3基础配置GRE 配置 PCPC1PC2 抓包检查OSPF建立GRE隧道建立 配置文档 前言 VPN &#xff1a;&#xff08;Virtual Private Network&#xff09;&#xff0c;即“…

国产飞腾ARM+FPGA电力行业 DCS 联合解决方案

联合解决方案概述 在火电的发展过程中&#xff0c;随着社会对电力资源需求越来越高&#xff0c;以往较为粗放式的发电已经行不通了&#xff0c;需要 更精细化的发电&#xff0c;以达到资源的最大利用。而这种控制都需要靠自动化技术来实现&#xff0c;单纯的人工是达不到这种 …

从第一性原理看大模型Agent技术

引 一个乐观主义者的悲观估计 随着大规模模型技术的兴起&#xff0c;我们正处于一个崭新的智能时代的黎明。我们有一个大胆的预测&#xff0c;未来的5到10年将可能带来一场大变局&#xff1a;99%的开发、设计和文字工作将被AI接管。这不仅仅是一个想象&#xff0c;而是对未来可…

算法学习——华为机考题库2(HJ11 - HJ20)

算法学习——华为机考题库2&#xff08;HJ11 - HJ20&#xff09; HJ11 数字颠倒 描述 输入一个整数&#xff0c;将这个整数以字符串的形式逆序输出 程序不考虑负数的情况&#xff0c;若数字含有0&#xff0c;则逆序形式也含有0&#xff0c;如输入为100&#xff0c;则输出为0…

政安晨的AI笔记——示例演绎OpenAI的ChatGPT与DALL·E提示词总原则(并融合创作一副敦煌飞天仙女图)

ChatGPT是由OpenAI开发的一种基于大规模预训练的语言生成模型。它建立在GPT&#xff08;Generative Pre-trained Transformer&#xff09;模型的基础上&#xff0c;通过大量的无监督学习和生成式任务训练来学习语言的概念和模式。 ChatGPT的原理是基于Transformer模型。Transfo…

java处理ppt方案详解

需求 需要系统中展示的ppt案例有一个动态展示的效果&#xff0c;也就是要有动画的交互&#xff0c;要求支持浏览器直接打开预览 背景 目前已经实现了前端上传pptx文件&#xff0c;后端解析为png的图片&#xff0c;前端掉接口返回对应的图片&#xff0c;模拟播放ppt的效果 各种尝…

Kafka_03_Consumer详解

Kafka_03_Consumer详解 Consumer消费消息订阅/拉取ConsumerRecord 消费位移位移提交位移消费 实现原理RebalanceConsumerInterceptorDeSerializer 多线程消费消费线程处理线程 Consumer Consumer(消费者): 从Partition拉取并消费消息(非线程安全) Topic的Partition在每个消费…

最新!2024顶级SCI优化!TTAO-CNN-BiGRU-MSA三角拓扑聚合优化、双向GRU融合注意力的多变量回归预测程序!

适用平台&#xff1a;Matlab 2023版及以上 TTOA三角聚合优化算法&#xff0c;将在2024年3月正式发表在中科院1区顶级SCI期刊《Expert Systems with Applications》上。 该算法提出时间极短&#xff0c;目前以及近期内不会有套用这个算法的文献。新年伊始&#xff0c;尽快拿下…

备战蓝桥杯---数据结构与STL应用(入门1)

话不多说&#xff0c;直接看题&#xff1a; 下面为分析&#xff1a;显然&#xff0c;我们要先合并最小的两堆&#xff08;因为他们在后边也得被计算&#xff0c;换句话&#xff0c;我们独立的看&#xff0c;某一堆的体力值为他自己重量*从现在到最后的次数&#xff09; 因此&a…

JAVA Web 学习(三)Web服务架构

五、软件架构模式——MVC MVC是一种 分层开发的模式 &#xff0c;其中&#xff1a;M-Model&#xff0c;业务模型&#xff0c;处理业务&#xff1b;V&#xff1a;View&#xff0c;视图&#xff0c;界面展示&#xff1b;C&#xff1a;Controller&#xff0c;控制器&#xff0c;处…

vulhub靶机activemq环境下的CVE-2015-5254(ActiveMQ 反序列化漏洞)

影响范围 Apache ActiveMQ 5.x ~ Apache ActiveMQ 5.13.0 远程攻击者可以制作一个特殊的序列化 Java 消息服务 (JMS) ObjectMessage 对象&#xff0c;利用该漏洞执行任意代码。 漏洞搭建 没有特殊要求&#xff0c;请看 (3条消息) vulhub搭建方法_himobrinehacken的博客-CSD…

柔性电流探头方向判断有哪些方法?干货分享!

柔性电流探头方向判断的方法干货分享&#xff01;从理论到实践&#xff0c;助您成为专业人士&#xff01;干货收藏&#xff0c;快看起来吧&#xff01;      柔性电流探头方向判断一直是电力行业测试中的关键问题之一&#xff0c;确切地判断电流方向对于测试电力系统的稳定…

分类预测 | Matlab实现GAF-PCNN-MATT格拉姆角场和双通道PCNN融合多头注意力机制的分类预测/故障识别

分类预测 | Matlab实现GAF-PCNN-MATT格拉姆角场和双通道PCNN融合多头注意力机制的分类预测/故障识别 目录 分类预测 | Matlab实现GAF-PCNN-MATT格拉姆角场和双通道PCNN融合多头注意力机制的分类预测/故障识别分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现G…

jsp 产品维修管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 产品维修管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.…

追觅科技发布全折叠高速吹风机Pocket

2月2日&#xff0c;追觅科技召开2024新品发布会&#xff0c;一系列年度新品亮相。现场&#xff0c;追觅科技发布了个护重磅新品——追觅Pocket折叠高速吹风机&#xff0c;这也是行业首个全折叠高速吹风机。 创新柔性折叠技术&#xff0c;直卷吹一机全能 追觅Pocket折叠高速吹风…

体育馆运动场地预定小程序的独特优势与用户体验

随着人们健康意识的提高&#xff0c;体育馆成为了大家进行锻炼和运动的重要场所。为了更好地满足用户的需求&#xff0c;体育馆需要开发一款预定场地的小程序&#xff0c;为用户提供便捷、高效的预定服务。本文将介绍如何使用乔拓云平台开发体育馆运动场地预定小程序&#xff0…

如何评价 Linux 中国停止运营?

如何评价 Linux 中国停止运营&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「Linux的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&…