java中的基本数据类型、自动装箱和拆箱、常量池、静态常量池、动态常量池

Java架构师交流群:793825326

java版本:jdk1.8

IDE:idea 18

int是值类型,Integer是引用类型,Integer是int的包装类。不管怎么实例化Integer都是引用类型。参考如下代码:

int i=127;

Integer integer1=new Integer(i);
Integer integer2=new Integer(i);
System.out.println(integer1==integer2);
System.out.println(integer1.equals(integer2));

integer1=i;
integer2=i;
System.out.println(integer1==integer2);
System.out.println(integer1.equals(integer2));

i=128;
integer1=i;
integer2=i;
System.out.println(integer1==integer2);
System.out.println(integer1.equals(integer2));

int a=integer1;
int b=integer2;
System.out.println(a==b);

这段代码的运行结果如下:

这里面首先integer1和integer2都是通过new的方式实例化的。在java里面,new就代表开辟一块内存空间。所以只要是new出来,不管equals是否相等,==的结果一定是false,因为它们是指向不同的引用(Integer的==操作表示比较引用,equals表示比较数值)。所以第一段代码的结果分别是false和true。

integer1=i; integer2=i;这两句代码涉及到了自动装箱操作,所谓装箱是指将值类型转为引用类型,Integer integer1=new Integer(i);这个操作属于手动装箱,而java提供了自动装箱功能。integer1=i;这个操作java在运行的时候等价于Integer integer1=new Integer(i);但实际上有些区别,因为通过比较引用你会发现其结果是返回true。也就是引用相等。前面我们说过,只要new,引用肯定不会相等的。那为何这里会相等呢,原因是java里面有个数值常量池,这个常量池里面存放了-128到127之间的数值常量。当出现integer1=i;这种自动装箱的操作时,编译器会优先去常量池里面找有没有包含i的常量,如果有,就直接把这个常量的引用给integer1,由于127在常量池范围内,所以最终的结果是integer1等于integer2的引用。

后面把i的值改为128的操作i=128;会导致自动装箱的时候,从常量池找不到,那么编译器就会new一个新的空间出来,所以integer1不等于integer2的引用。

int a=integer1; int b=integer2; System.out.println(a==b);这部分代码是自动拆箱的操作,所谓拆箱,就是将引用类型转为值类型,这段代码你也可以这么写:

int a=integer1.intValue();
int b=integer2.intValue();
System.out.println(a==b);

这样的话就是手动拆箱了。

现在我们看一下另外七种基本类型有没有这个特性:

System.out.println("double:");
double d=0.1d;
Double double1=d;
Double double2=d;
System.out.println("是否有常量池:"+(double1==double2));
System.out.println(double1.equals(double2)+"\r\n");

System.out.println("float:");
float f=0.1f;
Float float1=f;
Float float2=f;
System.out.println("是否有常量池:"+(float1==float2));
System.out.println(float1.equals(float2)+"\r\n");

System.out.println("char:");
char c='z';
Character character1=c;
Character character2=c;
System.out.println("是否有常量池:"+(character1==character2));
System.out.println(character1.equals(character2));

character1=new Character(c);
character2=new Character(c);
System.out.println(character1==character2);
System.out.println(character1.equals(character2)+"\r\n");

System.out.println("byte:");
byte b=127;
Byte byte1=b;
Byte byte2=b;
System.out.println("是否有常量池:"+(byte1==byte2));
System.out.println(byte1.equals(byte2));

byte1=new Byte(b);
byte2=new Byte(b);
System.out.println(byte1==byte2);
System.out.println(byte1.equals(byte2)+"\r\n");

System.out.println("boolean:");
Boolean boolean1=false;
Boolean boolean2=false;
System.out.println("是否有常量池:"+(boolean1==boolean2));
System.out.println(boolean1.equals(boolean2));

boolean1=new Boolean(false);
boolean2=new Boolean(false);
System.out.println(boolean1==boolean2);
System.out.println(boolean1.equals(boolean2)+"\r\n");

System.out.println("long:");
long l=127;
Long long1=l;
Long long2=l;
System.out.println("是否有常量池:"+(long1==long2));
System.out.println(long1.equals(long2));

long1=new Long(l);
long2=new Long(l);
System.out.println(long1==long2);
System.out.println(long1.equals(long2)+"\r\n");

