构造方法
说来惭愧,学Java有一段时间了,突然看到Java构造方法了,反而不知道它到底是干啥用的,于是就专门了解了一下构造方法。
构造方法呢,就是一种特殊的方法,每当一个类被实例化的时候,就会调用构造方法,而且只有构造方法被调用的时候,对象才会被分配内存空间。也就是说,每次我们使用new关键字的时候,构造方法至少会被调用一次。
这个时候可能就会有人讲了,我看到过很多类了,但是没有见到构造方法啊。这个时候就片面了哈,没有写不代表没有,而是被编译器给默认添加了一个默认的构造方法了。总在来讲Java中只有两种构造方法:有参构造和无惨构造
为什么要叫做构造方法,是因为在对象创建的时候,需要公共构造方法去初始化值,去描述对象的那些状态,去对应对象中的字段。
1,创建构造方法的规则
- 构造方法的名字必须和类名一致
- 构造方法没有返回值,返回的是一个类
- 构造方法不能是抽象的,静态的,最终的,同步的也就是说,他不能通过abstract,static,final,synchronized关键字修饰
- 这个有点难理解,解释一下,就是由于构造方法是不能被继承的,所以final和abstract是没有意义的,而且他是用于初始化一个对象的,所以static也是没有用的,多个线程也不会同时去创建内存地址相同的对象,所以锁也是没有意义的
具体语法格式如下:
public class people {
private String name;
private int age;
//无参构造
public people() {
}
//有参构造方法
public people(String name, int age) {
this.name = name;
this.age = age;
}
}
2,什么是默认构造方法
如果构造方法中没有参数,就说明他就是一个默认构造方法,也称为无参构造方法。
public class People {
private String name;
private int age;
//无参构造
public People() {
System.out.println("一个人的诞生");
}
//有参构造方法
public People(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
People people = new People();
}
}
上面的例子中,我们在People中创建了一个无惨的构造方法,它在我们创建对象的时候被调用
输出结果如下
一个人的诞生
通常情况下无参构造可以被省略的。
这个时候就有人会问,无参构造方法里面是空的,他到底是有什么用呢?关于这个问题,咱们先看代码
public class People {
private String name;
private int age;
//无参构造
public People() {
System.out.println("一个人的诞生");
}
//有参构造方法
public People(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
People people = new People();
//姓名null年龄0
System.out.println("姓名" + people.name + "年龄" + people.age);
}
}
从这里,我们就可以很明显的看出他的作用,就是为了给值赋予一个默认的片段。这里就是初始化了people俩属性的值,String的默认值为null,而int类型为0。
3,什么是有参构造
有参构造方法就肯定是由参数的构造方法。有了参数的话就可以为不同的对象供不同的值了。话不多说,先看代码
public class People {
private String name;
private int age;
//无参构造
public People() {
System.out.println("一个人的诞生");
}
//有参构造方法
public People(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
People people = new People("张三",18);
People people2 = new People("小帅",2);
//姓名null年龄0
//System.out.println("姓名" + people.name + "年龄" + people.age);
}
}
从这段代码中,我们就可以看出来有参构造的作用,可以在创建对象的时候直接赋予值。
4,如何重载构造方法
构造方法和方法是类似的,他也可以重载。其重载的方法很简单,就是只要提供不一样的参数即可,编译器就会去通过不同的参数找到对应的构造方法
public class People {
private String name;
private int age;
//无参构造
public People() {
System.out.println("一个人的诞生");
}
//有参构造方法
public People(String name, int age) {
this.name = name;
this.age = age;
}
public People(String name) {
this.name = name;
}
public static void main(String[] args) {
People people = new People("张三",18);
People people2 = new People("小帅",2);
People people3 = new People("老王");
//姓名null年龄0
//System.out.println("姓名" + people.name + "年龄" + people.age);
}
}
5,如何去复制对象
复制对象有三种方式去完成:
- 通过构造方法
- 通过对象的值
- 通过Object类的clone方法
第一种 通过构造方法
public class People {
private String name;
private int age;
//无参构造
public People() {
System.out.println("一个人的诞生");
}
//有参构造方法
public People(String name, int age) {
this.name = name;
this.age = age;
}
// public People(String name) {
// this.name = name;
// }
public People(People people) {
this.name = people.name;
this.age = people.age;
}
public static void main(String[] args) {
People people = new People("张三",18);
People people2 = new People("小帅",2);
People people4 = new People(people2);
// People people3 = new People("老王");
//姓名null年龄0
//System.out.println("姓名" + people.name + "年龄" + people.age);
}
}
这种方式是我们直接把类作为参数传入了,在调用的时候把我们想复制的类给直接传进去了,所以可以复制出来。
这个时候不知道有没有人想知道这俩复制的people是否是恒等于呢?答案是否定的。原因自己思考。
第二种,通过对象的值
public class People {
private String name;
private int age;
//无参构造
public People() {
System.out.println("一个人的诞生");
}
//有参构造方法
public People(String name, int age) {
this.name = name;
this.age = age;
}
// public People(String name) {
// this.name = name;
// }
public People(People people) {
this.name = people.name;
this.age = people.age;
}
public static void main(String[] args) {
People people = new People("张三",18);
People people2 = new People("小帅",2);
People people4 = new People(people2);
People people5 = new People();
people5.name = people2.name;
people5.age = people2.age;
// People people3 = new People("老王");
//姓名null年龄0
//System.out.println("姓名" + people.name + "年龄" + people.age);
if (people2 == people5){
System.out.println("一样");
}else {
System.out.println("不一样");
}
这个大家应该都能看懂,就是暴力赋值。这里的俩对象也不是恒等于哦。
第三种,通过Object类的clone方法
public class People implements Cloneable{
private String name;
private int age;
//无参构造
public People() {
System.out.println("一个人的诞生");
}
//有参构造方法
public People(String name, int age) {
this.name = name;
this.age = age;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
// public People(String name) {
// this.name = name;
// }
public People(People people) {
this.name = people.name;
this.age = people.age;
}
public static void main(String[] args) throws CloneNotSupportedException {
People people = new People("张三",18);
People people2 = new People("小帅",2);
People people4 = new People(people2);
People people5 = new People();
People people6 = (People) people2.clone();
people5.name = people2.name;
people5.age = people2.age;
// People people3 = new People("老王");
//姓名null年龄0
//System.out.println("姓名" + people.name + "年龄" + people.age);
if (people2 == people6){
System.out.println("一样");
}else {
System.out.println("不一样");
}
}
}
6,代码初始块
代码初始块是用来初始化一些成员变量,对象在创建的时候就会执行代码初始块。这样的话我们就可以用这个方法去进行一些骚操作。
public class Person {
List<String> list;
{
list = new ArrayList<>();
list.add("老王");
list.add("小红");
}
public static void main(String[] args) {
System.out.println(new Person().list);
}
}
这里因为使用的=,所有没有办法完成集合的初始化,所以后面只能用new关键字,不然就无法填充值。
这个时候有细心的朋友就会问,那么他和构造方法谁先执行呢?
老规矩,先看代码
public class Person {
public Person() {
System.out.println("无参构造");
}
List<String> list;
{
list = new ArrayList<>();
list.add("老王");
list.add("小红");
System.out.println("代码初始化块");
}
public static void main(String[] args) {
System.out.println(new Person().list);
}
}
输出结果:
代码初始化块
无参构造
[老王, 小红]
看到这个结果,是不是都以为初始化代码块要比构造方法先执行呢?其实不是这样子的。
对象在初始化的时候会先调用构造方法这个是毋庸置疑的,只不过,构造方法在执行的时候会把这个代码构造块给放在构造方法中其他代码之前,所以才会造成这个假象。
其实他真正的执行方法是这样子的
public class Person {
public Person() {
List<String> list;
{
list = new ArrayList<>();
list.add("老王");
list.add("小红");
System.out.println("代码初始化块");
}
System.out.println("无参构造");
}
public static void main(String[] args) {
System.out.println(new Person().list);
}
}
这样子就清晰了吧
代码的初始化来说,他有三个规则
- 类实例化时候执行代码初始化块
- 实际上,代码初始化块是在构造方法中执行的,只是他的位置靠前
- 执行顺序是从前到后