一、Java提供的数据类型
Java提供了8中原始的数据类型(byte,short,int,long,float,double,char,boolean),这些数据类型不是对象,相应的变量被定义后会立刻在栈上被分配内存空间。除此之外的数据类型,都是引用类型,引用类型在变量被声明时不会被分配内存空间,只是存储了一个内存地址而已。其实严格意义上讲,Java在8中数据类型外还提供了一种基本数据类型void,也有对应的封装类java.lang.void,只是无法直接对它进行操作。
注意:整数型的默认是 int 类型,带小数的默认是 double 类型。
1字节 | 2字节 | 4字节 | 8字节 |
---|---|---|---|
byte | short | int | long |
boolean | char | float | double |
引申:Java中的null是什么?
null不是一个合法的Object实例,它仅仅表明该引用类型目前没有指向任何对象,所以编辑器没有分配内存。与C语言一样,null是将引用变量的值置为0。
二、有关不可变类的理解
不可变类(immutable class)是指当创建了这个类的实例后,就不允许修改它的值了,也就是说一个对象被创建以后,在整个生命周期内,它的成员变量就不能被修改了。有点类似与常量(const)不允许别的程序进行修改。
Java类库中,所有基本类型的包装类都是不可变类(Byte、Boolean、Short、Char、Integer、Float、Long、Double),此外String也是不可变类。
那么疑问来了,如下代码如何解释:
String s = "Hello";
s += " World";
System.out.println(s);
运行结果是:Hello World
其实程序是在执行 s += " World" 时创建了一个新的对象"Hello World",s指向了这个新建的对象。原来的"Hello"字符串常量在内存中并没有被改变。
如此一来,下面的程序也就容易解释了。
public class Test{
public static void changeStringBuffer(StringBuffer ssb1,StringBuffer ssb2){
ssb1.append("world");
ssb2 = ssb1;
}
public static void main(String[] args) {
Integer a = 1;
Integer b = a;
b++;
System.out.println(a);
System.out.println(b);
StringBuffer sb1 = new StringBuffer("Hello sb1");
StringBuffer sb2 = new StringBuffer("hello sb2");
changeStringBuffer(sb1, sb2);
System.out.println(sb1);
System.out.println(sb2);
}
}
运行结果:
结果分析:
上面程序执行完 b++后,由于Integer是不可变类,因此会创建一个新值为2的Integer赋值给b,此时b和a已经没有任何关系。
对比理解StringBuffer类型的sb1、sb2以及引用传递入口的ssb1、ssb2,四者之间的引用关系变化。(StringBuffer是可变类)
调用函数前sb1和ssb1同时指向"Hello sb1",sb2和ssb2同时指向"Hello sb2"。调用完成后,ssb1改动了二者共同引用的地址空间的值,变为"Hello sb1word",同时ssb2指向了ssb1的引用地址空间,而外部的sb2的引用未受影响,以及sb2引用地址的值没有变化,故执行结果如结果所示。