A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© dev 中级黑马   /  2012-6-27 12:49  /  4570 人查看  /  8 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 翁游龙 于 2012-6-29 15:16 编辑

在一些书上看到,程序可以在3个地方对实例变量执行初始化:
1)定义实例变量时指定初始值;
2)非静态初始化块中对实例变量指定初始值;
3)构造器中对实例变量指定初始值
其中第1、2种方式比第3种方式更早执行,但第1、2种方式的执行顺序与它们在源程序
中的排列顺序相同,这些都能理解。可下面有个程序不是很理解:

class Cat{
        String name;
        int age;
        //使用构造器初始化name、age两个实例变量
        public Cat(String name, int age){
                System.out.println("---执行构造器");
                this.name = name;
                this.age = age;
        }
        {
                System.out.println("===执行非静态初始化块");
                weight = 2.0;
        }
        //定义时指定初始值
        double weight = 2.3;
        public String toString(){
                return "Cat[name=" + name + ",age=" + age + ",weight=" + weight +"]";
        }
}
public class InitTest{
        public static void main(String[] args){
                Cat cat = new Cat("kitty", 2);
                System.out.println(cat);
        }
}


上面程序使用了三种初始化方式,有个不明白的地方就是:
(1)如果是按照正常的执行流程,为什么变量weight在没定义之前就可以在代码快中使用
而且程序没有报错,正常执行了。结果为:

===执行非静态初始化块
---执行构造器
Cat[name=kitty,age=2,weight=2.3]

(2)如果是先执行double weight = 2.3;这句,再执行代码快中的代码,那为什么weight
输出结果不是2.0而是2.3?



评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

8 个回复

倒序浏览
首先明确这个是初始化问题,在没初始化之前内存中是不是就已经存在了一个weight变量?,但是默认值是0.0?接下来才进行初始化工作,定义实例变量时指定初始值和非静态初始化块中对实例变量指定初始值两种初始化执行顺序和他们的先后顺序有关,所以进行初始化工作的时候,代码块中的代码先执行,这个时候weight的值是2.0,然后执行的是double weight = 2.3这个时候weight的值是2.3,所以你最后看到的结果是2.3而不是2.0,如果把两个初始化语句调换一下,结果就是2.0了。

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

回复 使用道具 举报
原因


一、定义实例变量时指定初始值与非静态初始化块中对实例变量指定初始值 两者是同一优先级别的。
两者的执行,是看代码出现的先后顺序而来的。

二、按你写的程序 代码顺序,
当然是先执行 非静态初始化代码块
先weight = 2.0; 此是weight =2.0
接着执行
//定义时指定初始值
        double weight = 2.3;

此时weight =2.3。

所以只会打印出 2.3 不会打印 2.0。

要想打印 2.0,你调换下两者顺序就可以了。

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

回复 使用道具 举报
第一个问题:
为什么变量weight在没定义之前就可以在代码快中使用?  这是因为weight已经定义了,虽然是在代码的下面,但是它已经是定义了,这和C语言里面是一样的,你写的自定义函数要么得写在main函数前面,要么在main函数里面进行声明。java程序运行的时候,会为定义的变量开辟内存空间,所以不会报错。
但是你若将 double weight = 2.3; 注释掉,程序就会报错,说变量没有定义。
第二个问题:
先执行double weight = 2.3;这个语句,那么你得讲 这句话写到程序的前面去,
double weight= 2.3;
  {
    System.out.println("===执行非静态初始化块");
    weight = 2.0;
  }
输出结果是 2.0,并非2.3,我猜楼主你是这么想的,你觉得你的原程序中
{
       System.out.println("===执行非静态初始化块");
      weight = 2.0;  
}      
double weight = 2.3;
这个定义在下边,但是程序运行没报错,那么就是先运行 下面的赋值为2.3,然后再运行上面的  赋值为 2.0,可是结果却不是你所想的 2.0,对吧。
那说到这,楼主的问题我就知道了,你的一个关键想法是错的,程序运行一定会先执行定义的语句,这是错的,程序的运行是按照你代码的写法从上往下依次执行的,假如运行到了某个变量,如weight = 2.0; ,这个weight是没定义的,程序就会在下面的代码中寻找weight是不是定义了,没有定义就报错,定义了,那就给其赋值为2.0,而且不报错,接着,运行到下面double weight = 2.3; 再将其值赋为2.3,最后程序输出2.3。

