前言
java数据类型分为基本数据类型和引用数据类型。基本数据类型有8种,而引用数据类型又分为强引用,软引用,弱引用,虚引用。介绍完两种数据类型后,再说下和两种数据类型有关的问题,一是Java方法参数到底是传值还是传引用,二是“equals” & “==” & “hashcode”三者之间的区别。好,正式进入正文。
基本数据类型
Java一共8种基本数据类型:
- 整型:int, short, long, byte 分别是4, 2, 8, 1字节
- 浮点型:float, double 分别是4, 8字节
- char类型:char 是两个字节
- boolean类型:boolean 大小取决于java虚拟机,不同虚拟机大小不同
相关说明:
- 整型的范围与运行java代码的机器无关,而
C++
则与平台有关 - 大数值类(
BigInteger/BigDecimal
)可以实现任意精度的运算,使用静态的valueOf
方法将普通数值转换为大数值 - 基本数据类型不面向对象
包装类
有时候,需要将int
这样的基本类型转换为对象。所有基本类型都有一个与之对应的类,称为包装类。所有包装类均位于java.lang
包,包装类和基本数据类型的对应关系如下表所示:
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
主要用途
- 作为和基本数据类型对应的类型存在,方便涉及到对象的操作。
- 包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法。
具体实现
1、实现int和Integer类之间的转换:
在实际转换时,使用Integer类的构造方法和Integer类内部的intValue方法实现类型之间的相互转换:
2、Integer类内部的常用方法:
parseInt
方法:数字字符串转换为int数值toString
方法:将int类型转换为对应的String类型
自动拆装箱
JDK自从1.5(5.0)版本以后,引入了自动拆装箱的语法,进行基本数据类型和对应的包装类转换时,系统将自动进行,代码如下:
引用数据类型
引用数据类型包含类,接口,数组。
概念
当我们定义基本数据类型时,如下:
|
|
而引用类型就不是了,声明一个引用类型变量时,只给变量分配了引用空间,并没有分配数据空间。我们需要注意:变量a不是一个对象,实际上也没有引用对象。引用类型变量在声明后必须实例化才能对变量指向的对象进行访问。
|
|
四种引用类型
强引用(StrongerReference)
强引用是最普遍的引用类型,我们写代码时都会用到,如下:
|
|
内存空间不足时,Java虚拟机垃圾回收器不会回收它,虚拟机会通过抛出OutOfMemoryError
错误,使程序异常终止。
当我们不想使用该引用时,可以通过将该引用置null的方法来弱化引用,虚拟机在合适的时机便会回收该引用。如下:
|
|
显式的置a = null
,垃圾回收器认为该对象不存在引用,就可以回收该对象。
如果在一个方法的内部有一个强引用,这个引用保存在栈中,准确的说是Java虚拟机栈,而真正的引用内容(Object)保存在Java堆中。这个方法运行完成后就会退出方法栈,即引用内容的引用不存在,这个Object会被回收。
|
|
软引用(SoftReference)
如果一个对象只具有软引用,则内存空间足够时垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
|
|
当内存不足时,弱引用等价于:
|
|
SoftReference
保存了对一个Java对象的软引用后,在垃圾线程对这个Java对象回收前,SoftReference
类所提供的get()方法返回Java对象的强引用。另外,一旦垃圾线程回收该Java对象之后,get()方法将返回null。
实际应用
软引用在实际中有重要的应用,例如浏览器的后退按钮。按后退时,这个后退时显示的网页内容是重新进行请求还是从缓存中取出呢?这就要看具体的实现策略了。
- 如果一个网页在浏览结束时就进行内容的回收,则按后退查看前面浏览过的页面时,需要重新构建
- 如果将浏览过的网页存储到内存中会造成内存的大量浪费,甚至会造成内存溢出这时候就可以使用软引用
|
|
引用队列
软引用可以和一个引用队列(ReferenceQueue
)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
作为一个Java对象,SoftReference
对象除了具有保存软引用的特殊性之外,也具有Java对象的一般性。所以,当软可及对象被回收之后,需要一个适当的清除机制,避免大量SoftReference
对象带来的内存泄漏。具体使用方法如下:
|
|
那么当这个SoftReference
所软引用的object
被垃圾收集器回收的同时,ref
所强引用的SoftReference
对象被列入ReferenceQueue
。也就是说,ReferenceQueue
中保存的对象是Reference
对象,而且是已经失去了它所软引用的对象的Reference
对象。
弱引用(WeakReference)
弱引用与软引用的区别是:只具有弱引用的对象拥有更短的生命周期,垃圾回收器线程开始工作时,一旦发现只具有弱引用的对象,不管内存空间的大小,都会回收内存。但是垃圾回收器线程优先级很低,因此不一定会很快发现那些弱引用对象。
|
|
当垃圾回收器进行扫描回收时等价于:
|
|
如果这个对象是偶尔的使用,并且希望在使用时随时就能获取到,但又不想影响此对象的垃圾收集,那么你应该用 WeakReference
来记住此对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
虚引用(PhantomReference)
与其他几种引用都不同,虚引用不会决定对象的生命周期,如果一个对象只持有虚引用,那么它和没有任何引用一样,在任何时候都能被垃圾回收器回收。
虚引用和软引用及弱引用的区别就是,虚引用必须
和引用队列联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
|
|
总结
引用强度:
强引用 > 软引用 > 弱引用 > 虚引用
引用类型 | 被回收时间 | 用途 | 生存时间 |
---|---|---|---|
强引用 | 从不 | 普通使用 | JVM停止运行时 |
软引用 | 内存不足 | 对象缓存 | 内存不足时 |
弱引用 | 垃圾回收时 | 对象缓存 | GC运行后 |
虚引用 | UnKnown | UnKnown | UnKnown |
传值还是传引用
对Java来说,方法参数只有一种传递方式,就是”值传递”,当然这里需要对基本数据类型和引用数据类型做一个区分。
- 基本数据类型:传递的是基本类型的值的拷贝
- 引用数据类型:传递的是引用的对象的地址值的拷贝
|
|
输出结果为:
|
|
第2-4个例子输出结果解释图如下:
builder.append(" code ");
前后的变化如下图所示:
builder = new StringBuilder(" C++ ");
前后的变化如下图所示:
对于Java来说,引用是保存在虚拟机栈上的,而实际对象内容保存在堆中,引用是对象在堆中的地址值。当我们修改引用时,是让引用指向别的对象,并没有修改实际对象的值。
在C/C++中是通过指针运算符 *p来访问到指针p指向的堆上的对象的,然后再修改它。在Java中通过点操作符访问对象,再通过对象调用方法从而修改对象的实际内容,给引用赋值并不会改变实际对象内容。
“equals” & “==” & “hashcode”区别
equals()
方法定义在JDK的Object.java
中,Object
是所有类的超类,用来判断两个对象是否相等。hashcode()
方法定义在JDK的Object.java
中,用来获取散列码,散列码是对象在散列表中的索引位置,hashcode()
只在散列表中有用,在其他类中并没有用。
- “==” 用来判断两个对象的地址是不是相等
- “equals()”方法在没有被覆盖的情况下,效果等同于“==”,通常覆盖
equals()
方法来比较两个对象的内容是否相等 - 在散列表中,如果两个对象相等,那么
hashcode()
一定相等;反过来,如果hashcode()
相等,对象不一定相等。