Java数据类型
Java数据类型分为
- 基本数据类型(8大基本数据类型)
- 引用数据类型(数组、String、类、接口、枚举、注解)
Java数据类型的存储原理
1)非全局基本数据类型是直接存储在内存中的栈内存上,数据本身的值就是存储在栈空间里面
全局的基本数据类型是直接存储在堆内存中,如类变量、成员变量
2)引用数据类型以一种特殊的方式指向变量的实体,类似C的指针
引用数据类型变量在声明时不会分配内存,必须在堆内存中开启内存空间,然后把地址引用交给栈内存中的对象
Java 8大基本数据类型
记忆方式分2种
1)按类型(这种好记)
整数 byte、short、int、long
浮点数 float、double
字符 char
布尔 boolean
2)按字节数(1个字节8位)
8位1字节 boolean
8位1字节 byte
16位2字节 short、char
32位4字节 int、float
64位8字节 long、double
数据范围
Java中的变量,先声明,后使用
boolean true或false
byte -128 ~ 127
short -32768 ~ 32767
int -2147483648 ~ 2147483647
数值数据溢出
当数据的大小超出范围,而程序中未作数值范围检查时,这时会导致数据溢出
具体表现形式为最大值加1时,结果表示为范围最小值,即一种循环现象
处理方法:
1)做数值范围判断(必须)
2)类型转换,int转为long,注意long类型后加L
字符类型char
字符类型在内存中占2个字节,16位
但是严格来说,字符类型也是整数类型的一种
在计算机中,所有的文字数值都是一串0和1,即机器码
但是通过某种字符编码转换,即可把文字 --> 数值 --> 机器码,如char类型的a = '97'
常见的字符编码utf-8、unicode
不同的字符编码转换时会有错误发生,所以要统一编辑器采用的字符编码 utf8
转义字符
\t 制表符(相当于Tab)
\n 换行
\\ 反斜线
\f 换页
\b 倒退一格
\' 单引号
\r 归位
\'' 双引号
浮点数
带有小数点的数值在java中称为浮点数
- 单精度 float 32位
- 双精度 double 64位
使用浮点数类型,默认为double
在数值后加d或是f,可分别标识为double、float
布尔类型
boolean类型,只有true和false两个值
默认值为false
基本数据类型的默认值
byte (byte)0
short (short)0
int 0
long 0L
float 0.0f
double 0.0d
char \u0000
boolean false
在Java中,若基本数据类型变量声明时没有给变量赋值,则会给变量赋默认值
引用数据类型的默认值是null,避免空指针
数据类型的转换
1)自动类型转换
自动转换需要满足下面条件
转换前的数据类型与转换后的类型兼容
转换后的数据类型的表示范围比转换前的类型范围大
如整数与整数运算,结果仍为整数 10/3 = 3
整数与浮点数运算,结果为浮点数 10/3.0 = 3.33
实际上是,整数先转换为浮点数,然后再与浮点数进行运算
任何数据类型碰到字符串后都会向 String类型转换,如30+"Hello"
2)强制类型转换
强制转换是直接写在代码里的,又称显式转换
(要强制转换的类型)变量名
System.out.println((float)(10/3));
运算符
1)赋值运算符
a = 3
2)算术运算符
+ - * / %
/ 除法
% 取余(模运算)
3)关系运算符
> < >= <= == !=
注意 ==表示等于判断,=表示赋值
4)逻辑运算符
& && | ||
常用的是&&和||
&& 前后皆为真,运算结果才会为真
|| 前后有一个为真,运算结果才会为真
5)括号运算符
() 括号运算优先级最高
6)自增自减运算符
++a 先将a+1,再执行整个语句
--a 先将a-1,再执行整个语句
a++ 先执行整个语句,再将a+1
a-- 先执行整个语句,再将a-1
选择语句
if
if else
switch
max = x>y?x:y
下面给出switch标准结构
int i = 20;
switch(i/10){
case 1:
System.out.println("a=10");
break;
case 2:
System.out.println("a=20");
break;
case 3:
System.out.println("a=30");
break;
default:
System.out.println("i do not know what is a");
}
注意,每一个case后面都要跟break,这样才能跳出判断
default是当上述case都不满足时执行
循环语句
while
do while
for
foreach 作为特殊的for循环
下面给出while基本结构
// 当条件不为真,跳出
int res = 0;
int num = 1;
while (num <= 10){
res = res + num;
num = num + 1;
}
System.out.println(res);
注意,当while()括号中条件为假时跳出循环
do while与while基本类似,但是有2点需要注意(一般用while)
1)do while不会判断,直接先执行一次循环主体,再进行判断
2)while判断条件,都是为假时才会跳出循环
下面给出for基本结构
int res = 0;
for(int j=1;j<=10;j++){
res = res + j;
}
System.out.println(res);
注意,只有明确知道循环次数,就是用for循环
下面给出foreach基本结构
foreach并不是一个关键字,习惯上将这种特殊的for语句格式称之为“foreach”语句
常用于遍历数组、集合的元素,大大简化for遍历
int[] arr = new int[3];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
for(int x:arr){
System.out.println(x);
}
问题
基本数据类型与引用数据类型区别?
1)基本数据类型
关于基本数据类型到底存储在哪里?分2种情况,全局(堆)、非全局(栈)
参考链接 blog.csdn.net/balsamspear…
2)引用数据类型,继承于Object类(也是引用类型)都是按照Java里面存储对象的内存模型来进行数据存储的,使用Java内存堆和内存栈来进行这种类型的数据存储
简单地讲,“引用”是存储在有序的内存栈上的,而对象本身的值存储在内存堆上的
区别:
主要在于非全局基本数据类型是存储在栈上的,而引用数据类型,其具体内容都是存放在堆中,而栈中存放的是其具体内容所在内存的地址
另一个区别是,数值传递和引用传递
==和equals区别
1)对于基本数据类型
他们只有值可以比较,因此 ==比较的是值,基本数据类型没有equals()方法
2)对于引用数据类型
有堆栈空间之分,且栈空间存的是引用,堆空间存的是值内容
== 比较的是堆内存地址
注意:对于引用数据类型,每new一次,都会重新开辟堆内存空间,此时堆内存地址不同
如果是同一个new出来的对象,他们的==比较后的结果为true,否则比较后结果为false
equals()方法本身继承自Object超类,从源码中可以看出,使用的就是==,比较的也是对象的堆内存地址
但是一般来说,意义不大,所以,在一些类库当中这个方法被重写了
如String、Integer、Date
在这些类中,重写equals()方法,让其不再比较堆内存地址,而是堆内存中的值内容是否相同
总结来说
== 在基本数据类型中比较的是值内容,因为基本数据类型没有堆栈内存,也没有equals()方法
== 在引用数据类型中比较的是堆内存地址,equals()方法在Object基类中比较的也是堆内存地址,但是很多引用数据类型重写了此方法,让其比较的是堆内存中的值内容
单精度float和双精度double有什么区别?
float 单精度浮点数
double 双精度 浮点数
区别:
1)在内存中占有字节数不同
单精度浮点数,占有4个字节,32位
双精度浮点数,占有8个字节,64位
2)有效数字位数不同
单精度浮点数,有效位数8位
双精度浮点数,有效位数16位
3)数值取值范围
单精度浮点数的表示范围:-3.40E+38~3.40E+38
双精度浮点数的表示范围:-1.79E+308~-1.79E+308
4)程序处理速度不同
一般来说,CPU处理单精度浮点数的速度比处理双精度浮点数快
java中浮点数,默认为double,用float的话,需要强转(float)3.33
例如:
float a = 1.3; 会编译报错,正确的写法 float a = (float)1.3
或者float a = 1.3f;(f或F都可以不区分大小写)
注意,float有8位有效数字,第7位数字将会四舍五入
什么叫精度丢失?
简单地说,float和double类型主要是为科学计算和工程计算而设计的
虽然它们执行二进制浮点运算,能够在广泛的数值范围内提供更精确的快速近似和计算而精心设计的
但是,它们不能提供完全准确的结果,因此不能用于需要计算精确结果的场景中。
当浮点数达到一定的大数时自动使用科学计数法,这样的表示只是近似真实数而不等于真实数
当十进制小数转换为二进制时,也会出现无限循环或超出浮点数尾部的长度,见下图
小结:
在商业的加减乘除运算上只会用BigDecimal类型,因为它足够精确
为啥不用float和double呢?因为在从小数点转换到二进制时会丢失精度,产生不准确的尾数,导致结果不够精确
BigDecimal在处理的时候把十进制小数扩大N倍让它在整数上进行计算,并保留相应的精度信息
&&、||与&、|区别?
与,分为短路与和非短路与
或,分为短路或和非短路或
短路与A&&B,只要A出现false,则不会判断B,直接为false
非短路与A&B,需要判断2个条件A和B,哪怕A为false也会去判断B
所以使用短路与和短路或更快,更符合逻辑性
break与continue区别
break和continue都属于中断语句
break; 会强制程序中断循环,去执行外层的代码
continue; 会强制程序跳到循环的起点代码处,继续执行剩余的循环主体
如下,结果仅输出1234con6789,而不会输出5
for(int a=1; a<10; a++){
if(a == 5){
System.out.print("con");
continue;
}
System.out.print(a);
}
BigInteger 超大范围数值类型
Java中,由CPU原生提供的整形最大范围的是64位Long类型
但是当要使用的数超过Long类型时怎么办?
java.math.BigInteger就是用来表示任意大小的整数
BigInteger内部用的是一个int[]数组来模拟一个非常大的整数
BigInteger bi = new BigInteger("1234567890");
System.out.println(bi.pow(5)); // 2867971860299718107233761438093672048294900000
对BigInteger做运算时,只能使用实例方法
如加法:
BigInteger i1 = new BigInteger("1234567890");
BigInteger i2 = new BigInteger("12345678901234567890");
BigInteger sum = i1.add(i2); // 12345678902469135780
小结:
1)和Long类型比起来,BigInteger不会有范围限制,但是缺点是速度比较慢
2)BigInteger的加减乘除,只能使用实例方法,而不能使用运算符直接计算
3)BigInteger的父类是Number,因此也可以使用转换方法 转换位基本类型
转换为byte:byteValue()
转换为short:shortValue()
转换为int:intValue()
转换为long:longValue()
转换为float:floatValue()
转换为double:doubleValue()
但是在转换时如果超出范围,将直接抛出ArithmeticException异常。