根据链接点击打开链接得到的总结:
由java基本类型byte,int,short,long float,double,boolean,char 这八种定义的变量,在java为了追求速度是直接在栈中为期分配内存空间的,不是类的引用.在栈中有个”数据共享”的特性,比如,定义一个int a=3,栈会定义一个变量为a的引用,如果栈中一开始没有3,则栈会开辟一个存放字面值为3的地址.当再定义一个int b=3,栈会创建变量为b的引用,但是栈中已经有了一个字面值为3的地址,所以会出现a和b同时指向3的情况.
java把内存分为两部分,一部分栈内存,一部分是堆内存,在函数中定义的一些基本类型的变量和对象都是在栈内存中分配的,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。
而堆内存是用来存储new创建的对象和数组,其内存分配是由java虚拟机的自动垃圾回收器管理,在堆中产生了一个数组或对象之后,可以在栈中定义一个特殊的变量,让这个变量的值是数组或对象在堆内存的首地址,栈的这个变量变成了堆中的数组或对象的引用变量.以后就可以使用栈的引用变量来访问对的数组或对象.引用变量在运行到其作用域之外便被释放,而堆中的数组和对象直到没有变量引用他的时候才会变成垃圾被回收.
栈堆是先进后出,可以使用链表或数组表示,
队列是先进先出,只能在对尾添加数据,队头删除数据,但是,可以查看队头和队尾的数据,还有双端队列,在两端都可以插入和删除,可以用链表和数组表示。
数组:连续的内存空间保存数据,
链表:是在非连续的内存单元中保存数据。
集合:
collection是最基本的集合接口,list和set继承了collectin.map没有
list是有序的collection ,list能够精确的控制每个元素的插入位置
实现list接口的常见类有arraylist,linkedlist,vector,stack,
java 参数传递是值传递还是引用传递,数组和String作为参数传递的区别:
总结一下几点:1:Java参数传递方式只有一种,就是按值传递。
2:如果传入方法的是基本类型的东西,你就得到此基本类型的一份拷贝。如果是传递引用,就得到引用的拷贝。
3:String属于引用传递,但是它很特殊,在参数传递时它是重新new了一个String,导致前后的引用地址发生改变,在方法中改变的是新new的String的值。而原先的并没有改变。有很多朋友说string是不可变类型的,大概就是这个意思吧!
4:在堆内存的垃圾自动回收机制是:当创建的堆内存空间没有栈引用指向它的时候,系统会认为这个块区域变为垃圾,JAVA的自动垃圾回收机制会在适当的时候释放这块空间
下面我们具体说下值传递,首先是基本类型:为了加快程序运行速度,java创建基本类型a=4,首先会创建变量为a的引用,然后会先去栈中查找有4,就把4的地址付给a,也就是a直接指向4。如果没有4就创建4,在把4的地址赋值给a。
上图就是,在栈中创建一块变量为a的区域并为其非配地址,然后指向4.
如果在使用如下:
a=4;
f(a);
把a当做入参的时候只是把上图的4放到了方法中,并不是a的地址,在f()方法跟a是没有关系的。
当我们创建一个对象的时候,如:
Dog dog=new Dog();
上面这个其实是分为两部分的。java等号赋值运算是先执行右边再执行赋值运算给左边。右边是在堆中创建一块局域存放新对象dog,然后看左边是在栈中创建变量为dog的引用地址,赋值后执行堆中创建的dog区域。
当dog对象作为参数传递时:f(dog)
public void f(Dog dog){};
会在栈中拷贝一份dog,二者指向的堆内存地址是一样的,当我们再f()方法中修改dog的属性变量值时,也就是修改上图的堆内存中new Dog()的内容,同时也修改之前的对象的内容。
那么当是string的时候有什么不同呢?
String 是一种特殊的对象。因为string用的比较多,因此它在堆内存中有常量池的概念。
最明显的是我们创建string变量的方式大都是:String a=”aa”;咋一看不是基础类型创建的方式吗?其实它是在堆内存中有个aa,然后栈的a变量的引用地址指向它,如下:
当string变量作为参数传递时,
String a=”a”;
f(a);
public void f(String b){
b=“aa”;
}
System.out.println(a);
这段代码打印的结果还是a,因为string的特性,这里小编也不知到底层代码是怎样的。先记住吧!可以认为其实执行的过程等价于一下代码:
public void f(String b){
String b2=new String(b);
b2=”aa”;
}
这里有个new ,就知道又在堆中创建了一块区域,这块区域只有b2指向它,a指向的还是它自己的堆内存,所以a的值没有改变。
最后我们看一个常见的值传递的面试题:
public static void f(char[] ch2,String str2){
ch2[2]='g';
str2="dd";
}
public static void main(String[] args) {
char[] ch={'a','b','c'};
String str="abc";
f(ch, str);
System.out.println(str);
for(char c:ch){
System.out.print(c);
}
结果是:
abc
abg
这个题表达的就是string与对象值传递的区别。虽然这里是数组,其实跟对象是一样的,数组的元素可认为是对象的属性字段,类比下就行了。数组跟string类型经过f方法赋值后,数组的内容改变了,但是string的没有变。原因就是上面介绍的,数组改变的同一块堆内存。而string因为重新创建了一个对象,改变的值不是同一个堆内存,所以值没有变。
下面我们顺带介绍下:
Java中String类通过new创建和直接赋值字符串的区别
方式一:String a = “aaa” ;
方式二:String b = new String(“aaa”);
- 两种方式都能创建字符串对象,但方式一要比方式二更优。
- 因为字符串是保存在常量池中的,而通过new创建的对象会存放在堆内存中。
一:常量池中已经有字符串常量”aaa”
- 通过方式一创建对象,程序运行时会在常量池中查找”aaa”字符串,将找到的”aaa”字符串的地址赋给a。
- 通过方式二创建对象,无论常量池中有没有”aaa”字符串,程序都会在堆内存中开辟一片新空间存放新对象。
一:常量池中没有字符串常量”aaa”
- 通过方式一创建对象,程序运行时会将”aaa”字符串放进常量池,再将其地址赋给a。
- 通过方式二创建对象,程序会在堆内存中开辟一片新空间存放新对象,同时会将”aaa”字符串放入常量池,相当于创建了两个对象。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/106353.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...