Java学习笔记:具体解释传值和传引用
传值和传引用
When you’re passing primitives into a method ,you get a distinct copy of the primitive. When you’re passing a reference into a method , you get a copy of the reference.
以上引自《Thinging in Java》。总结一下就是无论Java參数的类型是什么。一律传递參数的副本。
在Java中,变量分为以下两类:
对于基本类型变量(int、long、double、float、byte、boolean、char),Java是传值的副本。
对于一切对象型变量,Java都是传引用的副本,事实上穿引用副本的实质就是复制指向地址的指针。
一、传值
例1:传Int类型的值
程序
@Test
public void passInt(){
int testInt = 0;
System.out.println("Before operation, testInt is : " + testInt);
intOperation(testInt);
System.out.println("After operation, testInt is : " + testInt);
}
public void intOperation(int i){
i = 5;
System.out.println("In operation, testInt is : " + i);
}
结果
Before operation, testInt is : 0
In operation, testInt is : 5
After operation, testInt is : 0
总结
结果不难看出来。虽说intOperation()方法改变了传进来的參数值,但对这个參数源本身并没有影响。參数类型是简单类型的时候。是按值传递的。以參数类型传递简单类型的变量时,实际上是将參数的值作为一个副本传进方法函数的,那么在方法函数中无论怎么改变值,其结果都是仅仅改变了副本的值,而不是源值。
二、传引用
例2:传对象型变量
代码
@Test
public void passClass(){
Person person = new Person(175,140);
System.out.println("Before classOperation, the person height is " + person.height +
" and the weight is " + person.weight);
classOperation(person);
System.out.println("After classOperation, the person height is " + person.height +
" and the weight is " + person.weight);
}
public void classOperation(Person person){
person.height = 190;
person.weight = 160;
System.out.println("In classOperation, the person height is " + person.height +
" and the weight is " + person.weight);
}
public class Person{
int height;
int weight;
public Person(int hei, int wei){
this.height = hei;
this.weight = wei;
}
}
结果
Before classOperation, the person height is 175 and the weight is 140
In classOperation, the person height is 190 and the weight is 160
After classOperation, the person height is 190 and the weight is 160
总结
从结果不难看出,在经过classOperation()处理之后。person的值发生了变化。
传引用和之前的传值是有一些差别的。能够这样理解:
传值:当前的值好比是一个苹果A。在Java中的传值就相当于是把这个苹果复制了一个苹果B,实际上传递的事实上是苹果B,也就是说无论对苹果B做出如何的改动,苹果A是不变的。
传引用:能够这样理解,当前的person是一个仓库,由于这个仓库(对象型变量)不像基本类型变量那么小,就好比一个仓库比一个苹果大的多的多一样。聪明的Java不会每次传递这个仓库的时候就又一次复制一份仓库传过去,它的做法是把钥匙A复制一把钥匙B(钥匙就相当于引用。引用指向仓库),传递的时候把钥匙B传递过去,和传值相似的地方在于钥匙B怎么改变都不影响钥匙A这个引用的值,可是钥匙A和钥匙B都指向同一个仓库,也就是说通过钥匙B来改变了这个仓库的值(比方偷取走一万吨粮食)。那么这个仓库的值就确确实实改变了,假设再通过钥匙A訪问这个仓库。得到的结果和B訪问时一样的(少了一万吨粮食)。
例3:传String类型
代码
@Test
public void passString(){
String testString = "Hello";
System.out.println("Before operation, testString is : " + testString);
stringOperation(testString);
System.out.println("After operation, testString is : " + testString);
}
public void stringOperation(String s){
s = "World";
System.out.println("In operation, testString is : " + s);
}
结果
Before operation, testString is : Hello
In operation, testString is : World
After operation, testString is : Hello
总结
String类型也是对象型类型,所以它是传引用副本。
可是问题来了,String类型也是对象型类型,那么为什么String类型的对象。经过stringOperation()后。值没有发生变化?
首先String类型是对象型变量,所以它是传引用的副本。
不要由于String在Java里面很易于使用并且不须要new,就觉得String是基本变量类型。
仅仅只是String是一个非可变类,使得其传值还是穿引用显得没什么差别。
然后来解决上面说的问题。事实上问题是出在String的创建上面了,在stringOperation()中。s = "World";
这条语句相当于运行了String s = new String("World");
。对,也就是说,在这种方法中的s
相当于是一个新的String对象,当这个函数结束时,s
作用消失。原来内存地址的值没有变化。
以下来具两个样例来说明这个问题:
例4:传String类型——使用new来创建新对象
代码
@Test
public void passString(){
String testString = new String("Hello");
System.out.println("Before operation, testString is : " + testString);
stringOperation(testString);
System.out.println("After operation, testString is : " + testString);
}
public void stringOperation(String s){
s = new String("World");
System.out.println("In operation, testString is : " + s);
}
输出
Before operation, testString is : Hello
In operation, testString is : World
After operation, testString is : Hello
总结
例4和例3的差别就在于,创建String都使用了new,最后的输出结果是不一样的。
例5:传对象型变量——在classOperation()使用new创建
代码
public class Person{
int height;
int weight;
public Person(int hei, int wei){
this.height = hei;
this.weight = wei;
}
}
@Test
public void passClass2(){
Person person = new Person(175,140);
System.out.println("Before classOperation, the person height is " + person.height +
" and the weight is " + person.weight);
classOperation2(person);
System.out.println("After classOperation, the person height is " + person.height +
" and the weight is " + person.weight);
}
public void classOperation2(Person person){
person = new Person(190,160);
System.out.println("In classOperation, the person height is " + person.height +
" and the weight is " + person.weight);
}
结果
Before classOperation, the person height is 175 and the weight is 140
In classOperation, the person height is 190 and the weight is 160
After classOperation, the person height is 175 and the weight is 140
总结
最后一个样例事实上就是为了说明一个情况,例3的stringOperation()中看到了字符串的赋值操作事实上就相当于例5中classOperation2()里面new出来的新对象。
三、总结
上面的分析主要是基于结果来推断的,可能不是特别准确。望批评指正。
Java学习笔记:具体解释传值和传引用的更多相关文章
- JAVA方法传递参数:传值?传引用?
先来看下面这三段代码: //Example1: public class Example1 { static void check(int a) { a++; } public static void ...
- java学习笔记 (8) —— Struts2 实现上传
1.新建upload.jsp <%@ page language="java" import="java.util.*" pageEncoding=&qu ...
- GO学习笔记:函数传值与传指针
当我们传一个参数值到被调用函数里面时,实际上是传了这个值的一份copy,当在被调用函数中修改参数值的时候,调用函数中相应实参不会发生任何变化,因为数值变化只作用在copy上. 为了验证我们上面的说法, ...
- 难道同事:Java 方法调用到底是传值还是传引用
Java 方法调用中的参数是值传递还是引用传递呢?相信每个做开发的同学都碰到过传这个问题,不光是做 Java 的同学,用 C#.Python 开发的同学同样肯定遇到过这个问题,而且很有可能不止一次. ...
- 难住了同事:Java 方法调用到底是传值还是传引用
Java 方法调用中的参数是值传递还是引用传递呢?相信每个做开发的同学都碰到过传这个问题,不光是做 Java 的同学,用 C#.Python 开发的同学同样肯定遇到过这个问题,而且很有可能不止一次. ...
- 关于Java对象作为参数传递是传值还是传引用的问题
前言 在Java中,当对象作为参数传递时,究竟传递的是对象的值,还是对象的引用,这是一个饱受争议的话题.若传的是值,那么函数接收的只是实参的一个副本,函数对形参的操作并不会对实参产生影响:若传的是引用 ...
- Java实参和形参与传值和传引用
实参和形参的定义: 形参出现函数定义中,在整个函数体内都可以使用,离开函数则不能使用. 实参出现在主函数中,进入被调函数后,实参变量也不能使用. 形参和实参的功能是做数据传送.发生函数调用时,主调函数 ...
- 《Java学习笔记(第8版)》学习指导
<Java学习笔记(第8版)>学习指导 目录 图书简况 学习指导 第一章 Java平台概论 第二章 从JDK到IDE 第三章 基础语法 第四章 认识对象 第五章 对象封装 第六章 继承与多 ...
- Java学习笔记(六):面向对象、接口和抽象类
类和对象 Java是一门面向对象的语言,下面我们来了解一下Java中的面向对象. 方法和重载 Java中的方法格式如下: 访问修饰符 返回值类型 方法名(参数){ 方法主体 } Java的方法支持重载 ...
随机推荐
- ICDAR 成绩 前5企业和高校
11月20日,有光学字符识别(OCR)领域“奥斯卡”之称的国际文档分析与识别大会(ICDAR)数据集最新结果公布,中国高校及企业包揽排行榜前五. ICDAR2015数据集前五名及框架名称分别是:云从科 ...
- FIR基本型仿真_03
作者:桂. 时间:2018-02-05 20:50:54 链接:http://www.cnblogs.com/xingshansi/p/8419452.html 一.仿真思路 设计低通滤波器(5阶,6 ...
- Talend 将Oracle中数据导入到hive中,根据系统时间设置hive分区字段
首先,概览下任务图: 流程是,先用tHDFSDelete将hdfs上的文件删除掉,然后将oracle中的机构表中的数据导入到HDFS中:建立hive连接->hive建表->tJava获取系 ...
- js省市级联实现
js省市级联实现. for [element] in [collection] 用于循环下标,常用于json for(index in arr){ console.info("下标:&quo ...
- [转]如何禁止 IIS 在 C:\Windows\System32\LogFiles\HTTPERR 中生成日志文件
1. 在注册表 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\HTTP\Parameters 中新建 dword 值:EnableError ...
- APACHE LOG4J™ 2
最近服务端开发需要用Log系统,于是研究了下APACHE下的Log框架. 目前日志系统,支持的语言有C++,PHP,.NET,JAVA.当然我是用Java服务端,选择用log4j吧.但突然发现log4 ...
- c#中lock的使用(用于预约超出限额的流程)
一个项目,预约系统,核心二张表:预约表,预约限额表 用户点击预约按钮后, 1. 先select 预约限额表把该预约时间段的限额取出来, 2. 再select 预约表把该预约时间已经预约上的次数算出来 ...
- Atitit 遍历文件夹算法 autoit attilax总结
Atitit 遍历文件夹算法 autoit attilax总结 _FileListToArray Lists files and\or folders in a specified folder (S ...
- C# DateTime的 ParseExact和 TryParseExact 使用说明
最近需要把“20121010”转换为“2012-10-10”格式,直接用Convert.ToDateTime("20121010"),系统报错“未被识别的DateTime类型”. ...
- Windows下断言的类型及实现
一.内容综述 本文主要介绍Windows下断言assert的实现,并总结断言的不同应用准则.最后给出一个windows自定义断言的方法. 本文行文参考<Debugging Windows Pro ...