0


JavaSE基础(七)---类和对象:“ 对象的构造及初始化”

在上一个小章节介绍了有关“类”和对象的初步认知,最主要的关键是:什么是面向对象和面向过程?如何定义一个类?怎么创建一个对象?如何访问对象的属性?


🐱‍🏍上一章节传送门:JavaSE基础(七)---类和对象之“类和对象的初步认知”_阿杭_的博客-CSDN博客Java中类和对象的初步认识,本章节将类和对象分成几个小篇章讲解里面的细节和表识。https://blog.csdn.net/weixin_50584850/article/details/123865302?spm=1001.2014.3001.5502

一、对象的初始化

1、如何初始化对象

通过基本的学习,我们知道在Java中方法内定义的局部变量必须要进行初始化,否则会出现编译错误!

public class TestDemo {
    public static void main(String[] args) {
        int a;                    //变量a没有进行初始化
        System.out.println(a);
    }
}

//会报出编译错误:Variable 'a' might not have been initialized

通过上述代码知道,局部变量一定要初始化,只要进行初始化就不会报出未初始化的错误!那定义一个类内的成员变量是否也需要初始化呢?

(1)我们在实例化一个对象后,可以通过引用变量名访问对象的属性来进行初始化。 以下面代码为例:

class Person{
    public String name;
    public int age;
    public String sex;

    public void show(){
        System.out.println(this.name+"的年龄为"+this.age);
    }
}
public class TestDemo {
    public static void main(String[] args) {
       Person person=new Person();       //实例化对象
       //初始化
       person.name="李华";        
       person.age=13;
       person.sex="boy";
       //打印
       person.show();
    }
}

//运行结果:李华的年龄为13

(2)我们也可以在类中定义一个成员方法,通过调用这个成员方法将实参传过去进行初始化。

class Person{
    public String name;
    public int age;
    public String sex;

    public void set(String name,int age,String sex){
        this.name=name;
        this.age=age;
        this.sex=sex;
    }
    public void show(){
        System.out.println(this.name+"的年龄为"+this.age);
    }
}
public class TestDemo {
    public static void main(String[] args) {
       Person person=new Person();
       person.set("李华",13,"boy");
       person.show();
    }
}

//运行结果:李华的年龄为13

🤔但是如果我们不对实例化出来一个对象进行初始化,直接调用show()方法会发什么事,事能正常运行还是会像没初始化局部变量一样报编译错误呢?

class Person{
    public String name;
    public int age;
    public String sex;

    public void show(){
        System.out.println(this.name+"的年龄为"+this.age);
    }
}
public class TestDemo {
    public static void main(String[] args) {
       Person person=new Person();
       person.show();
    }
}

运行结果:

  • 通过上述代码,发现即使成员变量不进行初始化,代码还是可以正常运行,只不过打印出来的是对应基本数据类型的默认值。*

对于类中成员变量的初始化可以分为两种,分别是就地初始化和默认初始化。

2、就地初始化

  • 当我们在类中声明成员变量时,直接给成员变量赋值,就称其为“就地初始化”!*
class Person{
    public String name="LiHua";
    public int age=13;
    public String sex="boy";

    public void show(){
        System.out.println(this.name+"的年龄为"+this.age+"性别为:"+this.sex);
    }
}
public class TestDemo {
    public static void main(String[] args) {
       Person person=new Person();
       person.show();
    }
}

//运行结果:LiHua的年龄为13性别为:boy

【注意】:代码编译完成后,编译器会将所有给成员初始化的这些语句添加到各个构造函数中.

3、默认初始化

当我们声明成员变量后,后续并未对其进行初始化,或实例化对象后的赋值,该成员变量会被编译器默认为0值。

当实例化一个对象时,在Java虚拟机层面中,会为这个对象在堆上分配内存空间。对象空间被申请好之后,对象中包含的成员已经设置好了初始值。如:
数据类型默认值int 0short0long 0Lfloat0.0fdouble0.0boolean
false
char'\u0000'byte0

class Person{
    public String name;
    public int age;
    public String sex;

    public void show(){
        System.out.println(this.name+"的年龄为"+this.age+"性别为:"+this.sex);
    }
}
public class TestDemo {
    public static void main(String[] args) {
       Person person=new Person();
       person.show();
    }
}

二、构造方法

1、什么是构造方法?

*** 构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且 在整个对象的生命周期内只调用一次。***

public class Date {
    public int year;
    public int month;
    public int day;

    // 构造方法:
    // 名字与类名相同,没有返回值类型,设置为void也不行
    // 一般情况下使用public修饰
    // 在创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次

    public Date(int year, int month, int day){
        this.year = year;
        this.month = month;
        this.day = day;
        System.out.println("Date(int,int,int)方法被调用了");

    }

    public void printDate(){
        System.out.println(year + "-" + month + "-" + day);

    }

    public static void main(String[] args) {
        // 此处创建了一个Date类型的对象,并没有显式调用构造方法
        Date d = new Date(2022,4,5); // 输出Date(int,int,int)方法被调用了
        d.printDate(); // 2022-4-5
    }

}

【注意】:构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间。

在实例化对象时,编译器自动调用new关键词后面的方法Date(),也就构造方法,但类中的成员变量总是得先进行初始化后才进行构造方法的调用。


2、构造方法的特性

1. 名字必须与类名相同

*2. 没有返回值类型,设置为void也不行 *

3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)


4. 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)

重载:方法名、没有返回值类型,参数列表不同的构造方法会构成 “方法的重载” !

