摘要:Java 也采用了构造器,并且还提供了一个垃圾收集器(garbage collector),当不再使用内存资源的时候,垃圾收集器会自动将其释放。

本文分享自华为云社区《一文带你了解 Java 中的构造器》,作者: 宇宙之一粟 。

C ++ 引入了构造器(constructor,也叫构造函数)的概念,它是在创建对象时被自动调用的特殊方法

Java 也采用了构造器,并且还提供了一个垃圾收集器(garbage collector),当不再使用内存资源的时候,垃圾收集器会自动将其释放。

构造器定义

在 Java 中,可以通过编写构造器来确保每个对象的初始化。但是这里有两个问题:

  1. 这个构造器使用的任何名字都有可能与类里某个成员相冲突;
  2. 编译器负责调用构造器,所以它必须始终知道应该调用哪个方法。

C++ 语言采用的方案就是将构造器和类的名字定义相同,Java 也采用了这个方案。

构造器的作用是用来建立一个新的类的实例,当一个对象被创建时,JVM 使用一个构造函数,并为其分配内存空间。

语法结构

class ClassName {
ClassName() {
}
}

例如,在下面的示例中,我们创建了一个名为 ReLearnConstructor 的构造函数。在构造函数内部,我们正在初始化 hello 变量的值。:

public class ReLearnConstructor {

String hello; // 属性
// 构造器
public ReLearnConstructor() {
hello = "Hello, Constructor!";
} public static void main(String[] args) { ReLearnConstructor rc = new ReLearnConstructor();
System.out.println(rc.hello);
}
}

注意创建 ReLearnConstructor 类的对象的语句:ReLearnConstructor rc = new ReLearnConstructor();

在这里,当创建对象时,调用 ReLearnConstructor 构造函数。并且,hello 变量的值被初始化。

因此打印的 hello 的值为:

构造器目的

构造函数的目的是初始化对象的状态,为所有声明的属性赋值。如果我们没有自定义构造函数,JVM 就会为这些属性分配默认值。

原始类型的默认值:

  • 整数类型是 0
  • 浮点类型是 0.0
  • 布尔类型是 false

对于其他 Java 引用类型,默认值是null,这意味着引用类型的属性没有被分配任何值。

后面可以用代码查看这些默认值。

构造器分类

在 Java 中,有三种类型的构造器:

  1. 无参构造器
  2. 有参构造器
  3. 默认构造器

无参构造器

与方法类似,Java 构造函数可能有参数,也可能没有任何参数。如果构造函数不接受任何参数,则称为无参数构造器。例如上述代码中 ReLearnConstructor 构造器就是:

// 无参构造器
public ReLearnConstructor() {
hello = "Hello, Constructor!";
}

有参构造器

字面理解,具有参数的构造函数称为有参数构造器。那为什么需要使用有参构造器?

有参构造器可用于为不同对象提供不同初始化的值。 例如:

public class ReLearnConstructor {

String languages;

// 接受单个参数的构造器
public ReLearnConstructor(String lang) {
languages = lang;
System.out.println("我在学习 " + languages + " 语言!");
} public static void main(String[] args) {
// 向构造器中传入不同的值
ReLearnConstructor rc1 = new ReLearnConstructor("Java");
ReLearnConstructor rc2 = new ReLearnConstructor("Go");
ReLearnConstructor rc3 = new ReLearnConstructor("Python");
}
}

运行结果:

默认构造器

如果我们不创建任何构造函数,Java 编译器会在程序执行期间自动创建一个无参数构造函数。这个构造函数称为默认构造函数。来看一个例子;

public class ReLearnConstructor {

String languages;
int a;
boolean b;
float c;
public static void main(String[] args) {
ReLearnConstructor rc = new ReLearnConstructor();
System.out.println("默认值:");
System.out.println("languages:" + rc.languages);
System.out.println("a:" + rc.a);
System.out.println("b:" + rc.b);
System.out.println("c:" + rc.c);
}
}

运行结果:

默认值:
languages:null
a:0
b:false
c:0.0

可以看到,我们还没有创建任何构造函数。因此,Java 编译器会自动创建默认构造函数。上述表格得以印证。

原生方法和构造器的区别

  • 构造函数必须与在 Java 中定义的类具有相同的名称
  • 当方法没有返回任何值时,构造函数不会返回任何类型,而方法则具有返回类型或 void
  • 在对象创建时,仅调用构造函数一次,而方法可以被调用任何次数

如果我们不用构造器来给属性赋值的话,可以先使用 new 运算符获取类的实例,并使用类的 setter 方法设置值,如下:

