Scala双重定义(2个方法具有相同的类型擦除)

发布于 2024-09-10 22:12:53 字数 556 浏览 2 评论 0原文

我在 scala 中写了这个,但它无法编译:

class TestDoubleDef{
  def foo(p:List[String]) = {}
  def foo(p:List[Int]) = {}
}

编译器通知:

[error] double definition:
[error] method foo:(List[String])Unit and
[error] method foo:(List[Int])Unit at line 120
[error] have same type after erasure: (List)Unit

我知道 JVM 没有对泛型的本机支持,所以我理解这个错误。

我可以为 List[String]List[Int] 编写包装器,但我很懒:)

我很怀疑,但是,是否有另一种方式来表达 List [String]List[Int] 类型不同?

谢谢。

I wrote this in scala and it won't compile:

class TestDoubleDef{
  def foo(p:List[String]) = {}
  def foo(p:List[Int]) = {}
}

the compiler notify:

[error] double definition:
[error] method foo:(List[String])Unit and
[error] method foo:(List[Int])Unit at line 120
[error] have same type after erasure: (List)Unit

I know JVM has no native support for generics so I understand this error.

I could write wrappers for List[String] and List[Int] but I'm lazy :)

I'm doubtful but, is there another way expressing List[String] is not the same type than List[Int]?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

等往事风中吹 2024-09-17 22:12:53

我喜欢 Michael Kramer 使用隐式的想法,但我认为它可以更直接地应用:

case class IntList(list: List[Int])
case class StringList(list: List[String])

implicit def il(list: List[Int]) = IntList(list)
implicit def sl(list: List[String]) = StringList(list)

def foo(i: IntList) { println("Int: " + i.list)}
def foo(s: StringList) { println("String: " + s.list)}

我认为这非常可读且简单。

[更新]

还有另一种似乎可行的简单方法:

def foo(p: List[String]) { println("Strings") }
def foo[X: ClassTag](p: List[Int]) { println("Ints") }
def foo[X: ClassTag, Y: ClassTag](p: List[Double]) { println("Doubles") }

对于每个版本,您都需要一个额外的类型参数,因此这无法扩展,但我认为对于三四个版本来说就可以了。

[更新2]

对于两种方法,我发现了另一个不错的技巧:

def foo(list: => List[Int]) = { println("Int-List " + list)}
def foo(list: List[String]) = { println("String-List " + list)}

I like Michael Krämer's idea to use implicits, but I think it can be applied more directly:

case class IntList(list: List[Int])
case class StringList(list: List[String])

implicit def il(list: List[Int]) = IntList(list)
implicit def sl(list: List[String]) = StringList(list)

def foo(i: IntList) { println("Int: " + i.list)}
def foo(s: StringList) { println("String: " + s.list)}

I think this is quite readable and straightforward.

[Update]

There is another easy way which seems to work:

def foo(p: List[String]) { println("Strings") }
def foo[X: ClassTag](p: List[Int]) { println("Ints") }
def foo[X: ClassTag, Y: ClassTag](p: List[Double]) { println("Doubles") }

For every version you need an additional type parameter, so this doesn't scale, but I think for three or four versions it's fine.

[Update 2]

For exactly two methods I found another nice trick:

def foo(list: => List[Int]) = { println("Int-List " + list)}
def foo(list: List[String]) = { println("String-List " + list)}
七月上 2024-09-17 22:12:53

您可以使用 Predef 中定义的 DummyImplicit 来代替发明虚拟隐式值,它似乎正是为此而设计的:

class TestMultipleDef {
  def foo(p:List[String]) = ()
  def foo(p:List[Int])(implicit d: DummyImplicit) = ()
  def foo(p:List[java.util.Date])(implicit d1: DummyImplicit, d2: DummyImplicit) = ()
}

Instead of inventing dummy implicit values, you can use the DummyImplicit defined in Predef which seems to be made exactly for that:

class TestMultipleDef {
  def foo(p:List[String]) = ()
  def foo(p:List[Int])(implicit d: DummyImplicit) = ()
  def foo(p:List[java.util.Date])(implicit d1: DummyImplicit, d2: DummyImplicit) = ()
}
巷雨优美回忆 2024-09-17 22:12:53