实例化对象时,会根据构造方法传过去参数列表的不同,调用相对应的构造方法。构造方法不止一个,是可以有多个的!

【注意】:方法名一定得相同;返回值类型不做要求,参数列表(顺序,类型,数量上的不同)一定得存在差异,否则就不是重载,而是重写了。

重写后续在有关多态的章节会介绍。

class Person{
    public String name;
    public int age;
    public String sex;

    public Person(){
        System.out.println("无参构造方法");
    }
    public Person(String name,int age){
        this.name=name;
        this.age=age;
        System.out.println("带两个参数的构造方法");
    }
}
public class TestDemo {
    public static void main(String[] args) {
       Person person=new Person();
       Person person1=new Person("LiHua",15);
    }
}

//运行结果;无参构造方法
//         带两个参数的构造方法

上述两个构造方法,分别时不带参数,和带两个参数的构造方法,两个方法之间构成了方法的重载!

我可以利用构造方法来对当前的对象的成员进行初始化。


5、如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。

在我们刚接触类和对象时,实例化一个对象,并没有自己创建一个构造方法,可为什么程序还是能正常运行?

这是因为,当我们用户没有手动定义一个构造方法(显示定义 ),编译器会自动生成一个隐式的构造方法(无参的构造方法)调用.

public Person(){

}

【注意】:一旦我们定义了一个构造方法后,编译器就不再为我们自动提供一个默认的不带参数的构造方法。

public class Date {
    public int year;
    public int month;
    public int day;
    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
    public void printDate(){
        System.out.println(year + "-" + month + "-" + day);
    }
    public static void main(String[] args) {
// 如果编译器会生成,则生成的构造方法一定是无参的
// 则此处创建对象是可以通过编译的
// 但实际情况是:编译期报错
        Date d = new Date();
        d.printDate();
    }
}

/*
Error:(26, 18) java: 无法将类 extend01.Date中的构造器 Date应用到给定类型;
需要: int,int,int
找到: 没有参数
原因: 实际参数列表和形式参数列表长度不同
*/

此处虽然有自己定义一个构造方法,但这个构造方法是带三个参数的,在实例化对象时并没有传三个参数过去,是无参的。而我们自己定义后,编译器是不会再自动提供默认的无参构造方法,所以该代码才报错。正确的做法,是再添加一个无参的构造方法,或在实例化对象的时候传三个参数给构造方法。


6、构造方法中,可以通过this调用其他构造方法来简化代码 !

借一个构造方法,内部再调用另外一个构造方法。

class Person{
    public String name;
    public int age;
    public String sex;

    public Person(){
        this("LiHua",17);
        System.out.println("无参构造方法");
    }
    public Person(String name,int age){
        this.name=name;
        this.age=age;
        System.out.println("带两个参数的构造方法");
        System.out.println(this.name+"年龄为:"+this.age);
    }
}
public class TestDemo {
    public static void main(String[] args) {
       Person person=new Person();

    }
}

  • 总是先执行完this()调用的构造方法,再回到原本的构造方法进行执行。*

【注意】:

1、在构造方法中使用this()调用其他的构造方法,this()调用语句一定要位于该构造方法内的第一行,因为this()一定得首先运行

2、因为this()只能放在第一行优先执行,所以一个构造方法里面只能调用一个this(),否则它们都想优先执行,没法都在第一行。

3、不能使用this()调用构造方法形成----环

【构造方法之间的循环反复调用,永无止境】

public Date(){
    this(1900,1,1);
}
public Date(int year, int month, int day) {
    this();
}
/*
无参构造器调用三个参数的构造器,而三个参数构造器有调用无参的构造器,形成构造器的递归调用
编译报错:Error:(19, 12) java: 递归构造器调用
*/

  1. 绝大多数情况下使用public来修饰,特殊场景下会被private修饰(后序讲单例模式时会遇到)

三、new关键字

对于实例化一个对象的语句,该语句不单单只是一个简单的语句,,在JVM层面需要做好多事情,下面简单介绍下:

    1. 检测对象对应的类是否加载了,如果没有加载则加载;*

由.java文件编译成.class文件时,一个字节码文件对应一个类,当用到类的时候要加载它。

2. 为对象分配内存空间;

*3. 处理并发安全问题比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突。*

(当有多线程时,为同一个对象分配一块内存,就会出现并发安全问题。为了避免发生冲突,你不能每一个线程在分配内存时,都分配到同一个地址,多个对象没法放进去同一个地方。)

四、总结

在本章节中介绍了对象的初始化和构造方法。

最主要的要点是:

💥1、【构造方法的本质】当我们实例化一个对象的时侯,一定会进行两步操作:为对象分配内存、调用合适的构造方法。

2、构造方法是一个没有返回值,类名相同,参数列表不同的多个方法。

3、当写一个类时,编译器会帮我们默认生成一个不带参数的构造方法;但只要我们用户自己定义了一个构造方法,编译器就不会再默认生成一个。(一个类中至少会有一个构造方法,即使用户没有定义)。

4、可以通过this()调用构造方法,但只能在构造方法中使用(在同一个构造方法内也就只能使用一次 )。而且必须放在构造方法内第一行。

5、this()不能形成“环”。

标签: java 后端

本文转载自: https://blog.csdn.net/weixin_50584850/article/details/123964675
版权归原作者 阿杭_ 所有, 如有侵权,请联系我们删除。

“JavaSE基础(七)---类和对象:“ 对象的构造及初始化””的评论:

还没有评论