Java是否优化了一个';它只是作为一个返回值吗?

Java是否优化了一个';它只是作为一个返回值吗?,java,optimization,jvm,Java,Optimization,Jvm,我为什么这么问: public class TestFoo { Foo foo = new Foo(); Method methodA = foo.getClass().getMethod("barA"); Method methodB = foo.getClass().getMethod("barB"); public TestFoo() throws NoSuchMethodException { } @Test public

我为什么这么问:

public class TestFoo {
    Foo foo = new Foo();
    Method methodA = foo.getClass().getMethod("barA");
    Method methodB = foo.getClass().getMethod("barB");


    public TestFoo() throws NoSuchMethodException {
    }


    @Test
    public void methodA() throws Exception {
        assertTrue(Integer.TYPE.equals(methodA.getReturnType()));
    }

    @Test
    public void methodB() throws Exception {
        assertTrue(Integer.TYPE.equals(methodB.getReturnType()));
    }
    @Test
    public void equalsSame() throws Exception{
        assertEquals(foo.barA(), foo.barB());
    }
}
我想知道的是,编译器端正在进行的任何优化都会使一个或另一个方法返回更好的结果。因为我已经读到python没有优化方法以使其运行得更快

示例:

public class TestFoo {
    Foo foo = new Foo();
    Method methodA = foo.getClass().getMethod("barA");
    Method methodB = foo.getClass().getMethod("barB");


    public TestFoo() throws NoSuchMethodException {
    }


    @Test
    public void methodA() throws Exception {
        assertTrue(Integer.TYPE.equals(methodA.getReturnType()));
    }

    @Test
    public void methodB() throws Exception {
        assertTrue(Integer.TYPE.equals(methodB.getReturnType()));
    }
    @Test
    public void equalsSame() throws Exception{
        assertEquals(foo.barA(), foo.barB());
    }
}
我已经声明了两个传递相同值的方法。但是
barA
通过内部字段声明返回它

public class Foo {
    public int barA(){
        int a = 1;
        return a;
    }

    public int barB(){
        return 1;
    }
}
测试:

public class TestFoo {
    Foo foo = new Foo();
    Method methodA = foo.getClass().getMethod("barA");
    Method methodB = foo.getClass().getMethod("barB");


    public TestFoo() throws NoSuchMethodException {
    }


    @Test
    public void methodA() throws Exception {
        assertTrue(Integer.TYPE.equals(methodA.getReturnType()));
    }

    @Test
    public void methodB() throws Exception {
        assertTrue(Integer.TYPE.equals(methodB.getReturnType()));
    }
    @Test
    public void equalsSame() throws Exception{
        assertEquals(foo.barA(), foo.barB());
    }
}
结果:

public class TestFoo {
    Foo foo = new Foo();
    Method methodA = foo.getClass().getMethod("barA");
    Method methodB = foo.getClass().getMethod("barB");


    public TestFoo() throws NoSuchMethodException {
    }


    @Test
    public void methodA() throws Exception {
        assertTrue(Integer.TYPE.equals(methodA.getReturnType()));
    }

    @Test
    public void methodB() throws Exception {
        assertTrue(Integer.TYPE.equals(methodB.getReturnType()));
    }
    @Test
    public void equalsSame() throws Exception{
        assertEquals(foo.barA(), foo.barB());
    }
}
测试表明,我实际上在两种方法中处理相同的值和返回类型

免责声明: 这张图片并不是要突出显示秒表,junit为每个方法运行,因为它与我所问的编译器优化没有任何联系

问题:

public class TestFoo {
    Foo foo = new Foo();
    Method methodA = foo.getClass().getMethod("barA");
    Method methodB = foo.getClass().getMethod("barB");


    public TestFoo() throws NoSuchMethodException {
    }


    @Test
    public void methodA() throws Exception {
        assertTrue(Integer.TYPE.equals(methodA.getReturnType()));
    }

    @Test
    public void methodB() throws Exception {
        assertTrue(Integer.TYPE.equals(methodB.getReturnType()));
    }
    @Test
    public void equalsSame() throws Exception{
        assertEquals(foo.barA(), foo.barB());
    }
}
Java是否真的试图优化掉“无用”的字段声明以更快地执行

我找不到一个问题来解决这个问题

使用:

public class TestFoo {
    Foo foo = new Foo();
    Method methodA = foo.getClass().getMethod("barA");
    Method methodB = foo.getClass().getMethod("barB");


    public TestFoo() throws NoSuchMethodException {
    }


    @Test
    public void methodA() throws Exception {
        assertTrue(Integer.TYPE.equals(methodA.getReturnType()));
    }

