美文网首页
Groovy 之命名参数

Groovy 之命名参数

作者: woshishui1243 | 来源:发表于2020-01-30 18:48 被阅读0次

    Groovy 中提供了一个减少输入的特性叫做命名参数(Named Parameter)。GroovyBean 可以通过在构造器调用中传递冒号隔开的属性名称和值进行构建。如:

    car = new Car(model : "BMW", color : "black");
    

    要说从外部表现上好像是先调用了空构造方法,然后是相应的 setter 方法进行设值。因此,我们所直接想像的应该相当于下列 Java 代码:

    Car car = new Car();
    car.setModel("BMW");
    car.setColor("black");
    

    不过,假如你把 Groovy 生成的 class 文件反编译一下就会发现 Groovy 为上面那行生成了如下代码:

    Class class1 = Car.class;
    Class class2 = groovy.lang.MetaClass.class;
    Car car = (
                (Car) (ScriptBytecodeAdapter.invokeNewN(class1, 
                                                        class1, 
                                                        ((Object) (new Object[] {
                                                              ScriptBytecodeAdapter.createMap(new Object[] {
                                                              //Groovy把命名参数转换成一个对象数组"model", "BMW", "color", "black",然后放到 Map 中,通过相应的 setter方法或属性名反射赋值
                                                            })
                                                          })
                                                        ))
                    )
                );
    

    只要发现可用的属性(不管是私有的还是别的),或是 setXxx() 方法的那个 xxx (符合 JavaBean 规范即可) 就可以拿来作为命名参数的名字。
    所以若再加以试验,就会知道那个 Car 必须要有一个空的构造方法,这是必要条件
    但它们的属性值如果有相应的 setter 方法就用 setter 方法赋值,如果没有就直接通过反射进行设值。所以并不要求属性有相应的 setter 方法,甚至是私有属性而无相应的 setter 方法也不打紧。即使只有一个光头的 setter 方法,无对应属性也是可以的。

    Groovy 是通过 org.codehaus.groovy.runtime.ScriptBytecodeAdapter 来完成这一过程的,看到 Bytecode 就知道它大概做了一些不光明的事情。

    前面看到了,一行代码可以完成多行代码的功能。迫不急切地,我们还是来点有实效性的东西,例如构造一个 JFrame 窗口:

    JFrame frame = new JFrame(
                    title:"Named Parameter",
                    size:[400,300],
                    location:new Point(300,200),
                    defaultCloseOperation:JFrame.EXIT_ON_CLOSE,
                    visible:true);
    

    对上面那样一个过程,我们可以一句话说完,简洁易懂。要领就在于你只要发现可用的属性(不管是私有的还是别的),或是 setXxx() 方法的那个 xxx (符合 JavaBean 规范即可) 就可以拿来作为命名参数的名字。
    还应注意的是:在给 size 赋值时 size:[400,300] 使用到了隐式构造(Implicit constructors),size 原本接收的是一个 Dimension,而实质 [400,300] 就是隐式的调用了 new Dimension(400,300)。所以 location 属性也可以写成 [300,200]。

    命名参数不仅可以应用于构造实例时,还能运用于普通方法调用上,而且这种机制就是可以接受 Map 对象作为参数的方法:
    例如,前面的那么代码可以写成:

    car = new Car(["model":"BMW","color":"black"]) 
    

    并且生成的字节码与原来完全一样,总之都是转换成对象数组,然后反射赋值。
    再说一个接受 Map 参数(只适用于键是字符串的情况)的方法,以命名参数形式来调用的例子:

    def desc(dog){
        println dog.name;
        println dog.breed;
    }
    

    调用时可用以下两种形式,效果是完全一样的:

    desc(name : "Lina", breed : "Labrador");
    desc(["name" : "Lina", "breed" : "Labrador"]);
    

    相关文章

      网友评论

          本文标题:Groovy 之命名参数

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