要了解 Michael Kramer 的解决方案,有必要认识到隐式参数的类型并不重要。重要的是它们的类型是不同的。

以下代码以相同的方式工作:

class TestDoubleDef {
   object dummy1 { implicit val dummy: dummy1.type = this }
   object dummy2 { implicit val dummy: dummy2.type = this }

   def foo(p:List[String])(implicit d: dummy1.type) = {}
   def foo(p:List[Int])(implicit d: dummy2.type) = {}
}

object App extends Application {
   val a = new TestDoubleDef()
   a.foo(1::2::Nil)
   a.foo("a"::"b"::Nil)
}

在字节码级别,两个 foo 方法都变成双参数方法,因为 JVM 字节码不知道隐式参数或多参数列表。在调用站点,Scala 编译器通过查看传入列表的类型(直到该列表不会被删除)来选择要调用的适当的 foo 方法(以及要传入的适当的虚拟对象)。之后)。

虽然它比较冗长,但这种方法减轻了调用者提供隐式参数的负担。事实上,如果 dummyN 对象是 TestDoubleDef 类私有的,它甚至可以工作。

To understand Michael Krämer's solution, it's necessary to recognize that the types of the implicit parameters are unimportant. What is important is that their types are distinct.

The following code works in the same way:

class TestDoubleDef {
   object dummy1 { implicit val dummy: dummy1.type = this }
   object dummy2 { implicit val dummy: dummy2.type = this }

   def foo(p:List[String])(implicit d: dummy1.type) = {}
   def foo(p:List[Int])(implicit d: dummy2.type) = {}
}

object App extends Application {
   val a = new TestDoubleDef()
   a.foo(1::2::Nil)
   a.foo("a"::"b"::Nil)
}

At the bytecode level, both foo methods become two-argument methods since JVM bytecode knows nothing of implicit parameters or multiple parameter lists. At the callsite, the Scala compiler selects the appropriate foo method to call (and therefore the appropriate dummy object to pass in) by looking at the type of the list being passed in (which isn't erased until later).

While it's more verbose, this approach relieves the caller of the burden of supplying the implicit arguments. In fact, it even works if the dummyN objects are private to the TestDoubleDef class.

话少情深 2024-09-17 22:12:53

由于类型擦除的奇妙作用,方法列表的类型参数在编译期间被擦除,从而将两个方法减少为相同的签名,这是一个编译器错误。

Due to the wonders of type erasure, the type parameters of your methods' List get erased during compilation, thus reducing both methods to the same signature, which is a compiler error.

时光沙漏 2024-09-17 22:12:53

正如 Viktor Klang 已经说过的,泛型类型将被编译器删除。幸运的是,有一个解决方法:

class TestDoubleDef{
  def foo(p:List[String])(implicit ignore: String) = {}
  def foo(p:List[Int])(implicit ignore: Int) = {}
}

object App extends Application {
  implicit val x = 0
  implicit val y = ""

  val a = new A()
  a.foo(1::2::Nil)
  a.foo("a"::"b"::Nil)
}

感谢 Michid< /a> 提示!

As Viktor Klang already says, the generic type will be erased by the compiler. Fortunately, there's a workaround:

class TestDoubleDef{
  def foo(p:List[String])(implicit ignore: String) = {}
  def foo(p:List[Int])(implicit ignore: Int) = {}
}

object App extends Application {
  implicit val x = 0
  implicit val y = ""

  val a = new A()
  a.foo(1::2::Nil)
  a.foo("a"::"b"::Nil)
}

Thanks for Michid for the tip!

总以为 2024-09-17 22:12:53

如果我结合 Daniel响应Sandor Murakozi 的回复在这里我得到:

@annotation.implicitNotFound(msg = "Type ${T} not supported only Int and String accepted")   
sealed abstract class Acceptable[T]; object Acceptable {
        implicit object IntOk extends Acceptable[Int]
        implicit object StringOk extends Acceptable[String]
}

class TestDoubleDef {
   def foo[A : Acceptable : Manifest](p:List[A]) =  {
        val m = manifest[A]
        if (m equals manifest[String]) {
            println("String")
        } else if (m equals manifest[Int]) {
            println("Int")
        } 
   }
}

我得到一个类型安全(ish)变体

scala> val a = new TestDoubleDef
a: TestDoubleDef = TestDoubleDef@f3cc05f

scala> a.foo(List(1,2,3))
Int

scala> a.foo(List("test","testa"))
String

scala> a.foo(List(1L,2L,3L))
<console>:21: error: Type Long not supported only Int and String accepted
   a.foo(List(1L,2L,3L))
        ^             

scala> a.foo("test")
<console>:9: error: type mismatch;
 found   : java.lang.String("test")
 required: List[?]
       a.foo("test")
             ^

逻辑也可能包含在类型类中(感谢jsuereth):
@annotation.implicitNotFound(msg = "Foo 不支持 ${T} 只接受 Int 和 String")
Sealed Trait Foo[T] { def apply(list : List[T]) : Unit }

object Foo {
   implicit def stringImpl = new Foo[String] {
      def apply(list : List[String]) = println("String")
   }
   implicit def intImpl = new Foo[Int] {
      def apply(list : List[Int]) =  println("Int")
   }
} 

def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)

