Java内存分区

堆与栈的比较
JAVA堆与栈都是用来存放数据的,那么他们之间到底有什么差异呢?既然栈也能存放数据,为什么还要设计堆呢?

1.从存放数据的角度:

      前面我们已经说明:

      栈中存放的是基本类型的变量or引用类型的变量

       堆中存放的是对象or数组对象.

       在栈中,引用变量的大小为32位,基本类型为1-8个字节。
      但是对象的大小和数组的大小是动态的,这也决定了堆中数据的动态性,因为它是在运行时动态分配内存的,生存期也不必在编译时确定,Java 的垃圾收集器会自动收走这些不再使用的数据。

2.从数据共享的角度:

    1).在单个线程类,栈中的数据可共享

    例如我们定义:

Java代码
  1. int a=3;  
  2. int b=3;  

    编 译器先处理int a = 3;首先它会在栈中创建一个变量为a 的引用,然后查找栈中是否有3 这个值,如果没找到,就将3 存放进来,然后将a 指向3。接着处理int b = 3;在创建完b 的引用变量后,因为在栈中已经有3这个值,便将b 直接指向3。这样,就出现了a 与b 同时均指向3的情况。

    而如果我们定义: 

Java代码
  1. Integer a=new Integer(3);//(1)  
  2. Integer b=new Integer(3);//(2)  

   这个时候执行过程为:在执行(1)时,首先在栈中创建一个变量a,然后在堆内存中实例化一个对象,并且将变量a指向这个实例化的对象。在执行(2)时,过程类似,此时,在堆内存中,会有两个Integer类型的对象。 

 

    2).在进程的各个线程之间,数据的共享通过堆来实现

        例:那么,在多线程开发中,我们的数据共享又是怎么实现的呢?

 

  如图所示,堆中的数据是所有线程栈所共享的,我们可以通过参数传递,将一个堆中的数据传入各个栈的工作内存中,从而实现多个线程间的数据共享

(多个进程间的数据共享则需要通过网络传输了。) 

 

3.从程序设计的的角度:

从软件设计的角度看,JVM栈代表了处理逻辑,而JVM堆代表了数据。这样分开,使得处理逻辑更为清晰。分而治之的思想。这种隔离、模块化的思想在软件设计的方方面面都有体现。


4.值传递和引用传递的真相

有了以上关于栈和堆的种种了解后,我们很容易就可以知道值传递和引用传递的真相:

1.程序运行永远都是在JVM栈中进行的,因而参数传递时,只存在传递基本类型和对象引用的问题。不会直接传对象本身

但是传引用的错觉是如何造成的呢?

在运行JVM栈中,基本类型和引用的处理是一样的,都是传值,所以,如果是传引用的方法调用,也同时可以理解为“传引用值”的传值调用,即引用的处理跟基本类型是完全一样的。

但是当进入被调用方法时,被传递的这个引用的值,被程序解释(或者查找)到JVM堆中的对象,这个时候才对应到真正的对象。

如果此时进行修改,修改的是引用对应的对象,而不是引用本身,即:修改的是JVM堆中的数据。


以上是某人总结,在此感觉很好,拿来引用。哈哈

面向过程:就是看到过程的执行,其实通过函数体现,并且不断的调用函数,并执行完过程。
面向对象:现在将所有的功能进行封装,面对的是封装了功能的实体(对象)
面向对象基于面向过程,将过程进行对象的封装
只要找到了对象,就可以使用对象以及对象的功能
结论:以后开发,想找对象以及对象的功能,若果没有,自己创建对象并将所需的功能定义到对象中,
以便后续自己或其他人使用。




1、面向对象是一种更符合人们思考习惯的思想
2、面向过程更多的体现是执行者,面向对象更多的体现是指挥者,指挥对象做事情
3、面向对象将复杂的问题简单化
在面向对象的世界中:万物皆对象。
引用型变量和基本数据类型的最大区别:
前者只是存储实体的地址,后者变量自己存储值


类与对象的关系:
类:对事物的描述,需要体现属性和行为
对象:该类事物创建的实例(实体),通过该对象调用具有的属性和行为


成员变量和局部变量的区别:
1、定义的位置不同
成员变量定义在类中,局部变量定义在方法以及语句里
2、在内存中的位置不同
存储在对内存的对象中,占内存的方法中
3,生命周期不同


4初始化不同
成员变量因为在堆内存中,所以默认初始化值
局部变量没有默认初始值,所以必须初始化后才可以使用
void show(){ int i; //这样并不开辟内存}//int i=4;正确


匿名对象
当对象对方法进行调用时,而且只调用一次时可以简化成匿名对象来调用
Car c =new Car(); c.run();-->new Car().run();
throw new RuntimeException();     //异常一旦发生,程序结束。


封装:
表现:
函数就是一个简单的封装体
1、提高了代码的复用性
2、隐藏了实现细节,还要对外提供可以访问的方式,以便于方便使用者调用
3、提高了安全性


以后实现类的封装必须将所有属性私有化,设置setXXX()和getXXX()方法来操作私有属性
Person p = new Person("李四");//这句执行时先new,在堆内存中创建对象,并分配地址,默认初始化,随后执行构造函数Person(String str)初始化。
Person p = new Person(); 调用默认的构造函数,是编译器编译时添加到class文件中去
构造函数细节:
1、一个类中可以有多个构造函数,它们的形式是以重载的形式出现的
2、构造函数中也是有return语句的,用于结束初始化动作
3、构造函数可以被private修饰,作用就是其他程序无法创建该类的对象
构造函数和一般函数:
1、写法不一样
2、运行上有差别,对象一创建就会仅调用一次对应的构造函数
一般方法是对象创建后,才会调用所需的一般函数,可以多次调用


this关键字来记录对象的地址,并通过this来初始化对象
那个对象调用this所在函数,this就代表哪个对象


对象调用的方法中都有this引用指向调用该方法的对象
构造函数用this调用其他构造函数,必须定义在第一行,因为初始化必须先执行,防止引起冲突


this的作用还可以区分局部变量和成员变量同名。


静态变量和成员变量:
1、所属范围不同
2、调用不同
3、加载时期不同
4、生命周期不同
5、内存存储区域不同(前者在方法区,后者在堆内存)


静态代码块:
特点:随着类的加载而执行,仅执行一次
作用:给类进行初始化  静态变量有两次初始化,一次是默认初始化,另一次是显示初始化
static{code....  }   在静态变量显示初始化之后


构造代码块:
在类中{code...},只要创建对象就会被调用,给所有对象进行初始化,构造函数只是进行特定的初始化
可以定义不同的构造函数的共性代码


局部代码块:控制局部变量的生命周期


对象的创建过程:
1、加载。class文件进方法区,并进行空间分配
2、如果有静态变量,先默认初始化,显示初始化
3、若果有静态代码块,要执行,仅一次
4、通过new在堆空间开辟空间,并明确首地址
5、对对象中的属性进行默认初始化
6、调用对应的构造函数机型初始化
7、构造函数内部:
1、调用父类的构造函数super()
2、成员变量的显示初始化
3、构造代码块初始化
4、构造函数内部自定义内容初始化
8、对象初始化完毕后,将首地址赋值给类类型变量


栈、堆、方法区、本地方法区、寄存器
栈:存储的都是局部变量
堆,存储都是实体(对象),每个实体都有一个首地址,
对内存的变量都有默认初始值,当实体不存在,就会被垃圾回收机制处理




























  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值