import java.util.Arrays;
class Person
{
private String name;
private int age;
@Override
public String toString() {
return Arrays.asList(name, String.valueOf(age)).toString();
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
// getters
}
// Initialize an object in Java
class Main
{
public static void main(String[] args)
{
Person person = new Person();
person.setName("Yuzhou1su");
person.setAge(22);
System.out.println(person);
}
}

通过构造器进行初始化就可以省去我们的 setter 方法。

如下的例子:

import java.util.Arrays;
class Person {
private String name;
private int age;
// 构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return Arrays.asList(name, String.valueOf(age)).toString();
}
}
class SimpleConstructor {
public static void main(String[] args) {
Person person = new Person("Yuzhou1su", 22);
System.out.println(person);
}
}

运行结果:

[Yuzhou1su, 22]

构造器重载

与 Java 方法重载类似,我们也可以创建两个或多个具有不同参数的构造函数。这称为构造函数重载。

public class ReLearnConstructor {

String language;

public ReLearnConstructor() {
this.language = "Java";
} // 构造器
public ReLearnConstructor(String language) {
this.language = language;
} public void getName() {
System.out.println("编程语言:" + this.language);
} public static void main(String[] args) {
ReLearnConstructor rc1 = new ReLearnConstructor(); ReLearnConstructor rc2 = new ReLearnConstructor("Python"); rc1.getName();
rc2.getName();
}
}

在上面的例子中,我们有两个构造函数:ReLearnConstructor() 和 ReLearnConstructor(String language)。在这里,两个构造函数都用不同的值初始化变量语言的值。根据创建对象时传递的参数,调用不同的构造函数,分配不同的值。

运行结果:

编程语言:Java
编程语言:Python

拷贝构造器

Java 中的拷贝构造方法是一种使用该类的一个对象构造另外一个对象的构造方法。

复制构造函数是一种特殊构造函数,用于将新对象创建为现有对象的副本。它只需要一个参数,它将是同一类的另一个实例。我们可以使用 this() 语句从复制构造函数中显式调用另一个构造函数:

public class ReLearnConstructor {

private String language;

// 构造器
public ReLearnConstructor(String language) {
this.language = language;
} // 拷贝构造器
public ReLearnConstructor(ReLearnConstructor rc) {
this.language = rc.language;
} public void getName() {
System.out.println("编程语言:" + this.language);
} public static void main(String[] args) {
ReLearnConstructor rc = new ReLearnConstructor("Python"); ReLearnConstructor copyOfrc = new ReLearnConstructor(rc); rc.getName();
copyOfrc.getName();
}
}

运行结果:

编程语言:Python
编程语言:Python

当需要拷贝一个带有多个成员变量的复杂对象或者想构造已存在对象的深拷贝对象时非常有用。

匿名内部类

除了上文介绍的使用构造器的方法,另一种初始化对象的方法是使用“双大括号初始化”。这将创建一个匿名内部类,其中只有一个实例初始化程序。建议不要使用这种方法。

import java.util.Arrays;
class Person
{
private String name;
private int age;
@Override
public String toString() {
return Arrays.asList(name, String.valueOf(age)).toString();
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
// getters
}
// Initialize an object in Java
class Main
{
public static void main(String[] args)
{
// Anonymous class
Person person = new Person() {{
// Initializer block
setName("Yuzhou1su");
setAge(22);
}};
System.out.println(person);
}
}

总结

  • 实例化对象时会隐式调用构造函数。
  • 创建构造函数的两条规则是:构造函数的名称应与类相同。Java 构造函数不能有返回类型。
  • 如果一个类没有构造函数,Java 编译器会在运行时自动创建一个默认构造函数。默认构造函数使用默认值初始化实例变量。例如 int 变量将被初始化为 0
  • 构造函数类型:
  • 无参构造器 - 不接受任何参数的构造函数参数化构造函数
  • 接受参数的构造器 - 接受参数的构造函数
  • 默认构造器 - 如果没有明确定义,Java 编译器会自动创建一个构造函数。
  • 构造函数不能被 abstract、static 或 final 修饰

编译器会报如下错误:

Illegal modifier for the constructor in type ReLearnConstructor; only public, protected & private are permitted
  • 构造函数可以重载但不能被覆盖

点击关注,第一时间了解华为云新鲜技术~

一文了解 Java 中的构造器的更多相关文章

  1. Java中的构造器与垃圾回收

