java内核之堆 栈深入理解以及String和堆 栈 常量池的深入关系

在讲解堆栈之前我们首先来谈谈对象是如何创建的

  1. 学习java要有一个思想:“一切都是源于对象的”。
  2. 何为对象?简单的说就是类的具体实现,就是一个实例。如果我们把类看作图纸,那么对象就是根据图纸造出来的实物。
  3. 如何创建对象?
    1.定位.class文件。触发条件:首次创造该类的对象或者首次访问该类的静态方法和静态域。
    2.加载.class文件,静态初始化(加载到方法区,下面会详细介绍)
    3.当用new来创建对象时,首先在堆上会给它分配足够的空间
    4.执行初始化。初始化顺序为 默认初始化–>字段定义处初始化语句–>构造方法
  4. 创建对象代码:Dog d=new Dog();
  5. 代码说明:Dog类是我自定义的一个类,只有一个默认构造器。创建对象代码:new Dog();Dog d只是我声明的一个对象的引用。

**

正文 栈 堆 方法区

**
1.什么是栈?简单来说,栈是随机访问存储器,可以通过栈指针从处理器哪里获取直接支持。
java某些数据存储于栈中----特别是对象引用,但是java对象不在其中。
2。什么是堆?堆是一种通用的内存池,用于存放java对象。当需要一个对象时,只需写一个小小的new代码,堆就会为我们的对象
分配足够的存储空间。
3.方法区:主要用于静态初始化,前面我们提到过java对象创建时首先要加载.class文件。.class文件就是加载到方法区。并进行静态初始化。
下面是一个java程序的代码,我们通过代码来具体的了解java程序执行时内存的变化。

public class Dog(){
public int age;
public static String name;
public double warehouse=1000.0;
public void eat(){System.out.println("我吃骨头")}
public static void watch(){System.out.println("我看人间百态");}
public static void main(String[] agrs){
	Dog d=new Dog();
	d.name="小曹";
	d.age=18;
	d.eat();
	d.watch();
}
}

java代码执行步骤
1.main是程序的接口,当我们执行程序的时候首先访问main()方法。main方法是静态方法,所以会触发.class文件的加载。
.class文件的加载时会进行静态初始化,并且静态初始化只在此刻进行一次。
2.进入main方法后进行,执行main方法语句。第一句 Dog d=new Dog();创建对象,首先在堆上分配一块足够大的存储空间。
并且这块空间会被清0.然后按照默认初始化–>字段定义处初始化语句–>构造方法的顺序进行初始化。d是引用,是存放在栈上的。
3.然后依次执行d.eat();d.watch();方法。方法的调用都发生在栈上。
下面附上原理图帮助理解:

在这里插入图片描述## String和堆 栈 常量池的关系
去年面试,考官问下面两个模块分别创建了多少对象。
模块一:

**String s1="123"+"456"**

模块二
String s="123"; Striing s1="456"; String s2=s+s1;
那么想要回答这个问题就必须清楚的了解String类的创建内核。
String类的创建
方式一:String str=“123”;
方式二:String str1=new String(“456”);
上面两种机制都创建了String对象但是实现的原理是不同的。下面就来进行具体的分析:
首先第一种:String str=“123”;
这种通过引号直接创建字符串对象,首先要从常量池中判断有没有"123"对象,如果有常量池中对象的引用就直接给str。
如果没有,就要在常量池中创建对象。
第二种::String str1=new String(“456”);
这是我们经常用的一种创建对象的方式。首先进行的是会在字符串常量池中创建一个对象(常量池先前没有"456"的情况),然后再在堆上分配内存创建对象。(这种方式是jdk1.6之前的方式,jdk1.6之前字符串常量池和堆是分开独立的)。但是jdk1.6后,字符串常量池包含到了堆里面,现在用此种方法创建字符串对象,不会在常量池和堆中都创建一个对象,只会在堆中创建一个对象,常量池中存储的是堆中所创建字符串对象的引用。

那么明白了原理,下面来进行拓展训练:
场景一:String s=“123”+“456”;
场景二:String s=“123”; String s1=s+“456”;
问题:两种字符串连接方式的具体实现?
分析:场景一:这种字面量的连接,java编译器会将其优化成String s=“123456”;最终只会创建一个对象!
分析:场景二:这种连接方式是一个对象的引用和另一个字面量的连接。底层是用 new StringBuilder,然后调用append方法。
即String s1=new StringBuilder.append(s).append(“456”).toString();这种情况下,它依然会涉及到两个字面量,所以在字符串常量池中依旧会创建两个对象,同时new StringBuilder.append(s).append(“456”).toString();也会在堆中创立一个对象。(jdk1.6以后版本的实行)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

马明智

你的鼓励就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值