其中给出:

scala> @annotation.implicitNotFound(msg = "Foo does not support ${T} only Int and String accepted") 
     | sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo {
     |         implicit def stringImpl = new Foo[String] {
     |           def apply(list : List[String]) = println("String")
     |         }
     |         implicit def intImpl = new Foo[Int] {
     |           def apply(list : List[Int]) =  println("Int")
     |         }
     |       } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
defined trait Foo
defined module Foo
foo: [A](x: List[A])(implicit evidence$1: Foo[A])Unit

scala> foo(1)
<console>:8: error: type mismatch;
 found   : Int(1)
 required: List[?]
       foo(1)
           ^    
scala> foo(List(1,2,3))
Int
scala> foo(List("a","b","c"))
String
scala> foo(List(1.0))
<console>:32: error: Foo does not support Double only Int and String accepted
foo(List(1.0))
        ^

请注意,我们必须隐式地编写[Foo[A]].apply(x) ,因为编译器认为implicitly[Foo[A]](x)意味着我们使用参数implicitly调用。

If I combine Daniels response and Sandor Murakozis response here I get:

@annotation.implicitNotFound(msg = "Type ${T} not supported only Int and String accepted")   
sealed abstract class Acceptable[T]; object Acceptable {
        implicit object IntOk extends Acceptable[Int]
        implicit object StringOk extends Acceptable[String]
}

class TestDoubleDef {
   def foo[A : Acceptable : Manifest](p:List[A]) =  {
        val m = manifest[A]
        if (m equals manifest[String]) {
            println("String")
        } else if (m equals manifest[Int]) {
            println("Int")
        } 
   }
}

I get a typesafe(ish) variant

scala> val a = new TestDoubleDef
a: TestDoubleDef = TestDoubleDef@f3cc05f

scala> a.foo(List(1,2,3))
Int

scala> a.foo(List("test","testa"))
String

scala> a.foo(List(1L,2L,3L))
<console>:21: error: Type Long not supported only Int and String accepted
   a.foo(List(1L,2L,3L))
        ^             

scala> a.foo("test")
<console>:9: error: type mismatch;
 found   : java.lang.String("test")
 required: List[?]
       a.foo("test")
             ^

The logic may also be included in the type class as such (thanks to jsuereth):
@annotation.implicitNotFound(msg = "Foo does not support ${T} only Int and String accepted")
sealed trait Foo[T] { def apply(list : List[T]) : Unit }

object Foo {
   implicit def stringImpl = new Foo[String] {
      def apply(list : List[String]) = println("String")
   }
   implicit def intImpl = new Foo[Int] {
      def apply(list : List[Int]) =  println("Int")
   }
} 

def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)

Which gives:

scala> @annotation.implicitNotFound(msg = "Foo does not support ${T} only Int and String accepted") 
     | sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo {
     |         implicit def stringImpl = new Foo[String] {
     |           def apply(list : List[String]) = println("String")
     |         }
     |         implicit def intImpl = new Foo[Int] {
     |           def apply(list : List[Int]) =  println("Int")
     |         }
     |       } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
defined trait Foo
defined module Foo
foo: [A](x: List[A])(implicit evidence$1: Foo[A])Unit

scala> foo(1)
<console>:8: error: type mismatch;
 found   : Int(1)
 required: List[?]
       foo(1)
           ^    
