Java——方法详细介绍

一、方法调用机制

1、方法调用机制详细介绍

下面对方法调用在内存中的情况进行分析,以下面的代码为例:

public class Test {public static void main(String[] args) {Person person = new Person();person.name = "张三";person.age = 18;int res = person.calcSum(1,2);}
}class Person {String name;int age;//求两个数字的和的方法public int calcSum(int num1,int num2) {return (num1 + num2);}
}

在执行语句

Person person = new Person();

时,会在堆区创建一个对象,然后在 main 函数的栈帧中会创建一个对象引用变量,这个引用变量中存储的引用就是刚才创建的对象的引用。

然后执行下面这两句代码,

person.name = "张三";
person.age = 18;

对对象的属性初始化。

然后执行下面的代码,

int res = person.calcSum(1,2);

这里在调用对象 person 的方法时,会再开辟一个栈帧,就是 calSum 的栈帧,

方法内的局部变量和方法的参数在被调用时存储在方法的栈帧中。

这里的参数是基本数据类型,所以传参进行的是值拷贝,将实际参数的值直接拷贝给在 calSum 栈帧中的形式参数变量,然后进行计算,最后返回值,在方法返回后,它的栈帧就会被销毁,将返回值赋给变量 res。

这里我们发现在调用一个方法时会开辟方法对应的栈帧,再这个方法返回时,它的栈帧就会被销毁。

最后当程序退出时,main 函数栈帧也会被销毁。

二、方法调用细节

方法内部不能再定义方法。

1、访问修饰符

类的属性有访问修饰符,类的成员方法也有访问修饰符,与类的属性一致。

访问修饰符:

在Java中,访问修饰符(Access Modifiers)用于控制类、方法和属性(字段)的可见性。它们决定了其他类是否能够访问特定的类成员(属性或方法)。Java中有四种主要的访问修饰符:

  1. public
  2. protected
  3. (什么都不写时的访问级别为默认)
  4. private
修饰符当前类同一个包子类(不同包)其他包
public
protected×
默认××
private×××

2、方法返回值

返回数据类型

如果方法声明中有返回数据类型,则方法体中的执行语句必须有 return 语句。return 语句用来返回与返回值类型一致或兼容(可以自动类型转换)的值。

无返回值类型

如果方法返回值类型是 void,则方法体中可以有 return 语句,就像下面这样:

return;

只写一个 return ,不返回任何值。或者可以没有 return 语句。void 表示方法不返回任何值。

3、每个方法只能返回一个值

