java中关于代码块的一些疑惑

今天早上起来一直学到现在,只搞了一个问题。其实自己也玩了好长时间。吃了两块冻了两天的西瓜,这口感。。真相60岁的老奶奶。。一点水分都没有。说说正题。这个问题是关于JAVA中构造代码块,静态构造代码块,成员变量放置的位置不同进而导致其执行顺序以及给变量初始化值的不同。这个问题很奇怪,本来按照常理来讲,我是应该可以解决掉的,但是发现,如果把它们的位置改一改,参数的传递就会出现问题,搞得我今天一天都在研究这个问题。后来翻资料了以后才把这个问题解决掉。其实我现在还有一些不明白的地方,等等有空问问老师吧,下面是我今天一天的收获。


按照常理来讲:构造代码块应该放置在成员变量下面。这个时候执行顺序是先给成员变量进行初始化,然后构造代码块在给成员变量进行赋值。举例如下(当然也会出现一些自己猜测错误的结果,总结如下):
代码一:
class BlockDemo2 {
private int a = 2;
{
a = 1;
System.out.println(“大家好,我是构造代码块”);
}
public static void main(String[] args) {
BlockDemo2 bd = new BlockDemo2();
System.out.println(bd.a);
}
}
这个代码的执行结果很明显是:大家好,我是构造代码块,1,类加载以后,先给成员变量a进行初始化值,然后再执行构造代码块给再次给a进行赋值。所以得到的结果是2.




这里按照常理来说final 修饰成员变量以后,就会变成常量,java中规定变量加final修饰以后就必须要给出初始化值,不然会报错,并且一旦给定值以后就不能进行修改。在采用构造代码块对final修饰的成员变量进行赋值的时候,有两种情况:一种情况是成员变量本身没有赋值,代码如下


class BlockDemo2 {
final int a;
public BlockDemo2() {}
{
a = 1;
System.out.println(“大家好,我是构造代码块”);
}
public static void main(String[] args) {
BlockDemo2 bd = new BlockDemo2();
System.out.println(bd.a);
}
}
打印结果是:大家好,我是构造代码块,1,这段代码中成员变量的初始化过程放在了构造代码块中。
另一种情况是成员变量本身已经给定了一个值。
class BlockDemo2 {
private final int a = 2;
{
a = 1;
System.out.println(“大家好,我是构造代码块”);
}
public static void main(String[] args) {
BlockDemo2 bd = new BlockDemo2();
System.out.println(bd.a);
}
}
结果是jvm虚拟机会报错,因为成员常量已经初始化,下面的构造代码块又给出赋值语句,所以,就出错了。


下面咱们再来看看调换构造代码块跟成员变量的位置后,会出现什么奇怪的现象。代码如下:
第一种情况-成员变量不给初始化:
class BlockDemo2 {
{
a = 3;
System.out.println("大家好");
}
private int a;
public static void main(String[] args) {
BlockDemo2 bd = new BlockDemo2();
System.out.println(bd.a);
}
}
代码中,我们把构造代码块放置在了成员变量的上面,当成员变量没有初始化的时候(其实系统已经默认给出了初始化值:0),构造代码块可以为其赋值,打印结果是:大家好, 3; 从这点说明先执行系统给定的默认初始化值,然后才会加载构造代码块中的赋值语句,对成员变量进行赋值。
如果我们拿着这个理论来推理下面的这串代码就会出现问题,来看看。
第二种情况成员变量手动进行初始化。
当成员变量给出初始化值时:
class BlockDemo2 {
{
a = 3;
System.out.println("大家好,我是构造代码块");
}
private int a = 2;
public static void main(String[] args) {
BlockDemo2 bd = new BlockDemo2();
System.out.println(bd.a);
}
}
打印结果是:大家好,我是构造代码块,2. 结果居然打印的是2,并且构造代码块中的打印语句竟然执行了。从这个例子中,我们可以得出以下总结:
1.当构造代码块放置在成员变量的上面的时候,如果成员变量没有初始化,则执行完构造代码块中可以为其进行赋值操作。
2.如果成员变量手动进行初始化操作,那么构造代码块中的赋值语句将不会被执行。


下面我们可以检验一下,如果手动初始化成员变量,让其值为0,这个值等于系统默认的初始化值。
class BlockDemo2 {
{
a = 3;
System.out.println("大家好");
}
private int a = 0;
public static void main(String[] args) {
BlockDemo2 bd = new BlockDemo2();
System.out.println(bd.a);
}
}
我们得到的打印结果是:大家好,0 。可见如果手动对成员变量进行初始化,不管值为多少,构造代码块中的赋值语句都不会执行。
第三种情况-----成员变量加final修饰成为常量,不进行初始化:
class BlockDemo2 {
{
a = 3;
System.out.println("大家好");
}
private final int a;
public static void main(String[] args) {
BlockDemo2 bd = new BlockDemo2();
System.out.println(bd.a);
}
}
这里打印的结果是3,说明调换构造代码块跟成员变量的位置以后,构造代码块还是可以给final修饰的成员变量进行赋值的,但是前提是该成员变量不能提前手动进行初始化操作。


