문제

I didn't want to write alot of boilerplate code, so I decided to write generic method for lazy-init.

import java.util._
import concurrent.ConcurrentHashMap

object GenericsTest {
  val cache: ConcurrentHashMap[Long, 
    ConcurrentHashMap[Long, 
      ConcurrentHashMap[Long, 
        ConcurrentHashMap[Long, Long]]]] = new ConcurrentHashMap()

  def main(args: Array[String]) {
    val x = get(cache, 1)(() => new ConcurrentHashMap())
    val y = get(x, 1)(() => new ConcurrentHashMap())
    val z = get(y, 1)(() => new ConcurrentHashMap())
  }

  def get[B, A](map: ConcurrentHashMap[A, B], a: A)(factory: () => B): B = {
    if (map.containsKey(a)) {
      map.get(a)
    } else {
      val b = factory()
      map.put(a, factory())
      b
    }
  }
}

This example is only running with hard-coded Long but not with generic A, what can be the problem? Maybe there is another way to do such things?

도움이 되었습니까?

해결책

The error is in this line:

val x = get(cache, 1)(() => new ConcurrentHashMap())

The problem is that the type of 1 is Int.

We have this method signature:

get[A, B](map: ConcurrentHashMap[A, B], a: A)(factory: () => B): B

The types of parameters passed in that problematic call are (B is that long nested type, it's irrelevant now):

ConcurrentHashMap[Long, B] and Int

So the compiler calculates that A must be the closest common ancestor of Long and Int, which is AnyVal, so finally it will use the passed parameters with the types of:

ConcurrentHashMap[AnyVal, B] and AnyVal

But ConcurrentHashMap is invariant in it's first type parameter, so the cache val can't be used as ConcurrentHashMap[AnyVal, B], so the compiler gives this error message (removed the long nested type parameter part, it doesn't matter now):

found   : java.util.concurrent.ConcurrentHashMap[Long, ...]
required: java.util.concurrent.ConcurrentHashMap[AnyVal, ...]
Note: Long <: AnyVal, but Java-defined class ConcurrentHashMap is invariant in type K.

To fix this you need to pass the second parameter as Long:

val x = get(cache, 1L)(() => new ConcurrentHashMap())
val y = get(x, 1L)(() => new ConcurrentHashMap())
val z = get(y, 1L)(() => new ConcurrentHashMap())
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top