数据类型
数据类型用来声明变量,程序运行过程中依照不同的数据类型来分配不同大小的空间
基本类型 Primitive Type
8种基本数据类型
- 整数型 byte,short,int,long
- 浮点型 float,double
- 布尔型 boolean
- 字符型 char
类型 | 字节 | 取值范围 |
---|---|---|
byte | 1 | -128~127 |
short | 2 | -32767~32768 |
int | 4 | -2147483647~2147483648 |
long | 8 | |
float | 4 | |
double | 8 | |
boolean | 1 | true/false |
char | 2 | 0-65535 |
short和char实际上容量相同,不过char可以表示更大的数字
字符型
char
char可以存储1个汉字,汉字占用两字节,char也占用两字节,char采用UNICODE编码
char c = 'ab';
/*报错信息:未结束的字符文字*/
char d = "a";
/*报错信息:类型不兼容*/
未结束的字符文字: 编译器认为 'a 之后应该有一个 ’ 但是出现了一个 b
转义字符
char s1 = '\t';
System.out.println("abc" + s1 + "def");
System.out.println("abc\tdef");
char s2 = '\n';
System.out.println("abc" + s2 + "def");
'\t’表示制表符tab
'\n’表示换行符
假设要输出一个 \
System.out.println('\');
这样是行不通的,因为\将后面的单引号转义为一个字面量,编译器认为此处少了一个单引号,所以应该是
System.out.println('\\');
若想输出 “test”
System.out.println("\"test\"");
\u 表示后面的内容是一个字符的Unicode编码,十六进制。
例如:
char x = '\u4e2d';
System.out.println(x); //输出了一个 中
UNICODE 编码
ASCII码采用1byte 存储
例如’a’ -> 97 ‘A’ -> 65 ; 而97 -> 0110 0001 , 'a’变为0110 0001 的过程是编码 反过来是解码
国际标准组织制定了ISO-8859-1编码方式(latin-1),向上兼容ASCII,不支持中文
简体中文编码方式:GB2312 < GBK < GB18030 繁体中文编码方式:big5
Java为了支持全球文字采用UNICODE编码,包括UTG-8,UTF-16,UTF-32等
整数型
int
在任何情况下,整数型字面量/数据被当作int类型处理,如果希望该字面量被当作long类型处理,需要在字面量后面加上L/l
- 整数型字面量:八进制以0开头,十六进制以0x开头
- 小容量转大容量 : 自动类型转换
- 大容量转小容量 : 需要加强制类型转换符,并且可能有精度损失
int a = 100; //数据当作int类型处理,不存在类型转换
long b = 200; //数据当作int类型处理,小容量转大容量,自动类型转换
long c = 300L; //300L是一个long类型的字面量,不存在类型转换
long d = 2147483647; //int类型最大值,自动类型转换
long e = 2147483648; /*报错信息:整数太大*/
报错是因为整数被看作int,而这个字面量超过了int的存储范围,编译报错。
解决办法: 在最后加一个L
long x = 100L;
int y = x; /*报错信息:不兼容的类型*/
报错是因为 编译器检查到2行代码处只知道x是一个long类型的值,而不知道其中存储的数据究竟是多少,解决办法是:
int y = (int)x; //进行强制类型转换
在底层转换的过程中:
long类型的100L : 00000000 00000000 00000000 00000000 00000000 00000000 00000000 01100100
转换为int类型时,会强制性的把前面的四个字节去掉,变为00000000 00000000 00000000 01100100
byte
byte x = 127;
byte y = 1;
按上面的规则: 整数型字面量被当作int处理,此处应该报错; 但是java还有一条规则:
当整数型字面量没有超过byte/short/char的取值范围时,那么这个整数型字面量可以直接赋值给byte
int 与 char的混合运算
先说三个重要结论:
- 当一个整数赋值给char类型的变量时,会自动转换成char字符类型,最终的结果是一个字符
char s1 = 'a';
System.out.println(s1); //输出正常
char s2 = 97;
System.out.println(s2); //得到的也是a
char s3 = 65535;
System.out.println(s3); //得到了一个未知字符
char s4 = 65536; /*报错: 不兼容的类型*/
- byte、short、char混合运算时,会各自先转换成int类型再运算
char c1 = 'a';
byte b = 1;
char s1 = c1 + b;/*报错:不兼容的类型*/
char s2 = 98;
第三行报错是因为 虽然整数可以直接赋给char类型,但是上面的运算结果得到的是一个int类型,这样JVM就会提示报错
- 多种数据类型混合运算时,最终结果的类型是容量最大的数据类型(结论二除外)
long a = 10L;
char c = 'a';
short s = 100;
int i = 30;
System.out.println(a + c + s + i);//结果是237
int x = a + c + s + i; /*报错信息:不兼容的类型:从long转换到int可能会有损失*/
浮点型
double
Java中规定任何一个浮点型数据都默认当作double类型处理,如果想让这个浮点型字面量被当作float类型来处理,需要在字面量最后加上F/f(1.0默认是double ,1.0f认为是float)
int i = 10.0/5; /*报错信息:不兼容的类型,从double转为int可能有损失*/
此处的运算满足上面的规则: 先将5转换为容量最大的数据类型double,再进行除法运算
float
float f = 3.14; /*报错信息:cannot convert from double to float*/
赋值给float类型变量:1. 最后加上f
2.强制类型转换
银行财务类
在银行或者财务问题中double的精度也是远远不够的,java提供了一种精度更高的类型:java.math.BigDecimal
float/double存在的问题:
float d1 = 212313131f;
float d2 = d1 + 1;
System.out.println(d1 == d2);//结果竟然是true 这就存在问题了
引用类型 Reference Type
类(String是类的一种),接口,数组等
String
String 表示字符串类型,属于引用数据类型;
Java中规定用""括起来的都是String对象,例如:“abc"就是一个String类型对象; 并且”"括起来的字符串是不可变的
在JVM中,以""括起来的字符串都是直接存储在 方法区 中的 字符串常量池 里,这是因为字符串在实际的开发中使用的太频繁了,这样做是为了提高执行效率
在JDK7.0之后就把字符串常量池移动到堆内存当中了。
String s1 = "abcdef";
String s2 = "abcdef" + "xy";
这两行实际上创建了三个字符串对象,一个是"abcdef",一个是"xy",另一个是字符串拼接后的"abcdefxy",也就是说 凡是以""括起来的,在字符串常量池中都有一份
String s3 = new String("xy");
用new调用构造方法时,一定会在堆内存中开辟存储空间,所以在此处是在堆内存中开辟了一个对象,该对象指向了已经存在的xy
以下是内存图: (此为JDK7.0前版本)
User user = new User(110,"张三");
String s1 = "hello";
String s2 = "hello"; //这个hello不会新建字符串对象
System.out.println(s1 == s2);
第三行比较的就是变量中保存的内存地址 ,结果为true
String x = new String("xyz");
String y = new String("xyz");
System.out.println(x == y);
System.out.println(x.equals(y));
第三行比较的是 x 和 y 中保存的 堆内存中的对象的内存地址,结果为false; 第四行调用了String类的equals方法,作用是比较两个字符串是否相等,所以结果为true