第四种情况-----对定义的成员变量采用静态修饰,这里又出现了一些问题。问题的关键点在于采用何种方式来调用成员变量是new一个对象来调用呢?还是直接调用呢?请看如下代码:


class BlockDemo2 {
{
a = 3;
System.out.println("大家好");
}
private static int a = 1;
public static void main(String[] args) {

BlockDemo2 bd = new BlockDemo2();
System.out.println(bd.a);
}
}
当用static给静态加上修饰了以后,并给出成员变量的值,依照我们上一个例子所总结出来的,如果在定义成员变量的时候手动进行了初始化,那么构造代码块中的赋值语句是不执行的。。但是狗血的一幕发生了。打印结果居然是:大家好,3. 结果跟前面总结的不一样。那么,如果在定义成员变量的时候没有进行初始化,会是什么样子的呢?看看下面的代码:


class BlockDemo2 {
{
a = 3;
System.out.println("大家好");
}
private static int a;
public static void main(String[] args) {
BlockDemo2 bd = new BlockDemo2();
System.out.println(bd.a);
}
}
运行java虚拟机以后,得到的打印结果是3,这里其实我们也可以猜到的。所以做如下总结:
当定义的成员变量加static修饰以后,无论在定义的时候是否进行手动初始化,构造代码块中的赋值语句都会执行,因而构造代码块中的赋值语句会覆盖成员变量中的初始值。


然而,这仅仅是在new一个对象的时候才会出现这样的结果,下面我们来看看如果利用静态修饰直接打印变量会出现什么样的结果,我们还是分两种情况,一种是在定义成员变量的时候不进行初始化值,另一种情况是在定义成员变量的时候对其进行初始化值操作。


一:定义成员变量的时候没有进行初始化。
class BlockDemo2 {
{
a = 3;
System.out.println("大家好");
}
private static int a;
public static void main(String[] args) {
System.out.println(a); }
}


出乎意料,这里打印的结果是0。 我们发现构造代码块中的赋值语句没有执行,并且让人感到惊讶的是构造代码块中的打印语句也没有执行。
二:定义成员变量的时候进行初始化值:
class BlockDemo2 {
{
a = 3;
System.out.println("大家好");
}
private static int a = 1;
public static void main(String[] args) {
System.out.println(a); //居然是0,狗血呀!!
}
}
这里打印的结果是1.
这是个什么情况呢? 。。因为构造代码块是在创建对象的时候才会加载,所以,如果直接调用变量而不去new一个对象,构造代码块是不会加载的。所以只会存在定义的成员变量的值。当我们没有对其进行初始化的时候,结果是0,这是系统默认给出的初始化值,而当我们在定义变量的时候手动初始化的时候,系统就不会给了,这个时候打印的就是我们自己给的值。


下面我们看看如果既存在静态代码块又存在着静态属性,会出现什么情况?


一:定义成员变量的时候对其进行初始化,分两种情况:1.创建对象调用成员变量,2 直接调用成员变量。
1.创建对象调用成员变量的例子:
class BlockDemo2 {
static {
a = 3;
System.out.println("大家好");
}
private static int a;
public static void main(String[] args) {

BlockDemo2 bd = new BlockDemo2();
System.out.println(bd.a);

//System.out.println(a);
}
}
在创建对象的情况下调用变量还是符合前面例子总结出来的规则,如果在定义成员变量的时候手动给出初始化值,那么静态代码块中的赋值语句就不会执行,但是打印语句是会执行的。如果在定义成员变量的时候没有手动初始化,那么静态代码块中的赋值语句就会执行,并给该变量进行赋值操作。


2利用静态的属性,直接调用成员变量。我们看看又会出现什么样的结果。




class BlockDemo2 {
static {
a = 3;
System.out.println("大家好,我是静态代码块");
//System.out.println(a);
}
private static int a = 1;
public static void main(String[] args) {
System.out.println(a);
}
}
这个时候打印出来的结果是:大家好,我是静态代码块,1,可以用到前面的理论,如果成员变量有初始化值,那么静态代码块中的赋值语句就不会执行。但是会执行静态代码块中的打印语句。  但是问题来了。如果此时,我们在静态代码块中直接调用a变量,是会出错的。
我们再看看如果在定义变量的时候不对其进行手动初始化值,那么结果是什么呢?
class BlockDemo2 {
static {
a = 3;
System.out.println("大家好,我是静态代码块");
//System.out.println(a);
}
private static int a;
public static void main(String[] args) {
System.out.println(a);
}
}
得到的结果是:大家好,我是静态代码块,3.经过这两段代码的比较,我斗胆总结出这样的结论:在加载类的过程中,静态成员变量的加载优先级高于静态代码块的加载优先级。也就是说,加载BlockDemo2类的字节码文件以后,方法进入到方法区之后,会先在堆内存中开辟空间加载a变量,这个时候加载静态构造代码块,如果a变量没有给出值,那么静态代码块中的赋值语句就会执行,如果a变量给出初始化值,那么静态代码块中的赋值语句就不会执行。并且,加载静态代码块的时候,是不能调用该变量的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值