数据类型
分为两类:原始数据类型 和 非原始数据类型(引用类型)
基本类型:
byte short char int long float double boolean
数据类型 | 默认值 | 默认占用内存大小 |
---|---|---|
boolean | false | 1 bit |
char | ‘\u0000’ | 2 byte |
byte | 0 | 1 byte |
short | 0 | 2 byte |
int | 0 | 4 byte |
long | 0L | 8 byte |
float | 0.0f | 4 byte |
double | 0.0d | 8 byte |
** char 占用2个字节的原因
Java使用Unicode编码(非ASCII码编码),\u0000是Unicode系统的最低范围
溢出:
int a = 130;
byte b = (byte)a;
输出
a = 130
b = -126
int 类型2byte byte类型1byte(-128 ~ 127)
a -> 00000000 10000010
强转为byte,只保留了低八位 10000010
**默认高一位代表符号
原码 – 反码 – 补码
原码 转 反码:除高一位,其他位反转
反码 转 补码 :反码 + 1
则 10000010(原码) – 11111101(反码) – 11111110(-(27 -2)= -126)
变量
是一个值可变的内存位置的名称。
根据变量名可以找到它所引用的数据的内存指针。
根据变量类型可知指针后数据占用的字节数。
变量类型(作用范围的不同) 局部变量 实例变量 静态变量
局部:方法中声明的变量
实例:类中非方法中的非static变量 == 成员变量
静态:类中的static变量
** 局部变量不能被声明为静态的(报错:Modifier ‘static’ not allowed here)
变量类型(数据类型的不同):原始数据类型变量,引用数据类型变量
JVM存储位置
变量在 方法区,栈内存,堆内存 的占用,分为两部分看。
变量 和 变量引用的数据
简称“变量分配” 和 “数据分配”
原始数据类型变量:“变量分配”、“数据分配” 在一起(方法区/堆内存/堆内存)
引用数据类型变量:“变量分配”、“数据分配” 不一定在一起
方法区和堆内存的数据是线程间共享的,线程可访问 方法区的
静态变量以及它所引用的对象的实例变量(static int i; 和 class对象)
** 方法区都是只加载一次的。
栈内存每个线程都有自己的虚拟机栈,栈帧间的数据是线程独有的。
??
字面量 可以理解为 “值”(等号右边的)
class Fruit {
// 静态变量且字面量
static int x = 10; // 静态 原始数据类型 变量和数据都 @方法区
static BigWaterMelon bigWaterMelon_1 = new BigWaterMelon(x);
// 静态变量且引用对象
//静态 引用数据类型 变量@方法区 数据@堆内存
int y = 20;
// 原始数据类型(成员变量) 变量和数据 @堆内存
BigWaterMelon bigWaterMelon_2 = new BigWaterMelon(y);
public static void main(String[] args) {
final Fruit fruit = new Fruit();
int z = 30;
BigWaterMelon bigWaterMelon_3 = new BigWaterMelon(z);
new Thread() {
@Override
public void run() {
int k = 100;
setWeight(k);
}
void setWeight(int waterMelonWeight) {
fruit.bigWaterMelon_2.weight = waterMelonWeight;
}
}.start();
}
}
class BigWaterMelon {
public BigWaterMelon(int weight) {
this.weight = weight;
}
public int weight;
}
https://www.cnblogs.com/xiaowangbangzhu/p/10366200.html
int a = 1;
String s = “1”,s1 = new String(“1”);
栈:基本数据类型和对象的引用 int a = 1; s,s1;
成员变量,new对象 == 堆
局部变量 == 栈
静态的 == 方法区
常量池:
静态常量池(class文件的常量池) + 运行时常量池
Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。
所谓静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分空间。
而运行时常量池,则是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。
虚拟机编译期对常量字符串拼接优化
String s1 = "Hi";
String s2 = "H"+"i";
//结果 s1 == s2;
String s3 = "H"+new String("i"); //这种的 编译期不会优化,所以 s1 != s3;(s3在堆中)
String s4 = "H"; String s5 = "i";
String s6 = s4 + s5; // 运行时s4 s5拼接出来的地址在堆中不确定,所以 s1 != s6
//intern方法会尝试将Hi字符串添加到常量池中,并返回地址。
String s8 = new String("Hi");
String s7 = s8.intern();// s1 == s8;
1、必须要关注编译期的行为,才能更好的理解常量池。
2、运行时常量池中的常量,基本来源于各个class文件中的常量池。
3、程序运行时,除非手动向常量池中添加常量(比如调用intern方法),否则jvm不会自动添加常量到常量池。
参考:
https://blog.csdn.net/HD243608836/article/details/87940295
https://blog.csdn.net/HD243608836/article/details/87940029
https://www.cnblogs.com/xiaowangbangzhu/p/10366200.html