Java中的构造函数与字段初始化顺序

在java中我们通过new ClassName()来创建对象,那么创建对象的整个过程是怎么样的呢?其实,在创建对象时, 首先虚拟机会为对象的所有字段分配内存, 包括哪些从父类继承来的字段, 而且会把这些字段初始化为它们各自类型的默认值, 比如数值类型的默认值为0, boolean类型的为false, char类型的为"\u0000", 引用类型为null。在此之后, 构造过程分为三个阶段 : 

1、调用父类的构造函数

2、用这些字段的初始器和初始化块来初始化它们;

3、执行构造函数体

其中,首先执行的时显式或者隐式的调用父类的构造函数, 如果使用了显式的调用this构造函数,那么这样的调用链将会链接下去,知道找到一个隐式或者显式的父类构造函数调用为止,然后调用该父类的构造函数。 父类的构造函数的执行过程也分为同样的三个阶段, 知道整个过程达到Object类的构造函数为止。任何作为显示构造函数调用的组成部分进行计算的对象都不允许引用当前对象的任何成员。

在第二阶段, 所有的字段初始化器和初始化块都是按照他们的生命顺序来执行的。这个阶段,允许引用当前对象的其他成员, 只要他们已经被声明过即可。

最后,执行构造函数体中的实际语句。如果该构造函数是被显式的调用,那么一旦其执行结束,控制流就会返回调用它的构造函数, 执行那个构造函数的剩余部分。这个过程将会不断地重复,直到在new构造语句中所使用的构造函数体都已经执行完成之后才停止。

如果在构造过程中抛出异常,那么new表达式将会在抛出那个异常的同时终止,此时不会返回任何新对象的引用。

下面是一个例子, 可以追中说明构造过程的不同阶段 :

package com.thingking.in.java;

// class x
public class X {
	protected int xMask = 0x00ff;
	protected int fullMask;

	public X() {
		fullMask = xMask;
	}

	public int mask(int origin) {
		return (origin & fullMask);
	}

}

// class y
class Y extends X {

	protected int yMask = 0xff00;

	public Y() {
		fullMask |= yMask;
	}

}
如果创建了一个ClassY的对象, 就可以逐步地进行构造, 那么就可以得到每一步的字段对应的值。


在第五步中,如果X的构造函数调用了mask方法,那么它使用的fullmask值将是0x00ff, 而不是0xffff。事实确实如此, 尽管在对象完全构造之后,对mask的调用所使用的fullmask值是0xffff。

而且, 假设类Y的实现覆盖了mask方法,且在计算中显式地使用了yMask字段。如果X的构造函数中使用的是mask方法,那么实际上它想调用的将是Y的mask方法,而此时yMask的值将是0而不是想要的0xff00。

在设计对象构造阶段调用的这些方法时,必须考虑以上这些因素。构造函数应该避免调用哪些可覆盖的方法, 即不是私有、静态的活着final的方法。如果确实调用了这样的方法,那么必须在文档中将它们清晰地列出来,以提醒所有想要用潜在的非常规的使用方式来覆盖这些方法的人。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
可以通过使用Java 8提供的Stream API和Lambda表达式来根据指定的字符串字段对List进行去重操作,并对相同的对象进行整数字段的累加。具体实现步骤如下: 1. 定义一个实体,包含需要去重和累加的字段,例如: ``` public class Person { private String name; private int age; // 其他字段... // 构造函数、getter和setter方法... } ``` 2. 初始化一个包含多个Person对象的List,例如: ``` List<Person> personList = new ArrayList<>(); personList.add(new Person("Tom", 20)); personList.add(new Person("Jerry", 18)); personList.add(new Person("Tom", 25)); personList.add(new Person("Jack", 22)); ``` 3. 使用Stream API进行去重和累加操作,例如: ``` Map<String, Person> resultMap = personList.stream().collect( Collectors.toMap( Person::getName, // 指定map的key Function.identity(), // 指定map的value (oldValue, newValue) -> { // 指定合并函数,用于累加相同名称的Person对象的age字段 oldValue.setAge(oldValue.getAge() + newValue.getAge()); return oldValue; } ) ); List<Person> resultList = new ArrayList<>(resultMap.values()); // 将map转换为List ``` 以上代码将根据Person对象的name字段进行去重,并将相同名称的Person对象的age字段进行累加。最终,得到一个新的List对象,其包含去重后的Person对象(相同名称的Person对象的age字段已经累加)。需要注意的是,此方法得到的Person对象的顺序可能与原始List的顺序不同。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值