zoukankan      html  css  js  c++  java
  • 范型方法 & 范型参数 & 范型返回值

    Java范型类

    public class FanXingClassTest {
        public static void main(String args[]){
            Test<Integer> intObj = new Test<Integer>(123);
            Test<String> strObj = new Test<String>("一二三");
            intObj.showType();
            strObj.showType();
        }
    }
    
    /**
     * 定义范型类
     * @param <T>
     */
    class Test<T>{
        private T ob; //定义范型的成员变量
    
        public Test(T ob){
            this.ob = ob;
        }
    
        public void setT(T ob){
            this.ob = ob;
        }
        public T getT(){
            return this.ob;
        }
    
        public void showType(){
            System.out.println("T的实际类型是:"+ob.getClass());
        }
    }

      对比一下没有使用范型类(如下代码),也可以输出一样的结果,为什么要使用范型类?类型检查??

    public class FanXingClassTest {
        public static void main(String args[]){
            Test intObj = new Test(123);
            Test strObj = new Test("一二三");
            intObj.showType();
            strObj.showType();
        }
    }
    /**
     * 定义普通类
     */
    class Test{
        private Object ob; // 不能定义T类型的变量??
    
        public Test(Object ob){
            this.ob = ob;
        }
    
        public void setT(Object ob){
            this.ob = ob;
        }
        public Object getT(){
            return this.ob;
        }
    
        public void showType(){
            System.out.println("T的实际类型是:"+ob.getClass());
        }
    }

    我们做实验如下:

    // 两个基本类:StringDemo和DoubleDemo
    public class StringDemo {
        private String str;
    
        public StringDemo(String str){
            this.str = str;
        }
    
        public void setStr(String str){
            this.str = str;
        }
        public String getStr(){
            return this.str;
        }
    }
    public class DoubleDemo {
        private Double doubleVal;
    
        public DoubleDemo(Double doubleVal){
            this.doubleVal = doubleVal;
        }
        public void setDoubleVal(Double doubleVal){
            this.doubleVal = doubleVal;
        }
        public Double getDoubleVal(){
            return this.doubleVal;
        }
    }
    
    // 因为上面的类中,成员和方法的逻辑都一样,就是类型不一样,因此考虑重构。Object是所有类的父类,因此可以考虑用Object做为成员类型,这样就可以实现通用了,实际上就是“Object泛型”,暂时这么称呼。
    public class ObjectDemo {
        private Object obj;
    
        public ObjectDemo(Object obj){
            this.obj = obj;
        }
        public void setObj(Object obj){
            this.obj = obj;
        }
        public Object getObj(){
            return this.obj;
        }
    }
    public class MyDemo {
        public static void main(String args[]){
            ObjectDemo str = new ObjectDemo("string");
            ObjectDemo dble = new ObjectDemo(123d);
            ObjectDemo obj = new ObjectDemo(new Object());
            System.out.println(str.getObj());
            System.out.println(dble.getObj());
            System.out.println(obj.getObj());
        }
    }
    
    // 在Java 5之前,为了让类有通用性,往往将参数类型、返回类型设置为Object类型,当获取这些返回类型来使用时候,必须将其“强制”转换为原有的类型或者接口,
    // 然后才可以调用对象上的方法。强制类型转换很麻烦,我还要事先知道各个Object具体类型是什么,才能做出正确转换。否则,要是转换的类型不对,比如将
    // “Hello Generics!”字符串强制转换为Double,那么编译的时候不会报错,可是运行的时候就挂了。那有没有不强制转换的办法----有,改用 Java5泛型来实现,
    // 示例见最上面FanXingClassTest<T>范型类的定义。

    范型类语法解释

    1. 使用<T>来声明一个类型持有者名称,然后就可以把T当作一个类型代表来声明成员、参数和返回值类型。
    2. class GenericsTest<T> 声明了一个泛型类,这个T没有任何限制,实际上相当于Object类型,实际上相当于 class GenericsTest<T extends Object>。
    3. 与Object泛型类相比,使用泛型所定义的类在声明和构造实例的时候,可以使用“<实际类型>”来一并指定泛型类型持有者的真实类型。类如
    GenericsTest<Double> douTest=new GenericsTest<Double>(new Double("33"));
    4. 实际上,当构造对象时不指定类型信息的时候,默认会使用Object类型,这也是要强制转换的原因.

    限制范型

      在上面的例子中,由于没有限制class GenericsTest<T>类型持有者T的范围,实际上这里的限定类型相当于Object,这和“Object泛型”实质是一样的。限制比如我们要限制T为集合接口类型。只需要这么做:class GenericsTest<T extends Collection>,这样类中的泛型T只能是Collection接口的实现类,传入非Collection接口编译会出错。注意:<T extends Collection>这里的限定使用关键字extends,后面可以是类也可以是接口。但这里的extends已经不是继承的含义了,应该理解为T类型是实现Collection接口的类型,或者T是继承了XX类的类型。
    // 限制范型
    public class CollectionGenTest<T extends Collection> {
        private T x;
        public CollectionGenTest(T x){
            this.x = x;
        }
        public T getX(){
            return this.x;
        }
        public void setX(T x){
            this.x = x;
        }
    }
    public class CollectionGenTestDemo {
        public static void main(String args[]){
            CollectionGenTest<ArrayList> test = new CollectionGenTest<ArrayList>(new ArrayList());
            System.out.println("实例化完成");
        }
    }

    // 多接口限制
    <T extends SomeClass & interface1 & interface2 & interface3>

    // 通配符范型
    <T extends Collection> //向下限制
    <?> //任意类型,相当于Object
    <T super Double> // 向上限制,Double类型或者其父类

    Java范型方法

    /**
     * 范型方法:只需在返回值前添加<T>
     */
    public class ExampleA {
        public <T> void f(T x){
            System.err.println(x.getClass().getName());
        }
    
        public static void main(String args[]){
            ExampleA exampleA = new ExampleA();
            exampleA.f("");
            exampleA.f(123);
            exampleA.f('a');
            exampleA.f(exampleA);
        }
    }

    // 使用泛型方法时,不必指明参数类型,编译器会自己找出具体的类型。泛型方法除了定义不同,调用就像普通方法一样
    // 一个static方法,无法访问泛型类的类型参数,所以,若要static方法需要使用泛型能力,必须使其成为泛型方法。

    方法

     1. 定义泛型方法时,必须在返回值前边加一个<T>,来声明这是一个泛型方法,

    2. Class<T>的作用就是指明泛型的具体类型,而Class<T>类型的变量c,可以用来创建泛型类的对象。为什么要用变量c来创建对象呢?既然是泛型方法,就代表着我们不知道具体的类型是什么,也不知道构造方法如何,因此没有办法去new一个对象,但可以利用变量c的newInstance方法去创建对象,也就是利用反射创建对象。

     3.   http://www.cnblogs.com/iyangyuan/archive/2013/04/09/3011274.html

  • 相关阅读:
    cocos2dx打飞机项目笔记七:各种回调:定时器schedule、普通回调callFunc、菜单回调menu_selector、事件回调event_selector
    cocos2dx打飞机项目笔记六:GameScene类和碰撞检测 boundingbox
    [Redis] 手动搭建标准6节点Redis集群(docker)
    [JavaSE 源码分析] 关于HashMap的个人理解
    [leetcode 周赛 150] 1161 最大层内元素和
    [leetcode 周赛 150] 1160 拼写单词
    [leetcode 周赛 149] 1157 子数组中占绝大多数的元素
    [leetcode 周赛 149] 1156 单字符重复子串的最大长度
    [leetcode 周赛 149] 1155 掷骰子的N种方法
    [leetcode 周赛 149] 1154 一年中的第几天
  • 原文地址:https://www.cnblogs.com/RunForLove/p/7093532.html
Copyright © 2011-2022 走看看