• 两岸民心相亲不可违逆(观沧海) 2019-06-24
  • 习近平新时代中国特色社会主义思想为解决人类问题贡献中国智慧 2019-06-22
  • 反击!欧盟成员国一致支持对美28亿欧元产品征收报复性关税 2019-06-22
  • 专访李毅立:走进国家 了解国情 续写中华情 2019-06-08
  • 现在,表面上看,很多城市绿树成荫,花卉草地到处都是,实际上地下空间已经掏空,建了车库、地下商城,雨水根本渗不下去。 2019-06-08
  • 你反来复去说1+1=2,真痴呆了?你应该讲点其他的吧,譬如,1+1=2,是客观事实还是规律,是真理还是谬误。 2019-06-05
  • 蜈蚣精的出游必备战靴 旅行路上皆战场 2019-06-05
  • 《法医秦明2》“长腿CP”最萌身高差吸睛 剧情高能 2019-06-04
  • 【春到渭南】随手拍渭南各地区春景,一贴看尽渭南春色! 2019-06-04
  • 如何像皇帝、老佛爷那样避个暑? 2019-05-30
  • 印度总理寓所附近现UFO?网友:外星人也想看莫迪 2019-05-21
  • 人民网评:建设一支生态环境保护铁军 2019-05-21
  • 这三个史无前例,让美国有点懵了 2019-05-18
  • 唐嫣蜡像入驻上海杜莎夫人蜡像馆--旅游频道 2019-05-18
  • 生活调查:过午不食可以养生减肥是真的吗? 2019-05-18
  • 冰球规则介绍:

    北京 切换校区

    全国24小时免费热线

    400-009-1906

    Java中的构造函数引用和方法引用

    时间:2019-01-28   来源:尚学堂   阅读:268

    JDK 8 见证了一个特殊特性的出现:构造函数引用和方法引用。在本文中, Adrian D. Finlay 探讨了开发人员如何释放构造函数引用的真正潜力。

    方法引用的一些背景

    如果你还不知道 Java 构造函数本身就是特殊的方法,那么阅读方法引用的基本示例将对读者有所帮助,通过了解这些内容,可以了解构造函数引用是什么。

    「方法引用为已经有名称的方法提供易读的 lambda 表达式?!?/span>

    「它们提供了一种无需执行就可以引用方法的简单方式?!?/span>

    以上引自《Java 8 编程参考官方教程(第 9 版)》,作者:Herbert Schildt

    译注:该书的第 8 版中文译本名称为:《Java 完全参考手册(第 8 版)》,第 9 版中文译本名称为:《Java 8 编程参考官方教程(第 9 版)》

    方法引用可以引用静态方法和实例方法,两者是通用的。方法引用是函数式接口的实例。虽然 Lambda 表达式允许你动态创建方法实现,但通常情况下,一个方法最终会调用 Lambda 表达式中的另一个方法来完成我们想要完成的工作。更直接的方法是使用方法引用。当你已经有一个方法来实现这个函数式接口时,这是非常有用的。

    让我们看一个使用静态方法及实例方法的示例。

    //step #1 - Create a funnctional interface.
    interface FuncInt {
        //contains one and only abstract method
        String answer(String x, boolean y);
    }
     
    //step #2 - Class providing method(s)that match FuncInt.answer()'s definition.
    class Answer {
        static String ans_math_static(String x, Boolean y) {
            return "\"" + x + "\"" + "\t = \t" + y.toString().toUpperCase();
        }
     
        String ans_math_inst(String x, Boolean y) {
            return "\"" + x + "\"" + "\t = \t" + y.toString().toUpperCase();
        }
    }

    译注:以上代码的测试用例如下,因静态方法与实例方法结果相同,仅以静态方法为例。

    Answer.ans_math_static("9 > 11 ?", false);
    Answer.ans_math_static("987.6 < 1.1 ?", false);
    Answer.ans_math_static("1 > 0.9 ?", true);
    Answer.ans_math_static("T/F: Is Chengdu in Sichuan?", true);
    Answer.ans_math_static("-1 % 0.2=0 ?", false);
    Answer.ans_math_static("T/F: Does Dwyne Wade play for the Knicks?", false);

    得到与原文举例相同的输出结果:

    "9 > 11 ?"    =  FALSE
    "987.6 < 1.1 ?"   =  FALSE
    "1 > 0.9 ?"   =  TRUE
    "T/F: Is Chengdu in Sichuan?"    =  TRUE
    "-1 % 0.2=0 ?"   =  FALSE
    "T/F: Does Dwyne Wade play for the Knicks?"  =  FALSE

    另请参阅:关于var的所有内容:局部变量类型推断如何清除Java代码冗余

    使用方法引用的主要步骤有:

    1. 定义一个函数式接口
    2. 定义一个满足函数式接口抽象方法要求的方法
    3. 使用对步骤2中定义的?(x :: y ) 方法引用实例化函数式接口的实例。
      译注:静态方法的方法引用格式为?类名 :: 方法名?;实例方法的方法引用格式为?对象实例名 :: 方法名?。
    4. 使用函数式接口实例调用方法:?Instance.AbstractMethod();

    这提供了一种创建方法实现的可插拔方式。Lambda 表达式和方法引用为 Java 编程带来了一个功能方面的提升。

    另请参阅:你到底有多了解Java的注解?

    构造函数的方法引用

    让我们开始详细讨论吧。

    构造函数和其他方法一样是方法。对吗?错。它们有点特殊,它们是对象初始化方法。尽管如此,它们仍然是一个方法,没有什么能阻止我们像其他方法引用一样创建构造函数的方法引用。

    //step #1 - Create a funnctional interface.
    interface FuncInt {
        //contains one and only abstract method
        Automobile auto(String make, String model, short year);
    }
     
    //step #2 - Class providing method(s)that match FuncInt.answer()'s definition.
    class Automobile {
     
        //Trunk Member Variables
        private String make;
        private String model;
        private short year;
     
        //Automobile Constructor
        public Automobile(String make, String model, short year) {
            this.make = make;
            this.model = model;
            this.year = year;
        }
     
        protected void what() {
            System.out.println("This Automobile is a" + year + " " + make + " " + model + ".");
        }
    }
     
    //Step #3 - Class making use of method reference
    public class ConstrRef {
     
        static void createInstance() {
        }
     
        public static void main(String[] args) {
            System.out.println();
     
            //Remember, a Method Reference is an instance of a Functional Interface. Therefore....
            FuncInt auto = Automobile::new;//We really don't gain much from this example
     
            //Example #1
            Automobile honda = auto.auto("honda", "Accord", (short) 2006);
            honda.what();
     
            //Example #1
            Automobile bmw = auto.auto("BMW", "530i", (short) 2006);
            bmw.what();
     
            System.out.println();
        }
    }

    输出结果

    This Automobile is a2006 honda Accord.
    This Automobile is a2006 BMW 530i.

    说明

    用户应该清楚的第一件事是这个基本示例没有那么实用。这是一种相当迂回的创建对象实例的方式。实际上,几乎可以肯定,你不会经历所有这些麻烦来创建一个 Automobile 实例,但是为了概念的完整性,还是要提及。

    使用构造函数的方法引用的主要步骤有:

    1. 定义一个只有抽象方法的函数式接口,该方法的返回类型与你打算使用该对象进行构造函数引用的对象相同。
    2. 创建一个类,该类的构造函数与函数式接口的抽象方法匹配。
    3. 使用对步骤 #2 中定义的构造函数的方法引用,实例化函数式接口的实例。
      译注:构造函数的方法引用格式为?类名 :: new
    4. 在步骤 #2 中使用构造函数引用实例化类的实例,例如?MyClass x = ConstructorReference.AbstractMethod (x, y, z…)

    构造函数引用与泛型一起使用的时候变得更有用。通过使用泛型工厂方法,可以创建各种类型的对象。

    让我们看一看。

    //step #1 - Create a funnctional interface.
    interface FuncInt<Ob, X, Y, Z> {
        //contains one and only abstract method
        Ob func(X make, Y model, Z year);
    }
     
    //step #2 - Create a Generic class providing a constructor compatible with FunInt.func()'s definition
    class Automobile<X, Y, Z> {
     
        //Automobile Member Variables
        private X make;
        private Y model;
        private Z year;
     
        //Automobile Constructor
        public Automobile(X make, Y model, Z year) {
            this.make = make;
            this.model = model;
            this.year = year;
        }
     
        protected void what() {
            System.out.println("This Automobile is a " + year + " " + make + " " + model + ".");
        }
    }
     
    //step #3 - Create a Non-Generic class providing a constructor compatible with FunInt.func()'s definition
    class Plane {
     
        //Automobile Member Variables
        private String make;
        private String model;
        private int year;
     
        //Plane Constructor
        public Plane(String make, String model, int year) {
            this.make = make;
            this.model = model;
            this.year = year;//Automatic unboxing
        }
     
        protected void what() {
            System.out.println("This Plane is a " + year + " " + make + " " + model + ".");
        }
    }
     
    //Step #3 - Class making use of method reference with generics
    public class ConstrRefGen {
     
        //Here is where the magic happens
        static <Ob, X, Y, Z> Ob factory(FuncInt<Ob, X, Y, Z> obj, X p1, Y p2, Z p3) {
            return obj.func(p1, p2, p3);
        }
     
        public static void main(String[] args) {
            System.out.println();
     
            //Example #1
            FuncInt<Automobile<String, String, Integer>, String, String, Integer> auto_cons = Automobile<String, String, Integer>::new;
            Automobile<String, String, Integer> honda = factory(auto_cons, "Honda", "Accord", 2006);
            honda.what();
     
            //Example #2
            FuncInt<Plane, String, String, Integer> plane_cons = Plane::new;
            Plane cessna = factory(plane_cons, "Cessna", "Skyhawk", 172);
            cessna.what();
     
            System.out.println();
        }
    }

    输出结果

    This Automobile is a 2006 Honda Accord.
    This Plane is a 172 Cessna Skyhawk.

    另请参阅:Java 中的 struct :如何像专业人士一样处理它们

    说明

    这里有很多东西需要消化。事实上,如果你以前从未深入研究过泛型,那么这些代码看上去可能相当晦涩。让我们分解一下。

    我们做的第一件事是创建一个通用的函数式接口。注意细节。我们有四个泛型类型参数:Ob、X、Y、Z。

    • Ob 代表要引用其构造函数的类。
    • X,Y,Z 代表该类的构造函数的参数。

    如果我们替换泛型方法占位符,抽象方法可能是这样的:?SomeClass func (String make, String model, int year)。注意,由于我们使接口具有了泛型,所以可以指定任何返回类型或我们希望返回的类实例。这释放了构造函数引用的真正潜力。

    接下来的两个部分相对简单,我们创建了相同的类,一个泛型类和一个非泛型类,以演示它们与在公共类中定义的工厂方法的互操作性。注意,这些类的构造函数与?FuncInt.func()?的方法签名是兼容的。

    进入公共类的文件。这个方法就是奇迹发生的地方。

    //Here is where the magic happens
    static <Ob, X, Y, Z> Ob factory(FuncInt<Ob, X, Y, Z> obj, X p1, Y p2, Z p3) {
        return obj.func(p1, p2, p3);
    }

    我们将该方法标记为静态的,所以我们可以不使用 ConstRefGen 实例,毕竟它是一个工厂方法。注意,factory 方法具有与函数式接口相同的泛型类型参数。注意,方法的返回类型是 Ob,它可以是由我们决定的任何类。当然,X、Y、Z是 Ob 中方法的方法参数。请注意,该函数以 FuncInt 的一个实例作为参数(类类型和方法参数作为类型参数),同时也接受 Ob 类型的类作为方法的参数。

    另请参阅:Reactor.js:用于响应式编程的轻量级库

    在方法体中,它调用方法引用并将在?factory()?中传递的参数提供给它。

    我们的第一个任务是创建一个符合?FuncInt<>?的方法引用。

    这里我们分别引用 Automobile 类和 Plane 类的构造函数。

    我们的下一个任务是创建一个带有方法引用的对象。

    为此,我们调用?factory()?并将它需要的构造函数引用以及?factory()?定义的有关构造函数的参数提供给它。factory()?可以灵活地创建对各种方法的构造函数引用,因为它是通用的。因为 Plane 类和 Automobile 类的构造函数匹配?FuncInt.func()?的方法签名,所以它们可作为?FuncInt.func()?的方法引用使用。factory()?通过调用?obj.func(x,y,z)?返回类的一个实例,这是一个构造函数方法引用,当求值时,它将为你提供指定为其参数的类的一个实例。

    斟酌这个问题一段时间,会发现它是Java的一个非常有用的补充???

    相关资讯

    • 北京校区
    • 山西校区
    • 郑州校区
    • 武汉校区
    • 四川校区
    • 长沙校区
    • 深圳校区
    • 上海校区
    • 广州校区
    • 保定招生办

    北京海淀区校区(总部):北京市海淀区西三旗街道建材城西路中腾建华商务大厦东侧二层尚学堂
    北京京南校区:北京亦庄经济开发区科创十四街6号院1号楼 赛蒂国际工业园
    咨询电话:400-009-1906 / 010-56233821
    面授课程:?JavaEE+微服务+大数据? ???大数据+机器学习+平台架构?????Python+数据分析+机器学习??人工智能+模式识别+强化学习???WEB前端+移动端+服务端渲染

     

    山西学区地址:山西省晋中市榆次区大学城大学生活广场万科商业A1座702

    郑州学区地址:河南电子商务产业园6号楼4层407
    咨询电话:0371-55177956

    武汉学区地址:武汉市东湖高新区光谷金融港B22栋11楼
    咨询电话:027-87989193

    四川学区地址:成都市高新区锦晖西一街99号布鲁明顿大厦2栋1003室
    咨询电话:028-65176856 / 13880900114

    网址://www.cssxt.com/
    咨询电话:0731-83072091

    深圳校区地址:深圳市宝安区航城街道航城大道航城创新创业园A4栋210(固戍地铁站C出口)
    咨询电话:0755-23061965 / 18898413781

    上海尚学堂松江校区地址:上海市松江区荣乐东路2369弄45号绿地伯顿大厦2层
    咨询电话:021-67690939

    广州校区地址:广州市天河区元岗横路31号慧通产业广场B区B1栋6楼尚学堂(地铁3号线或6号线到“天河客运站”D出口,右拐直走约800米)
    咨询电话:020-2989 6995

    保定招生办公室

    地址:河北省保定市竞秀区朝阳南大街777号鸿悦国际1101室

    电话:15132423123

    Copyright 2006-2019 北京尚学堂科技有限公司  京ICP备13018289号-19  京公网安备11010802015183  
    媒体联系:18610174079 闫老师  

    Java基础班,免费试学三周

  • 两岸民心相亲不可违逆(观沧海) 2019-06-24
  • 习近平新时代中国特色社会主义思想为解决人类问题贡献中国智慧 2019-06-22
  • 反击!欧盟成员国一致支持对美28亿欧元产品征收报复性关税 2019-06-22
  • 专访李毅立:走进国家 了解国情 续写中华情 2019-06-08
  • 现在,表面上看,很多城市绿树成荫,花卉草地到处都是,实际上地下空间已经掏空,建了车库、地下商城,雨水根本渗不下去。 2019-06-08
  • 你反来复去说1+1=2,真痴呆了?你应该讲点其他的吧,譬如,1+1=2,是客观事实还是规律,是真理还是谬误。 2019-06-05
  • 蜈蚣精的出游必备战靴 旅行路上皆战场 2019-06-05
  • 《法医秦明2》“长腿CP”最萌身高差吸睛 剧情高能 2019-06-04
  • 【春到渭南】随手拍渭南各地区春景,一贴看尽渭南春色! 2019-06-04
  • 如何像皇帝、老佛爷那样避个暑? 2019-05-30
  • 印度总理寓所附近现UFO?网友:外星人也想看莫迪 2019-05-21
  • 人民网评:建设一支生态环境保护铁军 2019-05-21
  • 这三个史无前例,让美国有点懵了 2019-05-18
  • 唐嫣蜡像入驻上海杜莎夫人蜡像馆--旅游频道 2019-05-18
  • 生活调查:过午不食可以养生减肥是真的吗? 2019-05-18
  • 时时彩走势图老时时彩 浙江快乐彩12选五开奖结果一 海底总动员图片 传奇霸业地图 风暴魔域手游官方版 老时时彩组六玩法技巧 冰球突破豪华版大奖 广东快乐10分开奖信息 4柔佛DT足球俱乐部 湛蓝深海走势图 双色球基本走势图图表 江西时时彩号码下载 打麻将的规律 搜狐彩票图表频道 古怪猴子输惨了 新梦幻诛仙寻宝网