    构造器 在我们初始化对象时,如果希望设置一些默认值,那么就可以使用构造器,在Java中,构造器使用和类同名的名字且没有返回值,如下 class Test{ private String name; T ...

  2. Java中是构造器创建对象吗?

    首先,这里说明” Java中是构造器创建对象 “这句话是完全错误的. Java中构造器的作用主要是为了初始化变量的值...其实在执行构造器之前,Java对象所需要的内存空间,已经产生了... 一般可以 ...

  3. java中的构造器

    构造器是什么 1.构造器,也称构造方法.构造函数.作用是构造出来一个类的实例,确保对象得到初始化. 2.构造器的格式: 权限修饰符 类名(无参/有参){}. 3.根据有无参数,可分为无参构造 和有参构 ...

  4. 一文解开java中字符串编码的小秘密

    目录 简介 Unicode的发展史 Unicode详解 UTF-8 UTF-16 UTF-32 Null-terminated string 和变种UTF-8 简介 在本文中你将了解到Unicode和 ...

  5. 【Java基本功】一文了解Java中继承、封装、多态的细节

    本节主要介绍Java面向对象三大特性:继承 封装 多态,以及其中的原理. 本文会结合虚拟机对引用和对象的不同处理来介绍三大特性的原理. 继承 Java中的继承只能单继承,但是可以通过内部类继承其他类来 ...

  6. Java中初始化的相关问题

    目录 局部变量的初始化 成员变量的初始化 构造器初始化 静态数据的初始化 总结 已经快半个月没写博客了,这周在看 Thinking in Java 这本书,准备将书中的第五章和第七章的内容整合一下,写 ...

  7. Java:API文档;文档注释中的javadoc标记;官方API;自己动手给项目建一个API文档

    1.什么是API文档 在Java语言中有3种注释 //单行注释 /* 多行注释 */ /** * 文档注释 */ API(应用程序接口)文档就是用javadoc命令提取文档注释生成的,html格式,用 ...

  8. java中的xpath,读取xml文档。

    1,入门 XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言. XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力.起初 X ...

  9. 关于Java中基类构造器的调用问题

    在<Java编程思想>第7章复用类中有这样一段话,值得深思.当子类继承了父类时,就涉及到了基类和导出类(子类)这两个类.从外部来看,导出类就像是一个与基类具有相同接口的新类,或许还会有一些 ...

随机推荐

  1. Python列表解析式的正确使用方式

    先来逼逼两句: Python 是一种极其多样化和强大的编程语言!当需要解决一个问题时,它有着不同的方法.在本文中,将会展示列表解析式 (List Comprehension).我们将讨论如何使用它?什 ...

  2. python线程池 ThreadPoolExecutor 的用法及实战

    写在前面的话 (https://jq.qq.com/?_wv=1027&k=rX9CWKg4) 文章来源于互联网从Python3.2开始,标准库为我们提供了 concurrent.future ...

  3. Nacos 的安装与服务的注册

    Nacos 的安装与服务的注册 我们都知道naocs是一个注册中心,那么注册中心是什么呢? 什么是注册中心? 它类似与一个中介角色(不收费的良心中介), 在微服务中起纽带的作用,它提供了服务和服务地址 ...

  4. 关于cpu体系架构的一些有趣的故事分享

    从排查一次匪夷所思的coredump,引出各种体系架构的差异. 本文中的所有内容来自学习DCC888的学习笔记或者自己理解的整理,如需转载请注明出处.周荣华@燧原科技 1 背景 从全世界有记载的第一台 ...

  5. Solution -「HNOI2013」消毒

    弱化一下,先考虑在二维上解决问题. 题目就转化为:有 \(n\) 个点 \((i, j)\) 需要被覆盖,而我们每次可以选一行或一列去覆盖,求覆盖所有点的最少选择次数. 如果我们对于每一个 \((i, ...

  6. 我有 7种 实现web实时消息推送的方案,7种!

    技术交流,公众号:程序员小富 大家好,我是小富- 我有一个朋友- 做了一个小破站,现在要实现一个站内信web消息推送的功能,对,就是下图这个小红点,一个很常用的功能. 不过他还没想好用什么方式做,这里 ...

  7. Kubernetes v1.24 基于containerd部署

      k8s每个节点安装containerd.   containerd安装参考<containerd安装博文>:https://www.cnblogs.com/punchlinux/p/1 ...

  8. 【高并发】通过源码深度分析线程池中Worker线程的执行流程

    大家好,我是冰河~~ 在<高并发之--通过ThreadPoolExecutor类的源码深度解析线程池执行任务的核心流程>一文中我们深度分析了线程池执行任务的核心流程,在ThreadPool ...

  9. TCP通信的概述

  10. 面试突击69:TCP 可靠吗?为什么?

    相比于 UDP 来说,TCP 的主要特性是三个:有连接.可靠.面向数据流.所谓的"有连接"指的是 TCP 中的连接管理机制,也就是著名的三次握手和四次挥手,就像打电话一样,想要正常 ...