Java 超详细讲解对象的构造及初始化

目录
  • 如何初始化对象
  • 构造方法
  • 特性
  • 默认初始化
  • 就地初始化

如何初始化对象

我们知道再Java方法内部定义一个局部变量的时候,必须要初始化,否则就会编译失败

要让这串代码通过编译,很简单,只需要在正式使用a之前,给a设置一个初始值就好
那么对于创造好的对象来说,我们也要进行相对应的初始化
我们先写一个Mydate的类

public class MyDate {

    public int year;
    public int month;
    public int day;

    /**
     * 设置日期:
     */
    public void setDate(int year,int month,int day) {
        this.year = year;
        this.month = month ;
        this.day = day;
    }

    public void printDate() {
        System.out.println("年:"+this.year+"月:"+this.month+"日:"+this.day);
    }
   public static void main(String[] args) {

        // this.printDate();

        MyDate myDate = new MyDate();

        myDate.setDate(2022,3,25);

        myDate.printDate();

        MyDate myDate2 = new MyDate();

        myDate2.setDate(2022,3,28);
        myDate2.printDate();

    }
}

我们可以看到,在Mydate类中,要在调用之前实现写好setDate才能将具体的日期设置到对象当中

我们通过这个例子就可以发现两个问题:

  • 每次对象创建好之后调用setDate方法设置具体时期,比较麻烦,那么对象该如何初始化呢?
  • 局部变量必须要初始化之后才能使用,那么为什么字段声明之后没有给初值,它依旧可以使用呢?

答案:

  • 我们可以运用构造函数来进行初始化
  • 因为这里和main函数中定义的局部变量不同,编译器会自动为你的字段声明的局部变量赋初始零值。

构造方法

当我们实例化一个对象的时候:必须会有这两步,但并不是一定只有这两步

  • 为对象分配内存
  • 调用合适的构造方法

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

class Person {
    public String name;
    public int age;

    //构造方法:
    //名字与类名相同,且没有返回值类型,void也不行
    //一般情况下使用public修饰
    //在创建对象的时候由编译器自动调用,并且在对象的声明周期内只调用一次
    public Person(String name,int age){
        this.name = name;
        this.age = age;
        System.out.println("构造方法被调用了")
    }
    public void eat() {
        System.out.println("吃饭!");
    }

    public void sleep() {
        System.out.println("睡觉!");
    }
    public static void main(String[] args){
        //在此处创建了一个Date类型的对象,并没有显式调用构造函数
        Person p = new Person("xiaohong",18);
        p.eat();
    }
}

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

特性

  • 名字必须和类名相同
  • 没有返回值类型,void也不行
  • 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生)
  • 构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)
class Student {
    //属性:成员变量-》类的内部  方法的外部的
    public String name;
    public int age;
    public double score ;
    public String sex;

    public Student() {
        //调用本类中   带有2个参数的构造方法,第一个参数的类型是String,第2个参数的类型是int
        this.age = 18;
        System.out.println("这个是不带参数的构造方法!");
    }

    public Student(String name,int age) {
        //this();
        this.age = age;
        this.name = name;
        System.out.println("这个是带2个参数的构造方法!");
    }

    public Student(String name, int age, double score, String sex) {
        this.name = name;
        this.age = age;
        this.score = score;
        this.sex = sex;
        System.out.println("带4个参数的构造方法!");
    }

    public void doClass() {
        System.out.println(name+"正在上课!");
        //this.doHomeWork();
    }
    public void doHomeWork(){
        System.out.println(name+"正在写作业");
    }

    public void show() {
        System.out.println("姓名:"+name+" 年龄:"+age+" 学分:"+score+" 性别:"+sex);
    }
}
//重载的时候

上述方法中:名字相同,参数列表不同,因此构成了方法重载
如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。

class MyGirlFired {
    public String name;
    public int age;
    public String eyes;

    public void eat() {
        System.out.println("吃火锅!");
    }
}

