精华内容
下载资源
问答
  • 泛型

    2017-04-04 19:34:23
    1. 泛型概述泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是...

    1. 泛型概述

    泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。

    泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。 Java语言引入泛型的好处是安全简单。

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

    泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。

    可以在集合框架(Collection framework)中看到泛型的动机。例如,Map 类允许您向一个 Map添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象。

    因为 Map.get() 被定义为返回 Object,所以一般必须将 Map.get() 的结果强制类型转换为期望的类型,如下面的代码所示:

      Map m = new HashMap();
      m.put("key", "blarg");
      String s = (String) m.get("key");

    要让程序通过编译,必须将 get() 的结果强制类型转换为 String,并且希望结果真的是一个 String。但是有可能某人已经在该映射中保存了不是 String 的东西,这样的话,上面的代码将会抛出 ClassCastException。

    理想情况下,您可能会得出这样一个观点,即 m 是一个 Map,它将 String 键映射到 String 值。这可以让您消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中。这就是泛型所做的工作。

    package cn.itcast_01;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    
    /*
     * ArrayList存储字符串并遍历
     * 
     * 我们按照正常的写法来写这个程序, 结果确出错了。
     * 为什么呢?
     *      因为我们开始存储的时候,存储了String和Integer两种类型的数据。
     *      而在遍历的时候,我们把它们都当作String类型处理的,做了转换,所以就报错了。
     * 但是呢,它在编译期间却没有告诉我们。
     * 所以,我就觉得这个设计的不好。
     * 回想一下,我们的数组
     *      String[] strArray = new String[3];
     *      strArray[0] = "hello";
     *      strArray[1] = "world";
     *      strArray[2] = 10;
     * 集合也模仿着数组的这种做法,在创建对象的时候明确元素的数据类型。这样就不会在有问题了。
     * 而这种技术被称为:泛型。
     * 
     * 泛型:是一种把类型明确的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。参数化类型,把类型当作参数一样的传递。
     * 格式:
     *      <数据类型>
     *      此处的数据类型只能是引用类型。
     * 好处:
     *      A:把运行时期的问题提前到了编译期间
     *      B:避免了强制类型转换
     *      C:优化了程序设计,解决了黄色警告线
     */
    public class GenericDemo {
        public static void main(String[] args) {
            // 创建
            ArrayList<String> array = new ArrayList<String>();
    
            // 添加元素
            array.add("hello");
            array.add("world");
            array.add("java");
            // array.add(new Integer(100));
            //array.add(10); // JDK5以后的自动装箱
            // 等价于:array.add(Integer.valueOf(10));
    
            // 遍历
            Iterator<String> it = array.iterator();
            while (it.hasNext()) {
                // ClassCastException
                // String s = (String) it.next();
                String s = it.next();
                System.out.println(s);
            }
    
            // 看下面这个代码
            // String[] strArray = new String[3];
            // strArray[0] = "hello";
            // strArray[1] = "world";
            // strArray[2] = 10;
        }
    }

    2. 泛型的好处

    Java 语言中引入泛型是一个较大的功能增强。不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的了。这带来了很多好处:

    2.1 类型安全

    泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。

    Java 程序中的一种流行技术是定义这样的集合,即它的元素或键是公共类型的,比如“String 列表”或者“String 到 String 的映射”。通过在变量声明中捕获这一附加的类型信息,泛型允许编译器实施这些附加的类型约束。类型错误现在就可以在编译时被捕获了,而不是在运行时当作 ClassCastException 展示出来。将类型检查从运行时挪到编译时有助于您更容易找到错误,并可提高程序的可靠性。

    2.2 消除强制类型转换

    泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。
    尽管减少强制类型转换可以降低使用泛型类的代码的罗嗦程度,但是声明泛型变量会带来相应的罗嗦。

    2.3 优化了程序设计,解决了黄色警告线

    3. 泛型的应用

    3.1 泛型的内部原理

    泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入。但是,编译器编译带类型说明的集合时会去除掉“类型”信息,目的就是使程序运行效率不受影响。因此,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。

    package com.itheima.day2;
    
    import java.util.ArrayList;
    
    public class GenericTest {
    
           public static void main(String[] args) {
                ArrayList<String> collection1 = new ArrayList<String>();
                ArrayList collection2 = new ArrayList();
                System. out.println(collection1.getClass() == collection2.getClass());
                 //结果:true
          }
    }

    由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add方法即可。

    package com.itheima.day2;
    
    import java.util.ArrayList;
    
    public class GenericTest {
    
           public static void main(String[] args) throws Exception {
                ArrayList<Integer> collection1 = new ArrayList<Integer>();
                collection1.getClass().getMethod( "add",Object.class).invoke(collection1, "abc");
                System. out.println(collection1.get(0));
          }
    }

    ArrayList类定义和ArrayList<Integer>类引用中涉及如下术语:

    • 整个称为ArrayList<E>泛型类型
    • ArrayList<E>中的E称为类型变量或类型参数
    • 整个ArrayList<Integer>称为参数化的类型
    • ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
    • ArrayList<Integer>中的<>念着typeof
    • ArrayList称为原始类型

    参数化类型与原始类型的兼容性:参数化类型可以引用一个原始类型的对象,编译报告警告,例如

    Collection<String> c = new Vector();//考虑到对以前代码的兼容性,编译器是可以通过的

    原始类型可以引用一个参数化类型的对象,编译报告警告,例如

    Collection c = new Vector<String>();//原来的方法接受一个集合参数,新的类型也要能传进去

    参数化类型不考虑类型参数的继承关系:

    Vector<String> v = new Vector<Object>(); //错误!不写<Object>没错,写了就是明知故犯
    Vector<Object> v = new Vector<String>(); //也错误!

    注意:

    假设Vector<String> v = new Vector<Object>();可以的话,那么以后从v中取出的对象当作String用,而v实际指向的对象中可以加入任意的类型对象;

    假设Vector<Object> v = new Vector<String>();可以的话,那么以后可以向v中加入任意的类型对象,而v实际指向的集合中只能装String类型的对象。

    编译器不允许创建泛型变量的数组。即在创建数组实例时,数组的元素不能使用参数化的类型。

    例如,下面语句有错误:

    Vector<Integer> vectorList[] = new Vector<Integer>[10];

    思考题:

    下面的代码会报错误吗?

    Vector v1 = new Vector<String>();
    Vector<Object> v = v1;

    答案:编译的时候是不会报错的,因为编译器是一行一行按照语法检查代码的,因此不会出错。

    4. 泛型类

    把泛型定义在类上,格式:public class 类名<泛型类型1,…>,注意:泛型类型必须是引用类型

    package cn.itcast_04;
    
    /*
     * 泛型类的测试
     */
    public class ObjectToolDemo {
        public static void main(String[] args) {
            // ObjectTool ot = new ObjectTool();
            //
            // ot.setObj(new String("风清扬"));
            // String s = (String) ot.getObj();
            // System.out.println("姓名是:" + s);
            //
            // ot.setObj(new Integer(30));
            // Integer i = (Integer) ot.getObj();
            // System.out.println("年龄是:" + i);
    
            // ot.setObj(new String("林青霞"));
            // // ClassCastException
            // Integer ii = (Integer) ot.getObj();
            // System.out.println("姓名是:" + ii);
    
            System.out.println("-------------");
    
            ObjectTool<String> ot = new ObjectTool<String>();
            // ot.setObj(new Integer(27)); //这个时候编译期间就过不去
            ot.setObj(new String("林青霞"));
            String s = ot.getObj();
            System.out.println("姓名是:" + s);
    
            ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
            // ot2.setObj(new String("风清扬"));//这个时候编译期间就过不去
            ot2.setObj(new Integer(27));
            Integer i = ot2.getObj();
            System.out.println("年龄是:" + i);
        }
    }
    //泛型类:把泛型定义在类上
    class ObjectTool<T> {
        private T obj;
    
        public T getObj() {
            return obj;
        }
    
        public void setObj(T obj) {
            this.obj = obj;
        }
    }

    5. 泛型方法

    把泛型定义在方法上,格式:public <泛型类型> 返回类型 方法名(泛型类型 .)

    package cn.itcast_05;
    
    public class ObjectToolDemo {
        public static void main(String[] args) {
            // ObjectTool ot = new ObjectTool();
            // ot.show("hello");
            // ot.show(100);
            // ot.show(true);
    
            // ObjectTool<String> ot = new ObjectTool<String>();
            // ot.show("hello");
            //
            // ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
            // ot2.show(100);
            //
            // ObjectTool<Boolean> ot3 = new ObjectTool<Boolean>();
            // ot3.show(true);
    
            // 定义泛型方法后
            ObjectTool ot = new ObjectTool();
            ot.show("hello");
            ot.show(100);
            ot.show(true);
        }
    }
    //泛型方法:把泛型定义在方法上
    class ObjectTool {
        public <T> void show(T t) {
            System.out.println(t);
        }
    }

    6. 泛型接口

    把泛型定义在接口上,格式:public interface 接口名<泛型类型1…>

    package cn.itcast_06;
    
    public class InterDemo {
        public static void main(String[] args) {
            // 第一种情况的测试
            // Inter<String> i = new InterImpl();
            // i.show("hello");
    
            // // 第二种情况的测试
            Inter<String> i = new InterImpl<String>();
            i.show("hello");
    
            Inter<Integer> ii = new InterImpl<Integer>();
            ii.show(100);
        }
    }
    //泛型接口:把泛型定义在接口上 
    interface Inter<T> {
        public abstract void show(T t);
    }
    // 实现类在实现接口的时候
    // 第一种情况:已经知道该是什么类型的了
    
    //public class InterImpl implements Inter<String> {
    //
    //  @Override
    //  public void show(String t) {
    //      System.out.println(t);
    //  }
    // }
    
    // 第二种情况:还不知道是什么类型的
    class InterImpl<T> implements Inter<T> {
    
        @Override
        public void show(T t) {
            System.out.println(t);
        }
    }

    7. 泛型高级(通配符)

    为了解决类型被限制死了不能动态根据实例来确定的缺点,引入了“通配符泛型”,针对上面的例子,使用通配泛型格式为

    package cn.itcast_07;
    
    import java.util.ArrayList;
    import java.util.Collection;
    
    /*
     * 泛型高级(通配符)
     * ?:任意类型,如果没有明确,那么就是Object以及任意的Java类了
     * ? extends E:向下限定,E及其子类
     * ? super E:向上限定,E极其父类
     */
    public class GenericDemo {
        public static void main(String[] args) {
            // 泛型如果明确的写的时候,前后必须一致
            Collection<Object> c1 = new ArrayList<Object>();
            // Collection<Object> c2 = new ArrayList<Animal>();
            // Collection<Object> c3 = new ArrayList<Dog>();
            // Collection<Object> c4 = new ArrayList<Cat>();
    
            // ?表示任意的类型都是可以的
            Collection<?> c5 = new ArrayList<Object>();
            Collection<?> c6 = new ArrayList<Animal>();
            Collection<?> c7 = new ArrayList<Dog>();
            Collection<?> c8 = new ArrayList<Cat>();
    
            // ? extends E:向下限定,E及其子类
            // Collection<? extends Animal> c9 = new ArrayList<Object>();
            Collection<? extends Animal> c10 = new ArrayList<Animal>();
            Collection<? extends Animal> c11 = new ArrayList<Dog>();
            Collection<? extends Animal> c12 = new ArrayList<Cat>();
    
            // ? super E:向上限定,E极其父类
            Collection<? super Animal> c13 = new ArrayList<Object>();
            Collection<? super Animal> c14 = new ArrayList<Animal>();
            // Collection<? super Animal> c15 = new ArrayList<Dog>();
            // Collection<? super Animal> c16 = new ArrayList<Cat>();
        }
    }
    
    class Animal {
    }
    
    class Dog extends Animal {
    }
    
    class Cat extends Animal {
    }

    泛型

    泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add方法即可。

    泛型引用和创建两端,给出的泛型变量必须相同

    泛型类

    A<T>
    Class<T> type

    泛型类中使用泛型

    • 成员类型
    • 返回值和参数类型
    • 局部变量的引用上
    class A<T> {
        private T bean;//泛型可在成员变量上使用
        public T fun(T t) {}//泛型可以在类中的方法上(返回值和参数类型)使用!
        public void fun2() {//泛型还可以在局部变量的引用类型上使用
            T b = ...
            new T();//不行的!
        }
    }

    泛型方法

    public <T> T add(T x, T y){ 
    }

    泛型方法与泛型类没有什么关系,泛型方法不一定非要在泛型类中!

    泛型的继承和实现

    class A<T> {
    }
    
    // AA不是泛型类,只是它爸爸是泛型类!
    class AA extends A<String> {
    
    } 

    继承泛型类

    • 子类不是泛型类:需要给父类传递类型常量

    当给父类传递的类型常量为String时,那么在父类中所有T都会被String替换!

    class AA1 extends A<String> {
    
    }
    • 子类是泛型类:可以给父类传递类型常量,也可以传递类型变量
    class AA3<E> extends A<E> {
    
    }

    通配符

    • 无限通配符

    类型推断

    • 通过反射的方式获取泛型的实际类型
    • 泛型只能是引用类型,不能是基本数据类型

    泛型擦除

    泛型会在编译时擦除,List和List这两个的字节码文件那一个都是List.class

    泛型封装

    本节内容原文链接:http://www.jianshu.com/p/d62c2be60617

    你真的会用Gson吗?Gson使用指南(一) 的第三节我介绍了在Gson中如何使用泛型来简化我们的类设计,但随之而来引入了一个新的问题:封装。不知道各位有没有想过这样一个问题:每次都要用 new TypeToken<XXX>(){}; 好麻烦,有没有更好的办法?

    有更好的办法么?当然有!相信也有不少人自己作了尝试,只是有人欢喜有人愁了,不过没关系,今天我们就来解决这个问题。

    约定

    1、本文涉及到的json格式

    // data 为 object 的情况
    {"code":"0","message":"success","data":{}}
    // data 为 array 的情况
    {"code":"0","message":"success","data":[]}

    2、假定第一种的对应的Java类型为 Result<XXX> ,第二种为 Result<List<XXX>>

    为何封装,如何封装

    1. 为何封装

    • new TypeToken<XXX>(){} 麻烦,IDE格式化后还不好看
    • 不同的地方每进行一次 new TypeToken<XXX>(){} 操作都会生成一个新的类
    • 对于任意类XXX都只有两种情况new TypeToken<Result<XXX>>(){}new TypeToken<Result<List<XXX>>>(){}
    • 方便统一管理

    2. 如何封装

    从上面的我们可以知道,最简单的方法就是提供两个方法分别对应data为Array和Object的情况并接收一个参数,即告知XXX的类型,自动将完成new TypeToken<XXX>(){}new TypeToken<Result<List<XXX>>>(){}的过程。

    方法原型:

    // 处理 data 为 object 的情况
    public static <T> Result<T> fromJsonObject(Reader reader, Class<T> clazz) {}
    // 处理 data 为 array 的情况
    public static <T> Result<List<T>> fromJsonArray(Reader reader, Class<T> clazz){}

    为何失败?

    对于那些尝试着封装过的人可能都这么写过:

    public static <T> Result<List<T>> fromJsonArray(Reader reader) {
        Type type = new TypeToken<Result<List<T>>>(){}.getType();
        return GSON.fromJson(reader, type);
    }

    当然上面的写法肯定是没有办法完成的,虽然代码不会报错,但运行结果肯定是不对的,因为这里的T 其实是一个 TypeVariable,他在运行时并不会变成我们想要的XXX,所以通过TypeToken 得到的 泛型信息只是 "Result<List<T>>"

    如何解决?

    既然TypeToken的作用是用于获取泛型的类,返回的类型为Type,真正的泛型信息就是放在这个Type里面,既然用TypeToken生成会有问题,那我们自己生成Type就行了嘛。

    Type是Java中所有类型的父接口,在1.8以前是一个空接口,自1.8起多了个getTypeName()方法,下面有ParameterizedTypeGenericArrayTypeWildcardTypeTypeVariable 几个接口,以及Class类。这几个接口在本次封装过程中只会用到 ParameterizedType ,所以简单说一下:

    ParameterizedType 简单说来就是形如“ 类型<> ”的类型,如:Map<String,User>。下面就以 Map<String,User> 为例讲一下里面各个方法的作用。

    public interface ParameterizedType extends Type {
         // 返回Map<String,User>里的String和User,所以这里返回[String.class,User.clas]
        Type[] getActualTypeArguments(); 
        // Map<String,User>里的Map,所以返回值是Map.class
        Type getRawType();
        // 用于这个泛型上中包含了内部类的情况,一般返回null
        Type getOwnerType(); 
    }

    所以,知道了这里需要的泛型是怎么回事,一切都好说了,下面我们来完成之前留下的空方法。

    1. 实现一个简易的 ParameterizedType

    public class ParameterizedTypeImpl implements ParameterizedType {
        private final Class raw;
        private final Type[] args;
        public ParameterizedTypeImpl(Class raw, Type[] args) {
            this.raw = raw;
            this.args = args != null ? args : new Type[0];
        }
        @Override
        public Type[] getActualTypeArguments() {
            return args;
        }
        @Override
        public Type getRawType() {
            return raw;
        }
        @Override
        public Type getOwnerType() {return null;}
    }

    2. 生成Gson需要的泛型

    2.1 解析data是object的情况
    public static <T> Result<T> fromJsonObject(Reader reader, Class<T> clazz) {
        Type type = new ParameterizedTypeImpl(Result.class, new Class[]{clazz});
        return GSON.fromJson(reader, type);
    }
    2.2 解析data是array的情况

    是Array的情况要比是Object的情况多那么一步。

    public static <T> Result<List<T>> fromJsonArray(Reader reader, Class<T> clazz) {
        // 生成List<T> 中的 List<T>
        Type listType = new ParameterizedTypeImpl(List.class, new Class[]{clazz});
        // 根据List<T>生成完整的Result<List<T>>
        Type type = new ParameterizedTypeImpl(Result.class, new Type[]{listType});
        return GSON.fromJson(reader, type);
    }

    本次代码较少,不提供源码

    虽然这篇博客是以Gson为例,但从上面的内容可以看出实际上和Gson关系不大,主要的内容还是Java的泛型基础,所以这种封装的方法同样适用于其它的框架。

    最后借这次机会给安利一个简易的泛型生成库 TypeBuilder ,其最初实现的目的就是让大家快速的生成泛型信息,同时也会作一些参数检查,保证正确性。

    用上面的代码给大家举个例子

    public static <T> Result<List<T>> fromJsonArray(Reader reader, Class<T> clazz) {
        Type type = TypeBuilder
                .newInstance(Result.class)
                .beginSubType(List.class)
                .addTypeParam(clazz)
                .endSubType()
                .build();
        return GSON.fromJson(reader, type);
    }
    
    public static <T> Result<T> fromJsonObject(Reader reader, Class<T> clazz) {
        Type type = TypeBuilder
                .newInstance(Result.class)
                .addTypeParam(clazz)
                .build();
        return GSON.fromJson(reader, type);
    }

    Type

    Type 是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型

    ParameterizedType

    ParameterizedType 表示参数化类型,如 Collection

    方法说明
    Type[ ] getActualTypeArguments()获取真实参数
    public abstract class BaseProtocol<T> {
        ...
        /**泛型解析*/
        protected T parsejson(String jsonString){
            ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
            Type[] args = genericSuperclass.getActualTypeArguments();
            Type type = args[0];
            return GsonUtil.changeGsonToBean(jsonString,type);
        }
    }
    展开全文
  • Build构建者模式,如何使用泛型

    千次阅读 2019-05-15 17:42:32
    Build构建者模式,如何使用泛型 public class Result implements Serializable { @ApiModelProperty(value = “状态码,0表示成功 其他表示失败”, example = “0”) private int status; @ApiModelProperty(value =...

    Build构建者模式,如何使用泛型

    public class Result implements Serializable {
    @ApiModelProperty(value = “状态码,0表示成功 其他表示失败”, example = “0”)
    private int status;
    @ApiModelProperty(value = “提示信息”, example = “ADS_SUCCESS”)
    private String message = “”;
    @ApiModelProperty(value = “数据”, example = “”)
    private T data;
    public T getData() {
    return data;
    }
    public void setData(T data) {
    this.data = data;
    }
    public int getStatus() {
    return status;
    }
    public void setStatus(int status) {
    this.status = status;
    }
    public String getMessage() {
    return message;
    }
    public void setMessage(String message) {
    this.message = message;
    }
    public Result() {
    }
    private Result(int status, String message, T data) {
    this.status = status;
    this.message = message;
    this.data = data;
    }
    public static Result.ResultBuiler builder(){
    return new Result.ResultBuiler();
    }
    public static class ResultBuiler{
    private int status;
    private String message;
    private T data;
    public Result.ResultBuiler status(int status){
    this.status = status;
    return this;
    }
    public Result.ResultBuiler message(String message){
    this.message = message;
    return this;
    }
    public Result.ResultBuiler data(T data){
    this.data = data;
    return this;
    }
    public Result build(){
    return new Result(this.status,this.message,this.data);
    }
    }
    }

    如何调用呢?直接上代码

    Result <User> result;
    result = Result.<User>builder().status(200).message(“success”).data(user).build();

    展开全文
  • 1、maven2默认使用java 1.5编译不支持泛型 2、当工程编码为UTF-8并含有中文时编译会出现字符错误 解决办法,修改pom文件加入maven-compiler-plugin插件 [code="pom"] maven-compiler-...
    1、maven2默认使用java 1.5编译不支持泛型
    
    2、当工程编码为UTF-8并含有中文时编译会出现字符错误

    解决办法,修改pom文件加入maven-compiler-plugin插件

    <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
    <compilerVersion>1.6</compilerVersion>
    <fork>true</fork>
    <source>1.6</source>
    <target>1.6</target>
    <encoding>UTF-8</encoding>
    </configuration>
    </plugin>
    展开全文
  • 一、Dart 泛型类与泛型方法、 二、Dart 泛型中的特定类型约束、 三、Dart 自带泛型、 四、完整代码示例、 五、 相关资源、





    一、Dart 泛型类与泛型方法



    泛型作用 : 为 类 , 接口 , 方法 提供复用性 , 支持类型不确定的数据类型 ;

    泛型类 : 提高代码复用程度 ;

    泛型方法 : 参数或返回值有泛型类型约束 , 参数或返回值类型必须符合对应的泛型类型 , 泛型使用时会进行类型检查约束 , 如果设置错误的类型 , 编译时报错 ;


    泛型类示例 :

    /// 泛型作用 : 为 类 , 接口 , 方法 提供复用性 , 支持类型不确定的数据类型
    ///
    /// 泛型类 : 提高代码复用程度
    /// 该类是一个缓存类 , 缓存的数据类型是 T 泛型 , 该类型可以是任意类型
    class Cache<T>{
      /// 缓存数据存储到该 Map 集合中
      Map<String, Object> _map = Map();
    
      /// 设置泛型缓存数据 , 该方法是泛型方法
      /// 此处将 T 类型的数据存放到 map 集合中
      void setCacheItem(String key, T value){
        _map[key] = value;
      }
    
      /// 取出泛型缓存数据 , 该方法是泛型方法
      T getCachedItem(String key){
        return _map[key];
      }
    }
    

    测试上述泛型类 :

    /// 泛型测试类
    class Generic{
    
      /// 该方法测试泛型类及泛型方法
      void test(){
        // 创建泛型类对象 , 泛型类型设置为 String 类型
        Cache<String> cache = Cache();
        // 调用泛型方法时 , 传入的参数必须符合对应的泛型类型
        // 泛型约束 : 泛型使用时会进行类型检查约束 , 如果设置错误的类型 , 编译时报错
        cache.setCacheItem("name", "Tom");
    
        // 获取缓存内容
        String value = cache.getCachedItem("name");
        print("泛型测试, 类型字符串, 获取的缓存内容为 ${value}");
    
    
        // 创建泛型类对象 , 泛型类型设置为 int 类型
        Cache<int> cache2 = Cache();
        // 调用泛型方法时 , 传入的参数必须符合对应的泛型类型
        // 泛型约束 : 泛型使用时会进行类型检查约束 , 如果设置错误的类型 , 编译时报错
        cache2.setCacheItem("age", 18);
    
        // 获取缓存内容
        int value2 = cache2.getCachedItem("age");
        print("泛型测试, 类型整型, 获取的缓存内容为 ${value2}");
      }
    
    }
    

    打印结果 :

    I/flutter (24673): 泛型测试, 类型字符串, 获取的缓存内容为 Tom
    I/flutter (24673): 泛型测试, 类型整型, 获取的缓存内容为 18
    




    二、Dart 泛型中的特定类型约束



    泛型还可以进行特定类型约束 , 如指定该泛型类型必须是某个类的子类 , 使用 <T extends Person> 约束该泛型必须是某个类的子类 ;

    泛型类示例代码 :

    /// 泛型中的特定类型约束
    /// 将泛型约束为某个类型的子类
    class Member<T extends Person>{
      T _person;
    
      /// 构造函数中设置 T _person 成员的值
      Member(this._person);
    
      /// 获取 _person 的名字
      String getName(){
        return _person.name;
      }
    }
    

    上述涉及到的两个类在 【Flutter】Dart 面向对象 ( 命名构造方法 | 工厂构造方法 | 命名工厂构造方法 ) 中定义 ;

    测试上述泛型类 :

        /// 泛型类测试
        /// 类泛型要求是 T extends Person , 泛型类型必须是 Person 的子类
        /// Student 是 Person 的子类
        Member<Student> member = Member(Student(6, "Tom", 18));
        String name = member.getName();
        print("泛型类测试, 获取的 T extends Person 泛型的 name 字段为 ${name}");
    

    测试打印结果 :

    I/flutter (24673): 泛型类测试, 获取的 T extends Person 泛型的 name 字段为 Tom
    




    三、Dart 自带泛型



    在 Flutter 的 main.dart 中的 State 就是泛型类 ;

    class _MyHomePageState extends State<MyHomePage> {
    }
    

    State 类中要求一个泛型 T , 该泛型类型必须继承 StatefulWidget 类 ;

    abstract class State<T extends StatefulWidget> extends Diagnosticable {
    }
    

    此处的 MyHomePage 就是 泛型类型 , 是 StatefulWidget 类的子类 , 符合 泛型要求 ;





    四、完整代码示例



    泛型类 , 泛型方法 , 泛型测试相关代码 :

    
    import 'package:flutterapphello/Dart_OOP.dart';
    
    /// 泛型测试类
    class Generic{
    
      /// 该方法测试泛型类及泛型方法
      void test(){
        // 创建泛型类对象 , 泛型类型设置为 String 类型
        Cache<String> cache = Cache();
        // 调用泛型方法时 , 传入的参数必须符合对应的泛型类型
        // 泛型约束 : 泛型使用时会进行类型检查约束 , 如果设置错误的类型 , 编译时报错
        cache.setCacheItem("name", "Tom");
    
        // 获取缓存内容
        String value = cache.getCachedItem("name");
        print("泛型测试, 类型字符串, 获取的缓存内容为 ${value}");
    
    
        // 创建泛型类对象 , 泛型类型设置为 int 类型
        Cache<int> cache2 = Cache();
        // 调用泛型方法时 , 传入的参数必须符合对应的泛型类型
        // 泛型约束 : 泛型使用时会进行类型检查约束 , 如果设置错误的类型 , 编译时报错
        cache2.setCacheItem("age", 18);
    
        // 获取缓存内容
        int value2 = cache2.getCachedItem("age");
        print("泛型测试, 类型整型, 获取的缓存内容为 ${value2}");
        
        
        /// 泛型类测试
        /// 类泛型要求是 T extends Person , 泛型类型必须是 Person 的子类
        /// Student 是 Person 的子类
        Member<Student> member = Member(Student(6, "Tom", 18));
        String name = member.getName();
        print("泛型类测试, 获取的 T extends Person 泛型的 name 字段为 ${name}");
    
      }
    
    }
    
    /// 泛型作用 : 为 类 , 接口 , 方法 提供复用性 , 支持类型不确定的数据类型
    ///
    /// 泛型类 : 提高代码复用程度
    /// 该类是一个缓存类 , 缓存的数据类型是 T 泛型 , 该类型可以是任意类型
    class Cache<T>{
      /// 缓存数据存储到该 Map 集合中
      Map<String, Object> _map = Map();
    
      /// 设置泛型缓存数据 , 该方法是泛型方法
      /// 此处将 T 类型的数据存放到 map 集合中
      void setCacheItem(String key, T value){
        _map[key] = value;
      }
    
      /// 取出泛型缓存数据 , 该方法是泛型方法
      T getCachedItem(String key){
        return _map[key];
      }
    }
    
    /// 泛型中的特定类型约束
    /// 将泛型约束为某个类型的子类
    class Member<T extends Person>{
      T _person;
    
      /// 构造函数中设置 T _person 成员的值
      Member(this._person);
    
      /// 获取 _person 的名字
      String getName(){
        return _person.name;
      }
    }
    
    

    涉及到的 Person 和 Student 类 :

    /// 定义 Dart 类
    /// 与 Java 语言类似, 所有的类默认继承 Object 类
    class Person{
    
      /// 定义变量
      String name;
      int age;
    
      /// 私有字段
      int _achievement;
    
      /// 标准构造方法, 下面的方法是常用的构造方法写法
      Person(this.name, this.age);
    
      /// get 方法 : 设置私有字段 achievement 的 get 方法,
      ///            让外界可以访问 Person 对象的 _achievement 私有成员
      int get achievement => _achievement;
    
      /// set 方法 : 设置私有字段 achievement 的 set 方法,
      ///            让外界可以设置 Person 对象的 _achievement 私有成员值
      set achievement(int achievement){
        _achievement = achievement;
      }
    
      /// 静态方法 , 通过类名调用
      static log(){
        print("log");
      }
    
      /// 重写父类的方法
      @override
      String toString() {
        return "$name : $age";
      }
    }
    
    /// 继承
    class Student extends Person{
    
      /// 私有变量, 以下划线开始的变量是私有变量
      int _grade;
    
      String school;
      String city;
      String address;
    
      /// 父类构造函数调用 : 如果父类有非空参数的构造函数, 子类必须实现相同参数的构造函数
      /// 如果该类有父类 , 那么先调用父类的构造方法 , 完成父类的初始化
      /// 然后才能完成自己的初始化
      ///
      /// this.school 指定自有参数
      /// {this.school} 是可选参数, 可选参数必须在构造函数参数列表中最后一个
      ///
      /// 默认参数 : 可选参数中如果用户不初始化该可选参数 , 那么为其指定一个默认值
      /// {this.city = "北京"} 指定了如果用户不初始化 city 变量, 那么为其初始化 "北京" 字符串值
      ///
      /// 初始化列表 : 冒号后面的内容就是初始化列表
      ///            父类构造器也是初始化列表
      ///            除了父类构造方法之外 , 还可以在子类构造方法体之前初始化示例变量
      ///            不同的初始化实例变量之间使用逗号隔开
      ///
      /// 父类构造方法 : 如果父类没有默认构造方法 (无参构造方法) ,
      ///              必须在初始化列表中调用父类构造函数 , super(name, age) ;
      ///
      /// 构造方法方法体 : 可以省略 ;
      Student(this._grade, String name, int age,
             {this.school, this.city = "北京"})
             : address = "北京市海淀区" ,
             super(name, age);
    
    
      // 命名构造方法
      // 定义格式 : 类名.方法名()
      // 父类构造函数 : 如果父类没有默认构造函数, 子类必须调用父类的构造函数
      Student.cover(Student student):super(student.name, student.age);
    
      // 命名构造方法也可以有方法体
      Student.init(Student student):super(student.name, student.age){
        print("命名构造方法 : name : ${student.name}, age : ${student.age}");
      }
    
      // 命名工厂构造方法 : factory 类名.方法名
      // 命名工厂构造方法可以有返回值
      // 如果类中有 final 修饰的成员 , 在命名构造方法中必须对其进行初始化
      //    但是在命名工厂构造方法中 , 可以不初始化 final 类型成员
      // 命名工厂构造方法可以有返回值
      factory Student.init2(){
        return Student(1, "Tom", 18);
      }
    
    }
    

    测试代码入口 : 在 main.dart 中的 _MyHomePageState 类中的 build 方法中 ;

    /// 省略其它源码
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        // 测试泛型
        Generic generic = Generic();
        generic.test();
      }
    }
    

    打印结果 :

    I/flutter (24673): 泛型测试, 类型字符串, 获取的缓存内容为 Tom
    I/flutter (24673): 泛型测试, 类型整型, 获取的缓存内容为 18
    I/flutter (24673): 泛型类测试, 获取的 T extends Person 泛型的 name 字段为 Tom
    




    五、 相关资源



    参考资料 :


    博客源码下载 :

    展开全文
  • java泛型泛型边界

    万次阅读 2016-05-02 15:39:29
    在网上发现这篇文章写得不错,地址:http://build.cthuwork.com:8081/wordpress/category/java教程/java再谈泛型/ 首先本文假定读者对Java的泛型有基础的了解,若需要请参考其他资料配合阅读。 泛型的泛参(type...
  • Kotlin 泛型

    2021-01-20 13:07:25
    泛型和委托 泛型的基本用法 Java 早在 1.5 版本中就引入了泛型的机制,因此,Kotlin 自然也就支持了泛型功能。但是 Kotlin 中的泛型与 Java 中的泛型有同有异,这里先看与 Java 中相同的部分。 泛型,是指在一般的...
  • java 泛型

    2016-05-14 18:10:14
    自己玩一下java 的泛型 /** * Create a synthetic successful response using {@code headers} with {@code body} as the * deserialized body. */ public static Response success(T body, Heade
  • 7 月——Go 团队发布并讨论了三套新的设计草案以供后续修改:new //go:build lines for file selection、 file system interfaces 和 build-time file embedding。 8 月——Go 1.15 版本主要提供优化与 bug 修复。...
  • 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展 1.泛型接口,接口持有泛型,类名<T> public interface TestApi<T> { T method1(T a); } 1.泛型类,类持有泛型,类名<T...
  • 泛型约束: fun <T : Comparable<T>> maxOf(a: T, b: T): T { return if (a > b) a else b } fun main() { val max = maxOf("Hello", "World") println(max) //输出World } 多个泛型参数,...
  • 只返回泛型实体 public static <T> T request2Bean(HttpServletRequest request,Class<T> clazz){} 集合泛型 ... lists(QueryBuilder build, TransportClient client, Class<T> ...
  • 泛型 typescriptTypeScript, a “superset of JS”, makes it easier to build maintainable, comprehensible, and scalable apps thanks to the power of type-checking. TypeScript是JS的“超集”,由于具有类型...
  • Java泛型遇到多态与Java泛型边界

    千次阅读 2017-04-20 15:49:42
    说明: 今天,继续学姐java编程思想-泛型这一章的时候,对于通配符的理解不够明白,于是又网上查了些资料,发现一篇写的很好的文章,在此记录学习一下
  • java泛型详解

    2020-03-30 08:01:25
    这次写一篇关于java泛型的文章,java泛型说难也不难,说容易也不容易,泛型的出现主要是为了帮助我们在编码时在编译时期就可以预先检查可能出现的错误类型转换问题。 1,泛型的定...
  • Java泛型详解

    2020-09-19 22:54:07
    Java泛型 个人技术博客(IBLi) CSDN Github 掘金 1、泛型定义 使用泛型机制编写的程序代码要比那些杂乱地使用Object变量,然后在进行强制类型转换的代码具有更好的安全性和可读性。 --《Java核心技术》 泛型是在...
  • Kotlin 之泛型详解

    千次阅读 2020-04-09 09:22:28
    文章目录泛型约束泛型的型变UnsafeVariance星投影泛型实现原理内联特化案例: 泛型约束 fun <T : Comparable<T>> maxOf(a: T, b: T): T { if (a > b) { return a } return b } fun <T> ...
  • Java中的泛型

    2017-12-01 21:42:38
    泛型(Generic)在jdk1.5被引入,它加入了一个全新的语法元素,并且好多类和方法都重新实现了泛型的版本,受之影响最大的就是Collections Framework了。本篇博客来讨论一下泛型的语法特征,并简要地讨论一下底层的实现...
  • java泛型应用详解

    2018-12-26 15:45:37
    在平时的开发过程中,很多哥们不清楚泛型的概念以及用法,所以很多时候,写了很多没必要的代码,又或者,看到别人在使用泛型的时候,感觉对方很牛逼。。。 其实,泛型没你想象的那么难,follow me一、为什么要使用...
  • Java泛型学习

    2017-06-05 14:54:00
    1、泛型的概念 泛型即“参数化类型”,就比如我们定义方法的时候,定义一个变量,称为形参,变量值根据传进去的实参的值不同而改变。而泛型的出现,就是为了解决类型也能根据传进去的类型改变的问题,所以称为参数...
  • Java泛型使用介绍

    2021-05-08 10:01:26
    Java泛型介绍1.为什么要使用泛型2.泛型使用方法2.1在类中使用范型2.2 泛型的通配符3.泛型擦除3.1 编译过程进行泛型擦除3.2泛型的检查3.3 在泛型类中不能new出泛型的对象 1.为什么要使用泛型 前面章节我们讲到了集合...
  • MVP泛型请求数据

    2017-12-05 19:48:19
    主要就是把MVP写了一个泛型请求了一个数据
  • kotlin 泛型和委托

    2020-04-22 17:04:31
    1.泛型 泛型允许我们不指定具体类型的情况下进行编程 泛型的两种定义方式:泛型类,泛型方法 //泛型类 class MyClass<T> { fun method(param: T): T { return param } } //泛型方法 fun <T> ...
  • 由于最近学习okHttp 这个开源框架,异步请求接口的CallBack是不支持泛型的,有没有什么办法扩展一下,使用的时候只需要传入一个url 一个 T 就直接得到解析后的实体对象. 把解析的过程对调用者透明, 当然已经有很好的...
  • 004-Kotlin泛型相关

    2021-05-07 17:48:20
    Kotlin泛型相关
  • java泛型类型In some situations, particularly when implementing the builder pattern or creating other fluent APIs, methods return this. The method’s return type is likely to be the same as the class ...
  • IDEA 中 maven 项目编译时提示 无法推断泛型 File ->Settings->Build, Execution, Deployment -> Compiler->Java Compiler 的 Use compiler 选择 Eclipse 。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,492
精华内容 8,596
关键字:

build泛型