scala> foo(List(1,2,3))
Int
scala> foo(List("a","b","c"))
String
scala> foo(List(1.0))
<console>:32: error: Foo does not support Double only Int and String accepted
foo(List(1.0))
        ^

Note that we have to write implicitly[Foo[A]].apply(x) since the compiler thinks that implicitly[Foo[A]](x) means that we call implicitly with parameters.

江湖正好 2024-09-17 22:12:53

还有(至少有一种)另一种方法,即使它不太好并且不是真正的类型安全:

import scala.reflect.Manifest

object Reified {

  def foo[T](p:List[T])(implicit m: Manifest[T]) = {

    def stringList(l: List[String]) {
      println("Strings")
    }
    def intList(l: List[Int]) {
      println("Ints")
    }

    val StringClass = classOf[String]
    val IntClass = classOf[Int]

    m.erasure match {
      case StringClass => stringList(p.asInstanceOf[List[String]])
      case IntClass => intList(p.asInstanceOf[List[Int]])
      case _ => error("???")
    }
  }


  def main(args: Array[String]) {
      foo(List("String"))
      foo(List(1, 2, 3))
    }
}

隐式清单参数可用于“具体化”擦除的类型,从而绕过擦除。您可以在许多博客文章中了解更多信息,例如 这个

发生的情况是,清单参数可以返回 T 被删除之前的值。然后,基于 T 的简单调度到各种实际实现即可完成剩下的工作。

可能有更好的方法来进行模式匹配,但我还没有看到。人们通常做的是在 m.toString 上进行匹配,但我认为保留类会更干净一些(即使它更冗长一些)。不幸的是Manifest的文档不是太详细,也许它还有一些可以简化它的东西。

它的一个很大的缺点是它并不是真正的类型安全:foo 会对任何 T 感到满意,如果你不能处理它,你就会遇到问题。我想可以通过对 T 进行一些限制来解决这个问题,但这会使事情变得更加复杂。

当然,这一切也不太好,我不确定是否值得这样做,特别是如果你很懒的话;-)

There is (at least one) another way, even if it is not too nice and not really type safe:

import scala.reflect.Manifest

object Reified {

  def foo[T](p:List[T])(implicit m: Manifest[T]) = {

    def stringList(l: List[String]) {
      println("Strings")
    }
    def intList(l: List[Int]) {
      println("Ints")
    }

    val StringClass = classOf[String]
    val IntClass = classOf[Int]

    m.erasure match {
      case StringClass => stringList(p.asInstanceOf[List[String]])
      case IntClass => intList(p.asInstanceOf[List[Int]])
      case _ => error("???")
    }
  }


  def main(args: Array[String]) {
      foo(List("String"))
      foo(List(1, 2, 3))
    }
}

The implicit manifest paramenter can be used to "reify" the erased type and thus hack around erasure. You can learn a bit more about it in many blog posts,e.g. this one.

What happens is that the manifest param can give you back what T was before erasure. Then a simple dispatch based on T to the various real implementation does the rest.

Probably there is a nicer way to do the pattern matching, but I haven't seen it yet. What people usually do is matching on m.toString, but I think keeping classes is a bit cleaner (even if it's a bit more verbose). Unfortunately the documentation of Manifest is not too detailed, maybe it also has something that could simplify it.

A big disadvantage of it is that it's not really type safe: foo will be happy with any T, if you can't handle it you will have a problem. I guess it could be worked around with some constraints on T, but it would further complicate it.

And of course this whole stuff is also not too nice, I'm not sure if it worth doing it, especially if you are lazy ;-)

烂人 2024-09-17 22:12:53

除了使用清单之外,您还可以使用以类似方式隐式导入的调度程序对象。在清单出现之前,我在博客中介绍了这一点:http://michid.wordpress。 com/code/implicit-double-dispatch-revisited/

这具有类型安全的优点:重载方法只能针对将调度程序导入到当前作用域的类型进行调用。

Instead of using manifests you could also use dispatchers objects implicitly imported in a similar manner. I blogged about this before manifests came up: http://michid.wordpress.com/code/implicit-double-dispatch-revisited/

This has the advantage of type safety: the overloaded method will only be callable for types which have dispatchers imported into the current scope.

