Java初始化对象的工具 - 构造器

简介: Java初始化对象的工具 - 构造器

一、构造器的作用

明确了类与对象的关系后,我们知道:类只是一个定义的结构,用来表述我们想要描述的事物,即具备哪些属性(成员变量),可以产生哪些行为(方法)。那么具体行为的发生,也就是方法的调用要靠对象来完成,同时属性值也要附着在对象上才有意义。创建对象的过程被叫做类的实例化,或者称为对象的初始化,在这个过程中需要使用的就是new关键字和类的构造器。

对于相关概念还不清楚的同学请进传送门:Java中的基本操作单元 - 类和对象

二、构造器的定义

1. 构造器的别称

没错,他们都是同一个意思。

  • 构造器
  • 构造方法
  • 构造函数

2. 构造器定义格式

构造器本身更像一种方法,因此定义的格式与方法类似,可以区别着进行记忆。构造器同样被定义在class的大括号内,构造器的定义格式如下:

public class className{
    // 构造器定义开始
    [权限修饰符] 类名(参数列表){
        // 代码部分
    }
    // 构造器定义结束
}

从以上的结构我们看到,构造器的声明格式与方法类似:

  • 以权限修饰符开头
  • 不能被static、final、abstract等修饰符修饰
  • 无返回值类型
  • 方法名称与类名相同
  • 一个类中可以出现多个构造方法,区别在于参数列表不同

那么,在这个构造方法当中我们都应该写些什么呢?还是从构造器的作用入手,既然他的作用是初始化一个对象,那么对象在初始化时最需要做的就是对属性赋值,所以如果有需要我们会在调用时传入某些属性的初始值,或者在对象初始化时执行某些代码,帮助我们判断对象初始化的状态。

public class Student{
    public Student(){
        System.out.println("学生对象初始化成功");
        // 其他代码
    }
}
public class Test{
    public static void main(String[] args){
        Student student = new Student();
        // 执行效果 -> 输出:学生对象初始化成功
    }
}

对于创建对象时为属性赋值的用法将在构造器的重载中演示。

3. 隐式构造器

在刚刚开始学习面向对象部分时,可能都会存在一个疑问,之前定义的class都没有定义构造器呀,不是一样可以通过new来创建实例吗?这是因为当一个类被定义后,如果没有手动的创建任何的构造方法,会默认提供一个空的构造器,供初始化使用,这个过程是编译时完成的。

public class Person{
}

我们对Person类进行编译,得到Person.class文件,然后我们对class文件进行反编译,就可以看到已经出现了一个空的构造器:

Java程序在执行时,加载的都是.class文件,并且所生成的.class文件与我们定义的.java文件一般都是存在差异的。所以这就能够解释,为什么明明我们在.java文件中没有定义构造器,但是在创建对象时却可以使用new调用到。

隐式构造器还有一个特点,就是如果我们已经手动创建了一个无参的构造器,或者一个有参的构造器,那么在编译时就不会生成无参构造器了。

public class Person{
    public Person(String name){
        System.out.println(name);
    }
}

此时,由于我们已经手动指定了一个构造器了,所以在编译时就不会再产生默认的无参构造器了,只会有自己手动定义的构造器:

那么,大家应该也注意到了一个问题,既然用new创建对象时是调用的构造器,那么现在我们自己定义了一个有参数的构造器,那么就会使得我们最常使用的new Person()这种实例化的代码报错,因为此时类中已经没有无参构造器可供调用了,也可以认为无参的构造器被覆盖了,必须要传入一个参数才能初始化对象。

public class Test{
    public static void main(String[] args){
        Person person = new Person();
        // 编译不通过,已经无法调用无参构造器来初始化对象
    }
}

那么如果我们还是想用这个无参构造器来创建对象该怎么办呢?没错,手动声明一下就好了,里面不需要写任何内容:

public class Person{
    // 无参构造器
    public Person(){}
    // 有参构造器,可以接收一个参数
    public Person(String name){
        System.out.println(name);
    }
}

我们来看一下效果,很明显,将会同时存在两个构造器,我们在使用new进行对象初始化的时候可以根据需要来使用。

