corajava--简单总结java泛型的应用

原文以及参考博客:

  1. java 泛型详解
  2. Java语法糖3:泛型

  3. Java总结篇系列:Java泛型

  4. JAVA泛型通配符T,E,K,V区别,T以及Class<T>,Class<?>的区别

 

泛型的定义

按照百度百科的介绍,泛型是Java SE 1.5的新增特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。泛型是具有占位符(类型参数)的类、结构、接口和方法,这些占位符是类、结构、接口和方法所存储或使用的一个或多个类型的占位符。泛型集合类可以将类型参数用作它所存储的对象的类型的占位符;类型参数作为其字段的类型和其方法的参数类型出现。泛型方法可以将其类型参数用作其返回值的类型或者其形参的类型之一。

在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。

java中泛型的特点

1、类型安全。类型错误现在在编译期间就被捕获到了,而不是在运行时当作java.lang.ClassCastException展示出来,将类型检查从运行时挪到编译时有助于开发者更容易找到错误,并提高程序的可靠性

2、消除了代码中许多的强制类型转换,增强了代码的可读性

3、泛型使用之后不会对一个对象的实例造成影响。所以无法通过定义不同的泛型去定义重载的方法。

 

泛型中E、T、?等标识符的区别及用法

其实使用java26个大写字符都可以,只不过使用以下的几个更有助于不同程序员之间的理解。比将T换成了A,在执行效果上是没有任何区别的,只不过我们约定好了T代表type,所以还是按照约定规范来比较好,增加了代码的可读性。

 Java泛型中的标记符含义: 

 E - Element (表示元素 在集合中使用,因为集合中存放的是元素) 

 T - Type(Java 类) 表示一个具体的java类型,多个参数时可以使用T1、T2、T3...... 

 K - Key(键)

 V - Value(值)

 N - Number(数值类型)

? -  表示不确定的java类型,用作类型通配符,表示任何类型的父类型。

 S、U、V  - 2nd、3rd、4th types

泛型约束

可以使用extends、super,此时extends不表示继承。它表示类型通配符的上限。假设有一组类继承关系C继承自B,B继承自A。如下代码所定义的TestConstraint类:创建对应的实例时,只能是B及其B类型的子类(C类)


public class TestExtends {
    public static void main(String[] args) {
        TestConstraint<B> bTestConstraint = new TestConstraint<B>();
        TestConstraint<C> cTestConstraint = new TestConstraint<C>();
       
        //使用A类型时,此时编译不通过:Type parameter 'com.songxl.generic.A' is not within its bound; should extend 'com.songxl.generic.B'
        TestConstraint<A> aTestConstraint = new TestConstraint<A>();

        //使用其他类型时也会编译报错:Cannot resolve symbol 'T'
        TestConstraint<T> tTestConstraint = new TestConstraint<T>();
    }
}

class TestConstraint <T extends B>{}

class A {}
class B extends A{}
class C extends B{}

相对应的还有类型通配符的下限:super。同样借助于上述代码,在一个方法行参中测试super的使用。表示传递参数时:只能是B类型或者是B类型的父类型。

public class TestExtends {
    public static void main(String[] args) {
        TestConstraint<A> aTestConstraint = new TestConstraint<A>();
        TestConstraint<B> bTestConstraint = new TestConstraint<B>();
        TestConstraint<C> cTestConstraint = new TestConstraint<C>();

        //如果使用B类型或者B类型的父类型作为参数时,就没有问题
        getData(aTestConstraint);
        getData(bTestConstraint);

        //如果使用C类型(B类型的子类)的参数,编译会报错
        getData(cTestConstraint);

        //如果使用其他类型的实参,也会编译报错的
        getData(13);
    }

    public static void getData(TestConstraint<? super B> data) {
        System.out.println("data:" + data);
    }
}

class TestConstraint<T extends A> { }
class A { }
class B extends A { }
class C extends B { }

泛型的几种使用情况比较

  • List<T>,List<Object>,List<?>区别

ArrayList<T> al=new ArrayList<T>(); 指定集合元素只能是T类型(实例化的时候需要将其定义为所需的类型。比如:ArrayList<String> list = new ArrayList<String>())。

Object和T不同点在于,Object是一个实际的类,并没有泛指谁,而T可以泛指Object,比方public void printList(List<T> list){}方法中可以传入List<Object> list类型参数,也可以传入List<String> list类型参数,但是public void printList(List<Object> list){}就只可以传入List<Object> list类型参数,如果传入List<String> list类型的参数就会报错。

?和T区别是?是一个不确定类,?和T都表示不确定的类型 ,但如果是T的话,函数里面可以对T进行操作,例如: T car = getCar(),而不能用? car = getCar()。

  • 在定义成员变量时

    //此时使用T时会报错:Cannot resolve symbol 'T',因为Class类在定义时使用了public final class Class<T>   表示此时需要指定具体的类型。
    private Class<T> t;
    //如果不确定用?,但是在实例化使用时需要指定具体的类型。
    private Class<?> t2;
  • 在定义方法的参数时

  public static void printList1(List<Object> list) {
        for (Object o : list) {
            System.out.print(o+" .");
        }
        System.out.println();
    }

    public static void printList2(List<?> list) {
        for (Object o : list) {
            System.out.print(o+" .");
        }
        System.out.println();
    }

    public static <T> T printList3(List<T> list) {
        for (T t : list) {
            T t1 = t;
            System.out.print(t+" .");
        }
        System.out.println();
        T t = list.get(0);
        return t;
    }

    public static void getData(TestConstraint<? super B> data) {
        System.out.println("data:" + data);
    }

    public static void getData2(TestConstraint<? extends B> data) {
        System.out.println("data:" + data);
    }
  • 在类上定义时

//假定有:
class A { }
class B extends A { }
class C extends B { }

//可以这么定义:
class Test<String>{}
class Test2<T>{}
class Tes4<T extends B>{}

//如下情况会报错:
//'class' or 'interface' expected
class Tes5<T super B>{}

//Unexpected wildcard
class Test3<?>{}

//具体案例
public class ArrayList<E>{}
public class HashMap<K,V>{}
public class ThreadLocal<T>{}

暂时了解到的只有这些,后续接触到了再补充。

 

因为LZ也是在网上查阅各位大佬的资料及自己的理解写的,在开头已经贴出原文地址。若果有错误,万望指正;如果涉及侵权,请联系本人删除。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值