java 方法 入参的参数的值,如果在方法体对参数进行修改,则 基本类型值不变,需要return 返回值;而引用类型如果不修改原指针时赋值将改变;
其中基本数据类型包含 8大基本类型 和 String
怎么理解而引用类型如果不修改原指针时赋值将改变:
如果 setVale(List list) 中 list集合,如果 对 list 集合重新赋予地址 eg. 方法体{ list=new list()},此时原值不变;如果对list 集合里面的数据赋值,则值会改变 . eg.方法体 {list.add(a)},打印list 值会改变;
思考原因:
因为 方法体 会建立临时表(局部变量表)会建立新的堆栈,对直接 的引用 不处理,所以 8大基本类型和string 还有 引用类型,直接处理不改变其值;但是 临时表 会 拿到 引用类型的指针,对指针的值重新赋值是可以的,所以 可以改变 list 集合里面的数据。
public static void main(String[] args) {
String S="ASDFASDF";
setValue(S);
System.out.println(S);
int i=466546;
setValueInt(i);
System.out.println(i);
//发现 基本数据类型 和 String 经过方法处理后 值不变化 String本质是final类型char数组
// 而数组 和 list 集合 经过 方法处理后 期 里面的值会发生变化
//说明 基本数据类型 和String 是值拷贝,而 数组和list 集合处理的是引用
StringBuilder str = new StringBuilder("546");
setValue(str);
System.out.println(str.toString()); //输出空字符串
setValue2(str);
System.out.println(str.toString()); //输出sss
}
public static void setValue(StringBuilder str){
str = new StringBuilder("sss111");
}
public static void setValue2(StringBuilder str){
str.append("sss222");
}
public static void setValue(String ss){
ss="adfasdfa";
}
public static void setValueInt(int ss){
ss=8888;
}
public class Test2 {
public static void setValue(String str){
str = "ss";
}
public static void setValue(Man str){
str = new Man("test");
}
public static class Man{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Man(String name) {
this.name = name;
}
@Override
public String toString() {
return "Man{" +
"name='" + name + '\'' +
'}';
}
}
public static void main(String[] args) {
String str = "s";
setValue(str);
System.out.println(str);
Man man = null;
setValue(man);
System.out.println(man);
}
}
如上面代码实践,结果输出
s
null
原因是方法在执行的时候有栈帧的概念,入栈的时候只是压栈方法参数是传入参数的副本。
JVM高级特性
此时区分数据类型:基本类型和引用类型
基本类型:值存放在局部变量表中,无论如何修改只会修改当前栈帧的值,方法执行结束对方法外不会做任何改变;此时需要改变外层的变量,必须返回主动赋值。
引用数据类型:指针存放在局部变量表中,调用方法的时候,副本引用压栈,赋值仅改变副本的引用。但是如果直接改变副本引用的值,修改了引用地址的对象,此时方法以外的引用此地址对象当然被修改。(两个引用,同一个地址,任何修改行为2个引用同时生效)
比如
public static void setValue(StringBuilder str){
str = new StringBuilder("sss");
}
public static void setValue2(StringBuilder str){
str.append("sss");
}
public static void main(String[] args) {
StringBuilder str = new StringBuilder();
setValue(str);
System.out.println(str.toString()); //输出空字符串
setValue2(str);
System.out.println(str.toString()); //输出sss
}
关于String,本质是final类型char数组,不可修改,只能赋值,在做参数传入方法修改时,其实是新建对象,必须返回重新对外面的变量赋值才会对外面的String引用生效。
看String源码的任意一个方法即可明白
/**
* Returns a string resulting from replacing all occurrences of
* {@code oldChar} in this string with {@code newChar}.
* <p>
* If the character {@code oldChar} does not occur in the
* character sequence represented by this {@code String} object,
* then a reference to this {@code String} object is returned.
* Otherwise, a {@code String} object is returned that
* represents a character sequence identical to the character sequence
* represented by this {@code String} object, except that every
* occurrence of {@code oldChar} is replaced by an occurrence
* of {@code newChar}.
* <p>
* Examples:
* <blockquote><pre>
* "mesquite in your cellar".replace('e', 'o')
* returns "mosquito in your collar"
* "the war of baronets".replace('r', 'y')
* returns "the way of bayonets"
* "sparring with a purple porpoise".replace('p', 't')
* returns "starring with a turtle tortoise"
* "JonL".replace('q', 'x') returns "JonL" (no change)
* </pre></blockquote>
*
* @param oldChar the old character.
* @param newChar the new character.
* @return a string derived from this string by replacing every
* occurrence of {@code oldChar} with {@code newChar}.
*/
public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = value.length;
int i = -1;
char[] val = value; /* avoid getfield opcode */
while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
if (i < len) {
char buf[] = new char[len];
for (int j = 0; j < i; j++) {
buf[j] = val[j];
}
while (i < len) {
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
//String的value 是final char[],一旦创建不能改变
return new String(buf, true);
}
}
return this;
}
引用类型会引起浅拷贝和深拷贝现象。
网友评论