面向对象 03:类与对象的创建、初始化和使用,通过 new 关键字调用构造方法,以及创建对象过程的内存分析

news2025/1/12 12:15:26

一、前言

记录时间 [2024-05-10]

系列文章简摘:
Java 笔记 01:Java 概述,MarkDown 常用语法整理
Java 笔记 11:Java 方法相关内容,方法的设计原则,以及方法的定义和调用
面向对象 01:Java 面向对象相关内容整体概述
面向对象 02:区分面向过程与面向对象,类和对象的关系

更多 Java 相关文章,请参考专栏哦。

本文内容主要关于类与对象的创建、初始化和使用,以及如何通过 new 关键字调用构造方法。此外,文章还对无参 / 有参这两种构造器进行描述,并通过内存分析创建对象的过程


二、类与对象的创建

以类的形式组织代码,以对象的形式封装数据。

1. 关键字 new

在 Java 中,关键字 new 是一个非常重要的运算符。

使用 new 关键字创建对象时:

  • 为该对象分配进行内存分配
  • 给对象进行默认的初始化
  • 在类中使用构造器进行调用。

2. 关键字 this

在 Java 中,关键字 this 是一个非常重要的引用,它在类的方法或构造器中使用,通常用于引用当前对象或当前实例的引用。

具体如下:

引用当前对象

类的内部this 关键字用来指代当前正在操作的这个类的对象实例。

当方法内部的局部变量与类的成员变量同名时,this 可以帮助明确指代成员变量,避免混淆。

例如:

public class Person {
    String name;

    public void setName(String name) {
        
        // 这里的 this.name 指的是 Person 类的成员变量 name
        this.name = name; 
    }
}

调用当前类的构造器

在一个构造器中,可以使用 this 关键字调用本类中的其他构造器。这种机制简化了代码,避免了重复初始化代码。

但是,必须作为构造器的第一条语句,并且只能在非静态构造器中使用。

例如:

public class Person {
    String name;
    int age;

