Java浅解 值传递和引用传递

2024-06-18 21:38
文章标签 java 引用 传递 浅解

本文主要是介绍Java浅解 值传递和引用传递,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在上一篇文章对象中,略微提出了一些值传递和引用传递的概念,感觉需要写出篇简单的理解一下。

首先声明一点,java的传递时值传递,而非引用传递(即指针)。

  • 值传递:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
  • 引用传递:引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。是C语言的一种传递方式。

如何体现是值传递,代码如下:

public class Test{public static void main(String[] args) {int a=10;//静态变量System.out.println(a);updata(a);System.out.println(a);}public static void updata(int a) {a=a+10;System.out.println("updata中a的值   "+a);}}
//输出结果
10
updata中a的值   20
10

可见在updata 中对a进行多了修改,但是没有实际的参数值a进行修改,而a的值只能在方法体内生效,也就是局部变量。

我们这里也就简单的拓展一下局内变量和全局变量。

  • 局部变量:也称内部变量,是指在一个函数内部或复合语句内部定义的变量。

    简单的看,就是在方法体内生效,在之外是不会生效的变量。

  • 成员变量(全局变量):就是在方法体之外的变量。

java 变量取值,会就近原则,就是方法体内部有就不会去外部寻找如何理解:

注意: 此处的的a会全局变量

public class Test{static int a=10;//全局变量public static void main(String[] args) {System.out.println(a);updata(a);System.out.println(a);}public static void updata(int a) {a=a+10;System.out.println("updata中a的值"+a);}}
//输出结果
10
updata中a的值   20
10

这样看程序运行似乎,虽然变成了全局变量,但是具体结果和局部变量没有什么区别。

请看下面代码:

public class Test{static int a=10;public static void main(String[] args) {System.out.println(a);updata();System.out.println(a);}public static void updata() {a=a+10;System.out.println("updata中a的值"+a);}}
//输出结果
10
updata中a的值20
20

看见结果变了,难道就不知值传递了吗?

不,还是值传递,但是在updata 方法中没有形参 int a,所以也就没有所谓参数传递。而其运行规则我们说过,就近原则,所以局部没有,那么就需要找外面的的,而updata 中的a也就是全局变量a。所以此处不是引用传递,而是两个变量作用域不同而结果不同而已。

我们区别了全局变量和局内变量,现在我们回来继续说java中的值传递,想要理解这个,就必须对于java的堆和栈进一步理解。

java内存中分三个区:堆,栈,方法区。

  • 堆:分配的是对象的存储空间,也就是new之后真正数据存在的内存空间。其中可以理解比如new Dog,而dog就会存储在堆当中,而其就是一个大房子,而其毛色 color,公母 sex 等属性就其里面的房间信息。

  • 栈:基本数据类型以及对象的引用的地址

  • 方法区:就是类运行的时候加载类的信息以及static修饰的变量。

    • 加载类的信息:
      1. 这个类型的完整有效名。
      2. 这个类的直接父类的有效名,当然接口和object是除外,两者无父类
      3. 以及类的类型修饰符 public abstract等
    • 方法信息:就是防护的修饰符,以及方法类型,方法的参数和类型等,方法有关信息
    • static修饰的模块,以及修饰的变量

    方法区包含以上,以及其他的域信息,方法表(提高运算是一种数据结构)等

现在有疑问了,不是说java是值传递吗?为什么栈的定义提到了引用。

java的参数传递的时候是值传递,而其java中也没有如同C语言中指针的概念(也就是引用),但是不代表其没有使用指针。

在这里插入图片描述

可以简单理解如上图所示的一个结构。

int num=10;
String str="apple";

因为int是基本数据类型,所以直接存储在栈中,而string是类,所以在栈中存放的是堆的地址。

在这里插入图片描述

看到上面结构,有的就了一个大胆的想法,那就是,如果用string 类型的话,是否在局部修改的时候会影响实际参数呢?不解释,先看代码:

public class Test{public static void main(String[] args) {String a="test";System.out.println(a);updata(a);System.out.println(a);}public static void updata(String a) {a=a+10;System.out.println("updata中a的值"+a);}}
//输出结果
test
updata中a的值test10
test

实参完全没有修改,不是说string是引用吗?为什么改变了而其实参没有改变。

在这里插入图片描述

其实这个就是在传递的时候形参复制了实参引用,但是string,本身尤其自己的特点,以为string 本身在建立后是不可改变的,但是所以虽然是通过+ 号进行了一个字符串添加,但是其意思就是新建了string对象,而其索引也就会变。

而如果需要string类型本身改变,因为大量使用string+会造成资源浪费,而java gc(垃圾回收)机制是jvm自己安排的。而是新建字符串,那就需要其衍生的两个类 StringBuffer和StringBuilder。这两个有append的方法可以在其对象上添加数据。

  1. StringBuilder 适用于单线程,其速度快但是不够安全。
  2. StringBuffer 适用于多线程,其速度慢但安全

现在我们看一下对象使用的引用,同样首先看代码

public class Dog {String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}public class Test{public static void main(String[] args) {Dog dog = new Dog();dog.setName("旺财")   System.out.println(dog.getName());updata(dog);System.out.println(dog.getName());}public static void updata(Dog dog) {dog.setName("元宝")System.out.println("updata中的值"+dog.getName());}}
//输出的值
旺财
updata中的值元宝
元宝

在这里插入图片描述

同理,也是传递了所在堆的地址,但是其没有新建一个dog对象,等于还是在原有的对象上调用了setName对dog进行赋值,所以本质还是值传递,而是引用一直没有说,但是一直存在。

这篇关于Java浅解 值传递和引用传递的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1073124

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟 开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚 第一站:海量资源,应有尽有 走进“智听

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca