java声明一个变量的开销大吗?

一直很纠结这个问题
Object o=null;
for(){
    o=Collection.get(i);
    ......
}
还是这样
for(){
   Object o=Collection.get(i);
    ......
}
求告知

回答: java声明一个变量的开销大吗?

  1. 哎,实践出真知!

    写代码看编译指令给你验证吧:

    第一种方式代码:

    import java.util.ArrayList;
    import java.util.List;

    public class Test {

        public static void main(String[] args) {
            List<String> list = new ArrayList<String>();

            for ( int i = 0 ; i < 100 ; i++ ) {
                list.add( "num-" + i );
            }

            String element = null;
            for ( int i = 0 , k = list.size() ; i < k ; i++ ) {
                element = list.get( i );
                System.out.println( System.identityHashCode( element ) );
            }
        }
    }


    第二种方式代码:

    import java.util.ArrayList;
    import java.util.List;

    public class Test {

        public static void main(String[] args) {
            List<String> list = new ArrayList<String>();

            for ( int i = 0 ; i < 100 ; i++ ) {
                list.add( "num-" + i );
            }

            for ( int i = 0 , k = list.size() ; i < k ; i++ ) {
                String element = list.get( i );
                System.out.println( System.identityHashCode( element ) );
            }
        }
    }


    使用 javap -c Test 查看 JVM 指令(第一种方式):
    H:\tmp>javap -c Test
    Compiled from "Test.java"
    public class Test extends java.lang.Object{
    public Test();
      Code:
       0:   aload_0
       1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
       4:   return

    public static void main(java.lang.String[]);
      Code:
       0:   new     #2; //class java/util/ArrayList
       3:   dup
       4:   invokespecial   #3; //Method java/util/ArrayList."<init>":()V
       7:   astore_1
       8:   iconst_0
       9:   istore_2
       10:  iload_2
       11:  bipush  100
       13:  if_icmpge       48
       16:  aload_1
       17:  new     #4; //class java/lang/StringBuilder
       20:  dup
       21:  invokespecial   #5; //Method java/lang/StringBuilder."<init>":()V
       24:  ldc     #6; //String num-
       26:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava
       29:  iload_2
       30:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuild
       33:  invokevirtual   #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
       36:  invokeinterface #10,  2; //InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
       41:  pop
       42:  iinc    2, 1
       45:  goto    10
       48:  aconst_null
       49:  astore_2
       50:  iconst_0
       51:  istore_3
       52:  aload_1
       53:  invokeinterface #11,  1; //InterfaceMethod java/util/List.size:()I
       58:  istore  4
       60:  iload_3
       61:  iload   4
       63:  if_icmpge       93
       66:  aload_1
       67:  iload_3
       68:  invokeinterface #12,  2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
       73:  checkcast       #13; //class java/lang/String
       76:  astore_2
       77:  getstatic       #14; //Field java/lang/System.out:Ljava/io/PrintStream;
       80:  aload_2
       81:  invokestatic    #15; //Method java/lang/System.identityHashCode:(Ljava/lang/Object;)I
       84:  invokevirtual   #16; //Method java/io/PrintStream.println:(I)V
       87:  iinc    3, 1
       90:  goto    60
       93:  return
    }


    48:获取 null 值
    49:将 null 压入 astore_2 区域
    这两个指令相当于:String line = null;

    68:从 List 中获取 i 的值
    73:类型检查
    76:将值的地址压入 astore_2 区域

    第二种方式的 JVM 指令:

    Compiled from "Test.java"
    public class Test extends java.lang.Object{
    public Test();
      Code:
       0:   aload_0
       1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
       4:   return

    public static void main(java.lang.String[]);
      Code:
       0:   new     #2; //class java/util/ArrayList
       3:   dup
       4:   invokespecial   #3; //Method java/util/ArrayList."<init>":()V
       7:   astore_1
       8:   iconst_0
       9:   istore_2
       10:  iload_2
       11:  bipush  100
       13:  if_icmpge       48
       16:  aload_1
       17:  new     #4; //class java/lang/StringBuilder
       20:  dup
       21:  invokespecial   #5; //Method java/lang/StringBuilder."<init>":()V
       24:  ldc     #6; //String num-
       26:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava
       29:  iload_2
       30:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuild
       33:  invokevirtual   #9; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
       36:  invokeinterface #10,  2; //InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
       41:  pop
       42:  iinc    2, 1
       45:  goto    10
       48:  iconst_0
       49:  istore_2
       50:  aload_1
       51:  invokeinterface #11,  1; //InterfaceMethod java/util/List.size:()I
       56:  istore_3
       57:  iload_2
       58:  iload_3
       59:  if_icmpge       91
       62:  aload_1
       63:  iload_2
       64:  invokeinterface #12,  2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
       69:  checkcast       #13; //class java/lang/String
       72:  astore  4
       74:  getstatic       #14; //Field java/lang/System.out:Ljava/io/PrintStream;
       77:  aload   4
       79:  invokestatic    #15; //Method java/lang/System.identityHashCode:(Ljava/lang/Object;)I
       82:  invokevirtual   #16; //Method java/io/PrintStream.println:(I)V
       85:  iinc    2, 1
       88:  goto    57
       91:  return
    }


    64:从 List 中获取 i 的值
    69:类型检查
    72:将值的地址压入 astore_4 区域

    从两种不同风格不同的 JVM 指令来说,几乎没有区别,我不知道楼上的各位何来第一种性能高的说法?
    变量的内存分配是在栈空间做的,而栈空间的操作是在编译时确定的。对于 JVM 来说,只是将堆中对象的内存地址压入栈空间中。

    对于编译时内联处理,以及 GC 的垃圾处理来说,尽量将局变量的作用域减少到最小的范围之内!

