Java把内存划分成两种:一种是栈内存,一种是堆内存
一. 在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配
当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所
分配的内存空间,该内存空间可以立即被另作他用。
二. 堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理
1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。
但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
3. 堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。
但缺点是,由于要在运行时动态分配内存,存取速度较慢。
![]()
例题1:
public class Student{
//学号
int id;
// 姓名
String name;
// 性别
boolean sex;
// 年龄
int age;
}
/*
当不使用 new关键字时,会出现什么问题?
*/
public class OOTest03{
public static void main(String[] args){
// 创建对象
//Student student = new Student();
Student student = null;
student.id = 1001;
student.name = "ming";
student.sex = true;
student.age = 18;
/*
抛出了空指针异常,因为student对象没有指向任何对象,
所以地址为 null, 我们又调用了student的属性,就导致了 空指针异常
*/
System.out.println("id = " + student.id);
System.out.println("name = " + student.name);
System.out.println("sex = " + student.sex);
System.out.println("age = " + student.age);
}
}
例题2:前面已提过
/*
定义一个Ming类
面向对象的封装性:
1. 属性私有化
2. 对外需要提供公开的setter 和 getter
*/
public class Ming{
private int age;
// set赋值
public void setAge(int a){
if(a < 0 || a > 10000){
System.out.println("你输入的年龄不合法 !");
return;
}
age = a;
}
// get取值
public int getAge(){
return age;
}
public static void main(String[] args){
//
}
}
/*
面向对象的封装性
*/
public class OOTest02{
public static void main(String[] args){
// 创建一个Arry类型的对象
Ming ming = new Ming();
// 取值(不能取)
// System.out.println(arry.age);
// 赋值(不能赋值)
//arry.age = 18;
//System.out.println(arry.age);
arry.setAge(-1);
System.out.println("ming的年龄是:"+ming.getAge());
}
}
例题3:
/*
参数传递
值传递(传递过去的都是值)
结论:只要是 基本数据类型,传递过去的都是值
基本数据类型 都是“值传递”
*/
public class OOTest04{
// java入口
public static void main(String[] args){
int i = 10;
method01(i);
System.out.println(i);//输出为10
}
public static void method01(int temp){
temp = 1;
}
}
例题4:
/*
引用传递(传址)
结论: 除了基本类型外 都是 址传递(引用传递)
*/
public class OOTest05{
public static void main(String[] args){
// 创建一个对象
Student stu = new Student();
stu.id = 10001;
stu.name = "arry";
stu.sex = true;
stu.age = 18;
method01(stu);
System.out.println("id = " + stu.id );
System.out.println("name = " + stu.name);
System.out.println("sex = " + stu.sex );
System.out.println("age = " + stu.age);
}
public static void method01(Student temp){
temp.name = "齐天";
}
/*
执行流程:
1. 执行main方法时,会在栈中创建main方法的栈帧,将局部变量 stu 引用保存到栈中
2. 将Student对象放在堆区中,并赋值
3. 调用method01方法,创建method01方法的栈帧
4. 将局部变量stu引用(也就是stu对象的地址),传递到method01方法中,并赋值给 temp
5. 此时,temp 和 stu 引用指向是同一个对象
6. 当method01方法中将name属性改变为 “齐天” 时,改变的是堆中属性
7. 所以会影响输出结果,最后输出结果为:“齐天”
8. main方法执行结束,此时的stu对象还在堆中,我们无法使用了,就变成了“垃圾对象”
java的 垃圾收集器GC会在某个时刻,将其清除
以上的程序执行过程,是址传递,也就是引用的传递
结论:
*/
}