`

public class Test{
    public static void main(String[] args){
        Person person1 = new Person();
        // 编译通过,执行后person1被成功实例化,无输出
        Person person2 = new Person("小明");
        // 编译通过,执行后person2被成功实例化,输出:小明
    }
}

4. 构造器的重载

从上面的例子我们已经可以看到,一个类结构中可以存在多个构造器,用于在有不同需要时被调用。而且由于构造器本身的主要作用是用于为类的属性赋初始值,所以在构造器中我们会指定一些参数,用于被调用时传入,为当前类的属性赋值。

public class Person{
    // 无参构造器
    public Person(){}
    // 两参构造器,可以给name和age属性赋值
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    // 三参构造器,可以给name、age和job属性赋值
    public Person(String name,int age,String job){
        this.name = name;
        this.age = age;
        this.job = job;
    }
    public String name;
    public int age;
    public String job;
}

在上面的代码中我们可以看到有三个构造器,名称相同,只有参数列表不同,这种关系被称为重载,在方法中也有类似的概念。可以看到构造器中存在部分代码,且都是赋值语句。

  • this关键字的用法

this可以指代当前对象,使用this可以调用出直接在类下定义的成员(变量和方法),其中一个最主要的作用就是可以区分同名的变量。我们在进行变量命名时,一直强调见名知意,那么问题就来了:在类中定义的成员变量名称已经确定了,而构造器中传入的参数就是为了给这些属性赋值的,那么参数的名称是不是应该和类成员变量一样才更能表达意思呢?如果这样的话就造成了参数列表中的变量名称与类成员变量的名称同名,这时就可以通过this来区分。

明确了this的用法,我们再来看构造器中的内容就很好理解了,将传入的参数赋值给当前对象的类成员变量,具体的调用过程我们看下面的例子。

三、构造器的调用

src
└──edu
    └──sandtower
        └──bean
            │    Person.java
        └──test
            │    Test.java

以上为实体类与测试类所在的目录结构,Person实体类所在包:edu.sandtower.bean,Test测试类所在包:edu.sandtower.test,则代码如下:

package edu.sandtower.bean;
public class Person{
    // 无参构造器
    public Person(){}
    // 三参构造器,可以给name、age和job属性赋值
    public Person(String name,int age,String job){
        this.name = name;
        this.age = age;
        this.job = job;
    }
    public String name;
    public int age;
    public String job;
}
package edu.sandtower.test;
// 导包操作:指明需要使用的Person类的所在位置
import edu.sandtower.bean.Person;
public class Test{
    public static void main(String[] args){
        Person person1 = new Person();
        // person1被成功实例化,各属性无初始值,可以手动赋值
        person1.name = "小张";
        person1.age = 26;
        person1.job = "Linux运维工程师";
        Person person2 = new Person("小李",25,"Java开发工程师");
        // person2被成功实例化,并具有如下初始值
        // name:小李
        // age:25
        // job:Java开发工程师
        // 输出进行验证
        System.out.println("name:" + person2.name);
        System.out.println("age:" + person2.age);
        System.out.println("job:" + person2.job);
    }
}

在进行对象的初始化时,可以根据需要取得一个空的对象(如:person1)后手动赋值,也可以通过有参构造器直接对属性赋值(如:person2),避免逐一赋值的麻烦。

目录
相关文章
|
2月前
|
设计模式 网络协议 数据可视化
Java 设计模式之状态模式:让对象的行为随状态优雅变化
状态模式通过封装对象的状态,使行为随状态变化而改变。以订单为例,将待支付、已支付等状态独立成类,消除冗长条件判断,提升代码可维护性与扩展性,适用于状态多、转换复杂的场景。
343 0
|
2月前
|
人工智能 监控 Java
Java与AI智能体:构建自主决策与工具调用的智能系统
随着AI智能体技术的快速发展,构建能够自主理解任务、制定计划并执行复杂操作的智能系统已成为新的技术前沿。本文深入探讨如何在Java生态中构建具备工具调用、记忆管理和自主决策能力的AI智能体系统。我们将完整展示从智能体架构设计、工具生态系统、记忆机制到多智能体协作的全流程,为Java开发者提供构建下一代自主智能系统的完整技术方案。
457 4
|
3月前
|
人工智能 Java API
Java AI智能体实战:使用LangChain4j构建能使用工具的AI助手
随着AI技术的发展,AI智能体(Agent)能够通过使用工具来执行复杂任务,从而大幅扩展其能力边界。本文介绍如何在Java中使用LangChain4j框架构建一个能够使用外部工具的AI智能体。我们将通过一个具体示例——一个能获取天气信息和执行数学计算的AI助手,详细讲解如何定义工具、创建智能体并处理执行流程。本文包含完整的代码示例和架构说明,帮助Java开发者快速上手AI智能体的开发。
1220 8
|
3月前
|
人工智能 缓存 监控
使用LangChain4j构建Java AI智能体:让大模型学会使用工具
AI智能体是大模型技术的重要演进方向,它使模型能够主动使用工具、与环境交互,以完成复杂任务。本文详细介绍如何在Java应用中,借助LangChain4j框架构建一个具备工具使用能力的AI智能体。我们将创建一个能够进行数学计算和实时信息查询的智能体,涵盖工具定义、智能体组装、记忆管理以及Spring Boot集成等关键步骤,并展示如何通过简单的对话界面与智能体交互。
1090 1
|
3月前
|
Java 开发者
Java 函数式编程全解析:静态方法引用、实例方法引用、特定类型方法引用与构造器引用实战教程
本文介绍Java 8函数式编程中的四种方法引用:静态、实例、特定类型及构造器引用,通过简洁示例演示其用法,帮助开发者提升代码可读性与简洁性。
|
4月前
|
缓存 安全 Java
Java反射机制:动态操作类与对象
Java反射机制是运行时动态操作类与对象的强大工具,支持获取类信息、动态创建实例、调用方法、访问字段等。它在框架开发、依赖注入、动态代理等方面有广泛应用,但也存在性能开销和安全风险。本文详解反射核心API、实战案例及性能优化策略,助你掌握Java动态编程精髓。
|
4月前
|
存储 人工智能 JavaScript
Java从作用域到对象高级应用​
本内容详细讲解了JavaScript中的作用域类型(函数作用域、块作用域、全局作用域)、作用域链、垃圾回收机制、闭包、变量提升、函数参数、数组方法、内置构造函数、对象高级知识、原型链、对象赋值、深浅拷贝、递归、异常处理及this指向等内容,全面覆盖JS核心概念与编程技巧。
61 0
|
5月前
|
存储 Java
Java对象的内存布局
在HotSpot虚拟机中,Java对象的内存布局分为三部分:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。对象头包含Mark Word、Class对象指针及数组长度;实例数据存储对象的实际字段内容;对齐填充用于确保对象大小为8字节的整数倍。
126 0
|
存储 Java
重温经典《Thinking in java》第四版之第五章 初始化与清理(三十三)
重温经典《Thinking in java》第四版之第五章 初始化与清理(三十三)
126 0
|
安全 Java 程序员
重温经典《Thinking in java》第四版之第五章 初始化与清理(二十六)
重温经典《Thinking in java》第四版之第五章 初始化与清理(二十六)
185 0