Java中的数据类型
Java是强类型语言
什么是强类型语言?
就是一个变量只能对应一种类型。而不是模棱两可的类型符号。
下面我通过一个例子来解释一下这个现象.
- javascript中可以用var表示许多数据类型
// 此时a为number
var a = 1;
// 此时a为字符串形式的'1'
var a = '1';
复制可以看到,javascript里面,可以用var来承载各种数据类型,但是在Java,你必须对变量声明具体的数据类型(Java10中也开放了var,目前我们讨论的版本为Java8) 。
8大数据类型
基本类型 | 存储所需大小 | 取值范围 |
---|---|---|
int | 4字节 | -2147483648~2147483647 |
short | 2字节 | -32768~32767 |
long | 8字节 | -9223372036854775808~9223372036854775807 |
byte | 1字节 | -128~127 |
float | 4字节 | 1.4e-45f~ 3.4028235e+38f |
double | 8字节 | 4.9e-324~1.7976931348623157e+308 |
char | 2字节 | \u0000~\uFFFF |
boolean | 根据JVM的编译行为会有不同的结果(1/4) | 布尔(boolean)类型的大小没有明确的规定,通常定义为取字面值 “true” 或 “false” |
NaN与无穷大
- NaN
在浮点数值计算中,存在一个NaN来表示该值不是一个数字
/**
* @author jaymin<br>
* 如何表示一个值不是数字
* 2021/3/21 14:54
*/
public class NaNDemo {
public static void main(String[] args) {
Double doubleNaN = new Double(0.0/0.0);
// 一个常数,其值为double类型的非数字(NaN)值
Double nan = Double.NaN;
System.out.println(doubleNaN.isNaN());
System.out.println(nan.isNaN());
}
}
复制- 正负无穷大
private static void isPositiveInfinityAndNegativeInfinity(){
double positiveInfinity = Double.POSITIVE_INFINITY;
double negativeInfinity = Double.NEGATIVE_INFINITY;
System.out.println(positiveInfinity);
System.out.println(negativeInfinity);
}
复制Result:
Infinity
-Infinity
复制浮点数存在精度问题
Java中无法用浮点数值来表示分数,因为浮点数值最终采用二进制系统表示。
/**
* @author jaymin<br>
* 浮点数无法表示分数
* @since 2021/3/21 15:07
*/
public class PrecisionDemo {
public static void main(String[] args) {
System.out.println(2.0 - 1.1);
// 如何解决?使用BigDecimal
BigDecimal a = BigDecimal.valueOf(2.0);
BigDecimal b = BigDecimal.valueOf(1.1);
System.out.println(a.subtract(b));
}
}
复制精度
向上转型和向下强转
- 向上转型
/**
*
*
* @author jaymin
* @since 2021/3/21 15:40
*/
public class ForcedTransfer {
public static void main(String[] args) {
int n = 123456789;
// 整型向上转换丢失了精度
float f = n;
System.out.println(f);
int n1 = 1;
float f1 = 2.2f;
// 不同类型的数值进行运算,将向上转型
System.out.println(n1 + f1);
}
}
复制这里我们看到两个现象:
- 整型可以赋值给浮点型,但是可能会丢失精度.
- 整形和浮点数进行相加,先将整型向上转型为float,再进行float的运算.
层级关系:double>float>long>int
- 面试官经常问的一个细节
此处能否通过编译?
short s1= 1;
s1 = s1 + 1;
复制答案是不能的,如果我们对小于 int 的基本数据类型(即 char、byte 或 short)执行任何算术或按位操作,这些值会在执行操作之前类型提升为 int,并且结果值的类型为 int。若想重新使用较小的类型,必须使用强制转换(由于重新分配回一个较小的类型,结果可能会丢失精度).
可以简单理解为: 比int类型数值范围小的数做运算,最终都会提升为int,当然,使用final可以帮助你解决这种问题.
- 正确示例
short s1= 1;
// 1. 第一个种解决办法
s1 = (short) (s1 + 1);
// 2. 第二种解决办法
s1+=1;
复制 final short a1 = 1;
final short a2 = 2;
short result = a1 + a2;
复制- 向下转型(强制转换)
场景: 在程序中得到了一个浮点数,此时将其转成整形,那么你就可以使用强转.
/**
* 数值之间的强转
*
* @author jaymin
* @since 2021/3/21 15:40
*/
public class ForcedTransfer {
public static void main(String[] args) {
double x = 2021.0321;
// 强转为整型
int integerX = (int) x;
System.out.println(integerX);
x = 2021.8888;
// 四舍五入
int round = (int) Math.round(x);
System.out.println(round);
}
}
复制Result:
2021
2022
复制如果强转的过程中,上层的数据类型范围超出了下层的数据类型范围,那么会进行截断.
可以执行以下程序来验证这个问题.
long l = Long.MAX_VALUE;
int l1 = (int) l;
System.out.println(l1);
int i = 300;
byte b = (byte) i;
// 128*2 = 256,300-256=44
System.out.println(b);
复制Reuslt:
-1
44
复制初始值
基本数据类型都会有默认的初始值.
基本类型 | 初始值 |
---|---|
boolean | false |
char | \u0000 (null) |
byte | (byte) 0 |
short | (short) 0 |
int | 0 |
long | 0L |
float | 0.0f |
double | 0.0d |
在定义对象的时候,如果你使用了基本类型,那么类在初始化后,如果你没有显性地赋值,那么就会为默认值。这在某些场景下是不对的(比如你需要在http中传输id,当对方没有传输id时,你应该报错,但是由于使用了基本的数据类型,id拥有了默认值0,那么此时程序就会发生异常)
定义对象的成员,最好使用包装类型,而不是基础类型.
Integer对象的缓存区
在程序中有些值是需要经常使用的,比如定义枚举时,经常会使用1,2,3作为映射值.Java的语言规范JLS中要求将-128到127的值进行缓存。(高速缓存的大小可以由-XX:AutoBoxCacheMax = <size>选项控制。在VM初始化期间,可以在sun.misc.VM类的私有系统属性中设置并保存java.lang.Integer.IntegerCache.high属性。)
- 使用==比较Integer可能会出现意想不到的结果
public static void main(String[] args) {
Integer a1 = Integer.valueOf(127);
Integer a2 = Integer.valueOf(127);
System.out.println(a1==a2);
Integer a3 = Integer.valueOf(128);
Integer a4 = Integer.valueOf(128);
System.out.println(a3==a4);
}
复制Result:
true
false
复制解决的办法很简单,使用equals来进行比较即可,Integer内部重写了equals和hashcode.
常用的一些转义字符
在字符串中,如果你想让输出的字符串换行,你就需要用到转义字符
转义字符 | Unicode | 含义 |
---|---|---|
\b | \u0008 | 退格 |
\t | \u0009 | 制表 |
\n | \u000a | 换行 |
\r | \u000d | 回车 |
\" | \u0022 | 双引号 |
\' | \u0027 | 单引号 |
\\ | \u005c | 反斜杠 |
\\. | - | . |
- 换行输出字符串
System.out.println("我马上要换行了\n我是下一行");