在Groovy中List和List <String>是否相同?

Ler*_*rve 16 groovy list arraylist

问题1

是否在Groovy中使用(List对象列表)或List<String>(字符串列表)是无关紧要的?

在下面的代码示例中,两个列表最终都是ArrayList(对象的ArrayList).本来希望第二个列表是一个ArrayList<String>(字符串的ArrayList).

Groovy在编译类时是否会丢失类型信息,并在执行编译的类时推断它?

例1

List untypedList = ["a", "b", "c"]
List<String> typedList = ["a", "b", "c"]

println "Untyped list List:       ${untypedList.getClass()}"
println "Typed list List<String>: ${typedList.getClass()}"
Run Code Online (Sandbox Code Playgroud)

输出1

Untyped list List:       class java.util.ArrayList
Typed list List<String>: class java.util.ArrayList // Would have expected ArrayList<String>
Run Code Online (Sandbox Code Playgroud)

问题2

我原以为typedList << new Integer(1)下面示例中的行会因异常而失败,因为我正在尝试将一个int字符串列入.任何人都可以解释为什么我可以添加intString-typed List

输出显示它仍然是Integer,即它不是在运行中转换为String"1".

例2

List untypedList = ["a", "b", "c"]
List<String> typedList = ["a", "b", "c"]

untypedList << new Integer(1)
typedList << new Integer(1) // Why does this work? Shouldn't an exception be thrown?

println "Types:"
println "Untyped list List:       ${untypedList.getClass()}"
println "Typed list List<String>: ${typedList.getClass()}"

println "List contents:"
println untypedList
println typedList

println "Untyped list:"
untypedList.each { println it.getClass() }
println "Typed list:"
typedList.each { println it.getClass() }
Run Code Online (Sandbox Code Playgroud)

输出2

Types:
Untyped list List:       class java.util.ArrayList
Typed list List<String>: class java.util.ArrayList
List contents:
[a, b, c, 1]
[a, b, c, 1]
Untyped list:
class java.lang.String
class java.lang.String
class java.lang.String
class java.lang.Integer
Typed list:
class java.lang.String
class java.lang.String
class java.lang.String
class java.lang.Integer
Run Code Online (Sandbox Code Playgroud)

tim*_*tes 24

"正常"运行Groovy时,泛型会在编译之前被丢弃,因此只在源代码中存在作为对开发人员有用的提醒.

但是,您可以使用@CompileStatic@TypeChecked使Groovy尊重这些泛型并在编译时检查事物的类型.

作为一个例子,考虑我有以下项目结构:

project
 |---- src
 |      |---- main
 |             |---- groovy
 |                    |---- test
 |                           |---- ListDelegate.groovy
 |                           |---- Main.groovy
 |---- build.gradle
Run Code Online (Sandbox Code Playgroud)

随着代码:

的build.gradle

apply plugin: 'groovy'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.codehaus.groovy:groovy-all:2.2.1'
}

task( runSimple, dependsOn:'classes', type:JavaExec ) {
    main = 'test.Main'
    classpath = sourceSets.main.runtimeClasspath
}
Run Code Online (Sandbox Code Playgroud)

ListDelegate.groovy

package test

class ListDelegate<T> {
    @Delegate List<T> numbers = []
}
Run Code Online (Sandbox Code Playgroud)

Main.groovy

package test

class Main {
    static main( args ) {
        def del = new ListDelegate<Integer>()
        del << 1
        del << 'tim'
        println del
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,运行gradle runSimple给我们输出:

:compileJava UP-TO-DATE
:compileGroovy
:processResources UP-TO-DATE
:classes
:runSimple
[1, tim]

BUILD SUCCESSFUL

Total time: 6.644 secs
Run Code Online (Sandbox Code Playgroud)

所以你可以看到,仿制药被扔掉了,它只是工作增加IntegersStrings对出List的所谓只Integers

现在,如果我们ListDelegate.groovy改为:

package test

import groovy.transform.*

@CompileStatic
class ListDelegate<T> {
    @Delegate List<T> numbers = []
}
Run Code Online (Sandbox Code Playgroud)

并再次运行:

:compileJava UP-TO-DATE
:compileGroovy
:processResources UP-TO-DATE
:classes
:runSimple
[1, tim]

BUILD SUCCESSFUL

Total time: 6.868 secs
Run Code Online (Sandbox Code Playgroud)

我们得到相同的输出!! 这是因为虽然ListDelegate现在已经静态编译,但是我们的Main类仍然是动态的,所以在构造之前仍然抛弃泛型ListDelegate...所以我们也可以Main.groovy改为:

package test

import groovy.transform.*

@CompileStatic
class Main {
    static main( args ) {
        def del = new ListDelegate<Integer>()
        del << 1
        del << 'tim'
        println del
    }
}
Run Code Online (Sandbox Code Playgroud)

现在重新运行gradle runSimple给我们:

:compileJava UP-TO-DATE
:compileGroovy
startup failed:
/Users/tyates/Code/Groovy/generics/src/main/groovy/test/Main.groovy: 10:
    [Static type checking] - Cannot find matching method test.ListDelegate#leftShift(java.lang.String).
    Please check if the declared type is right and if the method exists.
 @ line 10, column 9.
           del << 'tim'
           ^

1 error

:compileGroovy FAILED
Run Code Online (Sandbox Code Playgroud)

正如您所期望的那样,未能将String我们声明的List 添加到Integer.

其实,你只需要CompileStaticMain.groovy类和这个错误会有所回升,但我总是喜欢在那里我可以使用它,而不是在哪里,我需要.