Java学习笔记
Java学习笔记是一个持续更新的系列,工作多年,抽个空对自身知识做一个梳理和总结归纳,温故而知新,同时也希望能帮助到更多正在学习Java 的同学们。
本系列目录
入门篇
基础篇
数据类型
我们都知道Java语言是强类型语言,它的安全和健壮性部分也来自于此, 强类型语言即强制数据类型定义的语言。
一旦一个变量被指定了某个数据类型,如果不经过转换,那么该变量就永远是此数据类型了
在上一章中我们知道了变量需要申请内存空间来进行数据存储,那么给变量具体分配多少内存空间,就由变量的数据类型来决定,而在Java语言中有两大数据类型。
- 基本(内置)数据类型
- 引用数据类型
基本数据类型
基本数据类型,是Java内置的数据类型,直接存储在内存中的内存栈中,数据本身的值就是存储在栈空间里面,共有八种,又分为两大类,即数值类型,非数值类型,其中数值类型有六种,非数值类型有两种。
类型 | 关键字 | 大小 | 默认值 | 最大值 | 最小值 | 适用场景 |
---|---|---|---|---|---|---|
数值类型 | long | 64 位(8byte) | 0L | 9,223,372,036,854,775,807(2^63 -1) | -9,223,372,036,854,775,808(-2^63) | 整型,适用于比较大整数的系统上 |
数值类型 | double | 64 位(8byte) | 0.0d | +1.7 * 10^308 | -1.7 * 10^308 | 浮点型,适用于双精度的小数计算上 |
数值类型 | int | 32位(4byte) | 0 | 2,147,483,647(2^31 - 1) | -2,147,483,648(-2^31) | 整型,适用于整数计算 |
数值类型 | float | 32 位(4byte) | 0.0f | +3.4 * 10^38 | -3.4 * 10^38 | 浮点型,适用于单精度的小数计算上,比double占用内存少 |
数值类型 | short | 16 位(2byte) | 0 | 32767(2^15 - 1) | -32768(-2^15) | 整型,像 byte 那样节省空间 |
数值类型 | byte | 8位(1byte) | 0 | 127(2^7-1) | -128(-2^7) | 整型,适用于大型数组中节约空间,主要代替整数 |
非数值类型 | char | 16 位(2byte) | \u0000(空字符) | \uffff(即为 65535) | \u0000(即为 0) | 字符型,可以储存任何字符 |
非数值类型 | boolean | 没有明确大小 | false | 布尔型,只有两个取值,true和false |
我们也可以通过代码来查看基本数据类型的取值范围,大小和默认值,这里示范一种byte类型
public class HelloWrod {
byte by;
public static void main(String[] args) {
// byte
System.out.println("基本类型:byte 二进制位数:" + Byte.SIZE);
System.out.println("包装类:java.lang.Byte");
System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE);
System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE);
System.out.println("默认值 :" + by);
}
}
运行结果如下:
基本类型:byte 二进制位数:8
包装类:java.lang.Byte
最小值:Byte.MIN_VALUE=-128
最大值:Byte.MAX_VALUE=127
默认值 :0
类型转换
每个函数都可以强制将一个表达式转换成某种特定数据类型,在Java中,类型转换主要用在赋值和方法调用以及算术运算三种场景。
数据类型的转换是在所赋值的数值类型和被变量接收的数据类型不一致时发生的,它需要从一种数据类型转换成另一种数据类型。
基础数据类型的转换可以分为自动类型转换(隐式转换)和强制类型转换(显式转换)两种。
自动类型转换
当两种数据类型彼此兼容即都是基础数据类型,并且满足转换前的数据类型的位数要低于转换后的数据类型。
基础数据类型的转换规则
- 数值型数据的转换
byte→short→int→long→float→double - 字符型转换为整型
char→int
例如
byte 类型向 short 类型转换时,由于 short 类型的取值范围较大,会自动将 byte 转换为 short 类型,short类型转换byte时,则会出现编译错误。
在运算过程中,由于不同的数据类型会转换成同一种数据类型,所以整型、浮点型以及字符型都可以参与混合运算
强制类型转换
当两种数据类型不兼容,或目标类型的取值范围小于源类型时,自动转换将无法进行,这时就需要进行强制类型转换。
由于是大范围取值转为小范围取值,自然会丢失部分数据。
强制类型转换规则:(type)变量标识符
,type
是变量要转换成的数据类型。
目标取值范围小于源类型时,例如
short类型的强制转换为byte类型。
包装器类型,装箱与拆箱
Java为每种基本数据类型都提供了对应的包装器类型,而装箱就是 自动将基本数据类型转换为包装器类型,拆箱就是 自动将包装器类型转换为基本数据类型
Integer i = 10; //装箱
int n = i; //拆箱
int n2= i.intValue();//拆箱
Integer i2 =Integer.valueOf(n2); //装箱
装箱过程是通过调用包装器的valueOf
方法实现的,而拆箱过程是通过调用包装器的typeValue
方法实现的,type
指具体类型。
下表是基本数据类型对应的包装器类型:
基本数据类型 | 包装器类型 |
---|---|
int | Integer |
byte | Byte |
short | Short |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
引申一下,请问以下代码运行之后输出结果是什么?
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
正确的结果
true
false
你答对了吗?为什么会出现这种情况,其实是因为在通过valueOf
方法创建Integer
对象的时候,如果数值在[-128,127]
之间,便返回指向IntegerCache.cache
中已经存在的对象的引用,否则创建一个新的Integer
对象(具体内容需要跟踪Integer源代码)。
所有的包装器类型都属于引用数据类型,什么是引用数据类型呢?
引用数据类型
在Java中,引用类型指向一个对象,指向对象的变量是引用变量,所有引用类型的默认值都是null
,引用类型的数据存储在内存的堆中,一个引用变量可以用来引用任何与之兼容的类型。
引用数据类型是指由类型的实际值引用(类似于指针)表示的数据类型,如果为某个变量分配一个引用类型,则该变量将引用(或“指向”)原始值,“引用”(reference)是c++的一种新的变量类型,是对C的一个重要补充。
引用类型继承于Object
类(也是引用类型)都是按照Java里面存储对象的内存模型来进行数据存储的,使用Java内存堆和内存栈来进行这种类型的数据存储,即“引用”是存储在有序的内存栈上的,而对象本身的值存储在内存堆上的;
Java中提供了四种引用类型,由于优化JVM垃圾回收机制,也便于让程序员通过代码决定某些对象的生命周期,Java程序中默认95%情况下都是强引用类型。
-
强引用
是指创建一个对象并把这个对象赋给一个引用变量,强引用是我们最常见的普通对象引用。对于强引用对象,就算是出现了OOM也不会对该对象进行回收,死都不收。
只要还有强引用指向一个对象,就能表明对象还活着,垃圾收集器不会碰这种对象。
当一个对象被强引用变量引用时,它处于可达状态,不可能被垃圾回收,即该对象以后永远都不会被用到,JVM也不会回收,因此强引用是造成java内存泄漏的主要原因之一。例如
User user=new User(); String str ="hello";
-
软引用
如果一个对象具有软引用,内存空间足够,垃圾回收器就不会回收它。需要用
java.lang.ref.SoftReference
类来实现,相对强引用弱化一些的引用,可以让对象豁免一些垃圾收集。
通常用在对内存敏感的程序中,比如缓存就有用到软引用。例如
import java.lang.ref.SoftReference; public class HelloG