    @Test
    public void methodB() throws Exception {
        assertTrue(Integer.TYPE.equals(methodB.getReturnType()));
    }
    @Test
    public void equalsSame() throws Exception{
        assertEquals(foo.barA(), foo.barB());
    }
}
  • jdk 1.8.0_121
  • JUnit4.10

    • 鉴于OP的更新,这里的真正答案非常基本:java是一种静态编译语言

      方法的签名。。。这是签名上写的。签名表示返回一个int值。这就是任何签名为int的方法将返回的结果。Java体系结构中的任何内容都不允许您在运行时动态更改这些内容。从这个角度来看,您对返回类型的测试都是假的。语言设计意味着答案总是“方法返回
      int
      。请注意:如果返回类型是引用类型,比如
      Number
      ,那么当然可以让一个方法返回Long实例,另一个方法返回Integer对象(导致不同类型,但仍然是Number的子类型)

      除此之外,OP还讨论了不同的执行时间

      是的,junit运行秒表粗略地告诉您每个测试运行多长时间。但这是而不是测量。为了理解代码的真正性能影响,您必须进行真正的测量。从这个角度来看:junit的数字并不代表您认为它们的意思。它们不是得出此类结论的合适基础来自的离子


      有关如何获得更有意义的数字的更多指导,请参阅。

      如果我们举一个例子:

      class Main  {
          int foo() {
              int i = 0;
              return i;
          }
      
          int bar() {
              return 0;
          }
      
          public static void main(String[] args) {
              new Main().foo();
              new Main().bar();
          }
      }
      
      并查看字节码:

      class my.pckage.Main extends java.lang.Object{
      my.pckage.Main();
        Code:
         0:   aload_0
         1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
         4:   return
      
      int foo();
        Code:
         0:   iconst_0  //push zero onto the stack
         1:   istore_1  //pop off the stack and store in local variable
         2:   iload_1   //load an int value from local variable 1
         3:   ireturn   //return an integer from a method
      
      int bar();
        Code:
         0:   iconst_0
         1:   ireturn
      
      public static void main(java.lang.String[])   throws java.lang.Exception;
        Code:
         0:   new     #2; //class my/pckage/Main
         3:   dup
         4:   invokespecial   #3; //Method "<init>":()V
         7:   invokevirtual   #4; //Method foo:()I
         10:  pop
         11:  new     #2; //class my/pckage/Main
         14:  dup
         15:  invokespecial   #3; //Method "<init>":()V
         18:  invokevirtual   #5; //Method bar:()I
         21:  pop
         22:  return
      
      }
      
      class my.pckage.Main扩展了java.lang.Object{
      my.pckage.Main();
      代码:
      0:aload_0
      1:invokespecial#1;//方法java/lang/Object。“:()V
      4:返回
      int foo();
      代码:
      0:iconst_0//将零推到堆栈上
      1:istore_1//从堆栈中弹出并存储在局部变量中
      2:iload_1//从局部变量1加载一个int值
      3:ireturn//从方法返回一个整数
      int-bar();
      代码:
      0:iconst_0
      1:我轮到你了
      publicstaticvoidmain(java.lang.String[])抛出java.lang.Exception;
      代码:
      0:new#2;//类my/pckage/Main
      3:dup
      4:invokespecial#3;//方法“”:()V
      7:invokevirtual#4;//方法foo:()I
      10:流行音乐
      11:new#2;//类my/pckage/Main
      14:dup
      15:invokespecial#3;//方法“”:()V
      18:invokevirtual#5;//方法栏:()I
      21:流行音乐
      22:返回
      }
      
      您可以看到,在这个级别上没有对其进行优化


      至于JIT编译器是否决定在运行时对此进行优化,将取决于目标的特定平台。

      这不是一个字段,而是一个局部变量“不需要尝试和优化这些东西,因此,如果我制作了一个Java编译器,它不优化这些东西,并且符合Java要求的所有内容,那么它将是一个有效的Java编译器。但是我保证你会发现Java的通用发行版,一定要删除无用的局部变量。我真的怀疑你的测试有什么要说的。甚至您的执行时间也可能低于1ms,因为这些方法不计算任何内容。如果有差异,请检查生成的字节码。JIT编译器还可以进行一些额外的优化。但如果我是你,我不会太在意这些微观优化。@Michael一切都是从“错误”的假设开始的。。。我希望在这里添加更多相关信息。编译器不需要对流进行足够的分析,以发现它们是相同的。但在实践中,它确实会找到答案。为了完整性起见,您是否可以添加一个示例,说明这个示例中的“真实”度量是什么样的,以及如何进行?