评分

参与人数 1技术分 +1 收起 理由
黄奕豪 + 1 赞一个!

查看全部评分

回复 使用道具 举报
上面程序使用了三种初始化方式,有个不明白的地方就是:
(1)如果是按照正常的执行流程,为什么变量weight在没定义之前就可以在代码快中使用,
而且程序没有报错,正常执行了。结果为:
===执行非静态初始化块
---执行构造器
(2)如果是先执行double weight = 2.3;这句,再执行代码快中的代码,那为什么weight
输出结果不是2.0而是2.3?

首先变量在没定义以前绝不能使用..
为证明在这个代码块里加:
  {
                System.out.println("===执行非静态初始化块");
                weight = 2.0;
System.out.println(weight);
        }
结果是报错的,提示:Cannot reference a field before it is defined
意思是不在一个字段定义以前使用...
也就是肯定是先执行的double weight = 2.3;
原因是这个静态代码块里的weight = 2.0;在代码块里才有效,出了代码块就会被java虚拟机的自动垃圾回收器处理..




回复 使用道具 举报
我认为吧,
{
                System.out.println("===执行非静态初始化块");
                weight = 2.0;
}
是一个构造代码块,它在对象一建立就运行,你建立几个对象它就会运行几次,作用是给所有对象进行初始化,所以当你new出一个cat对象时,它就运行一次,输出===执行非静态初始化块,也给weight初始化一次。它是先于构造函数运行的,然后运行构造函数,输出---执行构造器,同时给对应对象进行初始化,把参数赋给namet和age。然后向下运行再给weight赋值为2.3。最后输出cat时自动调用toString()方法
回复 使用道具 举报
dev 中级黑马 2012-6-28 18:16:09
7#
李文龙 发表于 2012-6-27 13:19
第一个问题:
为什么变量weight在没定义之前就可以在代码快中使用?  这是因为weight已经定义了,虽然是在 ...

如果是像你说的这样:程序运行到weight=2.0这里时,weight还没被定义,
程序会在下面代码中寻找weight是不是定义了,没有定义就报错,有定义就给其赋值2.0,
接着继续运行下面double=2.3。那么为什么我把weight=2.0从代码快中移出来,如下

        {
                System.out.println("===执行非静态初始化块");
               
        }
        //定义时指定初始值
        weight = 2.0;
        double weight = 2.3;

程序却会报错,标错提示为:"需要 <标识符>",而不会像你说的那样继续往下寻找
是否有定义,这里不是很明白?

评分

参与人数 1技术分 +1 收起 理由
刘蕴学 + 1 求知精神甚佳

查看全部评分

回复 使用道具 举报
翁游龙 发表于 2012-6-28 18:16
如果是像你说的这样:程序运行到weight=2.0这里时,weight还没被定义,
程序会在下面代码中寻找weight是 ...

嗯,楼主不愧是爱学习的人,能发现问题是好事呀。我来给你说说
{
                System.out.println("===执行非静态初始化块");
                weight = 2.0;
        }
        //定义时指定初始值
        double weight = 2.3;
  weight = 2.0;这个在{}里面与在下面是不一样的,在{}里面,相当于是一个方法一样,方法里面的变量你可以自己定义,也可以直接调用外部主函数里面的,外部主函数的变量定义在上还是在下无所谓。而在下面,就是你刚说的这个问题,变量的定义,呵呵,相信没人会先赋值,然后在声明类型吧,这是约定俗成的。不知懂否

评分

参与人数 1技术分 +1 收起 理由
刘蕴学 + 1

查看全部评分

回复 使用道具 举报
dev 中级黑马 2012-6-29 15:15:43
9#
李文龙 发表于 2012-6-28 19:40
嗯,楼主不愧是爱学习的人,能发现问题是好事呀。我来给你说说
{
                System.out.println("= ...

你分析得非常好,我也能明白,问题解决了。非常感谢!
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马