美文网首页
泛型方法

泛型方法

作者: 呆呆李宇杰 | 来源:发表于2017-09-10 16:32 被阅读157次

    引言

    泛型不仅可以应用于整个类上,还可以在类中包含参数化的方法。而这个类所在的类可以是泛型类,也可以是非泛型类。这就意味着,是否拥有泛型方法,与所在的类是否是泛型没有关系。

    泛型方法可以让该方法独立于整个类而变化。这就意味着,只要能做到,那么就应当使用泛型方法。也就是说,如果泛型方法可以取代整个类泛型化,那么就应该只使用泛型方法,因为它可以使事情更加地清楚明白。
    另外,对于一个static的方法而言,无法访问泛型类的类型参数,所以static要想使用泛型,则必须声明为泛型方法。

    定义

    要定义泛型方法,只需将泛型参数列表置于返回值之前,如下。

    public class GenericMethods {
        public <T> void f(T x) {
            System.out.println(x.getClass().getName());
        }
    
        public static void main(String[] args) {
            GenericMethods gm = new GenericMethods();
            gm.f("");
            gm.f(1);
            gm.f(1.0);
            gm.f(1.0f);
            gm.f('c');
            gm.f(gm);
        }
    }
    
    // Outputs
    java.lang.String
    java.lang.Integer
    java.lang.Double
    java.lang.Float
    java.lang.Character
    com.daidaijie.generices.method.GenericMethods
    

    GenericMethods并不是参数化的,尽管这个类和其内部的方法可以被同时参数化,但是在上面例子中,只有方法f()具有类型参数,这是由该方法的返回类型前面的类型参数列表指明的。

    注意,当使用泛型类的时,必须在创建对象的时候指定类型参数的值,而使用泛型方法的时候,通常不必指明参数类型,因为编译器会为我们找出具体的类型。这称为类型参数推断。因此,我们可以像调用普通方法一样调用f(),而且就像是f()被无限次的重载过。它甚至可以接受GenericMethods作为其类型参数。
    如果调用f()的时候传入基本类型,那么将触发自动打包机制,将基本类型的值包装对应的对象。泛型方法和自动打包机制减少了许多之前我们不得不编写的代码。

    类型推断的作用

    在Java SE7之前,如果要创建一个泛型对象,那么将必须写非常啰嗦的代码来实现。如果创建一个持有ListMap,就要像下面那样。

    Map<Person,List<? extends Pet>> petPeople = new HashMap<Person,List<? extends Pet>>(); 
    

    然而,在泛型方法中,类型参数推断可以为我们简化一部分的操作。我们可以编写一个工具类,它包含各种各样的static方法,专门用于创建各种常用的容器对象。

    public class New {
        public static <K, V> Map<K, V> mapOf() {
            return new HashMap<K, V>();
        }
    
        public static <T> List<T> listOf() {
            return new ArrayList<T>();
        }
    
        public static <T> LinkedList<T> linkListOf() {
            return new LinkedList<T>();
        }
    
        public static <T> Set<T> setOf() {
            return new HashSet<T>();
        }
    
        public static <T> Queue<T> queue() {
            return new LinkedList<T>();
        }
    
        public static void main(String[] args) {
            Map<String, List<String>> sls = New.mapOf();
            List<String> ls = New.listOf();
            LinkedList<String> lls = New.linkListOf();
            Set<String> ss = New.setOf();
            Queue<String> qs = New.queue();
        }
    }
    

    以上的类型推断的一个使用,尽管说这段代码在Java SE7之前为创建类型少写了很多代码,但是如果有人需要阅读以上的代码,他必须去分析工具类New,以及New所隐含的功能,这似乎导致了与不使用News的工作效率差不多。

    类型推断的限制

    在Java SE8之前,类型推断也有一定限制,类型推断只对赋值操作有效,将一个泛型方法调用的结果作为参数,传递给另一个方法,这时候编译器并不会执行类型判断。在这种情况下,编译器认为,调用泛型方法后,其返回值被赋给一个Object类型的变量。

    public class LimitsOfInference {
        static void f(Map<Person, List<? extends Pet>> petPeople) {}
    
        public static void main(String[] args) {
            f(New.mapOf()); // compile error before java8
        }
    }
    

    显式的类型说明

    在泛型的方法中,可以显示的指明类型,不过这种语法非常少用。要显示的指明类型,必须在点操作符与方法名之间插入尖括号,然后将类型置于尖括号内。如果是定义该方法的类的内部,必须在点操作符之前使用this关键字,如果是使用static的方法,必须在点操作符之前加上类名,这种写法看解决LimitsOfInference中的问题。

    public class LimitsOfInference {
        static void f(Map<Person, List<Pet>> petPeople) {
        }
    
        public static void main(String[] args) {
            f(New.<Person, List<Pet>>mapOf());
        }
    }
    

    泛型和可变参数列表也能够很好的共存

    public class GenericVarargs {
        public static <T> List<T> makeList(T... args) {
            List<T> result = new ArrayList<>();
            for (T item : args) {
                result.add(item);
            }
            return result;
        }
    
        public static void main(String[] args) {
            List<String> ls = makeList("A");
            System.out.println("ls = " + ls);
            ls = makeList("A", "B", "C");
            System.out.println("ls = " + ls);
            ls = makeList("ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""));
            System.out.println("ls = " + ls);
        }
    }
    
    // Outputs
    ls = [A]
    ls = [A, B, C]
    ls = [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]
    

    相关文章

      网友评论

          本文标题:泛型方法

          本文链接:https://www.haomeiwen.com/subject/bavzjxtx.html