System.out.println("short:");
short s=127;
Short short1=s;
Short short2=s;
System.out.println("是否有常量池:"+(short1==short2));
System.out.println(short1.equals(short2));

short1=new Short(s);
short2=new Short(s);
System.out.println(short1==short2);
System.out.println(short1.equals(short2)+"\r\n");

这段代码的执行结果如下:

double:
是否有常量池:false
true

float:
是否有常量池:false
true

char:
是否有常量池:true
true
false
true

byte:
是否有常量池:true
true
false
true

boolean:
是否有常量池:true
true
false
true

long:
是否有常量池:true
true
false
true

short:
是否有常量池:true
true
false
true

我们可以看到有常量池的是

char:它的常量池范围是多少,我目前还搞不清,你可以尝试一下输入不同的char,看看输出结果。

byte:它的常量池范围就是一个字节的大小,-128到127。

boolean:它的常量池范围就两个false和true。

long:同int。

short:同int。

short:同int。

 

另外单独说一下string,string没有常量池,但是string在值相同的情况,只开辟一块内存空间:

String string1="abcsfsdfsdfsdfsdfsdfsdgsgfdsgdsfsdghgfjghjfdgsdfs";
String string2="abcsfsdfsdfsdfsdfsdfsdgsgfdsgdsfsdghgfjghjfdgsdfs";
System.out.println(string1==string2);
System.out.println(string1.equals(string2));

string1=new String("abcsfsdfsdfsdfsdfsdfsdgsgfdsgdsfsdghgfjghjfdgsdfs");
string2=new String("abcsfsdfsdfsdfsdfsdfsdgsgfdsgdsfsdghgfjghjfdgsdfs");
System.out.println(string1==string2);
System.out.println(string1.equals(string2)+"\r\n");

这段代码的执行结果如下:

true
true
false
true

这里面之所以第一次string1==string2为true,并不是常量池导致的结果,而是因为当String string2="abcsfsdfsdfsdfsdfsdfsdgsgfdsgdsfsdghgfjghjfdgsdfs";执行这句的时候,会检查内存区是否已经包含了值等于"abcsfsdfsdfsdfsdfsdfsdgsgfdsgdsfsdghgfjghjfdgsdfs"的string,如果有,则直接把地址给string2,如果没有,则开辟一个新的空间。

同样的具备这个特性还包括八种基本数据类型。这里我们总结一下,只要代码中出现常量,什么意思呢,就是类似于"abc"、2、0.2这种东西,系统就会主动去常量池检查是否已经存在,如果不存在就创建一个常量,如果存在就直接把引用拿出来用。

看下面的代码:

String str="abc";
System.out.println(str.intern()==str);

执行结果为:true

intern()的作用是去常量池检查是否存在值和str一样的常量,如果存在,就返回它的引用,如果不存在就创建一个,再返回它的引用。这里面因为代码中出现了"abc",会导致常量池多出来值等于"abc"的常量,这样通过str.intern()获取的引用自然和str的引用一样,因为它们都是指向常量池中的"abc"的引用。

看下面的代码:

String str=new String("abc");
System.out.println(str.intern()==str);

它的执行结果为false。

由于代码中出现了"abc",所以虚拟机会去常量池里面检查是否存在"abc"这个常量,如果不存在则新建一个。同时还要新开辟一个存在str的内存空间,并把引用给str。这样其实产生了两个引用,常量池中的"abc"的引用和str的引用,str.intern()得到的是常量池中的"abc"的引用,str得到是因为new而新开的内存引用,那么自然str.intern()==str就会false了。

关于这部分的详细信息可以看下这篇博客:https://blog.csdn.net/seu_calvin/article/details/52291082

前面一种常量池,叫静态常量池,后面一种常量池,叫动态常量池。很明显,系统里面一开始肯定是没有"abcsfsdfsdfsdfsdfsdfsdgsgfdsgdsfsdghgfjghjfdgsdfs"这个常量的,但是随着系统的运行,这个常量出现,先去动态常量池检查是否已经存在,如果存在,则使用已有的,如果不存在,则在动态常量池增加一个常量

你可能感兴趣的:(java中的基本数据类型、自动装箱和拆箱、常量池、静态常量池、动态常量池)