java声明一个变量后,NEW 实例两次,这个变量会在内存中分配几个内存空间?

  1. Q

    public class Test {
    public static void main(String[] args) {
    Tv power=new Tv();
    System.out.println(power.hashCode());
    power=new Tv();
    System.out.println(power.hashCode());
    }

    }



    运行结果:
    1569228633
    778966024
    每次都不一样。
  2. A
    一个引用,两个实例对象。

请问如何在postgre下声明一个变量

  1. Q
    请问如何在postgre下声明一个变量 ?我在SQL中定义如下,现在转化成为postgre,总是有问题,不知道如何解决。
    declare @A datetime
    declare @B decimal(13,5) 
    declare @X decimal(13,5)
    declare @Y decimal(13,5)

    set @A=(select top 1 N_A from task1   where n_id=1 order by N_date desc)
    set @B=(select top 1 N_B from task1  where n_id=1 order by N_date desc)

    while right(convert(varchar(19),@A,120),8) between '00:00:00'and'03:00:00'
    begin
    set @X=round(RAND()*10,0)
    set @Y=round(RAND()*10,0)
    set @A=dateadd(mi,15,@A)
    set @[email protected][email protected]

    INSERT INTO task1(N_date,n_id,ACQ_9010)
    VALUES(@A,1,@B)

    end


    现在我在声明变量中遇到了问题,
    [email protected],但是总是报错,不知道是为什么?

    DECLARE

      n_date timestamp :=(select top 1 N_A from task1   where n_id=1 order by N_date desc);
      end
  2. A
    ZW=# CREATE FUNCTION dtA() RETURNS SETOF record AS $$
    ZW$# DECLARE n_date timestamp :=(select N_A from task1 where n_id=1 order by N_d
    ate desc limit 1);
    ZW$# BEGIN
    ZW$# END;
    ZW$#  $$ LANGUAGE plpgsql;
    CREATE FUNCTION
    ZW=#

在java中一个变量让两个类共同使用,必须定义成static吗?

  1. Q
    问题:在java中一个变量让两个类共同使用,必须定义成static吗?担心用static会造成内存泄露。有没有更好的方式?
  2. A
    参考享元设计模式

声明一个char**变量如何进行初始化?

  1. Q
    我想声明一个变量,类似于main的参数argv,即char **,想在声明的时候就初始化,能否实现?

    例如:
    char ** args={"ls","-l",NULL};#这样声明不成功
  2. A
    顺便问一下,如果不采用定义中间变量的方法,能够实现初始化时消除警告?


    警告是因为,害怕你通过指针来修改字串常量,因为字串常量分配在全局区,而不是在函数的堆栈区,程序员可能会存在非法操作,造成内存入侵。只是警告而已。

    消除警告的话:

    #pragma warning(disable : 警告号)

    在头文件中加上这么一句就可以了……

    还有……最好少用 ** 类的指针,或者说最好杜绝这类指针的出现。

不能在函数内部声明一个委托,而必须在类的内部?

  1. Q
    既然说委托是一种类型安全的"函数指针",那么为什么不能在函数的内部来声明一个委托,就像是声明一个变量那样,而必须在一个类的内部呢?
    干嘛要有这样的限制,没有这样的限制会有什么问题?
  2. A
    既然说委托是一种类型安全的"函数指针",。。。

    应该说委托的实例是一种‘类型’安全的"函数指针。

    这里’类型安全‘中说的‘类型’,则是你的委托的声明(比如返回什么类型,有几个参数,参数是什么类型等)。
    实际上,委托的类型还真的是dotnet的一个类,一个继承于MulticastDelegate的class。
    只不过该类型定义不用你自己写,编译器帮你生成而已。

    既然委托类型的声明实际上是声明一个类,那么,它就不能放到方法里面。
    因为,到目前为止,C#方法里面不能声明一个命名类。

