自定义泛型 类/接口、通配符的使用

时间:2024-4-16    作者:老大夫    分类: JAVA


1.自定义泛型类/接口

1.1 格式

class A<T>{}
interface B <T1,T2>{}

1.2 使用说明

  1. 我们在声明完自定义泛型类以后,可以在类的内部(比如:属性、方法、构造器中)使用类的泛型。

  2. 我们在创建自定义泛型类的对象时,可以指明泛型参数类型。一旦指明,内部凡是使用类的泛型参数的位置,都具体化为指定的类的泛型类型。

  3. 如果在创建自定义泛型类的对象时,没有指明泛型参数类型,那么型将被擦除,泛型对应的类型均按照Object处理,但不等价于0bject。
    经验:泛型要使用一路都用。要不用,一路都不要用。

  4. 泛型的指定中必须使用引用数据类型。不能使用基本数据类型,此时只能使用包装类替换

  5. 除创建泛型类对象外,子类继承泛型类时、实现类实现泛型接口时,也可以确定泛型结构中的泛型参数
    如果我们在给泛型类提供子类时,子类也不确定泛型的类型,则可以继续使用泛型参数。
    我们还可以在现有的父类的泛型参数的基础上,新增泛型参数。

  6. 异常不能带泛型

  7. 不能在静态方法中使用泛型。因为使用静态方法时会预先加载,这个时候还不知道泛型是否指明了类型。

2.自定义泛型方法

在方法中指明了泛型,就是泛型方法吗?

不是,如下不属于泛型方法。

public T getT() {return t}

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

2.1 举例

//通常在形参列表和返回值类型会出现泛型参数T
//权限修饰符 <T> 返回值类型 方法名 (形参列表 ){}
public <E> E method(E e){
    return e
}

就看方法前有没有声明< E >,否则会被认为是泛型类,让编译器知道这个是个泛型的方法。

2.2 说明

声明泛型方法时,一定要添加泛型参数< T >
泛型参数在方法调用时,指明其具体的类型
泛型方法可以根据需要声明为static的
泛型方法所属的类是否是一个泛型类,都可以。

在 Java 中,泛型类型参数是在实例化时确定的,并且静态方法是属于类而不是属于对象的。因为泛型类型参数是在实例化时才会被确定,而静态方法在编译期就已经确定了,所以无法使用泛型类型参数。
另外,对于静态方法来说,它们不能访问非静态的成员变量或者调用非静态的方法,因为在调用静态方法时可能还没有创建对象。如果允许泛型类型参数用于静态方法,则会与这种限制相矛盾。
因此,在 Java 中,我们无法在静态方法中使用泛型类型参数。如果需要在静态方法中使用泛型类型,则可以将泛型类型参数声明为该类的一个属性或者方法的形参,然后通过这个属性或者形参来使用泛型类型。

泛型在继承上的体现

  1. 类SuperA是类A的父类,则G< SuperA >与 G < A>的关系:
    G< SuperA > 和 G< A>是并列的两个类,没有任何子父类的关系比如:ArrayList< 0bject> 、ArrayList< String>没有关系

子类的泛型已经指定类型了,就不能向上转换类了。

例如,

Person<String> per=null;
Person<Object> per1=null;
//per不可以赋值给per1

如果per可以赋值给per1那么per1可以添加非String类型元素,String的限制将会消失,所以不可以。

  1. 类SuperA是类A的父类或接口,SuperA< G> 与 A< G>的关系

如果都指定类型为String,子类是可以赋值给父类的,内容类型都一样
例如:

public class Test11 {
        @org.junit.Test
        public void test111(){
            List<String> list1 = null;
            ArrayList<String> list2 = new ArrayList<>();
            list2.add("asd");
            list2.add("dsa");
            list1 = list2;
            System.out.println(list1);
        }
}

通配符的使用

  1. 通配符: ?

  2. 使用说明
    G< ?>可以看做是G< A>类型的父类,即可以将G< A>的对象赋值给G< ?>类型的引用(或变量)
    举例 ArrayList< ? >
    这里Object类型的List和String类型的都可以放进< ?>的List中

   @Test
    public void test12(){
            List<?> list=null;
            List<Object> list1=null;
            List<String> list2=null;

            list=list1;
            list=list2;
        }
  1. 读写操作的特点
    读写数据的特点(以集合ArrayList<?>为例说明)>
    读取数据:允许的,读取的值的类型为0bject类型>
    写入数据:不允许的。特例:写入null值。
    @Test
    public void test2() {
            List<?> list = null;
            List<String> list1 = new ArrayList<>();
            list1.add("AA");
            list = list1;
            //读取数据(以集合为例说明)
            Object obj = list.get(0);
            System.out.println(obj);
            //写入数据(以集合为例说明),不可以写入,但是null可以
//            list.add("BB");
            list.add(null);
        }
  1. 有限制条件的通配符
    List<? extends A> :可以将List< A>或List< B>赋值给List<? extends A>。其中B类是A类的子类
    List <? super A> :可以将List< A>或List< B>赋值给List<? extends A>。其中B类是A类的父类
  @Test
    public void test6(){
            List<? extends Father> list = null;
            List<Object> list1 = null;
            List<Father> list2 = null;
            List<Son> list3 = null;
            //Object不可以赋值,可以把extends理解为小于等于号,只有它的子类和本身类的可以赋值
            list = list1;
            list = list2;
            list = list3;
        }

    @Test
    public void test7(){
        List<? super Father> list = null;
        List<Object> list1 = null;
        List<Father> list2 = null;
        List<Son> list3 = null;
        //Son不可以赋值,可以把super理解为大于等于号,只有它的父类和本身类的可以赋值
        list = list1;
        list = list2;
        list = list3;
    }

有条件的通配符的读写

技巧:开发中,遇到了带限制条件的通配符,在赋值时,如果没报错,那就正常使用。
如果报错了,知道不能这样写。改改!

举例:

@Test
    public void test3_1() {
        List<? extends Father> list = null;
        List<Father> list1 = new ArrayList<>();
        list1.add(new Father());
        list = list1;
        //读取数据: 可以的
        Father father = list.get(0);
        //写入数据: 不可以的。例外:list.add(null);
        list.add(new Father());
        list.add(new Son());
    }

    @Test
    public void test4_1() {
        List<? super Father> list = null;
        List<Father> list1 = new ArrayList<>();
        list1.add(new Father());
        list = list1;
        //读取数据: 可以的
        Object obj = list.get(0);
        //写入数据:
        list.add(null);
        //下界为Father类,Father以下的类都可以放入
        list.add(new Object());
        list.add(new Father());
        list.add(new Son());
    }

版权所有:伸手党盘
文章标题:自定义泛型 类/接口、通配符的使用
文章链接:https://ssdpan.cn/?post=388
本站文章来源于网络搜集和原创,仅供学习使用,未经授权请勿用于任何商业用途,如有侵权及时联系删除

推荐阅读:


扫描二维码,在手机上阅读