深入理解java方法调用时的参数传递
2017-11-09 18:08
761 查看
深入理解java方法调用与参数传递,解决以下问题:Java方法调用是如何传递参数的?
被调用方法对调用方法内的变量有什么影响?
java能使用返回值void的中间方法对变量进行加工吗?
为什么静态成员变量的改变影响是全局的?
同一个方法同时被多个线程调用线程安全吗?
1,[b]每个线程都有一个方法链,即虚拟机栈。虚拟机栈是线程私有的,是方法执行的内存模型,每个栈帧都对应一个执行方法。开始执行,栈帧入栈,执行完毕,栈帧出栈。[/b]
![](https://img-blog.csdn.net/20171117101223593?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzIzMzEwNzM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
2,局部变量表slot中的值:基本类型为字面值,String等引用reference类型为指向堆内句柄的指针或直接指向堆内对象的指针,总之是地址值。(由于reference类型在Java虚拟机规范中只规定了一个指向对象的引用,并没有定义这个引用应该通过何种方式去定位、访问堆中的对象的具体位置,所以对象访问方式也是取决于虚拟机实现而定的。目前主流的访问方式有使用句柄和直接指针两种)3,方法中变量的使用基于局部变量表的slot索引值:每个方法执行都对应一个栈帧,都有独立的局部变量表,方法执行过程中方法内部通过变量表的slot的索引值来定位和使用变量。所以一个方法调用另一个方法时,不可能将“某个栈的某个栈帧的某个索引值”这种定位描述传递过去,所以方法调用时的参数传递采用值传递——基本类型的字面值、reference的地址值。4,方法调用通过操作数栈实现参数传递:概念模型下,栈帧上下独立,调用方法对应栈帧中局部变量表和操作数栈都均不受影响;虚拟机优化下,下面栈帧的操作数栈可以与上面栈帧的局部变量表重叠,无需额外的参数复制,调用方法对应栈帧中操作数栈内的值改变,局部变量表不受影响。
![](https://img-blog.csdn.net/20171117102226257?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzIzMzEwNzM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
5,被调用方法对调用方法的影响:首先,由上可知,每个栈帧的局部变量表都是独立的,不受方法调用影响。值操作不会影响到调用方法变量,无论是基本类型的字面值还是引用类型的地址值;
非原子操作:synchronized,Lock
非原子操作+指令重排序结果受影响:synchronized、 lock+volatile
ThreadLocal<T>;
7,那么你说实例成员变量是因为0位Slot的引用类型“this”,那么静态成员变量呢?他为什么会在多例情况下,受到方法执行的影响,导致多例多线程的线程安全呢?由于在类加载过程中的准备阶段,静态变量的内存被分配到方法区,赋初值(另外,初始化阶段,通过<Clinit>类构造器被初始化,且只执行一次)。而方法区和堆一样是线程共享的内存区域,即对所有线程的所有类型的所有实例的所有方法都是共享的,,,,,就是说谁都能使用它并更改它,且对整个虚拟机产生影响。静态方法:静态方法中是没有this的引用,所以静态方法中不能直接使用实例变量只能使用静态变量(类变量),直接操作方法区中共享的变量内存;
实例方法:多例情况下,每个this指向一个实例,可以理解为通过操作每个this,间接操作着它们共享的静态变量(实际上,仍然是直接操作方法区中共享的变量内存);
注意:
静态变量在类加载中被立即解析成指向方法区内存的直接引用(指针),所以执行过程是直接操作
4000
方法区共享的变量内存。
实例变量被 立即解析 或 惰性解析 为相对偏移量,即相对对象头(实例所在内存地址的起始位置)的偏移值,以此来定位不同实例中的变量。
简单理解为:方法调用的参数传递是值传递:基本类型字面值、引用类型地址值;
方法执行对应栈帧的局部变量表是独立的,不受方法调用影响;
值操作不会影响调用方法,但实例操作可以改变堆内实例信息,堆内存是共享的。
被调用方法对调用方法内的变量有什么影响?
java能使用返回值void的中间方法对变量进行加工吗?
为什么静态成员变量的改变影响是全局的?
同一个方法同时被多个线程调用线程安全吗?
1,[b]每个线程都有一个方法链,即虚拟机栈。虚拟机栈是线程私有的,是方法执行的内存模型,每个栈帧都对应一个执行方法。开始执行,栈帧入栈,执行完毕,栈帧出栈。[/b]
2,局部变量表slot中的值:基本类型为字面值,String等引用reference类型为指向堆内句柄的指针或直接指向堆内对象的指针,总之是地址值。(由于reference类型在Java虚拟机规范中只规定了一个指向对象的引用,并没有定义这个引用应该通过何种方式去定位、访问堆中的对象的具体位置,所以对象访问方式也是取决于虚拟机实现而定的。目前主流的访问方式有使用句柄和直接指针两种)3,方法中变量的使用基于局部变量表的slot索引值:每个方法执行都对应一个栈帧,都有独立的局部变量表,方法执行过程中方法内部通过变量表的slot的索引值来定位和使用变量。所以一个方法调用另一个方法时,不可能将“某个栈的某个栈帧的某个索引值”这种定位描述传递过去,所以方法调用时的参数传递采用值传递——基本类型的字面值、reference的地址值。4,方法调用通过操作数栈实现参数传递:概念模型下,栈帧上下独立,调用方法对应栈帧中局部变量表和操作数栈都均不受影响;虚拟机优化下,下面栈帧的操作数栈可以与上面栈帧的局部变量表重叠,无需额外的参数复制,调用方法对应栈帧中操作数栈内的值改变,局部变量表不受影响。
5,被调用方法对调用方法的影响:首先,由上可知,每个栈帧的局部变量表都是独立的,不受方法调用影响。值操作不会影响到调用方法变量,无论是基本类型的字面值还是引用类型的地址值;
a=10; //int a a=“aaa”; //String a a=new User(); //User a实例操作改变了引用类型地址值指向的堆内实例信息,堆是共享的,所以调用方法内所看到的实例信息也是被改变的;
a.setName("aaa"); //User a6,既然我们已经说过,每个栈帧的局部变量表都是独立的,参数传递又是值传递,为什么同一实例的方法执行会影响到成员变量,甚至是线程安全?reference类型可能是改变了实例信息,那么基本类型呢?由于,存储在局部变量表0位Slot中的是指向自身实例的reference类型“this”。对成员变量的操作,即是对this实例信息的操作。同时单例多线程下,会造成线程安全。线程安全解决方式:原子操作(基本类型的读取和赋值):volatile关键字;
非原子操作:synchronized,Lock
非原子操作+指令重排序结果受影响:synchronized、 lock+volatile
ThreadLocal<T>;
7,那么你说实例成员变量是因为0位Slot的引用类型“this”,那么静态成员变量呢?他为什么会在多例情况下,受到方法执行的影响,导致多例多线程的线程安全呢?由于在类加载过程中的准备阶段,静态变量的内存被分配到方法区,赋初值(另外,初始化阶段,通过<Clinit>类构造器被初始化,且只执行一次)。而方法区和堆一样是线程共享的内存区域,即对所有线程的所有类型的所有实例的所有方法都是共享的,,,,,就是说谁都能使用它并更改它,且对整个虚拟机产生影响。静态方法:静态方法中是没有this的引用,所以静态方法中不能直接使用实例变量只能使用静态变量(类变量),直接操作方法区中共享的变量内存;
实例方法:多例情况下,每个this指向一个实例,可以理解为通过操作每个this,间接操作着它们共享的静态变量(实际上,仍然是直接操作方法区中共享的变量内存);
注意:
静态变量在类加载中被立即解析成指向方法区内存的直接引用(指针),所以执行过程是直接操作
4000
方法区共享的变量内存。
实例变量被 立即解析 或 惰性解析 为相对偏移量,即相对对象头(实例所在内存地址的起始位置)的偏移值,以此来定位不同实例中的变量。
简单理解为:方法调用的参数传递是值传递:基本类型字面值、引用类型地址值;
方法执行对应栈帧的局部变量表是独立的,不受方法调用影响;
值操作不会影响调用方法,但实例操作可以改变堆内实例信息,堆内存是共享的。
相关文章推荐
- 深入理解Java方法调用的参数传递
- 深入理解Java中方法的参数传递机制
- 深入理解Java的方法调用一(值传递和引用传递)
- JAVA本地方法调用(3)对象参数传递
- 理解 Delphi 的类(十) - 深入方法[3] - 调用时参数分割
- JAVA本地方法调用(2)数组参数传递
- 深入理解Java的方法调用二(多态性)
- Java方法参数- 值调用的理解
- 深入理解Java虚拟机笔记---方法调用http://www.tuicool.com/articles/vQVzIje
- 深入理解Java参数传递
- Java方法调用时传递参数问题
- java中调用存储过程并传递list集合参数的方法
- 波哥学java, 5.10.3 理解main()方法 String[] args的使用 向 java 中传递参数
- 关于Java中方法调用时参数的传递
- Java中方法调用参数传递的方式是传值,尽管传的是引用的值而不是对象的值。(Does Java pass by reference or pass by value?)
- 关于Java中方法调用时参数的传递
- 我的理解:Java 中方法的参数全部都是按“值”传递的
- 关于Java中方法调用时参数的传递
- java方法调用中参数传递的方式
- c/c++/java,函数调用的参数的传递方法