一些遗漏和易错的知识点
1.每种具体类型的默认值
• 每种具体类型都有不同的默认值;
• 当没有为一个属性变量赋值时,会根据类型为其赋值为默认值;
• 注意: char 的默认值是\u0000,等同于一个空字符; boolean 的默认值是 false
static 静态变量的初始值是JVM默认的初始值,定义一个静态变量的时候都会有一个初始默认值;
类型 | 默认值 |
---|
byte | 0 |
short | 0 |
int | 0 |
long | 0 |
float | 0.0 |
double | 0.0 |
char | “空字符”(\u0000) |
boolean | false |
2. 基本数据类型的显式和隐式转换
• 虽然类型之间可以进行强制的隐式转换,但是也需要有一定的前提;
• 数值类型和 boolean 类型之间就不能转换;强制也不可以;
byte b=1;
boolean b2=false;
b2=b; (编译错误)
b2=(boolean)b; (编译错误)
3.基本数据类型的赋值和比较运算
• 用“=”可以为任何一种基本数据类型的变量赋值;
• 赋值时主要不要超过表示范围,否则将出现编译错误;
byte b1=127;
byte b2=129;
• char类型使用’’引用单个字符赋值;也可以使用非负整数迚行赋值;
char c1='a';
char c2=12;
char c3='ab';
char c4=12.8;
char c5=-199;
• Java中默认的整数类型是 int ,默认的小数类型是 double ;
• 使用f/F后缀显式表示 float 类型;使用d/D后缀显式使用 double 类型;
float f1=1;
float f2=1.0;
float f3=(float)1.0
float f4=1.0f;
double d1=1.0;
double d2=1.0d;
可以使用==、!=、>、<、>=、<=对基本数据类型的数值迚行比较运算;比较的是其二进制的值;
4. 引用类型的赋值和比较运算
• 在Java语言言中,除了上节学习到的 8种基本数据类型,其他类型都是引用类型;
• 也可以说,任何一个对象都是引用类型;
• 引用类型使用=赋值;
• 除了 String 、包装器类(共8个)外,都需要使用 new 关键字;
• 引用类型可以使用==、!=进行比较,比较的是引用类型的地址,不是内容;(之前关于string的一个问题有说明)
• 引用类型不能使用>、>=、<=、<进行比较;
• 当只声明了一个引用类型变量,却没有为其赋值,则此时该变量为null;
5. Java中字符串final特性
• 这个类型在实际编程中使用非常非常非常多;
• 这个类使用了 final 修饰,意思是不能被扩展,不能被修改;
6.字符串常量池
• 字符串可以用两种方式赋值有一个非常重要的特征,即不可变性(immutable);
• 不可变的意思是:一旦一个字符串被创建后,它的值就不能被修改;
String s1="Hello";
s1="World";
并不是把Hello改为了World,而是重新分配空间存储World;
s1的值发生了改变,指向了新的空间;
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201130015332649.bmp#pic_center)
• 为了能够重用这些不变的字符串,Java使用了字符串常量池;
• 凡是用=直接赋值的方式得到的字符串,都存储在常量池中;相同的共用一个具体字符串;
• 使用new创建的字符串不适用常量池,每次都分配新的内存空间;(这个很重要)
String s2="Hello";
String s3="Hello";
String s4=new String("Hello");
String s5=new String("Hello");
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201130015346429.bmp?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3podWFuZzE1,size_16,color_FFFFFF,t_70#pic_center)
• s1不s2使用=赋值,所以使用到常量池,指向同一个Hello;
• s3不s4使用new创建,没有用常量池,每次都分配新的空间,指向一个新的Hello;
• 输出结果如下,能验证论:
System.out.println("s2==s3"+(s2==s3));
System.out.println("s4==s5"+(s4==s5));
System.out.println("s2==s4"+(s2==s4));
s2==s3 true
s4==s5 false
s2==s4 false
7. String、StringBuffer、StringBuilder的区别
• Java语言中的有一个 StringBuffer 类,称为字符串缓冲区;所表示的也是一个字符序列;
• 这个类型必须用new创建对象,和 String 相反,它是可变的类;
StringBuffer sbf1=new StringBuffer ("Etc");
StringBuffer sbf2=new StringBuffer (" Java");
sbf1.append(sbf2);
System.out.println(sbf1);
• 证明: StringBuffer 是一个可变的字符串类;
• Java语言言中的还有一个 StringBuilder 类,与StringBuffer 兼容,但是不保证线程同步;
8.关于float和double的精度问题
问:为什么下面两种情况下输出的结果不一样?
double d3=0.3d;
float d4=0.3f;
System.out.println("d3==d4 "+(d3==d4));
double d3 = 0.5d;
float d4 = 0.5f;
System.out.println("d3==d4 " + (d3 == d4));
• 这题其实和二进制有关,我们要先知道十进制的小数怎么转换成二进制;
• 十进制的小数转换为二进制,主要是小数部分乘以 2,取整数部分依次从左往右放在小数点后,直至小数点后为0(乘二取整法)。例如十进制的0.125,要转换为二进制的小数:
0.125*2=0.25 取0
0.25*2=0.5 取0
0.5*2=1.0 取1
即为二进制为 0.001
• 这边再顺便说下二进制的小数转换为十进制:
二进制的小数转换为十进制主要是乘以 2 的负次方,从小数点后开始,依次乘以2的负一次方,2的负二次方,2的负三次方等。例如二进制数0.001转换为十进制;
一个有限位数的整数一定能转换成有限位数的二进制。但是小数部分就不一定了,一个有限位数的小数并不一定能转换成有限位数的二进制,只有末位是 5 的小数才有可能转换成有限位数的二进制,其它的小数都不行。这边又要提到精度问题;
float 和 double 的尾数部分是有限的,固然不能容纳无限的二进制;即使小数能够转换成有限的二进制,也有可能会超出尾数部分的长度,此时也不能容纳。这样就必须“四舍五入”,将多余的二进制“处理掉”,只保留有效长度的二进制,这就涉及到了精度的问题。也就是说,浮点数不一定能保存真实的小数,很有可能保存的是一个近似值。
float 和 double 的范围是由指数的位数来决定的;
float 的指数位有8位,而 double 的指数位有 11位,分布如下:
1bit(符号位)
8bits(指数位)
23bits(尾数位)
double:
1bit(符号位)
11bits(指数位)
52bits(尾数位)
计算机相关的数字(浮点数)问题的表述中,有一个基本表达法:
(浮点)数值 = 尾数 × 底数 ^ 指数 (附加正负号)
指数部分是有符号的,占一个字节,那么按照补码的表示规则,自然就是-128到127。于是,float的范围为-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;double的范围为-2^1024 ~ +2^1024,也即-1.79E+308 ~ +1.79E+308。
float 和 double 的精度是由尾数的位数来决定的;
对于 float,尾数部分有 23 位,再加上一个隐含的整数 1,一共是 24 位。最后一位可能是精确数字,也可能是近似数字(由四舍五入、向零舍入等不同方式得到);除此以外,剩余的23位都是精确数字。从二进制的角度看,这种浮点格式的小数,最多有 24 位有效数字,但是能保证的是 23 位;也就是说,整体的精度为 23~24 位。如果转换成十进制,224 = 16777216,一共8位;也就是说,最多有 8 位有效数字,但是能保证的是 7 位,从而得出整体精度为 7~8 位。
对于 double,同理可得,二进制形式的精度为 52~53 位,十进制形式的精度为 15~16 位。
回到这题上:
0.5的二进制刚好是0.1 ,小数点就一位,所以 float 和 double 的精度就没有差别了;
0.3的二进制有 53位, float 的精度只有 24位,所以25后的都会被省略掉,所以0.3的为false;