【问题标题】:Why does java reflection shows object method as instance's one, not static?为什么java反射将对象方法显示为实例的方法,而不是静态的?
【发布时间】:2014-08-11 12:37:27
【问题描述】:

默认的 java 控制台应用程序使用 main 方法运行传递的类,该方法应使用 static 修饰符声明。

所以,我尝试创建这样的类作为对象,而不是直接使用静态修饰符。但令人惊讶的是,我得到了没有静态修饰符的 main 方法。

$ scala
Welcome to Scala version 2.10.3-20130923-000000-e2fec6b28d (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_60).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import java.lang.reflect.Modifier
import java.lang.reflect.Modifier

scala> object Main {
     | def main(args : Array[String]) = println("hello")
     | }
defined module Main

scala> val method = Main.getClass.getMethod("main", classOf[Array[String]])
method: java.lang.reflect.Method = public void Main$.main(java.lang.String[])

scala> Modifier.isStatic( method.getModifiers )
res0: Boolean = false

所以Main 对象包含实际上不是静态的main 方法。

我想使用 java 命令来运行 scala 类,而不是使用特定的 scala 命令。

如何从 scala 对象中获取静态 main 方法?


更新:

建议搜索具有相同名称但没有“$”符号作为后缀的类。所以,我继续 REPL 会话试图找到这个类

scala> val loader = Main.getClass.getClassLoader
loader: ClassLoader = scala.tools.nsc.interpreter.IMain$TranslatingClassLoader@fdf3a48

scala> val mc = Class.forName("Main", true, loader)
java.lang.ClassNotFoundException: Main
    at scala.tools.nsc.interpreter.AbstractFileClassLoader.findClass(AbstractFileClassLoader.scala:69)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:270)
    at .<init>(<console>:11)
    at .<clinit>(<console>)
    at .<init>(<console>:7)
    at .<clinit>(<console>)
    at $print(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:734)
    at scala.tools.nsc.interpreter.IMain$Request.loadAndRun(IMain.scala:983)
    at scala.tools.nsc.interpreter.IMain.loadAndRunReq$1(IMain.scala:573)
    at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:604)
    at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:568)
    at scala.tools.nsc.interpreter.ILoop.reallyInterpret$1(ILoop.scala:756)
    at scala.tools.nsc.interpreter.ILoop.interpretStartingWith(ILoop.scala:801)
    at scala.tools.nsc.interpreter.ILoop.reallyInterpret$1(ILoop.scala:774)
    at scala.tools.nsc.interpreter.ILoop.interpretStartingWith(ILoop.scala:801)
    at scala.tools.nsc.interpreter.ILoop.command(ILoop.scala:713)
    at scala.tools.nsc.interpreter.ILoop.processLine$1(ILoop.scala:577)
    at scala.tools.nsc.interpreter.ILoop.innerLoop$1(ILoop.scala:584)
    at scala.tools.nsc.interpreter.ILoop.loop(ILoop.scala:587)
    at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply$mcZ$sp(ILoop.scala:878)
    at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply(ILoop.scala:833)
    at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply(ILoop.scala:833)
    at scala.tools.nsc.util.ScalaClassLoader$.savingContextLoader(ScalaClassLoader.scala:135)
    at scala.tools.nsc.interpreter.ILoop.process(ILoop.scala:833)
    at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:83)
    at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96)
    at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:105)
    at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

我可能认为我需要从 scala 编译器实用程序中调用特殊函数来获取已定义类的包装器


已解决:

我做了更多的实验,并确认 scalac 的行为与 scala REPL 不同。第一个为每个对象生成附加类,并且该类具有对象的静态方法。如果您创建一个类和他的伴生对象,那么伴生对象的方法将被添加到关联的类中,而无需创建额外的代理。这适用于任何方法,即使是那些签名与主方法签名不同的方法

【问题讨论】:

  • 谷歌搜索“scala 静态方法”消除了所有歧义:Scala 没有静态方法。 Java 静态方法的等价物是对象中的函数。
  • @vptheron ... 并且 op 期望对象方法是静态的,但反射却相反。
  • 最后一个错误仅与 REPL 的使用有关:其中定义的类正在被包装

标签: java scala main


【解决方案1】:

Scala 编译器确实创建了一个静态 main 方法:

$ cat Main.scala 
object Main {
  def main(args: Array[String]) = println("hello")
}
$ scalac Main.scala
$ ls *class
Main.class  Main$.class
$ javap -cp . Main
Compiled from "Main.scala"
public final class Main {
  public static void main(java.lang.String[]);
}
$ javap -cp . Main$
Compiled from "Main.scala"
public final class Main$ {
  public static final Main$ MODULE$;
  public static {};
  public void main(java.lang.String[]);
}
$ java -cp /usr/local/scala/lib/scala-library.jar:. Main
hello

【讨论】:

    【解决方案2】:

    如果你反编译这个:

    package test
    import java.lang.reflect.Modifier
    object Main {
      def main(args: Array[String]): Unit = {
        val method = Main.getClass.getMethod("main", classOf[Array[String]])
        println(Modifier.isStatic(method.getModifiers)) // false
    
        println(Main.getClass.getName()); // test.Main$
    
        val act = Class.forName("test.Main");
        val method2 = act.getMethod("main", classOf[Array[String]])
        println(Modifier.isStatic(method2.getModifiers)) // true !!!
      }
    }
    

    你会看到两个类:

    1)

    public final class Main$
    {
      ...
      public void main(String[] args)
      {
        ...
      }
      ...
    }
    

    2)

    public final class Main
    {
      public static void main(String[] paramArrayOfString)
      {
        ...
      }
    }
    

    【讨论】:

      【解决方案3】:

      我会在真正出现后立即删除这个答案,但这并不是 scala 没有静态方法,问题是 [错误?] 使用 java 反射进行此类检查:

      /tmp » echo 'object Main {  def main(args : Array[String]) = println("hello") }' > Main.scala
      /tmp » scalac Main.scala
      /tmp » javap Main      
      Compiled from "Main.scala"
      public final class Main {
        public static void main(java.lang.String[]);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-02-15
        • 1970-01-01
        • 1970-01-01
        • 2020-05-04
        • 1970-01-01
        • 2010-09-27
        • 1970-01-01
        相关资源
        最近更新 更多