夏天碎花小短裙 2024-09-17 22:12:53

我从 http://scala-programming-language.1934581.n4.nabble.com/disambiguation-of-double-definition-resulting-from-generic-type-erasure-td2327664.html
作者:亚伦·诺夫斯特鲁普

再打败这匹死马......

我想到一个更干净的黑客方法是使用独特的虚拟类型
对于其签名中已删除类型的每个方法:

object Baz {
    private object dummy1 { implicit val dummy: dummy1.type = this }
    private object dummy2 { implicit val dummy: dummy2.type = this } 

    def foo(xs: String*)(implicit e: dummy1.type) = 1
    def foo(xs: Int*)(implicit e: dummy2.type) = 2
} 

[...]

Nice trick I've found from http://scala-programming-language.1934581.n4.nabble.com/disambiguation-of-double-definition-resulting-from-generic-type-erasure-td2327664.html
by Aaron Novstrup

Beating this dead horse some more...

It occurred to me that a cleaner hack is to use a unique dummy type
for each method with erased types in its signature:

object Baz {
    private object dummy1 { implicit val dummy: dummy1.type = this }
    private object dummy2 { implicit val dummy: dummy2.type = this } 

    def foo(xs: String*)(implicit e: dummy1.type) = 1
    def foo(xs: Int*)(implicit e: dummy2.type) = 2
} 

[...]

ゃ人海孤独症 2024-09-17 22:12:53

我尝试改进 Aaron Novstrup 和 Leo 的答案,使一组标准证据对象变得重要且更加简洁。

final object ErasureEvidence {
    class E1 private[ErasureEvidence]()
    class E2 private[ErasureEvidence]()
    implicit final val e1 = new E1
    implicit final val e2 = new E2
}
import ErasureEvidence._

class Baz {
    def foo(xs: String*)(implicit e:E1) = 1
    def foo(xs: Int*)(implicit e:E2) = 2
}

但这会导致编译器抱怨,当 foo 调用另一个需要相同类型隐式参数的方法时,隐式值的选择不明确。

因此,我只提供以下内容,在某些情况下更简洁。此改进适用于值类(扩展 AnyVal 的值类)。

final object ErasureEvidence {
   class E1[T] private[ErasureEvidence]()
   class E2[T] private[ErasureEvidence]()
   implicit def e1[T] = new E1[T]
   implicit def e2[T] = new E2[T]
}
import ErasureEvidence._

class Baz {
    def foo(xs: String*)(implicit e:E1[Baz]) = 1
    def foo(xs: Int*)(implicit e:E2[Baz]) = 2
}

如果包含的类型名称相当长,请声明一个内部trait以使其更加简洁。

class Supercalifragilisticexpialidocious[A,B,C,D,E,F,G,H,I,J,K,L,M] {
    private trait E
    def foo(xs: String*)(implicit e:E1[E]) = 1
    def foo(xs: Int*)(implicit e:E2[E]) = 2
}

然而,值类不允许内部特征、类或对象。因此还要注意 Aaron Novstrup 和 Leo 的答案不适用于值类。

I tried improving on Aaron Novstrup’s and Leo’s answers to make one set of standard evidence objects importable and more terse.

final object ErasureEvidence {
    class E1 private[ErasureEvidence]()
    class E2 private[ErasureEvidence]()
    implicit final val e1 = new E1
    implicit final val e2 = new E2
}
import ErasureEvidence._

class Baz {
    def foo(xs: String*)(implicit e:E1) = 1
    def foo(xs: Int*)(implicit e:E2) = 2
}

But that will cause the compiler to complain that there are ambiguous choices for the implicit value when foo calls another method which requires an implicit parameter of the same type.

Thus I offer only the following which is more terse in some cases. And this improvement works with value classes (those that extend AnyVal).

final object ErasureEvidence {
   class E1[T] private[ErasureEvidence]()
   class E2[T] private[ErasureEvidence]()
   implicit def e1[T] = new E1[T]
   implicit def e2[T] = new E2[T]
}
import ErasureEvidence._

class Baz {
    def foo(xs: String*)(implicit e:E1[Baz]) = 1
    def foo(xs: Int*)(implicit e:E2[Baz]) = 2
}

If the containing type name is rather long, declare an inner trait to make it more terse.

