/**
 * 生成一个没有重复元素的整型数组
 */
private static int[] createArray(final int length) {
int[] a = new int[length];
Set<Integer> set = new HashSet<Integer>();
Random rand = new Random();
for(int i=0, x=-1; i<a.length;) {
x = rand.nextInt(length*5); //这里编译器会不会优化?
if(set.add(x) == true) {
a[i++] = x;
}
}
return a;
}
在上述代码中,"length*5"这一乘法操作被写到了循环中,如果每次都做乘法,效率显然比较低下
我在声明函数的时候,特地把length声明为final的,请问编译器会优化吗?

解决方案 »

  1.   

        private static int[] createArray(final int length) {
            int[] a = new int[length];
            int len = 5 * length;
            Set<Integer> set = new HashSet<Integer>();
            Random rand = new Random();
            for(int i=0, x=-1; i<a.length;) {
                x = rand.nextInt( len ); //这里编译器会不会优化?
                if(set.add(x) == true) {
                    a[i++] = x;
                }
            }
            return a;
        }这么写不就得了?另外这里编辑器没法优化。
      

  2.   

    错误的思想啊,不过我重现审视了一下,我才发现你写了个final,以JVM的能力,也许会优化。
    很难讲。(有也是运行时的优化,不可能是编译时的优化。)但是多写一行,不是问题。
      

  3.   

    为啥不能是编译时优化啊?
    编译器连循环都能给你展开了,替换个常量毫无难度啊传说中的循环展开:
    for(int i=0; i<3; i++)
      a[i] = i;//据说为了提高效率,编译器会把它变成
    a[0]=0;
    a[1]=1;
    a[2]=2;
    //这样就不用分支预测了
      

  4.   

    编译过程中,编译器不知道形参length的值啊,怎么可能知道呢。一定是运行中知道的。
    第一次运行,可能出现替换。
      

  5.   


    而且也不行啊,这个函数不知道被哪些地方调用了,length并非总是一个固定值啊。可能是3, 可能是4。所以里面的代码也没有办法真正替换的。
      

  6.   

    编译器应该没有执行优化操作
    下面是方法的字节码
    public static int[] createArray(int);
      Code:
       0:   iload_0 
       1:   newarray int
       3:   astore_1 
       4:   new     #16; //class java/util/HashSet
       7:   dup //
       8:   invokespecial   #18; //Method java/util/HashSet."<init>":()V
       11:  astore_2
       12:  new     #19; //class java/util/Random
       15:  dup
       16:  invokespecial   #21; //Method java/util/Random."<init>":()V
       19:  astore_3
       20:  iconst_0 
       21:  istore  4
       23:  iconst_m1
       24:  istore  5 
       26:  goto    61
       29:  aload_3
       30:  iload_0
       31:  iconst_5
       32:  imul 
       33:  invokevirtual   #22; //Method java/util/Random.nextInt:(I)I
       36:  istore  5
       38:  aload_2
       39:  iload   5
       41:  invokestatic    #26; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       44:  invokeinterface #32,  2; //InterfaceMethod java/util/Set.add:(Ljava/lang/Object;)Z
       49:  ifeq    61
       52:  aload_1
       53:  iload   4
       55:  iinc    4, 1
       58:  iload   5
       60:  iastore
       61:  iload   4 
       63:  aload_1
       64:  arraylength
       65:  if_icmplt       29
       68:  aload_1
       69:  areturn
      

  7.   

    编译器不会对方法中定义的final型做任何优化.
    下面是两个方法:          public void m1(final int i){
    System.out.println(i*7);
    }

    public void m2(int i){
    System.out.println(i*7);
    }
    编译后的字节码如下:public void m1(int);
      Code:
       0:   getstatic       #39; //Field java/lang/System.out:Ljava/io/PrintStream;
       3:   iload_1
       4:   bipush  7
       6:   imul
       7:   invokevirtual   #58; //Method java/io/PrintStream.println:(I)V
       10:  returnpublic void m2(int);
      Code:
       0:   getstatic       #39; //Field java/lang/System.out:Ljava/io/PrintStream;
       3:   iload_1
       4:   bipush  7
       6:   imul
       7:   invokevirtual   #58; //Method java/io/PrintStream.println:(I)V
       10:  return
    很容易看出来两者是一样的,并没有把final考虑进去
      

  8.   

    编译器不给力啊
    听说数据库里加了 not null 限制的字段,排序速度会有提升
    java为啥不考虑优化呢?
      

  9.   

    更正一下上面的回复, 编译器只会对编译期已知的"字面常量"以及"字面常量"的基本运算(加减乘除)作优化处理,举个例子:
    public void m1(){
    final int total = 7; System.out.println(total * 5);
    }
    编译后的字节码如下:public void m1();
      Code:
       0:   bipush  7
       2:   istore_1
       3:   getstatic       #39; //Field java/lang/System.out:Ljava/io/PrintStream;
       6:   bipush  35
       8:   invokevirtual   #57; //Method java/io/PrintStream.println:(I)V
       11:  return你的length在编译期的值不可确定,所以编译器无法做出优化处理了
      

  10.   

    jvm运行时执行的方法栈就写在字节码中,如果楼上认为从字节码中看不出来,那想听听楼上的高见, 如何去观察jvm运行时是如何优化的呢?
      

  11.   


    你听说过Java算斐波那契数列比C++快的传说没? JVM会缓存一些中间结果,使得有些重复过的递归调用变成了查表。而C++=>ASM就做不到。但是Java依赖聪明的JVM就行了。
    但是你编译出来的JVM的byte code,估计你看不到编译出来的 查表/存表 这类的代码。为什么?优化不仅仅体现在字节码上。Java的Hotspot中的Profile Monitor就是干这个的。如果length * 5被多次调用了,也许它就会出来优化一下。
    【以上都是我合理猜测了,我是没用证据的】
      

  12.   


    就算你的猜测都是合理的,但是除了jvm的设计实现者之外没有人清楚底层是如何运行的,是不是?
    我们可以控制的也就是java源码和jvm字节码而已,所以我们提到的“编译器优化”也就只能到这一层面而已。你能通过你的源码去控制jvm运行时的优化么?
      

  13.   

    原来你不是想听高见啊。那我废什么话啊。很难讲“能”“不能”。看开发者的经验。更好的了解Java HotSpot虚拟机,就能有助于写出利于被优化的代码。
    最后,你的第一句说:“就算”从心理学上说,你开始接受我一部分观点了,但是还在嘴硬
      

  14.   

    我说我想听听"高见",是说我不懂jvm内部是如何运行,如何优化的, 如果你深谙此道,非常欢迎你来讲解一下.
    但是如何仅仅是基于有限的jvm虚拟机知识的"猜测", 实在是不足以信服.没有实践,就没有发言权,你说能写出利于jvm优化的代码,就请给出个简单的例子说明,否则就是在空谈!最后,我说"就算",是因为你说的关于jvm的理论我不能确定对错,我不能妄下判断而已. 这和嘴硬不硬没有关系.