(一), 基本数据类型
java提供了8种基本数据类型, 它们都不具备对象的特性, 没有属性和行为, 基本数据类型是指不可再分的原子数据类型, 内存中直接存储此类型的值, 通过内存地址即可直接访问到数据, 并且此内存区域只能存放这种类型的值
java的8种基本数据类型包括boolean, byte, char, short, int, long, float, double和refvar, 前8种数据类型表示生活中的真假, 字符, 整数和小数, 最后一种refvar是面向对象世界中的引用变量, 也叫引用句柄
默认值虽然都与0有关, 但是它们之间都存在区别, 比如, boolean的默认值以0表示的false, JVM并没有针对boolean数据类型进行赋值的专用字节码指令, boolean flag=false 就是用ICONST_0, 即常数0来进行赋值
byte的默认值以一个字节的0表示, 在默认值的表示上使用了强制类型转化
float的默认值以单精度浮点数0.0f表示, 浮点数的0.0使用后缀f和d区别标识
char的默认值只能是单引号的’\u0000’表示NUL, 注意不是null, 它就是一个空的不可见字符, 在码表中是第一个, 其码值为0, 与’\n’换行之类的不可见控制符的理解角度是一样的, 注意, 不可以用双引号方式对char进行赋值, 那是字符串的表示方式
在代码中直接出现的没有任何上下文的0和0.0分别默认为int和double类型, 可以使用JDK10的类型推断证明:
var a=0; Long b=a; 代码编译出错, 因为在自动装箱时, 0默认是int类型, 自动装箱为Integer, 无法转化为Long类型
引用分成两种数据类型: 引用变量本身和引用指向的对象
这里把引用变量称之为refvar,而把引用指向的实际对象简称为refobj
refvar是基本的数据类型, 它的默认值是null, 存储refobj的首地址, 可以直接使用双等号进行等值判断,而平时使用refvar.hashCode()返回的值, 只是对象的某种哈希计算, 可能与地址有关, 与refvar本身存储的内存单元地址是两回事, 作为一个引用变量, 不管它是指向包装类, 集合类, 字符串类还是自定义类, refvar均占用4B空间, 注意它与真正对象refobj之间的区别, 无论refobj是多么小的对象, 最小占用的存储空间是12B(用于存储基本信息, 称为对象头), 但由于存储空间分配必须是8B的倍数, 所以初始分配的空间至少是16B
一个refvar至多存储一个refobj的首地址, 一个refobj可以被多个refvar存储下它的首地址, 即一个堆内对象可以被多个refvar引用, 如果refobj没有被任何refvar指向, 那么它迟早会被垃圾回收, 而refvar的内存释放, 与其他基本数据类型类似
(二), 包装类型
Integer会缓存-128~127之间的值, 对于Integer var=?在-128-127之间的赋值, Integer对象由IntegerCache.cache产生,会复用已有对象, 这个区间内的Integer值可以直接使用==进行判断, 但是这个区间之外的所有数据都会在堆上产生, 并不会复用已有对象, 因此, 推荐所有包装类之间值的比较, 全部使用equals()方法
各个包装类的缓存区间如下:
(三),字符串
字符串相关类型主要有三种: String, StringBuilder, StringBuffer, String是只读字符串, 典型的immutable对象, 对它的任何改动, 其实都是创建一个新对象, 再把引用指向该对象, String对象赋值操作后, 会在常量池中进行缓存, 如果下次申请创建对象时, 缓存中已经存在, 则直接返回相应引用给创建者, 而StringBuffer则可以在原对象上进行修改, 是线程安全的, JDK5引入的StringBuilder与StringBuffer均继承自AbstractStringBuilder, 两个子类的很多方法都是通过"super.方法()"的方式调用抽象父类中的方法, 此抽象类在内部与String一样, 也是以字符数组的形式存储字符串的, StringBuilder是非线程安全的, 把是否需要进行多线程锁交给工程师决定, 操作效率比StringBuffer高, 线程安全的对象先产生是因为计算机的发展总是从单线程到多线程, 从单机到分布式
在非基本数据类型的对象中, String是支持直接相加操作的对象, 这样操作比较方便, 但在循环体内, 字符串的连接方式应该使用StringBuilder的append方法进行扩展