Scala:使用类型参数信息访问静态Java方法
我使用一个Java代码生成器(不幸的是,我无法摆脱它),它输出如下代码:Scala:使用类型参数信息访问静态Java方法,java,scala,generics,type-inference,type-parameter,Java,Scala,Generics,Type Inference,Type Parameter,我使用一个Java代码生成器(不幸的是,我无法摆脱它),它输出如下代码: abstract class Abs1 { //... } abstract class Abs2 { //... } interface I { //... } public static final class C1 extends Abs implements I { public final static Inner newInstance() { return Inner.create(); } p
abstract class Abs1 { //... }
abstract class Abs2 { //... }
interface I { //... }
public static final class C1 extends Abs implements I {
public final static Inner newInstance() { return Inner.create(); }
public final class Inner extends Abs2 {
private static Inner create() { return new Inner(); }
}
public final static C1 build() {
// builds the object instantiating some fields with defaults
}
}
final static class C2 extends Abs implements I {
// exactly same as in C1:
public final static Inner newInstance() { return Inner.create(); }
public final class Inner extends Abs2 {
private static Inner create() { return new Inner(); }
}
public final static C1 build() {
// builds the object instantiating some fields with defaults
}
}
我有许多其他的类,像C1和C2在相同的风格。
正如您所看到的,每个外部类(C1、C2…)都有一个内部类,始终命名为内部类。此外,所有内部类都扩展了同一个抽象类
我想从字符串创建每个外部类的实例。我有一个实用工具(合并),可以将实例与其字符串合并
def createC1(str: String) = {
val ins = C1.newInstance
Merger(ins, str)
ins.build
}
def createC2(str: String) = {
val ins = C2.newInstance
Merger(ins, str)
ins.build
}
。。。这似乎是明显的代码重复。所以我想利用类型参数化
def build[A <: Abs](str: String) = {
val ins = A.newInstance // this obviously won't compile - but this is my intent
Merger(ins, str)
ins.build
}
为什么它不推断ins1
中的类型
编辑:使外部类保持静态。问题
您试图创建的代码的主要问题是,您试图访问泛型类型的静态
方法。Java和Scala中的泛型类型都不允许访问与该类型关联的静态方法。我已经阅读了一些相当复杂的反射,您可以使用这些反射来访问泛型类型的companion
对象,但是我强烈建议您在这种情况下避免类似的操作,因为这样的代码非常脆弱且不可维护。毕竟,任何抽象的目标都是使代码更易于使用,而不是更难
两个解决方案
在这种情况下,您可以轻松地做一些事情来进行抽象,使使用此代码更容易处理我假设您根本无法修改生成的代码,因为如果可以,我将跳过一些更好的方法来处理此问题。
解决方案1结构类型
此问题的第一个也是最简单的解决方案是使用结构类型。考虑下面的代码(它是Scala代码,但它应该java中的概念相同)。< /P>
现在,我想用下面的函数调用newInstance
,它不会编译
这只比你理想的解决方案稍微多一点。但是,请注意,编译器发出警告的原因是结构类型需要反射,因此会导致运行时性能下降。但是,如果代码不在程序的关键部分,您可能不会担心它
解决方案2,只需传递函数
我们可以直接传递函数来完成工作,而不是使用结构类型。这比structural类型版本稍微详细一些,但也稍微快一些,更安全一些
scala> def makeInstance[A <: InnerFoo, B <: Foo](newInstanceProc: => A, buildProc: => B): B = {
| newInstanceProc
| // do some stuff
| buildProc
| }
makeInstance: [A <: InnerFoo, B <: Foo](newInstanceProc: => A, buildProc: => B)B
scala> makeInstance(Bar.newInstance, Bar.build)
res19: Bar = Bar$$anon$1@4d0402b
scala>def makeInstance[ab:B={
|newInstanceProc
|//做点什么
|buildProc
| }
makeInstance:[A B)B
scala>makeInstance(Bar.newInstance,Bar.build)
res19:Bar=Bar$$anon$1@4d0402b
公共最终类内部扩展Abs2
是否应该有static
修饰符?我认为没有它是不合法的。@Isomarte:我将外部类设置为static。它现在应该是有效的。最后一段代码为您编译了吗?我不确定它是否不能满足您的要求,或者根本无法编译。我无法在我的REPL上编译等效代码。@isomarte您能告诉我确切的代码块吗?最后一块,您使用ClassTag
。
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait Foo
trait InnerFoo
trait Bar extends Foo
trait Baz extends Foo
object Bar {
class InnerBar extends InnerFoo
def newInstance: InnerBar = new InnerBar
def build: Bar = new Bar {}
}
object Baz {
class InnerBaz extends InnerFoo
def newInstance: InnerBaz = new InnerBaz
def build: Baz = new Baz {}
}
// Exiting paste mode, now interpreting.
defined trait Foo
defined trait InnerFoo
defined trait Bar
defined trait Baz
defined object Bar
defined object Baz
def makeInstance[A <: Foo, B <: InnerFoo]: B = {
A.newInstance
// do some stuff
A.build
}
scala> def makeInstance[A <: InnerFoo, B <: Foo](static: { def newInstance: A; def build: B }) = {
| static.newInstance
| // do some stuff
| static.build
| }
warning: there were two feature warnings; re-run with -feature for details
makeInstance: [A <: InnerFoo, B <: Foo](static: AnyRef{def newInstance: A; def build: B})B
scala> makeInstance(Bar)
res16: Bar = Bar$$anon$1@1601e47
scala> makeInstance(Baz)
res17: Baz = Baz$$anon$2@6de54b40
scala> def makeInstance[A <: InnerFoo, B <: Foo](newInstanceProc: => A, buildProc: => B): B = {
| newInstanceProc
| // do some stuff
| buildProc
| }
makeInstance: [A <: InnerFoo, B <: Foo](newInstanceProc: => A, buildProc: => B)B
scala> makeInstance(Bar.newInstance, Bar.build)
res19: Bar = Bar$$anon$1@4d0402b