Groovy def l = [1, 2, 3] as BlockingQueue

萝らか妹 提交于 2021-02-05 12:02:04

问题


If I write something like def l = [1, 2, 3] as Socket which is obviously nonsense, I get this:

org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object '[1, 2, 3]' with class 'java.util.ArrayList' to class 'java.net.Socket' 

That makes sense.

Now I try something less adventurous:

import java.util.concurrent.BlockingQueue

def l = [1, 2, 3] as BlockingQueue
println l.class
println l

This doesn't throw an exception, and prints the following:

class ArrayList1_groovyProxy
[1, 2, 3]

So what's ArrayList1_groovyProxy, and why am I able to cast the list to BlockingQueue without error despite the fact that it fails (l doesn't end up being an BlockingQueue instance)?

Edit:

  • First of all, I'd like to point out that def l = [1, 2, 3] as List works well, and produces a regualr instance of ArrayList despite the fact that both List and BlockingQueue are interfaces.
  • Second, after Dónal's answer, I tried the following:

    def l = [1, 2, 3] as BlockingQueue
    assert l instanceof BlockingQueue
    println l.class
    println l
    

    This printed the following lines and no assertion exceptions were thrown:

    class ArrayList1_groovyProxy
    [1, 2, 3]
    

    However, this line does throw a MissingMethodException:

    l.offer(5)
    

    So the assertion somehow succeeds, but trying to use l as a BlockingQueue throws an exception.

  • Third, the same happens if I try def l = [1, 2, 3] as Map This code:

    def l = [1, 2, 3] as Map
    assert l instanceof Map
    println l
    println l.getClass()
    

    produces no errors and prints:

    [1, 2, 3]
    class ArrayList1_groovyProxy
    

回答1:


It's just Groovy being cute. It's able to see that you're trying to create a collection, but it can't figure out how to construct a BlockingQueue. It's falling back to a proxied ArrayList. If you'd gone with a type declaration on the left side instead of a "def," it would have blown up. Again, it's getting cute because you're using a def. Annoying, isn't it? :)




回答2:


Using x as y is not casting, it's Coercion (see Section 8.7 of the Groovy Manual).

Coercion does not check type safety when casting.

Also, BlockingQueue is an interface. I'm not sure why you would cast an object as an interface.

Try running this:

import java.util.concurrent.LinkedBlockingQueue 
LinkedBlockingQueue l = [1, 2, 3] as LinkedBlockingQueue
println(l instanceof LinkedBlockingQueue)
println(l.class)
println(l.metaClass.methods*.name.sort().unique())
​

You get:

true
class java.util.concurrent.LinkedBlockingQueue
[add, addAll, clear, contains, containsAll, drainTo, element, equals, getClass, hashCode, isEmpty, iterator, notify, notifyAll, offer, peek, poll, put, remainingCapacity, remove, removeAll, retainAll, size, take, toArray, toString, wait]

You can't have an instance of an interface, so it had no idea what you asked it to do. For instance, try running new BlockingQueue(), you can't because you can't have an instance of an interface. This is why you cannot cast an Object to be an interface.




回答3:


why am I able to cast the list to BlockingQueue without error despite the fact that it fails (l doesn't end up being an BlockingQueue instance)?

Why are you so sure that l is not a BlockingQueue instance? The following (which you can run in the Groovy console) indicates that it is a BlockingQueue instance:

import java.util.concurrent.BlockingQueue

// this assignment would be impossible if l is not a BlockingQueue
BlockingQueue l = [1, 2, 3] as BlockingQueue

// this assertion would throw an exception if l is not a BlockingQueue
assert l instanceof BlockingQueue

FYI, you can remove a lot of uncertainty about types by defining the types of your variables, rather than using def.



来源:https://stackoverflow.com/questions/40195462/groovy-def-l-1-2-3-as-blockingqueue

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!