class Supercalifragilisticexpialidocious[A,B,C,D,E,F,G,H,I,J,K,L,M] {
    private trait E
    def foo(xs: String*)(implicit e:E1[E]) = 1
    def foo(xs: Int*)(implicit e:E2[E]) = 2
}

However, value classes do not allow inner traits, classes, nor objects. Thus also note Aaron Novstrup’s and Leo’s answers do not work with a value classes.

恏ㄋ傷疤忘ㄋ疼 2024-09-17 22:12:53

我没有对此进行测试,但为什么上限不起作用?

def foo[T <: String](s: List[T]) { println("Strings: " + s) }
def foo[T <: Int](i: List[T]) { println("Ints: " + i) }

擦除翻译是否从 foo( List[Any] s ) 两次更改为 foo( List[String] s ) 和 foo( List[Int] i ):

http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ108

我想我在版本 2.8 中读到过,上限现在以这种方式编码,而不是总是 Any。

要重载协变类型,请使用不变边界(Scala 中有这样的语法吗?...我认为没有,但将以下内容作为上述主要解决方案的概念附录):

def foo[T : String](s: List[T]) { println("Strings: " + s) }
def foo[T : String2](s: List[T]) { println("String2s: " + s) }

然后我假设隐式转换在代码的擦除版本中被消除。


更新:问题是 JVM 删除的方法签名上的类型信息多于“必要”的信息。我提供了一个链接。它从类型构造函数中删除类型变量,甚至删除这些类型变量的具体绑定。存在概念上的区别,因为擦除函数的类型绑定没有概念上的非具体化优势,因为它在编译时已知并且不随泛型的任何实例而变化,并且调用者必须不调用类型不符合类型绑定的函数,那么如果擦除的话,JVM 如何强制执行类型绑定呢?那么一个链接表示类型绑定保留在元数据中编译器应该访问。这解释了为什么使用类型边界不能启用重载。这也意味着 JVM 是一个开放的安全漏洞,因为类型限制方法可以在没有类型限制的情况下调用(哎呀!),所以请原谅我假设 JVM 设计者不会做这样不安全的事情。

当我写这篇文章时,我不明白 stackoverflow 是一个通过答案质量对人们进行评级的系统,就像对声誉的竞争一样。我以为这是一个分享信息的地方。在我写这篇文章时,我正在从概念层面比较具体化和非具体化(比较许多不同的语言),所以在我看来,删除类型绑定没有任何意义。

I didn't test this, but why wouldn't an upper bound work?

def foo[T <: String](s: List[T]) { println("Strings: " + s) }
def foo[T <: Int](i: List[T]) { println("Ints: " + i) }

Does the erasure translation to change from foo( List[Any] s ) twice, to foo( List[String] s ) and foo( List[Int] i ):

http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ108

I think I read that in version 2.8, the upper bounds are now encoded that way, instead of always an Any.

To overload on covariant types, use an invariant bound (is there such a syntax in Scala?...ah I think there isn't, but take the following as conceptual addendum to the main solution above):

def foo[T : String](s: List[T]) { println("Strings: " + s) }
def foo[T : String2](s: List[T]) { println("String2s: " + s) }

then I presume the implicit casting is eliminated in the erased version of the code.


UPDATE: The problem is that JVM erases more type information on method signatures than is "necessary". I provided a link. It erases type variables from type constructors, even the concrete bound of those type variables. There is a conceptual distinction, because there is no conceptual non-reified advantage to erasing the function's type bound, as it is known at compile-time and does not vary with any instance of the generic, and it is necessary for callers to not call the function with types that do not conform to the type bound, so how can the JVM enforce the type bound if it is erased? Well one link says the type bound is retained in metadata which compilers are supposed to access. And this explains why using type bounds doesn't enable overloading. It also means that JVM is a wide open security hole since type bounded methods can be called without type bounds (yikes!), so excuse me for assuming the JVM designers wouldn't do such an insecure thing.

At the time I wrote this, I didn't understand that stackoverflow was a system of rating people by quality of answers like some competition over reputation. I thought it was a place to share information. At the time I wrote this, I was comparing reified and non-reified from a conceptual level (comparing many different languages), and so in my mind it didn't make any sense to erase the type bound.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文