• java泛型


    1         泛型

    1.1            泛型的作用

    泛型有两种作用,一种是让接口或方式更通用,一种是限制作用。

    第一种是一种是让接口或方式更通用,泛型和C++的模板很相似,有时在定义函数或者接口时,不确定需要传入的参数是什么类型,这时可能要创建多个重载函数来枚举所有的数据类型。而有了泛型之后,直接用一个标识符代替具体的数据类型,在调用的时候传入具体的数据类型给标识符。从而实现接收任意数据类型的方法。例如:

    public interface Generator<T> {

        public T next();

    }

    第二则是限制作用。例如创建List时是以Object作为基类,所以可以放入任何类型的对象List arrayList = new ArrayList();arrayList.add("aaaa");arrayList.add(100);但是在输出的时候,不知道输出是什么类型。使用不当会导致奔溃。所以需要通过泛型来限制输入数据的类型。List<String> arrayList = new ArrayList<String>();只能输入String类型的数据,其他类型数据则会报错。

    1.2            泛型的使用

    1.2.1             泛型类

    泛型类的定义

    public class Generic<T>{

        //key这个成员变量的类型为T,T的类型由外部指定 

        private T key;

        public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定

            this.key = key;

        }

        public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定

            return key;

        }

    }

    泛型对象的创建

    //泛型的类型参数只能是类类型(包括自定义类),不能是简单类型

    //传入的实参类型需与泛型的类型参数类型相同,即为Integer.

    Generic<Integer> genericInteger = new Generic<Integer>(123456);

    Log.d("泛型测试","key is " + genericInteger.getKey());

    也可以省略泛型形参,会根据输入的数据类型自动识别。

    Generic generic2 = new Generic(55.55);

    Generic generic3 = new Generic(false);

    1.2.2             泛型接口

    定义泛型接口:

    public interface Generator<T> {

        public T next();

    }

    实现泛型接口

    (1)不指定泛型类型,实现类中也要加入泛型标识

    class FruitGenerator<T> implements Generator<T>{

        @Override

        public T next() {

            return null;

        }

    }

    (2)指定泛型类型,实现类中无需泛型标识

    public class FruitGenerator implements Generator<String> {

        private String[] fruits = new String[]{"Apple", "Banana", "Pear"};

        @Override

        public String next() {

            Random rand = new Random();

            return fruits[rand.nextInt(3)];

        }

    }

    1.2.3             泛型方法

     首先在public与返回值之间的<T>必不可少,这表明这是一个泛型方法,

        public <T> T showKeyName(Generic<T> container){

            System.out.println("container key :" + container.getKey());

            //当然这个例子举的不太合适,只是为了说明泛型方法的特性。

            T test = container.getKey();

            return test;

        }

    在泛型类中者形参中带有泛型标识符public void showKeyValue1(T key) ;showKeyValue1(Generic<Number> obj);带有通配符的函数 public void showKeyValue2(Generic<?> obj);或返回值是泛型标识符public T getKey();这些都不算是真正的泛型方法。其中的泛型标识符是类的泛型标识符,创建对象时传入实际的数据类型,调用泛型方法时,必须传入创建对象时的泛型数据类型。泛型类中泛型方法声明泛型标识符T可以与泛型类的泛型标识符T一样,也可以换成E,或者其他标识符。泛型方法中的标识符在泛型方法调用时,传入实际的数据类型,与泛型类中的标识符T没有必然联系,例如泛型类传入的类型是String,并不代表泛型方法中的T也是String类型。而是在泛型方法调用时传入具体的数据类型。总之泛型标识符只是用来标识,由传入数据类型决定。

    1.2.4             泛型可变参数

    泛型也可以用于可变参数:

    public <T> void printMsg( T... args){

        for(T t : args){

            Log.d("泛型测试","t is " + t);

        }

    }

    printMsg("111",222,"aaaa","2323.4");//传入不同类型的变量。

    1.2.5             静态方法与泛型

    因为静态方法属于类,而不属于对象,所有无法使用创建对象传入泛型的数据类型。所以静态方法如果要用泛型的话,只能定义为泛型方法。在静态方法调用时,传入具体的数据类型。

    public class StaticGenerator<T> {

       //public static void show(T t){..};ERROR此时编译器会提示错误信息:

    public static <T> void show(T t){ }};

    1.2.6             泛型通配符?

    Ingeter是Number的一个子类,Ingeter变量可以传给Number。但是Generic<Ingeter>变量却不可以传给Generic<Number>,不是子类和父类关系。这样就无法传递,因此类型通配符云而生。

    public void showKeyValue1(Generic<?> obj);

    使用?代替具体的类型实参,可以把?看成所有类型的父类。任何类型的Generic<Number>、Generic<String>、Generic<Integer>等都可以传入,Generic<?>各种泛型的父类,但是只能作为泛型形参,不能创建对象保存数据。可以解决不确定具体类型时,直接用?号代替;但同时也引入另外一个问题,因为不确定是什么类型,所在方法中只使用Object类中的基本功能方法。不可以用传入类型的特殊的方法。

    1.2.7             泛型的边界

    泛型的作用是能够传入任意数据类型,但是有时需要限制输入的类型范围,例如只允许number的子类传入。这时就需要设置边界;

    public void showKeyValue1(Generic<? extends Number> obj);

    这样只有Number的子类构成的变量Generic<Integer>、Generic<Float>等才可以传人,而Generic<String>则不能传入。这就是边界。

    泛型类也可以设置边界:

    public class Generic<T extends Number>{};

    泛型方法也可以设置边界:

    public <T extends Number> T showKeyName(Generic<T> container){};

    1.2.8             泛型数组

    Java是不支持泛型数组的,也就是说下面的这个例子是不可以的:

    List<String>[] ls = new ArrayList<String>[10]; 

    那么为什么不可以呢?来看一个例子:

    List<String>[] lsa = new List<String>[10]; // 实际是不可行,先假设可以这样.

    Object o = lsa;//创建一个object引用指向数组

    Object[] oa = (Object[]) o;

    List<Integer> li = new ArrayList<Integer>();//新建一个Integer的 List

    li.add(new Integer(3));//加入一个数据

    oa[1] = li; // 将list赋值给数组的第一个元素

    String s = lsa[1].get(0); //这里会报异常

    由于JVM泛型的擦除机制,在运行时JVM是不知道泛型信息的,所以可以给oa[1]赋上一个ArrayList而不会出现异常,但是在取出数据的时候却要做一次类型转换,所以就会出现ClassCastException,如果可以进行泛型数组的声明,上面说的这种情况在编译期将不会出现任何的警告和错误,只有在运行时才会出错。所以无法创建指定类型的泛型数组,可以采用通配符的方式创建数组:

    List<?>[] lsa = new List<?>[10]; // OK, array of unbounded wildcard type.   

    Object o = lsa;   

    Object[] oa = (Object[]) o;   

    List<Integer> li = new ArrayList<Integer>();   

    li.add(new Integer(3));   

    oa[1] = li; // Correct.   

    Integer i = (Integer) lsa[1].get(0); // OK

    因为使用了通配符,所以获取数据后需要进行强制类型转换,就不会出错。

    自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取:

    https://www.cnblogs.com/bclshuai/p/11380657.html

    百度云盘下载地址:

    链接:https://pan.baidu.com/s/1swkQzCIKI3g3ObcebgpIDg

    提取码:mc8l

    微信公众号获取最新的软件和视频介绍

    QStockView

  • 相关阅读:
    eclipse添加xsd
    Ibatis 后台打印完整的sql语句
    eclipse 将文件夹作为sourcefolder
    git:hook declined FATAL: W refs/heads DENIED by fallthru error
    单点登陆CAS安装过程中可能遇到的问题
    单点登录的原理与CAS技术的研究
    【转载】软件开发模式对比(瀑布、迭代、螺旋、敏捷)
    UML工具选择
    UML 用例图,时序图,活动图的定义以及区别
    基于UML的需求分析和系统设计个人体会
  • 原文地址:https://www.cnblogs.com/bclshuai/p/10593620.html
Copyright © 2020-2023  润新知