在上面的代码中,没有定义任何构造方法,编译器就会默认为我们生成一个不带参数的构造方法
️:一旦用户定义了,编译器则不再生成任何构造函数

class MyGirlFired {
    public String name;
    public int age;
    public String eyes;

    public MyGirlFired(String name,int age){
        this.name = name;
        this.age = age;
    }
    public void eat() {
        System.out.println("吃火锅!");
    }

    public static void main(String[] args) {
        //如果编译器会生成,则生成的构造方法一定是无参数的
        //则此处创建对象是可以通过编译的
        //但实际上会报错
        MyGirlFired xHong = new MyGirlFired();
    }
}

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

class Student {
    //属性:成员变量-》类的内部  方法的外部的
    public String name;
    public int age;
    public double score ;
    public String sex;

    public Student() {
        //调用本类中   带有2个参数的构造方法,第一个参数的类型是String,第2个参数的类型是int
        this("yumi",18);
        //this("bit3",99,98.9,"女");
        System.out.println("这个是不带参数的构造方法!");
    }

    public Student(String name,int age) {
        //this();
        this.age = age;
        this.name = name;
        System.out.println("这个是带2个参数的构造方法!");
    }

    public Student(String name, int age, double score, String sex) {
        this.name = name;
        this.age = age;
        this.score = score;
        this.sex = sex;
        System.out.println("带4个参数的构造方法!");
    }

    public void doClass() {
        System.out.println(name+"正在上课!");
        //this.doHomeWork();
    }
    public void doHomeWork(){
        System.out.println(name+"正在写作业");
    }

    public void show() {
        System.out.println("姓名:"+name+" 年龄:"+age+" 学分:"+score+" 性别:"+sex);
    }
}

️注意:

  • this()必须是构造方法中的第一条语句,且只能放在构造函数中
  • 不能形成“环”

例如

绝大多数情况我们都用public来修饰,特殊场景下会被private修饰

默认初始化

上面我们提到了一个问题:为什么局部变量在使用时必须要用初始化,而成员变量可以不用呢?

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

    public Date(int year,int month,int day){
        //成员变量在定义之前,并没有给出初始值,那为什么就可以使用呢?
        System.out.println(this.year);
        System.out.println(this.month);
        System.out.println(this.day);
    }

    public static void main(String[] args) {
        //此处a并没有初始化,编译器报错;
        //Error:(24,28)Java:可能尚未初始化变量a
        //int a;
        //System.out.println(a);
        Date d = new Date(2022,3,29);
    }
}

要搞清楚这个过程,我们需要知道new关键字背后所发生的一些事情

Date d = new Date(2021,6,9);

在程序层面只是简单的一条语句,而在JVM层面则需要做好多事情

  • 检测对象对应的类是否加载了,如果没有加载则加载
  • 为对象分配内存空间
  • 处理并发安全问题

比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突

  • 初始化所分配的空间

即:对象空间被申请好了之后,对象中包含的成员已经设置好了初始值

数据类型 默认值
byte 0
char ‘\u0000’
short 0
int 0
long 0L
boolean false
float 0.0f
double 0.0
reference null
  • 设置对象头信息(关于对象内存模型后面再说)
  • 调用构造方法,是给对象中的各个成员赋值

就地初始化

在声明成员变量时,就直接给出了初始值

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

    public Date(){
        System.out.println(this.year);
        System.out.println(this.month);
        System.out.println(this.day);
    }
    public Date(int year,int month,int day){
        //成员变量在定义之前,并没有给出初始值,那为什么就可以使用呢?
        System.out.println(this.year);
        System.out.println(this.month);
        System.out.println(this.day);
    }

    public static void main(String[] args) {
        //此处a并没有初始化,编译器报错;
        //Error:(24,28)Java:可能尚未初始化变量a
        //int a;
        //System.out.println(a);
        Date d1 = new Date(2022,3,29);
        Date d2 = new Date();
    }
}

//运行结果:
//0
//0
//0
//0
//0
//0

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