eclipse中java类中声明静态变量serialVersionUID是干什么用的?

  1. Q
    我用ide为eclipse,创建java类之后,每个java类都有一个警告信息,说没有声明静态变量serialVersionUID,请问eclipse中java类中声明静态变量serialVersionUID是干什么用的?如何声明及赋值?
  2. A
    嗯,跟Eclipse没关系。它只是建议你应该给一个serialVersionUID会比较好。这个变量的说明在java.lang.Serializable的文档里有写:
    http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/io/Serializable.html
    引用序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的 serialVersionUID 与对应的发送者的类的版本号不同,则反序列化将会导致 InvalidClassException。可序列化类可以通过声明名为 "serialVersionUID" 的字段(该字段必须是静态 (static)、最终 (final) 的 long 型字段)显式声明其自己的 serialVersionUID:

    ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
    如果可序列化类未显式声明 serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认 serialVersionUID 值,如“Java(TM) 对象序列化规范”中所述。不过,强烈建议 所有可序列化类都显式声明 serialVersionUID 值,原因计算默认的 serialVersionUID 对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的 InvalidClassException。因此,为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值。还强烈建议使用 private 修改器显示声明 serialVersionUID(如果可能),原因是这种声明仅应用于立即声明类 -- serialVersionUID 字段作为继承成员没有用处。

为什么a类中可以声明一个a类的变量?

  1. Q
    public class Ddppfamily{
      public Ddppfamily ddpp;
    
      //....
    
    }
    

    为什么在Ddppfamily类中声明一个Ddppfamily的变量?菜鸟问题,请大家不要见笑。
  2. A
    我想说的是,“为什么”有很多层次,这么笼统的问可能很难得到理想的答案。

    如果你说“为什么在Java语言里这样写是合法的”,那是因为Java语言规范中允许递归类型的定义——递归类型就是:1、直接递归,像顶楼的代码那样一个类型直接包含那个类型的成员;2、相互递归,就是A类的实例包含B类的实例为成员,而B类的实例也包含A类的实例为成员。

    如果是问“为什么能够实现递归类型”,这既涉及到编译过程也涉及到运行时的支持。
    编译时,可以先对整个编译单元在类声明/成员声明的一层扫描一次,将类的结构分析出来之后,再深入到可执行的语句一层;然后到分析语句的语义时,类结构已经明确,查找成员所需要的符号表已经建立好了,所以分析能继续下去。
    Java里除了原始类型之外的变量都是引用类型的(数组有细微的例外,忽略)。引用的作用只是指向一个对象(或者为空);引用本身并不包含对象里的所有数据。所以这样的代码完全是可以的:
    public class Foo {
      private Foo ref;
    
      public Foo() {
        this(this); // 让ref成员指向这个实例自身
      }
    
      public Foo(Foo ref) {
        this.ref = ref;
      }
    }

    引用的这个语义由Java运行时提供支持,运行没问题。

    至于数学概念上“递归类型”的定义……或许你还不需要钻那么深 ^ ^

请教在masm的子程序proc中怎么声明一个字符串变量?

  1. Q
    我是用在别的语言的内嵌汇编,这个语言直接支持置入汇编的机器码,所以我都是在外面写好了功能,生成机器码再调用。
    而为了方便,该语言在每个子程序进入前都隐含的执行了ENTER,也就是 push ebp, mov ebp,esp 这个;
    换句话说,我这里运行的汇编代码实际上就是masm中的一个子程序而已:

    子程序 PROC
    push ebp
    mov ebp,esp       ;这两句默认就有了,是隐藏的看不见
    可以写入汇编的机器码……
    子程序 ENDP

    当然,我可以直接在第一句来个leave让他隐含的指令回去,但是一般没什么意义。。。哦说多了,这些都不是我想问的;
    我只是在表达,这里仅仅是汇编中.code中的一个小小的proc,我应该不可以像完整的汇编代码那样声明一个全局的字符串变量:
    变量 db "我要声明的字符串", 0
    貌似这样是不行的,关于这个问题其实我搜索了好长时间都没有比较明确的答案。。。
    比如masm32中带了一些宏,在那个“macros.asm”文件里,比如CTXT,CADD,szText 这些都是用于字符串的,但是我试了试不好用(或许是我不会用,也没找到具体演示的例子),首先我不是把字符串向API里传递参数,我最大的需求的将其放入esi或edi中(当然放的是字符串地址啦);
    假设我要在这个子程序中产生一个字符串:"abcabc",我现在只知道最笨的办法:
    local @txt[7]:byte
    然后将其每个字节赋值为ASCII:61h, 62h, 63h, 61h, 62h, 63h, 0
    也就是说我得写7句指令。。。我晕,我觉得肯定有比这个正常的方法吧?要是我的字符串长一些,那可咋整啊?

    请前辈教教我:在子程序中声明一个字符串变量,并将其地址赋值给esi即可。。。
    万分感激!
  2. A
    .386
    .model flat, stdcall
    .code
    start:
    jmp next
    szStr db "12345678", 0
    next:
    call getPtr
    getPtr:
    pop esi
    add esi, -14  ;call getPtr opcode长度5字节+字符串长度9字节
    end start
    end