1 Java数据类型概念
数据类型在计算机语言里面,是对内存位置的一个抽象表达方式,可以理解为针对内存的一种抽象的表达方式。
接触每种语言的时候,都会存在数据类型的认识,有复杂的、简单的,各种数据类型都需要在学习初期去了解,Java是强类型语言,所以Java对于数据类型的规范会相对严格。
数据类型是语言的抽象原子概念,可以说是语言中最基本的单元定义。
在Java里面,本质上讲将数据类型分为两种:基本类型和引用数据类型。
1 基本类型:简单数据类型是不能简化的、内置的数据类型、由编程语言本身定义,它表示了真实的数字、字符和整数。
2 引用数据类型:Java语言本身不支持C++中的结构(struct)或联合(union)数据类型,
它的复合数据类型一般都是通过类或接口进行构造,类提供了捆绑数据和方法的方式,同时可以针对程序外部进行信息隐藏。
1.1 基本类型
Java基本类型共有八种,基本类型可以分为三类:
- 字符类型 :
char - 布尔类型 :
boolean - 数值类型 :
byte、short、int、long、float、double
数值类型又分为 :
- 整数类型 :
byte、short、int、long - 浮点数类型 :
float、double
Java中的数值类型不存在无符号的,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变。
JAVA中还存在另外一种基本类型void,它也有对应的包装类 java.lang.Void,不过我们无法直接对它们进行操作。
8种类型表示范围如下:
byte:1字节,8位,最大存储数据量是255,存放的数据范围是-128~127之间。
short:2字节,16位,最大数据存储量是65536,数据范围是-32768~32767之间。
int:4字节,32位,最大数据存储容量是2的32次方减1,数据范围是负的2的31次方到正的2的31次方减1。
long:8字节,64位,最大数据存储容量是2的64次方减1,数据范围为负的2的63次方到正的2的63次方减1。
float:4字节,32位,数据范围在3.4e-45~1.4e38,直接赋值时必须在数字后加上f或F。
double:8字节,64位,数据范围在4.9e-324~1.8e308,赋值时可以加d或D也可以不加。
boolean:参见注,只有true和false两个取值。
char:2字节,16位,存储Unicode码,用单引号赋值。
注:单个的boolean类型变量,即boolean b,在这里说b是和int 一样占有四个字节,我觉得不合适。
在oracle的官方文档[JVM第七版本]的描述中对boolean类型进行编译的时候是把boolean类型的值以int的形式映射到编译器上的,
并且在JVM中都没有专门处理boolean 类型的指令,应该是在程序读到boolean时,会在内存的“data”区开辟一块空间用来存放true或false。
public class Calcsizof {
private static void calSize() {
System.out.println(Integer: + Integer.SIZE/8); // 4
System.out.println(Short: + Short.SIZE/8); // 2
System.out.println(Long: + Long.SIZE/8); // 8
System.out.println(Byte: + Byte.SIZE/8); // 1
System.out.println(Character: + Character.SIZE/8); // 2
System.out.println(Float: + Float.SIZE/8); // 4
System.out.println(Double: + Double.SIZE/8); // 8
System.out.println(Boolean: + Boolean.toString(false)); //false
}
public static void main(String[] args) {
Calcsizof calcsizof= new Calcsizof();
Calcsizof.calSize();
}
}
1.2 引用类型
Java有 5种引用类型(对象类型):
- 类
- 接口
- 数组
- 枚举
- 标注
引用类型:底层结构和基本类型差别较大
JVM的内存空间:
- Heap堆空间:分配对象 new Student()
- Stack栈空间:临时变量 Student stu
- Code代码区 :类的定义,静态资源 Student.class
Student stu = new Student(); //new 在内存的堆空间创建对象
stu.study(); //把对象的地址赋给stu引用变量
上例实现步骤:
- 1 JVM加载Student.class 到Code区 new Student()在堆空间分配空间并创建一个Student实例
- 2 将此实例的地址赋值给引用stu, 栈空间
基本类型的优势:数据存储相对简单,运算效率比较高,包装类的优势:有的容易,比如集合的元素必须是对象类型,满足了java一切皆是对象的思想;
区别:基本数据类型和引用类型的区别主要在于基本数据类型是分配在栈上的,而引用类型是分配在堆上的(需要java中的栈、堆概念)。
1.3 封装类
从JDK 5.0开始,Java里面出现了自动拆箱解箱的操作,基于这点需要做一定的说明:
对应原始的数据类型,每种数据类型都存在一个引用类型的封装类,分别为Boolean、Short、Float、Double、Byte、Int、Long、Character,这些类型都是内置的封装类,这些封装类(Wrapper)提供了很直观的方法,针对封装类需要说明的是,每种封装类都有一个xxxValue()的方法,通过这种方法可以把它引用的对象里面的值转化成为基本变量的值,不仅仅如此,每个封装类都还存在一个valueOf(String)的方法直接把字符串对象转换为相应的简单类型。
在JDK 5.0之前,没有存在自动拆解箱的操作,即Auto Box操作,所以在这之前是不能使用以下方式的赋值代码的:Integer a = 0;
这种赋值方式不能够在JDK 1.4以及以下的JDK编译器中通过,但是JDK 5.0出现了自动拆解箱的操作,所以在JDK 5.0以上的编译器中,以上的代码是可以通过的
整形类型&封装类:
byte ---------> Byte
short ---------> Short
int ---------> Integer
long ---------> Long
浮点类型&封装类
float ---------> Float
double ---------> Double
字符类型&封装类
char ---------> Character
布尔类型&封装类
boolean ---------> Boolean
Java中的封装类:
封装类将基本类型对象化的意义在于,开发者更容易操作基本类型,包括以下基本类型下的常量(Max Min)等,下面我们一Integer为例,总结一下封装。
1、MIN_VALUE常量的定义 :可以让我们更加容易取得int类型的最小值
2、toXXXString的定义:可以让开发者更容易的将int转为X进制的字符串
3、与2相反,能够将字符串解析成int,如果不在范围内则抛出NumberFormatException异常
4、final 表示此类不允许继承再次封装
5、Comparable 表示此类型可以进行比较并对此类对象集合进行排序
6、Number表示所有的封装类均继承了Number抽象类并实现部分所需的方法,且Number类实现了java.io.Serializable 接口,可以序列化
1.3.1 封装类的装箱
public class Test {
public static void main(String[] args) {
Integer I = new Integer(100);//装箱 【基本类型---->封装类】
int ii = I;//拆箱 【封装类---->基本类型】
System.out.println(I);
System.out.println(ii);
}
}
输出:
100
100
1.3.2 封装类的比较
public class Test {
public static void main(String[] args) {
Integer I1 = 100;// 装箱1
Integer I2 = 100;// 装箱2
Integer I3 = 200;// 装箱3
Integer I4 = 200;// 装箱4
System.out.println(I1 == I2);
System.out.println(I3 == I4);
}
}
输出:
true
false
为什么同样的装箱操作后,结果却不一样?
先看下源码:
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return <strong>IntegerCache.cache[i + (-IntegerCache.low)];</strong>
return <strong>new Integer(i);</strong>
}
原来在Integer中有一个缓存机制,对于-128 ~127的封装类在装箱时直接获取的是缓存中的Integer对象,对于100当然获取的就是同一个对象了,所以使用==比较了内存的地址,故返回true,而200 超出了缓存大小需要new 重新开辟内存,所以返回false。
所以对于封装类属于引用类型,在比较时使用equal才是正确的!!!
1.4 常量
1.4.1 整型常量
十六进制整型常量:以十六进制表示时,需以0x或0X开头,如0xff,0X9A。
八进制整型常量:八进制必须以0开头,如0123,034。
二进制整型常量:二进制必须以0b开头,如0b101,0b111。
长整型:长整型必须以L作结尾,如9L,342L。
浮点数常量:由于小数常量的默认类型是double型,所以float类型的后面一定要加f(F)。
同样带小数的变量默认为double类型。
如:
float f;
f=1.3f;//必须声明f
1.4.2 字符常量
字符型常量需用两个单引号括起来(注意字符串常量是用两个双引号括起来)。
Java中的字符占两个字节。一些常用的转义字符:
①\r表示接受键盘输入,相当于按下了回车键;
②\n表示换行;
③\t表示制表符,相当于Table键;
④\b表示退格键,相当于Back Space键;
⑤’表示单引号;
⑥’'表示双引号;
⑦\表示一个斜杠\。
⑦\表示一个斜杠\。
1.4.3 数据类型转换
1.4.3.1 低级别转高级别
其实低级别就相当于较小的一个容器 A(容积: 0 ~ 10ml);高级别则为大一点的容器B(容积: 0 ~ 1000ml),
由于两个容积不同 (A < B),所以我们在使用场景有所不同,容器A可以作为试管,而容器B可以作为喝水的杯子。
举例 1:byte —> int
public class Test {
public static void main(String[] args) {
byte b = 12; //小容器
int i = b; //小容器--->大容器
System.out.println(b);
System.out.println(i);
System.out.println(i==b);
}
}
输出:
12
12
true
举例 2:char —> short
注:char 虽然表现为字符,但是在数值转换中它将表现为Ascll码值, 比如 ‘a’ 的 ASCLL码为97。
public class Test {
public static void main(String[] args) {
char a = 'a';
char b = 'b';
int ia = a;
int ib = b;
System.out.println("ia = " + ia);
System.out.println("ib = " + ib);
}
}
输出:
ia = 97
ib = 98
1.4.3.2 同级别
同级别的转换,主要涉及三种,在此只总结第一种,浮点与整型之间转换将会在后面总结。
1. char <----------> short
2. int <----------> float (后面总结)
3. long <----------> double(后面总结)
在上面的一张图片中,我们能够发现char 和 short的取值范围并非相同,只有一部分交集,所以如果直接相互转换必定会出现错误,在Java中可以通过强转来完成,当然也是存在一定的风险,比如:将char c = 65535 直接转换给 short s = c 时,虽然我们可以如下面代码编译通过,但是因为short的最大取值为 32767 ,已经超出了short的取值范围,在程序运行时必定出错。所以当我们使用数值转换时定要小心。最终建议:尽量不要使用转换类型,后面将会总结DigDecimal类的操作以解决此类问题。
public class Test {
public static void main(String[] args) {
char c = 65535;
short s = (short) c;<strong>//需要强转</strong>
System.out.println(c);
System.out.println(s);
}
}
输出:
?
-1
1.4.3.3 高级别转低级别(强转)
对于高级别向低级别的转换则涉及的名词就是“强转”,也是存在一定的风险。
主要表现为两种:
1、转换错误
2、丢失精度
1.4.3.4 整型类型间的强转
int —> char 【转换错误】
public class Test {
public static void main(String[] args) {
int i = 65536;//Character.MAX_VALUE + 1
char s = (char) i;<strong>//需要强转</strong>
System.out.println("i = "+i);
System.out.println("s = "+(int)s);
}
}
输出:
i = 65536
s = 0
1.4.3.5 浮点类型间的强转
double —> float 【丢失精度】
public class Test {
public static void main(String[] args) {
double d = Float.MAX_VALUE + 1;
float f = (float) d;<strong>//需要强转</strong>
System.out.println("d = " + d);
System.out.println("f = " + f);
}
}
输出:
d = 3.4028234663852886E38
f = 3.4028235E38
1.4.3.6 整型类型&浮点类型之间的强转
举例 1:float —>int【丢失精度】 | 【转换错误】 | 【转换错误】&【丢失精度】
下面的例子属于最严重的错误类型:【转换错误】&【丢失精度】
public class Test {
public static void main(String[] args) {
float f = Float.MAX_VALUE;
int i = (int) f;
System.out.println("f = " + f);
System.out.println("i = " + i);
}
}
输出:
f = 3.4028235E38
i = 2147483647
强制类型转换的风险很大,可能有一些取值范围存在交集部分转换正常,而非交集部分则差之千里。这最容易出现“偶现问题”,难于定位。在使用时一定要熟悉转换的取值范围。
1.5 Java中的数据类型与内存的关系
在Java中,每个存放数据的变量都是有类型的,如:
char ch;
float x;
int a,b,c;
ch是字符型的,就会分配到2个字节内存。不同类型的变量在内存中分配的字节数不同,同时存储方式也是不同的。
所以给变量赋值前需要先确定变量的类型,确定了变量的类型,即确定了数据需分配内存空间的大小,数据在内存的存储方式。
1.5.1 Java数据类型存储原理
- 1 基本数据类型的存储原理:所有的简单数据类型不存在“引用”的概念,基本数据类型都是直接存储在内存中的内存栈上的,数据本身的值就是存储在栈空间里面,而Java语言里面八种基本数据类型是这种存储模型;
- 2 引用类型的存储原理:引用类型继承于Object类(也是引用类型)都是按照Java里面存储对象的内存模型来进行数据存储的,使用Java内存堆和内存栈来进行这种类型的数据存储,简单地讲,“引用”是存储在有序的内存栈上的,而对象本身的值存储在内存堆上的;
区别:基本数据类型和引用类型的区别主要在于基本数据类型是分配在栈上的,而引用类型是分配在堆上的(需要java中的栈、堆概念),
基本类型和引用类型的内存模型本质上是不一样的。
例1:我们分析一下”==“和equals()的区别,定以两个String对象:
Stringa="abc";
Stringb="abc";
//然后
if(a==b){
System.out.println("a==b");
}else{
System.out.println("a!=b");}
程序输出: a!=b
原因:a和b的地址是不相同的,a**==b比较的是两个变量的地址**
例2:定义两个基本类型:
int a=4;
int b=4;
if(a==b){
System.out.println("a==b");
}
else{
System.out.println("a!=b");
}
输出:a==b
原因:==比较的是两个变量的内容
猜想:不论是基本数据类型还是引用类型,他们都会先在栈中分配一块内存,对于基本类型来说,这块区域包含的是基本类型的内容;而对于对象类型来说,这块区域包含的是指向真正内容的指针,真正的内容被手动的分配在堆上。
2 附录
2.1 引用数据类型
- 数组
- String:字符串型,用于存储一串字符
2.2 变量声明及使用
数据类型变量名 =值、表达式;
例:String name = “柯南”;
int a= 50;
注:“=”并不是数学中的“等号”,而是一个赋值运算符
2.3 变量命名规则
- 必须以字母、下划线“_”、或“$”符号开头
- 可以包括数字、区分大小写
- 不能使用Java语言的关键字,例如int、class、public等
2.4 六种运算符:
· 算术运算符
· 赋值运算符
· 关系运算符
· 逻辑运算符
· 位运算符
· 三元运算符
2.4.1 算术运算符
+:加法运算,求操作数的和
-:减法运算,求操作数的差
*:乘法运算,求操作数的乘积
/:除法运算,求操作数的商
%:求余运算,求操作数相除的余数
++:自增,操作数自加1
–:自减,操作数自减1
2.4.2 赋值运算符
=:将右边的值赋给左边,例:int a = 1;
+=:左右两边的和相加赋给左边,例:int a = 1; a+=2;结果a的值为3
-=:左边减去右边的差赋给左边,例:int a =5;a-=2;结果a的值为3
=:两边数值相乘的值赋给左边,例:int a = 2;a=2;结果a的值为4
/=:左边除以右边的值赋给左边,例:int a = 6;a/=2;结果a的值为3
%=:左边除以右边的余数赋给左边,例:int a =7;a%=2;结果a的值为1
2.4.3 关系运算符
>:大于,例:int a = 1;int b = 2;System.out.print(a > b);其结果为false
<:小于,例:int a = 1;int b = 2;System.out.print(a < b);其结果为true
>=:大于等于,例:int a = 1;int b = 2;System.out.print(a >= b);其结果为false
<=:小于等于,例:int a = 1;int b = 2;System.out.print(a <= b);其结果为true
==:等于,例:int a = 1;int b = 2;System.out.print(a == b);其结果为false
!=:不等于,例:int a = 1;int b = 2;System.out.print(a != b);其结果为true
其结果都是boolean类型,即要么是true要么是false
2.4.4 逻辑运算符
&&:与、并且(短路), 两个条件同时为真时,结果为真
||:或、或者(短路), 两个条件有一个为真时,结果即为真
!:非,(!+条件) 条件为真时,结果为假


被折叠的 条评论
为什么被折叠?