5.一个类至少会有1个构造函数,就算你没有写!
6.构造方法 本质 就是来实例化对象的时候调用
(1)分配内存
(2)调用合适的构造方法
7.this可以用来调用本类中的其他构造方法【构造方法当中使用】
且必须放在第一行!所以,只能在当前构造方法当中,调用一次
8.this的用法:

  • this.data 访问属性
  • this.func(); 访问方法
  • this(); //用来调用本类中的其他构造方法

9.this不能形成环。

有错误请大家批评指正
感谢阅读

到此这篇关于Java 超详细讲解对象的构造及初始化的文章就介绍到这了,更多相关Java 对象的构造内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java——对象初始化顺序使用详解

    一. 代码块的概念 在探究对象初始化顺序之前,我们先通过代码来了解一下代码块的概念. class Test{ public static String str1; //静态字段 public String str2; //普通字段 static{ //静态代码块 } { //构造代码块 } public Test() { //构造函数 } } 二. 创建子类对象时,对象的初始化顺序 1. 字段初始化.代码块和构造函数的执行顺序 我们先看代码和结果 public class CodeBlockTe

  • 深入介绍Java对象初始化

    前言 在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的. 自动初始化(默认值) 一个类的所有基本数据成员都会得到初始化,运行下面的例子可以查看这些默认值: class Default{ boolean t; char c; byte b; short s; int i; long l; float f; double d; public void show() { System.out.println("基本类型 初始化值\n"+ "bo

  • Java中对象初始化顺序的详细介绍

    前言 在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.最近我发现了一个有趣的问题,这个问题的答案乍一看下骗过了我的眼睛.看一下这三个类: package com.ds.test; public class Upper { String upperString; public Upper() { Initializer.initialize(this); } } package com.ds.test; public class Lower extends

  • java对象初始化代码详解

    本文主要记录JAVA中对象的初始化过程,包括实例变量的初始化和类变量的初始化以及final关键字对初始化的影响.另外,还讨论了由于继承原因,探讨了引用变量的编译时类型和运行时类型 一,实例变量的初始化 这里首先介绍下创建对象的过程: 类型为Dog的一个对象首次创建时,或者Dog类的static字段或static方法首次访问时,Java解释器必须找到Dog.class(在事先设定好的路径里面搜索):  找到Dog.class后(它会创建一个Class对象),它的所有static初始化模块都会运行.

  • Java和Ceylon对象的构造和验证

    当变换Java代码为Ceylon代码时,有时候我会遇到一些Java类构造器混淆了验证与初始化的情形.让我们使用一个简单但是人为的代码例子来说明我想阐述的意思. 一些坏代码 考虑下面的Java类.(伙计,不要在家里写这样的代码) public class Period { private final Date startDate; private final Date endDate; //returns null if the given String //does not represent

  • 基于java构造方法Vector创建对象源码分析

    目录 前言 构造方法Vector()分析 构造方法Vector(int)分析 构造方法Vecotor(int,int)分析 构造方法Vector(Collection)分析 重要字段介绍(不含基类中定义的字段) (注意:本文基于JDK1.8) 前言 Vector是线程安全的动态数组类,提供4个创建Vector对象的构造方法,接下来我们逐个分析每个创建Vector对象的构造方法 构造方法Vector()分析 public Vector() { this(10); } 用于创建Vector对象的默认

  • Java杂谈之类和对象 封装 构造方法以及代码块详解

    目录 1. 类和对象的初步认知 2. 类的实例化 3. 类的成员 字段(属性/成员变量) 方法 static 关键字 修饰字段 修饰方法 修饰代码块(暂不讲) 修饰类(暂不讲) 4. 封装 5. 构造方法 6. this 用法 关于引用的几个注意事项: 7. 代码块 Java当中的类和对象 1. 类和对象的初步认知 java 是一门面向对象的语言,所谓面向对象有别于面向过程,面向对象是只需对象之间的交互即可完成任务,但是面向过程的话,需要我们将每一个步骤都详细地做出来.比如,以洗衣服为例,如果是

  • 详解Java基础篇--面向对象1(构造方法,static、this关键字)

    面向对象,面向过程的区别.拿下五子棋来说: 面向过程分析: 开始游戏 黑棋先走 绘制画面 判断输赢 轮到白棋 绘制画面 判断输赢 返回步骤2 输出结果 面向对象分析: 黑白双方,双方行为是一模一样的 棋盘系统,负责绘制画面 规则系统,判断犯规.输赢 传统的面向过程编程是思考问题的解决步骤,这种思维方式适用于问题规模较小时.可是当问题规模大,要求程序有更好的可扩展性,能更快速地查错时面向对象设计思想就能体现出其优势.面向对象更接近人类地自然思维方式,将现实世界中的事物抽象为对象和对象的方法. 面向

  • Java如何通过反射获取私有构造、私有对象、私有字段、私有方法

    Java反射获取私有构造.私有对象.私有字段.私有方法 1. 创建测试的私有对象 /** * @author lirong * @desc 测试对象 * @date 2019/06/20 20:07 */ public class Person { private int age = 5; private String name; private Person(){} private String test(String name){ System.out.println("name: &quo

  • Java 超详细讲解对象的构造及初始化

    目录 如何初始化对象 构造方法 特性 默认初始化 就地初始化 如何初始化对象 我们知道再Java方法内部定义一个局部变量的时候,必须要初始化,否则就会编译失败 要让这串代码通过编译,很简单,只需要在正式使用a之前,给a设置一个初始值就好那么对于创造好的对象来说,我们也要进行相对应的初始化我们先写一个Mydate的类 public class MyDate { public int year; public int month; public int day; /** * 设置日期: */ pub

  • Java 超详细讲解类的定义方式和对象的实例化

    目录 1.面对对象的初步认识 1.1什么是面向对象 1.2面向对象与面向过程 2.类的定义与使用 2.1简单认识类 2.2 类的定义格式 3.类的实例化 3.1什么是实例化? 3.2重点笔记 总结 1.面对对象的初步认识 1.1什么是面向对象 用面向对象的思想来涉及程序,更符合人们对事物的认知,对于大型程序的设计.扩展以及维护都非常友好. 1.2面向对象与面向过程 举一个买手机的例子 以面向对象的方式来处理买手机这件事的话,我们就不需要关注买手机的过程,具体手机怎么买,如何到手,用户不用去关心,

  • Java 超详细讲解类的定义方式和对象的实例化

    目录 1.面对对象的初步认识 1.1什么是面向对象 1.2面向对象与面向过程 2.类的定义与使用 2.1简单认识类 2.2 类的定义格式 3.类的实例化 3.1什么是实例化? 3.2重点笔记 总结 1.面对对象的初步认识 1.1什么是面向对象 用面向对象的思想来涉及程序,更符合人们对事物的认知,对于大型程序的设计.扩展以及维护都非常友好. 1.2面向对象与面向过程 举一个买手机的例子 以面向对象的方式来处理买手机这件事的话,我们就不需要关注买手机的过程,具体手机怎么买,如何到手,用户不用去关心,

  • Java 超详细讲解设计模式之中的建造者模式

    目录 1.什么是建造者模式? 2.建造者模式的定义 3.建造者模式的优缺点 4.建造者模式的结构 5.建造者模式代码演示 6.建造者模式的应用场景 7.建造者模式和工厂模式的区别 1.什么是建造者模式? 我们知道在软件开发过程中有时需要创建一个很复杂的对象,通常由多个子部件按一定的步骤组合而成. 例如,比如我们在自己在组装一台计算机的时候,需要有 CPU.主板.内存.硬盘.显卡.机箱.显示器.键盘.鼠标等部件组装而成的.比如学校需要采购100台计算机,学校不可能自己把零件买过来自己组装,肯定是告

  • Java 超详细讲解数据结构中的堆的应用

    目录 一.堆的创建 1.向下调整(以小堆为例) 2.创建堆 3.创建堆的时间复杂度 二.堆的插入和删除 1.堆的插入 2.堆的删除 三.堆的应用 1.堆排序 2.top-k问题 [求最小的K个数] 四.常用接口的介绍 1.PriorityQueue的特性 2.优先级队列的构造 一.堆的创建 1.向下调整(以小堆为例) 让parent标记需要调整的节点,child标记parent的左孩子(注意:parent如果有孩子一定先是有左孩子) 如果parent的左孩子存在,即:child < size,

  • Java 超详细讲解字符流

    目录 一.字符流的由来 二.编码表 字符集: Unicode字符集: UTF-8编码规则: 三.字符串中的编码解码问题 编码方法(IDEA): 解码方法(IDEA): 四.字符流的编码解码问题 四.字符流写数据的五种方法 五.字符流读数据的两种方法 一.字符流的由来 由于使用字节流操控中文时不是很方便,Java就提供了字符流来进行操控中文 实现原理:字节流+编码表 为什么用字节流进行复制带有中文的文本文件时没有问题? 因为底层操作会自动进行字节拼接成中文 怎样识别该字节是中文呢? 汉字在存储时,

  • Java 超详细讲解数据结构中的堆的应用

    目录 一.堆的创建 1.向下调整(以小堆为例) 2.创建堆 3.创建堆的时间复杂度 二.堆的插入和删除 1.堆的插入 2.堆的删除 三.堆的应用 1.堆排序 2.top-k问题(求最小的K个数) 四.常用接口的介绍 1.PriorityQueue的特性 2.优先级队列的构造 一.堆的创建 1.向下调整(以小堆为例) 让parent标记需要调整的节点,child标记parent的左孩子(注意:parent如果有孩子一定先是有左孩子) 如果parent的左孩子存在,即:child < size, 进

  • Java 超详细讲解设计模式之中的抽象工厂模式

    目录 抽象工厂模式 1.什么是抽象工厂 2.抽象工厂模式的优缺点 3.抽象工厂模式的结构与实现 4.抽象工厂方法模式代码实现 5.抽象工厂模式的应用场景 6.抽象工厂模式的扩展 抽象工厂模式 前面文章介绍的工厂方法模式中考虑的是一类产品的生产,比如案例中的百事可乐工厂只能生产百事可乐,可口可乐工厂只能生产可口可乐,也就是说:工厂方法模式只考虑生产同等级的产品. 1.什么是抽象工厂 在现实生活中许多工厂是综合型的工厂,能生产多种类)的产品,就拿案例里面的可乐来说,在节日的时候可能会有圣诞版的可乐,

  • Java 超详细讲解IO操作字节流与字符流

    目录 IO操作 字节流 FileInputStream FileOutputStream 字节流读写案例 字符流 FileReader FileWriter 字节流与字符流的区别 IO操作 字节流 java.io.InputStream 输入流,主要是用来读取文件内容的. java.io.OutputStream 输出流,主要是用来将内容字节写入文件的. FileInputStream 该流用于从文件读取数据,它的对象可以用关键字 new 来创建. 有多种构造方法可用来创建对象. 可以使用字符串

  • Java超详细讲解设计模式之一的工厂模式

    目录 工厂模式 1.简单工厂 1.1结构 1.2实现 1.3优缺点 1.4扩展 2.工厂方法 2.1结构 2.2实现 2.3优缺点 3.抽象工厂 3.1结构 3.2实现 3.3优缺点 4.模式扩展 4.1实现 工厂模式 在Java应用程序中对象无处不在,这些对象都需要进行创建,如果创建的时候直接new对象,那么如果我们要更换对象,所有new对象的地方都需要进行更改.违背了软件设计原则中的开闭原则.如果我们使用工厂生产对象,只需要在工厂中关注对象的改变即可,达到了与对象解耦的目的,工厂模式最大的特

随机推荐