    public Person() {
        this("未知", 0); // 调用带有两个参数的构造器
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

作为方法的参数传递

可以使用 this 关键字将当前对象作为一个参数传递给其他方法。

例如:

先编写一个 Person 类,在 introduce() 方法中调用 display() 方法,并将当前类的对象作为参数传递。

public class Person {
    
    // Person 类中的 name 属性的对象是 zhangsan
    String name = "zhangsan";
    
    void display(Person friend) {
        System.out.println("朋友的名字是: " + friend.name);
    }

    void introduce() {
        display(this); // 将当前对象作为参数传递
    }
}

接着,在 main ()方法中,实例化一个 Person 类,并调用该类中的 introduce() 方法,得到输出结果。

public static void main(String[] args) {

    // 实例化一个 Person 类
    Person person = new Person();
    
    // 调用该类中的方法
    person.introduce();

}

// 得到输出结果:朋友的名字是: zhangsan

返回当前对象的引用

在某些情况下,可以让方法返回 this,以便实现链式调用或者构建流式接口。

例如:

public class StringBuilderExample {
    
    StringBuilder sb = new StringBuilder();

    public StringBuilderExample append(String str) {
        sb.append(str);
        return this; // 返回当前对象,允许链式调用
    }
}

3. 创建和初始化对象

在 Java 中,创建和初始化对象是一个基本且核心的过程,以下是创建和初始化对象的基本步骤。

准备学生类

在类中,只能写属性和方法。

先准备学生类 Student 用于创建和初始化对象的演示。该类中,包含 name 和 age 两个属性,以及一个 study 方法。

// 学生类
public class Student {

    // 属性:字段
    String name;    // null
    int age;        // 0

    // 方法
    public void study() {
        System.out.println(this.name + "在学习");
    }
}

创建和初始化

Application 类中,创建 main 方法。注意,一个项目应该只有一个 main 方法。

使用 new 关键字,以及默认构造器创建 Student 对象。

在这个示例中,为 Student 类创建了 xiaoming 和 zhangsan 两个对象,并分别给它们赋值。

public static void main(String[] args) {

    // 类:抽象的,实例化
    // 类实例化后返回一个自己的对象
    // student 对象就是一个 Student 类的具体实例

    Student xiaoming = new Student();
    Student zhangsan = new Student();

    // 给 xiaoming 对象赋值
    xiaoming.name = "小明";
    xiaoming.age = 3;
    System.out.println(xiaoming.name);
    System.out.println(xiaoming.age);

    // 给 zhangsan 对象赋值
    zhangsan.name = "张三";
    zhangsan.age = 3;
    System.out.println(zhangsan.name);
    System.out.println(zhangsan.age);

}

使用

  • 使用对象的属性:student.name
  • 使用对象的方法:student.study()

三、构造器

1. 构造器概述

在 Java 中,类的构造器,也称为构造方法,是一种特殊类型的方法。

构造器的主要职责是初始化新创建的对象,是在进行创建对象的时候必须要调用的。通过使用构造器,开发者能够灵活地控制对象实例化的细节。

构造器具有以下特点和规则:

  • 名称匹配:构造器的名称必须与类名完全相同,这是区分构造器与其他方法的基本方式。
  • 无返回类型:构造器没有返回类型声明,即使它实际上隐式地返回了新创建的实例的引用,也不需要像普通方法那样声明一个返回类型。
  • 自动调用:每当使用 new 关键字创建类的实例时,相应的构造器会自动被调用
  • 初始化:构造器的主要任务是对新创建对象的成员变量进行初始化,可以设置默认值或者基于传入参数进行特定的初始化。
  • 重载:构造器支持重载,意味着在同一个类中可以有多个构造器,只要它们的参数列表不同即可。这样可以根据不同的场景提供多种初始化方式。
  • 默认构造器:如果一个类没有定义任何构造器,Java 编译器会自动为该类生成一个默认(无参数)构造器。

注意:一旦为类定义了一个或多个构造器,编译器就不会再自动生成默认构造器。


2. 无参 / 有参构造器

下面是一个简单的 Java 类及其无参 / 有参构造器的示例:

public class Student {
    String name;
    int age;

    // 默认构造器
    public Student() {
        this.name = "匿名";
        this.age = 0;
    }

    // 带参数的构造器
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 其他方法...
}

在这个例子中,Student 类有两个构造器:

  • 一个是无参数的默认构造器,用于创建一个名字默认为"匿名"、年龄默认为 0 的学生对象;
  • 另一个构造器接受两个参数,允许在创建对象时指定学生的姓名和年龄。

3. 构造器的作用

使用 new 关键字,本质上是在调用构造器,构造器一般用于初始化值。可分为无参构造有参构造

无参构造

一个类即使什么都不写,它也会有一个默认构造方法,即无参数构造器。

例如,Person 类中的构造默认构造器 Person()。当 Person 类中没有写构造方法时,Person() 默认存在。

public Person() {
}

当然,我们可以显式地定义构造器,使其具备实例化初始值的功能。

如图所示,在默认构造器中为 name 属性赋初值。

public Person() {
    this.name = "yuanyuan";
}

当使用 new 关键字实例化 person 对象时,它会调用默认构造器,并为 name 属性赋初值 yuanyuan,所以 person.name 的值为 yuanyuan

在这里插入图片描述


有参构造

一旦定义了有参构造,Java 就不会默认生成无参构造器。因此,此时无参构造需要显式定义。

生成一个带参构造器:(快捷键 alt+insert,或者右键 Generate

// 使用 alt+insert 快速生成构造器
public Person(String name) {
    this.name = name;
}

使用 new 关键字实例化对象的同时,传递值:

Person person1 = new Person("zhangsan");

它会调用带参构造器,并为 name 属性赋初值 zhangsan,所以 person1.name 的值为 zhangsan

在这里插入图片描述


四、内存分析

1. 以 Pet 类为例

准备一个 Pet 类:

public class Pet {
    String name;
    int age;
    
    public void shout() {
        System.out.println("叫了一声");
    }
}

2. 内存分析

在 Java 中,创建对象的过程涉及内存管理的几个关键区域,主要包括栈内存、堆内存和方法区

第一步

在代码中声明一个对象变量时,比如 Pet pet;,变量 pet 会被分配在栈内存中。此时,变量 pet 仅是一个引用(可以理解为一个地址),并没有指向实际的对象。

第二步

使用 new 关键字创建对象,如 pet = new Pet(); 时,Java 在堆内存中分配一块足够大的内存空间来存放 Pet 对象的所有实例变量。

这些实例变量包括基本类型,以及引用类型。

创建后,这些实例变量被默认初始化,基本类型的默认值(如 int=0, boolean=false 等),引用类型为 null 值。

同时,相应的构造器会被执行,用于初始化这些实例变量(如果有的话)。构造器可以设置初始值,执行一些初始化逻辑等。

第三步

完成对象创建和初始化后,堆内存中对象的地址会被复制给栈内存中的变量 pet

此时,pet 变量就指向了堆内存中的实际对象。

第四步

可以使用对象中的属性和方法。比如,分别给 Pet 类的 dog 对象和 cat 对象的属性 name 赋值。

Pet dog = new Pet();
Pet cat = new Pet();

赋值方法:

dog.name="旺财";
cat.name="喵喵";

接着分别调用 shout() 方法:

dog.shout();
cat.shout();

其他

类的元数据(如类名、父类、实现的接口、静态变量、静态方法等)存储在方法区或元数据区

当类第一次被加载时,其相关信息就会被放入此区域。构造器的信息也位于此区域。

通过这个过程,Java 确保了对象的创建是安全且高效的,同时也支持了垃圾回收机制,自动管理不再使用的对象所占用的内存空间。


此处附上一张创建对象内存分析的配图,来源于《狂神说 Java》配图。

主要是为了说明:为什么不同的对象调用同一个类的同一个属性,比如 namedog.namecat.name 是不一样的。

在这里插入图片描述


五、总结

本文内容主要关于类与对象的创建、初始化和使用,以及如何通过 new 关键字调用构造方法。此外,文章还对无参 / 有参这两种构造器进行描述,并通过内存分析创建对象的过程


一些参考资料

狂神说 Java 零基础:https://www.bilibili.com/video/BV12J41137hu/
TIOBE 编程语言走势: https://www.tiobe.com/tiobe-index/
Typora 官网:https://www.typoraio.cn/
Oracle 官网:https://www.oracle.com/
Notepad++ 下载地址:https://notepad-plus.en.softonic.com/
IDEA 官网:https://www.jetbrains.com.cn/idea/
Java 开发手册:https://developer.aliyun.com/ebook/394
Java 8 帮助文档:https://docs.oracle.com/javase/8/docs/api/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1661166.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数学:人工智能领域的基石与灵魂

在科技日新月异的今天,人工智能(AI)已经渗透到了我们生活的方方面面,从智能家居、智能医疗到自动驾驶、智能客服,AI无处不在。然而,当我们赞叹于AI的神奇时,却往往忽视了其背后的推动力——数学…

Leetcode—2105. 给植物浇水 II【中等】

2024每日刷题&#xff08;131&#xff09; Leetcode—2105. 给植物浇水 II 实现代码 class Solution { public:int minimumRefill(vector<int>& plants, int capacityA, int capacityB) {int size plants.size();int i 0;int j size - 1;int capA capacityA;in…

结合创新!通道注意力+UNet,实现高精度分割

在U-Net网络中加入通道注意力机制能显著提升模型的性能&#xff01; 具体点说是在U-Net的卷积层之后添加一个通道注意力模块&#xff0c;这样这个模块可以学习不同通道之间的权重&#xff0c;并根据这些权重对通道进行加权&#xff0c;从而增强重要通道的特征表示。 这种结合…

【WebGIS实例】(14)MapboxGL 加载地形高程数据

前言 官网示例&#xff1a;Add 3D terrain to a map | Mapbox GL JS | Mapbox 大佬博客&#xff1a;Mapbox GL基础&#xff08;七&#xff09;&#xff1a;地形数据的处理与加载 (jl1mall.com) 加载Mapbox地形数据 map.once(style.load, () > {map.addSource(mapbox-dem,…

常见扩频系统的基础概念和模型

扩频系统是一种通信技术&#xff0c;它通过将信号的频谱扩展到一定程度来实现传输&#xff0c;这种系统的设计和实现涉及到多种不同的方法和技术。 扩频系统的主要特点和好处包括&#xff1a; 抗干扰能力强&#xff1a;由于信号被扩展到较宽的频带上&#xff0c;单位带宽内的功…

代码随想录算法训练营第六十二天|503.下一个更大元素II、42.接雨水

代码随想录算法训练营第六十二天|503.下一个更大元素II、42.接雨水 503.下一个更大元素II 给定一个循环数组 nums &#xff08; nums[nums.length - 1] 的下一个元素是 nums[0] &#xff09;&#xff0c;返回 nums 中每个元素的 下一个更大元素 。 数字 x 的 下一个更大的元…

jenkins使用gitLab(极狐)认证登陆

jenkins安装 GitLab Authentication插件 我因为java版本和最新GitLab Authentication 1.19版本不兼容&#xff0c;选择了本地安装 找个历史版本1.13版本&#xff0c;然后下载到电脑上 - 本地上传插件并安装 在极狐上创建一个应用 - 配置应用信息 应用名&#xff1a;jenkinsLo…

GAMMA Lab——知识图谱和LLM大模型

图机器学习的发展与分类 图基础模型 LLM基础模型 GNN LLM 前沿工作

【Web后端】servlet基本概念

1.ServletAPI架构 HttpServlet继承GenericServletGenericServlet实现了Servlet接口&#xff0c;ServletConfig接口,Serializable接口自定义Servlet继承HttpServlet 2.Servlet生命周期 第一步&#xff1a;容器加载Servlet第二步&#xff1a;调用Servlet的无参构造方法&#xf…

Oracle -在线回缩表

conn scott/tiger DROP TABLE EMP1 PURGE; CREATE TABLE EMP1 AS SELECT * FROM EMP; alter table emp1 enable row movement; -- 启动回缩特性 insert into emp1 select * from emp1; / / commit; -- 增加到14000行 -- 分析表的结构 analyze table emp1 comput…

mysql从库SHOW SLAVE STATUS字段详解

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 mysql从库SHOW SLAVE STATUS字段详解 前言输出字段展示字段说明 前言 在数据库的舞台上&#xff0c;主从同步就像是一场华丽的舞蹈&#xff0c;而SHOW SLAVE STATUS命令则是这场舞蹈的灯光&#xff0…

Spark Streaming笔记总结(保姆级)

万字长文警告&#xff01;&#xff01;&#xff01; 目录 一、离线计算与流式计算 1.1 离线计算 1.1.1 离线计算的特点 1.1.2 离线计算的应用场景 1.1.3 离线计算代表技术 1.2 流式计算 1.2.1 流式计算的特点 1.2.2 流式计算的应用场景 1.2.3 流式计算的代表技术 二…

10个超实用的Excel技巧!207套Excel模板(电商、数据分析、排班表、工作计划表)

职场如战场&#xff0c;掌握Excel技能&#xff0c;让你的工作效率飙升&#xff01; 今天&#xff0c;我给大家分享10个Excel的超实用技巧&#xff0c;让你从Excel小白秒变大神&#xff01; 1️⃣ 快速求和&#xff1a;使用 Alt 一键求和&#xff0c;告别手动输入SUM函数。 …

【HMWeb】HTML使用Leaflet实现本地离线地图Gis应用

下载Leaflet 官网下载&#xff1a;https://leafletjs.com/reference.html CSDN&#xff1a;https://download.csdn.net/download/hmxm6/89291989 选择版本号 添加html文件 加入代码 <!DOCTYPE html> <html lang"en"> <head><meta charset&qu…

智慧公厕解决什么问题?实现了什么样的价值?

公共厕所一直是城市管理的难题&#xff0c;常常面临着卫生条件不佳、管理不善以及使用体验差等问题。为了解决这些困扰城市的难题&#xff0c;智慧公厕应运而生。智慧公厕不仅应用了信息化和数字化技术&#xff0c;还通过全方位的智能化应用&#xff0c;彻底改变了传统公厕的面…

(十)JSP教程——config对象

config对象是脚本程序配置对象&#xff0c;表示当前JSP页面的配置信息。由于JSP页面通常无需配置&#xff0c;因此该对象在JSP页面中比较少见。 config对象可以读取一些初始化参数的值&#xff0c;而这些参数一般在web.xml配置文件中可以看到&#xff0c;并通过config对象的相应…

Python写了for i in range(10)却只打印一遍?

题目&#xff1a;定义一个两个参数的重复打印函数&#xff0c;第一个参数指定要打印的字符串&#xff0c;第二个参数指定要重复打印的次数&#xff0c;在主程序中调用该函数&#xff0c;打印10遍你的学号姓名。 为什么调用函数后结果只打印了一遍? 看了题目感觉就很诡异&#…

计算图与自动微分

计算图与自动微分 一、自动梯度计算1.1 数值微分&#xff08;Numerical Differentiation&#xff09;1.2 符号微分&#xff08;Symbolic Differentiation&#xff09;1.3 自动微分&#xff08;Automatic Differentiation&#xff0c;AD&#xff09;1.3.1 计算图1.3.2 正向传播1…

Vue3:项目创建

Vue 3 相对于 Vue 2 带来了许多改进和优点&#xff0c;这些改进主要是为了提高性能、开发体验和可维护性。但是对于创建项目&#xff0c;Vue3也可以采用跟Vue2相同的方式。 使用CLI创建 1. 安装Vue CLI 首先&#xff0c;确保你已经安装了Node.js&#xff08;建议使用LTS版本…

深入理解nginx http响应限速功能

目录 1. 引言2. 配置参数2.1 limit_rate 配置指令2.2 limit_rate_after 配置指令2.3 其他限速配置 3. 源码分析 1. 引言 在现代互联网应用中&#xff0c;服务器的性能和响应速度是至关重要的。为了保证服务器的稳定性和可靠性&#xff0c;限制客户端对服务器的访问速度是一项重…