每个方法只能返回一个值,那如果要返回多个值怎么办呢,就可以使用以下方法:

    public int[] example(int num1,int num2) {//...int[] arr = new int[2];//...return arr;}

这样在堆区创建一个数组对象,然后返回其引用,就可以实现返回的引用可以访问一个数组,就可以通过这个数组存储多个值了。

对于这里所说的返回数组类型,实际上返回的不是一整个数组,而是数组的引用。

所以在我们调用这个方法时,也要使用数组引用变量来接受其返回值。

int[] arr = example(1,2);

4、形参和实参

形参是指在方法声明中定义的参数,它们作为占位符,用于接收调用者传递的实际参数值。

  1. 定义位置:形参定义在方法的参数列表中。
  2. 作用范围:形参的作用范围仅限于方法内部。
  3. 数据类型:形参需要指定类型,可以是基本数据类型或引用数据类型。
public class Example {// 形参是 a 和 bpublic int add(int a, int b) {return a + b;}
}

在上述示例中,ab 是形参。

实参是指在方法调用时传递给方法的实际值或对象,这些实际值或对象被传递给形参。

  1. 定义位置:实参在方法调用时提供。
  2. 传递方式:实参的值或引用被复制给形参,在方法执行过程中使用。
  3. 类型匹配:实参的类型必须与形参的类型兼容。
public class Test {public static void main(String[] args) {Example example = new Example();// 实参是 5 和 3int result = example.add(5, 3);System.out.println("Result: " + result);}
}

在上述示例中,53 是实参。

在方法调用时,实参的类型必须与形参的类型匹配或兼容。例如,如果形参是 int 类型的,实参也必须是 int 类型或可以隐式转换为 int 类型。

三、方法传参机制

上面我们提到方的形参和实参,下面我们介绍一下方法的传参机制。Java中的方法参数传递机制是值传递(Pass-by-Value),对于基本类型的参数,传递的是数据的副本;对于引用类型的参数,传递的是对象的引用副本。

1、基本数据类型传参

下面我们看一个经典的例子:

public class Test {public static void swap(int a, int b) {int temp = a;a = b;b = temp;}public static void main(String[] args) {int num1 = 1;int num2 = 2;swap(num1,num2);System.out.println("num1 = " + num1 + "\nnum2 = " + num2);}
}

运行这段代码,运行结果为:

可以发现这里两个变量的值并未完成交换。这是为什么呢?

在主函数中调用 swap 函数时,会开辟 swap 函数的栈帧,然后形参变量会存储在 swap 函数的栈帧中,然后会将主函数中的两个变量的值拷贝(赋值)给 swap 函数栈帧中的两个形参变量。

然后会进行 swap 函数栈帧中的两个形参变量的值的交换,这个操作不会影响 main 函数栈帧中的两个实参变量,因为 swap 栈帧中的两个形参变量和 main 函数栈帧中的两个实参变量是相互独立的变量。

然后 swap 函数的语句执行完成后,swap 栈帧会被销毁,两个 swap 中的形参变量也被销毁。

这时 main 函数中的两个实参变量没有受到任何影响,所以还是原样,所以实参的值没有被交换。

所以说对于基本数据类型(如 intfloatchar 等),传递的是值的副本。方法内部对形参的修改不会影响实际参数的值。因为形参和实参是两个独立的变量,修改其中一个变量的值对另一个变量没有影响。

例如:

public class ValuePassing {public static void modifyPrimitive(int number) {number = 10;}public static void main(String[] args) {int original = 5;modifyPrimitive(original);System.out.println("Original value after method call: " + original);}
}

输出结果:

Original value after method call: 5

在这个示例中,original 的值被复制给 number,方法内部对 number 的修改不会影响 original 的值。originalnumber 是两个相互独立的变量,original 在 main 函数栈帧中,number 在 modifyPrimitive 函数栈帧中。修改其中一个变量的值不影响另一个变量。

2、引用类型传参

下面我们看一个例子:

public class Test {public static void modify(Person person) {person.age = 0;}public static void main(String[] args) {Person student = new Person();student.age = 19;modify(student);System.out.println(student.age);}
}class Person {String name;int age;}

我们运行这段代码,运行结果为:

这里为什么可以在方法内对数据进行改动呢?下面我们详细分析:

首先在主函数中创建了一个 Person 类的对象引用变量 student,然后再堆区中创建对象,将对象的引用返回给对象引用变量。

然后将 student 的 age 属性更改为了 19。

然后就调用了 modify 函数,这时 modify 的形参 person 就会存储在 modify 函数栈帧中,

然后实参 student 就会将其中村村的引用的副本赋值给形参 person,也就是将图中的 0xffff0011 赋值给形参,然后形参中存储的引用就也是 0xffff0011 了,这时使用形参也能访问到 student 这个对象了。

然后 modify 函数中的 person.age = 0; 语句就会访问 student 对象,然后修改其 age 属性。这时 student.age 就被修改成 0 了。

这里在方法内部使用对象引用变量 person 存储的引用访问对应的对象,然后改动对象的属性,实参引用的对象的属性也发生了变化,是因为这里的形参中的引用与实参中的引用是指向同一个对象的引用。

如果形参中的引用改变了的话,就没办法改动实参引用的对象的属性了。详细看下面的这个例子。

下面再看另一个例子:

public class Test {public static void reassign(Person person) {person = new Person();person.age = 18;}public static void main(String[] args) {Person student = new Person();student.age = 20;reassign(student);System.out.println(student.age);}
}class Person {String name;int age;}

运行结果:

下面我们进行详细分析:

首先在主函数中创建了一个 Person 类的对象引用变量,然后在堆区中创建对象 student,将对象的引用返回给对象引用变量。

Person student = new Person();
student.age = 20;

然后将 student 对象的 age 属性改为 19。

然后调用 reassign 函数,会开辟相应的函数栈帧,这时形参会被实参的拷贝赋值,实参是对象引用变量 student,实参中存储的是一个对象的引用,然后将这个引用赋值给形参。这时形参也指向 student 对象,形参也可以访问 student 对象。

然后 reassign 函数又在堆区中创建类一个 Person 类对象,

person = new Person();
person.age = 18;

将对象的引用返回给形参 person,这时 person 中存储的就是这个新创建的对象的引用了,person 就不能访问 student 对象了。

然后将这个新创建的对象的 age 属性改为18。

然后 reassign 函数语句执行完毕,reassign 函数栈帧就会被销毁,然后那个新创建的对象也因为失去被引用的机会而被垃圾回收机制回收。

这时我们发现 student 对象的 age 属性并没有什么改变。这是因为在 reassign 函数内对形参重新分配一个对象的引用对实参是没有影响的,因为形参和实参是两个相互独立的对象引用变量。

由此我们知道,对于引用数据类型(如对象和数组),传递的是对象的引用的副本。如果形参和实参存储的引用是同一个的话,方法内部对形参引用的对象进行修改会影响实际参数引用的对象,但对形参重新分配引用不会影响实际参数存储的引用。因为形参和实参是两个独立的对象引用变量。

四、方法调用实例

在了解到了上面这么多方法的使用注意事项后,我们可以实现一些实例,加增加方法使用的熟练度。

1、克隆对象

public class Test {public static Person copyPerson(Person person) {Person newPerson = new Person();//在堆区创建一个新的对象newPerson.name = person.name;//将原来的对象的属性赋值给新的对象newPerson.age = person.age;return newPerson;//返回新对象的引用}public static void main(String[] args) {Person p = new Person();p.name = "张三";p.age = 19;Person p1 = copyPerson(p);//调用对象拷贝方法System.out.println(p1.name + " " + p1.age);System.out.println("两个对象是否是同一个 " + (p == p1));//通过比较引用确定两个对象是否相等}
}class Person {String name;int age;
}

运行结果:

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

“双一流名校”苏州大学计算机专业好考吗?苏州大学计算机考研考情分析

苏州大学(Soochow University),简称“苏大”,坐落于历史文化名城苏州,国家“211工程”重点建设高校,国家国防科技工业局和江苏省人民政府共建高校,国家“双一流”世界一流学科建设高校&#xff…

【爬虫实战项目一】Python爬取豆瓣电影榜单数据

目录 一、环境准备 二、编写代码 2.1 分页分析 2.2 编码 一、环境准备 安装requests和lxml pip install requests pip install lxml 二、编写代码 2.1 分页分析 编写代码前我们先看看榜单的url 我们假如要爬取五页的数据,那么五个url分别是: htt…

vue3-使用富文本编辑器-wangEditor-文章发表1

最近在搞项目:我们组内几位成员正在搞一个网站搭建,以后更新会比较缓慢 引言:如果要网站要用的富文本编辑器的话,这边推荐用wangEditor 官网地址传送 : wangEditorhttps://www.wangeditor.com/ 我现在还在扩展我的写文章用的富文本编辑器 现在我将简单介绍一下其基本使用方…

基于STM32开发的智能农业监控系统

目录 引言环境准备智能农业监控系统基础代码实现:实现智能农业监控系统 4.1 土壤湿度传感器数据读取4.2 温湿度传感器数据读取4.3 水泵与风扇控制4.4 用户界面与数据可视化应用场景:农业环境监测与管理问题解决方案与优化收尾与总结 1. 引言 随着智能…

Apache ShardingSphere实战与核心源码剖析

Apache ShardingSphere实战与核心源码剖析 1.数据库架构演变与分库分表介绍 1.1 海量数据存储问题及解决方案 如今随着互联网的发展,数据的量级也是成指数的增长,从GB到TB到PB。对数据的各种操作也是愈加的困难,传统的关系性数据库已经无法满足快速查询与插入数据的需求。…

msvcp140_CODECVT_IDS.dll的解决方法是什么?有多少种解决方法

msvcp140_CODECVT_IDS.dll 是一个动态链接库(DLL)文件,属于微软Visual C 2015运行时库的一部分。这个文件主要负责字符编码转换,支持Unicode与其他字符集之间的转换,如UTF-8与UTF-16。它对于运行时库的多语言支持至关重…

Golang | Leetcode Golang题解之第133题克隆图

题目: 题解: func cloneGraph(node *Node) *Node {if node nil {return node}visited : map[*Node]*Node{}// 将题目给定的节点添加到队列queue : []*Node{node}// 克隆第一个节点并存储到哈希表中visited[node] &Node{node.Val, []*Node{}}// 广…

算法题目学习汇总

1、二叉树前中后序遍历:https://blog.csdn.net/cm15835106905/article/details/124699173 2、输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。 public class Solution {private Tr…

网络学习(二)DNS域名解析原理、DNS记录

目录 一、为什么要使用DNS?二、因特网的域名结构三、DNS域名解析原理【含详细图解】四、DNS记录(A记录、AAAA记录、CNAME记录等) 一、为什么要使用DNS? 我们知道,TCP/IP 协议中是使用 IP 地址和端口号来确定网络上的某…

优质免费的 5 款翻译 API 接口推荐

当谈到翻译API时,我们通常指的是一种编程接口,它允许开发者将文本从一种语言翻译成另一种语言。这些API通常由专业的翻译服务提供商提供,如谷歌翻译 API、实时翻译API、腾讯翻译API、DeepL翻译API、Azure翻译API等。 这些API通常提供多种语言…

day31贪心算法part01| 理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和

**455.分发饼干 ** 视频讲解 | 力扣链接刚开始想到的&#xff0c;但是这样太暴力了&#xff0c;太笨了 class Solution { public:int findContentChildren(vector<int>& g, vector<int>& s) {// 胃口g 饼干尺寸sint result 0;sort(s.begin(), s.end());…

[数据集][目标检测]厨房积水检测数据集VOC+YOLO格式88张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;88 标注数量(xml文件个数)&#xff1a;88 标注数量(txt文件个数)&#xff1a;88 标注类别数…

冯喜运:6.11#现货黄金#美原油#行情趋势分析及操作建议

【黄金消息面分析】&#xff1a;随着全球经济的波动&#xff0c;黄金作为传统的避险资产&#xff0c;其价格走势一直备受投资者关注。上周五&#xff0c;美国非农就业报告的强劲表现给美联储降息预期泼了冷水&#xff0c;同时&#xff0c;中国5月份未增持黄金&#xff0c;结束了…

免费,C++蓝桥杯等级考试真题--第11级(含答案解析和代码)

C蓝桥杯等级考试真题--第11级 答案&#xff1a;D 解析&#xff1a; A. a b; b a; 这种方式会导致a和b最终都等于b原来的值&#xff0c;因为a的原始值在被b覆盖前没有保存。 B. swap(a&#xff0c;b); 如果没有自定义swap函数或者没有包含相应的库&#xff0c;这个选项会编…

技术前沿 |【大模型InstructBLIP进行指令微调】

大模型InstructBLIP进行指令微调 一、引言二、InstructBLIP模型介绍三、指令微调训练通用视觉语言模型的应用潜力四、InstructBLIP的指令微调训练步骤五、实验结果与讨论六、结论与展望 一、引言 随着人工智能技术的快速发展&#xff0c;视觉语言模型&#xff08;Vision-Langu…

SpringMVC[从零开始]

SpringMVC SpringMVC简介 1.1什么是MVC MVC是一种软件架构的思想&#xff0c;将软件按照模型、视图、控制器来划分 M:Model&#xff0c;模型层&#xff0c;指工程中的JavaBean&#xff0c;作用是处理数据 JavaBean分为两类&#xff1a; 一类称为实体类Bean&#xff1a;专…

Python数据分析II

目录 1.HS-排序返回前n行 2.HS-相关性 3.缺失值处理 4.时间 5.时间索引 6.分组聚合 7.离散分箱 8.Concat关联(索引关联) 9.Merge关联(字段关联) 10.join合并(左字段,右索引) 11.行列转置及透视表 12.数据可视化-面向过程 13.数据可视化-面向对象 14.快速生成柱状…

设计模式 —— 观察者模式

设计模式 —— 观察者模式 什么是观察者模式观察者模式定义观察者模式的角色观察者模式的使用场景观察者模式的实现 被观察者&#xff08;Subject&#xff09;观察者&#xff08;Observer&#xff09;通知&#xff08;notify&#xff09;更新显示&#xff08;update&#xff09…

Apache Pulsar 从入门到精通

一、快速入门 Pulsar 是一个分布式发布-订阅消息平台&#xff0c;具有非常灵活的消息模型和直观的客户端 API。 最初由 Yahoo 开发&#xff0c;在 2016 年开源&#xff0c;并于2018年9月毕业成为 Apache 基金会的顶级项目。Pulsar 已经在 Yahoo 的生产环境使用了三年多&#…

26-LINUX--I/O复用-select

一.I/O复用概述 /O复用使得多个程序能够同时监听多个文件描述符&#xff0c;对提高程序的性能有很大帮助。以下情况适用于I/O复用技术&#xff1a; ◼ TCP 服务器同时要处理监听套接字和连接套接字。 ◼ 服务器要同时处理 TCP 请求和 UDP 请求。 ◼ 程序要同时处理多个套接…