Groovy语法

作者: 刺雒 | 来源:发表于2018-08-05 17:31 被阅读271次

    注释

    • 单行注释//
    //这是单行注释
    
    • 多行注释/**/
    /*这是多行注释*/
    

    // GroovyDoc注释/** */

    /**
    * 这是文档注释
    */
    

    变量名

    • 普通变量名和Java规则一样
    • 引用变量,变量点后面可以跟引用值,可以使用java不允许的符号比如破折号等,比如
    map = [:]
    map."name" = "james"
    map."a-b-c" = "dota"
    
    map./slashy string/
    map.$/dollar slashy string/$
    
    def firstname = "Homer"
    map."Simpson-${firstname}" = "Homer Simpson"
    

    字符串

    • 单引号字符串
    'hello world'
    
    • 三引号字符串表示多行
    """ line 1
    line 2
    line 3
    
    • 双引号字符串,可以使用或者{}在字符串中进行插值,其中${}可以插入值或者表达式,但是表达式必须要以某种形式返回值否则值为null。
      其中$只对a.b有效,对其他语句无效如方法调用,大括号等,如果想输入$符号可以使用""
    "2 + 3 is ${2+3}" // output 2+3 is 5
    "2 + 3 is ${def i = 2; def j = 3; i+j}" // output 2 + 3 is 5
    
    def person = [name: 'James', age: 36]
    "$person.name is 36" // output James is 36
    "person is $def age = 10" // 不合法
    ""
    
    • 当字符串中存在${->}形式,这表示一个闭包,闭包包含0个参数或者1个参数
      0个参数的闭包会调用toString()作为值,即->后面的值会toString,如果是表达式必须要有返回值,否则为null
      1个参数的闭包会传入的参数类型为StringWriter,用这个参数可以追加内容, 可以使用"<<"操作符追加内容
    def person = "1 + 2 is ${->3}"
    
    def person = "1 + 2 is ${w -> w.append("5")}"
    def person = "1 + 2 is ${w -> w << "5"}"
    
    • 上述两种插值方法对比,采用闭包的好处可以动态更新数据,如果变量值更新了,闭包所用参数也对应更新。
      如下所示可以看出,当num值更新时,字符串闭包内的值也改变了, 普通传值没有改变是因为创建String的时候值就已经确定了。
    def num = 3
    def normal = "1 + 2 is ${-> num}"
    def cls = "1 + 2 is ${num}"
    println(normal) // output "1 + 2 is 3"
    println(cls) // output "1 + 2 is 3"
    
    num = 5
    println(normal) // output "1 + 2 is 3"
    println(cls) // output "1 + 2 is 5"
    
    • 字符串使用插值,类型则会被转换为GString,类型,值得注意的是GString类型的hashCode和String类型的hashCode是不一样的
    def key = "a"
    map = [${key}:"James"]
    printfln map["a"] // output null
    
    • Char类型可以用以下三种来表示
    def a = 'A'
    
    def b = 'A' as char
    
    def c = (char)'A'
    

    Numbers

    • 整数数据类型基本和Java一样分别是byteshortcharintlongBigInteger
      如果类型修饰符为def,会根据范围,自动识别对应的数据类型
      def i = 10
      println i instance of Interger // Output ture
      
    • 小数数据类型分别是floatdoubleBigDecimal
      float a = 1.2
      double b = 1.21
      
    • 数字可以添加下划线,使某些大数看起来更加清楚
    long i =  1223_123_1L
    long i = 0x7fff_8fff_0000_ffff
    
    • 通过数字后缀来代表数据类型
    Integer a = 42I或42i
    Long b = 42L或42l
    BigInteger c = 42G或42g
    Double d = 42.2D或42.5d
    Float e = 42.2F或42.1f
    BigDecimal f = 42.24G或42.24g
    

    List

    • Groovy使用逗号分隔值(用方括号括起来)来表示列表,默认类型为List, 一个List的值可以是不同类型
    def listone = [1,2,3,4]
    def listtwo = [1, 1.24, "hello"]s
    
    • List是ArrayList的实例,可以通过as进行转换成其他类型的List
    def list = [1,2,3,4] as LinkedList
    
    • List索引可以使用以下几种形式, 可以用<<添加值
    def list = [1,2,3,4]
    list[-1]
    list[2]
    list[1..3]
    
    list << 5
    
    • 多维List
    list = [[0,1],[2,3]]
    list[0][1]
    

    Arrays

    • Arrays的形式上和List是一样的,但是如果需要Arrays类型数据,需要通过变量指定数据类型或者通过as强转
    int[] list = [1,2,3,4,5]
    def list = [1,2,3,4] as int[]
    
    • 索引,多维数组等定义和List一样

    Maps

    • Groovy使用逗号分隔值(用方括号括起来),键值对冒号分隔来表示Map
    def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']
    
    colors['pink'] = '#FF00FF'
    colors.yellow = '#FFFF00'
    
    • 如果想要引用变量作为key值,则需要加上括号
    def key = 'pink'
    def map = [(key) :123]
    

    操作符

    • ** 表示次方, 下面表示2的3次方
    def num = 2 ** 3
    
    • 双目运算符?:,是一个false 赋值
    def a = 8
    def b = a < 7 ?:10
    // 等价于
    if(a < 7) {
        b = ture
    } else {
        b = 10
    }
    
    • *.操作符,将cars中make元素全部收集到同一个列表
    class Car {
        String make
        String model
    }
    def cars = [
           new Car(make: 'Peugeot', model: '508'),
           new Car(make: 'Renault', model: 'Clio')]       
    def makes = cars*.make                                
    assert makes == ['Peugeot', 'Renault'] 
    
    • Spread操作符可以将list列表中值传入符合list数量的方法中, 也可以直接插入到另外一个list中
    def list = [1,2,3]
    int f(int i, int j, int z) {
        return i * j + z
    }
    
    f(*list)
    
    def other = [4,5, *list] // output [4,5,1,2,3]
    def other = [4,5, list] // output [4,5,[1,2,3]]
    
    • map中也可以使用
    def map = [red : 0x1]
    def add = [green : 0x2, * : map]
    // output [green:34, red:17]
    
    • Range操作符.., 生成一个有序列表
    def i = 0..5 // output [0,1,2,3,4,5]
    def i = 0..<5 // output [0,1,2,3,4]
    def i = 'a'..'d' // output ['a','b','c','d']
    
    • 比较操作符<=>, 类似java中的compareTO方法,
    (1<=>1) = 0
    (2<=>1) = 1
    (2<=>3) = -1
    
    • 下标操作符,类似getAt()或putAt()方法
    def list = [0,1,2,3,4]
    list[3] = 5 // output [0,1,2,5,4]
    list[4] // output 4
    
    • 成员关系操作符in,判断一个数据成员是否在列表当中
    def list = [1,2,3]
    5 in list // output false
    
    • Identity操作符,==操作符在Groovy和Java中使用是不一样的, ==比较是值是否相等,equals比较的是内存地址是否一样
    def list1 = [1,2,3]
    def list2 = [1,2,3]
    list1.is(list2) // output false
    list1 == list2 // output true
    
    Integer a = new Integer(5);
    Integer b = new Integer(5);
    println a.is(b) // output false
    println a == b // output true
    
    • 转换操作符as,as操作符如果符合转换规则,就可以转换,否则会抛异常。如果转换为另外一个类型就会创建一个新的对象
    Integer x = 123 as String  // output "123"
    String a = "123" as Map // 抛异常
    
    • Groovy支持运算符重载

    • 包支持用别名
    import java.util.Date as SQLDate
    
    SQLDate date = new SQLDate() 
    
    • 脚本和类,Groovy会把脚本转换成一个类,这个类继承于Script,最终调用的还是main()方法,我们在写脚本中写的方法会被加入到类中,写的语句全部在run()方法中。
    println 'Hello'                                 
    int power(int n) { 2**n }                       
    println "2^6==${power(6)}"
    
    // 转换之后
    import org.codehaus.groovy.runtime.InvokerHelper
    class Main extends Script {
        int power(int n) { 2** n}                   
        def run() {
            println 'Hello'                         
            println "2^6==${power(6)}"              
        }
        static void main(String[] args) {
            InvokerHelper.runScript(Main, args)
        }
    }
    
    • 脚本中变量作用域。
      变量如果声明类型,则无法被其他方法访问,因为这个变量相当于run方法中的局部变量
      变量如果没有声明类型,则会被脚本绑定,脚本会和其他方法共享这些数据
    int declared  = 0
    undeclared  = 10
    void pow() {
        println declared
        println undeclared
    }
    
    pow()
    
    • 反编译之后的代码, 可以看到run方法中会把变量值传入,pow方法中把值取出来
    public class Study extends Script
    {
      public void pow()
      {
        CallSite[] arrayOfCallSite = $getCallSiteArray();
        arrayOfCallSite[2].callCurrent(this, arrayOfCallSite[3].callGroovyObjectGetProperty(this));
        arrayOfCallSite[4].callCurrent(this, arrayOfCallSite[5].callGroovyObjectGetProperty(this));
      }
      
      public Object run()
      {
        CallSite[] arrayOfCallSite = $getCallSiteArray();
        int declared = 0;
        int i = 10;
        ScriptBytecodeAdapter.setGroovyObjectProperty(Integer.valueOf(i), Study.class, this, (String)"undeclared");
        pow();
       }
      
      public static void main(String... args)
      {
        CallSite[] arrayOfCallSite = $getCallSiteArray();
        arrayOfCallSite[0].call(InvokerHelper.class, Study.class, args);
      }
      
    }
    

    方法和类

    • 如果没有可见修饰符修饰,默认是public的,并且会自动转换成属性,自然省去get和set方法
    public class Study {
        public String name;
    
        class School {
            Study study = new Study();
            public void driver() {
            }
        }
    }
    
    • 一个文件可以包含多个类,如果没有类默认是脚本(当然最后还是会转换为一个类)

    • 不论是构造函数还是普通函数参数都可以通过列表传入, 方法参数可以设置默认值

    public class Study {
        public Study(String name, int age) {
            
        }
        
        public void pow(int a, int b = 9) {
        }
    }
    
    
    Study study = ["1",2] 
    study.pow([5,6])
    study.pow(5)
    
    • 方法可变参数列表
      可以传入任意个参数
      T[]和T..是等价的,也表示可见参数,意味方法参数列表为数组的,都表示可变参数。
      如果出现多个方法重载,比如一个方法参数列表是可见参数,另外一个方法参数列表是具体个数参数,以含具体个数参数方法为主
      void f(int[] a);
      void f(int a);
      
      f(1) // 调用的是f(int a)方法
      

    Traits(特征)

    • 是Groovy独有的面向对象特性,有几点特性:由行为构成、可以实现接口、行为可以重载,兼容静态类型的检查和编译。可以看成具有方法实现和状态的接口,关键字trait
    trait FlyingAbility {                           
        String fly() {
            println "I'm flying!" 
        }          
    }
    
    class Bird implements FlyingAbility {}          
    def b = new Bird()                              
    println b.fly()  
    
    • 可以含有抽象方法
    trait Greetable {
        abstract String name()                              
        String greeting() { "Hello, ${name()}!" }           
    }
    
    • 可以定义private方法
    trait Greeter {
        private String greetingMessage() {                      
            'Hello from a private method!'
        }
        String greet() {
            def m = greetingMessage()                           
            println m
        }
    }
    
    • 可以使用this操作符
    public trait FlyingAbility {
        
        String fly() {
            return this
        }
    }
    
    • 可以定义属性
    trait Named {
        String name                             
    }
    
    • 可以定义私有和共有字段
    trait Counter {
        public int num = 1
        private int count = 0                   
        int count() { count += 1; count }       
    }
    
    • 和接口一样支持多重继承
    trait FlyingAbility {                           
            String fly() { "I'm flying!" }          
    }
    trait SpeakingAbility {
        String speak() { "I'm speaking!" }
    }
    
    class Duck implements FlyingAbility, SpeakingAbility {}
    
    • 方法可以被覆盖、相互继承
    trait FlyingAbility {                           
            String fly() { 
                "I'm flying!" 
            }          
    }
    trait SpeakingAbility extends FlyingAbility {
        String fly() {
            "I can speaking!" 
        }
    }
    

    闭包

    • 闭包是一个匿名函数,拥有函数的特征,写法如下{ [closureParameters -> ] statements }, 有以下几种写法
    { item++ }                                          
    
    { -> item++ }                                       
    
    { println it }                                      
    
    { it -> println it }                                
    
    { name -> println name }                            
    
    { String x, int y ->                                
        println "hey ${x} the value is ${y}"
    }
    
    { reader ->                                         
        def line = reader.readLine()
        line.trim()
    }
    
    • 闭包作为一个对象,是groovy.lang.Closur一个实例,可以赋值给该类的实例对象
    def listener = { e ->  e } 
    println listener //output `groovy.lang.Closure`对象
    println listener("lis") // output  "lis"
    
    Closure callback = { println 'Done!' }     
    
    Closure<Boolean> isTextFile = {
        File it -> it.name.endsWith('.txt')                     
    }
    
    • 闭包可以像其他方法一样被调用,可以像其他函数一样传参进入,也可以当成一个对象调用call方法
    def isOdd = { 
        int i -> i%2 != 0 
    }
    
    isOdd(2)
    isOdd.call(2)
    
    
    • 闭包跟函数一样,参数列表可以是对象,基本类型,可选列表,也可以给参数设置默认值,
      不过和函数不同的地方,如果闭包没有确切定义一个参数列表,闭包就会定义一个隐式参数it
    def f = {-> printfln it}
    def f = {it -> println it}
    

    闭包中的this,owner,delegate

    • this:在一个类中定义闭包,闭包中的this指向该类,
      getThisObject()this是等价的。
      类中定义闭包使用this,则指向内部类,在该闭包中可以调用该类的成员变量和方法
      闭包中嵌套使用闭包,this也是指向类
      总之,无论闭包怎么嵌套,闭包中使用this就指向离他最近的类
    class Enclosing {
        void run() {
            def whatIsThisObject = { getThisObject() }          
            assert whatIsThisObject() == this                   
            def whatIsThis = { this }                           
            assert whatIsThis() == this   //  等价                     
        }
    }
    class EnclosedInInnerClass {
        class Inner {
            Closure cl = { this }                               
        }
        void run() {
            def inner = new Inner()
            // 内部类定义闭包使用this,则指向内部类
            assert inner.cl() == inner                      
        }
    }
    class NestedClosures {
        void run() {
            def nestedClosures = {
                def cl = { this }                               
                cl()
            }
            // 闭包嵌套闭包,则this也指向类
            assert nestedClosures() == this                     
        }
    }
    
    • owner: 指向一个封闭的对象,可以是一个类或者闭包
      ownergetOwner()是等价的
      如果闭包定义在内部类中,指向的也是这个内部类
      但是如果owner在嵌套闭包内,则指向的是outer闭包,并非和this一样是类
      总结:和this一样都是返回封闭对象,但是this值包含类,owner包含了闭包和类

    • delegate: 委托可以被赋值成定义的任何对象,默认情况下,delegateowner的指向范围一样
      但是区别是delegate可以被赋于其他对象,而owner则不行

      class Person {
        String name
      }
      class Thing {
        String name
      }
      def p = new Persong(name: "Normal")
      def t = new Thing(name : "Teapot")
      
      def a = { 
        delegate.name.toUpperCase() 
      }
      
      def b = {
        owner.name.toUpperCase()
      }
      
      a.delegate = p 
      a() // output NORMAL
      b.owner = t 
      b() //报错,因为不允许被转为t对象
      

    相关文章

      网友评论

        本文标题:Groovy语法

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