Object-Oriented in Groovy

Keywords: Android Java JDK Windows Attribute

As for groovy support scripts and classes, the previous section will briefly describe the relationship between scripts and classes. This section mainly introduces the related knowledge of classes in groovy, that is, object-oriented knowledge.

1. Types

1.1 Primitive Type

groovy supports the same raw data types as java, boolean, char, short, int, long, float, double.

Category 1.2

Classes in groovy are very similar to those in java, but the following are unique to groovy:

  • The fields modified by public are automatically converted into attribute variables, which can avoid many redundant get and set methods.
  • If the attribute or method has no access modifier, the default is public, and in java it is proteced.
  • The class name does not need to be the same as the file name.
  • Multiple first-level classes can be defined in a file. If no class is defined, the groovy file is considered a script file.

1.2.1 General Class

groovy's common class is similar to java, using the new keyword to get instances.

1.2.2 Internal Classes

Internal classes are basically similar. Here's an example:

class Outer2 {
    private String privateStr = 'some string'

    def startThread() {
       new Thread(new Inner2()).start()
    }

    class Inner2 implements Runnable {
        void run() {
            println "${privateStr}."
        }
    }
}

1.2.3 abstract classes

Abstract classes are basically similar to java:

abstract class Abstract {         
    String name

    abstract def abstractMethod() 

    def concreteMethod() {
        println 'concrete'
    }
}

1.3 Interface

groovy's interface is similar to java's and supports interface inheritance interface.

1.4 Construction Method

groovy's construction method is slightly different from java's. groovy's construction method supports location and naming parameters. Let's look at it in detail below.

1.4.1 Method for Constructing Location Parameters

Location construction parameters are similar to the usual construction methods in java, and they have different meanings in different locations. As follows:

class PersonConstructor {
    String name
    Integer age

    PersonConstructor(name, age) {          
        this.name = name
        this.age = age
    }
}

def person1 = new PersonConstructor('Marie', 1)  
def person2 = ['Marie', 2] as PersonConstructor  
PersonConstructor person3 = ['Marie', 3]        

Groovy has two more ways of writing when calling the constructor. Because the location is fixed, even the PersonConstructor person3 = ['Marie', 3] notation groovy can initialize you internally.

1.4.2 Named Parameter Construction Method

Named parameter constructors do not require user definition. When a class does not have a constructor, it defaults to a named parameter constructor.

class PersonWOConstructor {                                  
    String name
    Integer age
}

def person4 = new PersonWOConstructor()                      
def person5 = new PersonWOConstructor(name: 'Marie')         
def person6 = new PersonWOConstructor(age: 1)                
def person7 = new PersonWOConstructor(name: 'Marie', age: 2) 

1.5 Method

The method of defining groovy is also simple, using the keyword def or return value. The methods in groovy all have return values. If no return statement is written, the last line of the groovy accounting method statement returns the result.

Here are four different legal definitions:

def someMethod() { 'method called' }                           
String anotherMethod() { 'another method called' }             
def thirdMethod(param1) { "$param1 passed" }                   
static String fourthMethod(String param1) { "$param1 passed" }

Naming parameters of 1.5.1 method

To use named parameters in a custom method, use Map as the only parameter, as follows:

def foo(Map args) { "${args.name}: ${args.age}" }
foo(name: 'Marie', age: 1)

Default parameters for the 1.5.2 method

The groovy method supports default parameters, so that their parameters become optional. When the parameters are not filled in, the default parameters are used:

def foo(Map args) { "${args.name}: ${args.age}" }
foo(name: 'Marie', age: 1)

Variable Length Parameters of 1.5.3 Method

This also exists in java, for example:

def foo(Map args) { "${args.name}: ${args.age}" }
foo(name: 'Marie', age: 1)

1.6 Annotations

Annotations in groovy are similar to those in java, but they have more features than those in java. Here's a brief introduction.

Closure parameters for annotations 1.6.1

In groovy, one interesting linguistic feature is that closures can be used as parameter values for annotations. Under what circumstances are such annotations commonly used? For example, sometimes the software runtime depends on its running environment and operating system, and it behaves differently for different environments or systems. Look at this example:

class Tasks {
    Set result = []
    void alwaysExecuted() {
        result << 1
    }
    @OnlyIf({ jdk>=6 })
    void supportedOnlyInJDK6() {
        result << 'JDK 6'
    }
    @OnlyIf({ jdk>=7 && windows })
    void requiresJDK7AndWindows() {
        result << 'JDK 7 Windows'
    }
}

Tasks class is used to complete always Executed, supported OnlyIn JDK6, requires JDK7 and Windows three tasks, but different tasks have different requirements for environment and system. Here @OnlyIf is used to express the requirements for environment and system.

@Retention(RetentionPolicy.RUNTIME)
@interface OnlyIf {
    Class value()                    
}

In groovy, if you need to have annotations accept closures, you just need to define a value value value of the Class type as above. So OnlyIf can accept closures as its value.

Then write the processing class:

class Runner {
    static <T> T run(Class<T> taskClass) {
        def tasks = taskClass.newInstance()                                         
        def params = [jdk:6, windows: false]                                        
        tasks.class.declaredMethods.each { m ->                                     
            if (Modifier.isPublic(m.modifiers) && m.parameterTypes.length == 0) {   
                def onlyIf = m.getAnnotation(OnlyIf)                                
                if (onlyIf) {
                    Closure cl = onlyIf.value().newInstance(tasks,tasks)            
                    cl.delegate = params                                            
                    if (cl()) {                                                     
                        m.invoke(tasks)                                             
                    }
                } else {
                    m.invoke(tasks)                                                 
                }
            }
        }
        tasks                                                                       
    }
}

Similar to java, the method of retrieving Task objects by reflection is followed by retrieving their OnlyIf annotations. If successful, the closure of OnlyIf is extracted for invocation.

2 Traits (features)

trait is a unique object-oriented grammatical feature in groovy. It has the following functions:

  • Behavior Composition
  • Runtime Interface Implementation
  • Behavior overload
  • Compatible with static type checking and compiling

Trait can be seen as an interface with method implementation and state, defined using the trait keyword:

trait FlyingAbility {                           
        String fly() { "I'm flying!" }          
}

A flight capability certificate is defined above. It uses the same keyword implements as the interface.

class Bird implements FlyingAbility {}          
def b = new Bird()                              
assert b.fly() == "I'm flying!" 

This looks a bit like inheritance, but it's different. Trat just embeds its methods and states into the implementation class, without the parent-child relationship of the parent-child relationship in inheritance.

Some grammatical features of trait:

  • The definition of abstract method is supported in trait, and its implementation class must implement this abstract method.
  • Private methods can be defined in trait, and their implementation classes cannot be accessed.
  • The this keyword in trait refers to its implementation class.
  • trait implements interfaces.
  • A trait defines a property that is automatically attached to the class that implements the trait.
  • trait can define private fields due to the storage of related states.
  • Trat can define common fields, but to avoid the problem of diamonds, it can be obtained in different ways, as follows:
trait Named {
    public String name                      
}
class Person implements Named {}            
def p = new Person()                        
p.Named__name = 'Bob'   
  • The first class can implement multiple trait s.
  • The implementation class overrides the default method in trait.
  • Trait can inherit another trait using the keyword extends, and if you want to inherit more than one, use the implements keyword.
  • Tras can be dynamically implemented at runtime using the keyword as.

The above is a brief introduction to object-oriented knowledge in groovy. For more detailed information, please refer to the official documentation.

Posted by theBond on Sat, 22 Jun 2019 17:41:40 -0700