java基础(一) 深入解析基本类型
一、基本类型的简介
基本类型的两条准则:
- Java中,如果对整数不指定类型,默认时int类型,对小数不指定类型,默认是double类型。
- 基本类型由小到大,可以自动转换,但是由大到小,则需要强制类型转换。
所占的字节数:
byte: 1个字节;
char: 2个字节;
short: 2个字节;
int: 4个字节;
long: 8个字节;
float: 4个字节;(6位小数,指数是:10-38~1038; 范围:)
double: 8个字节;
char:Java中用 "\u四位十六进制的数字 (即使在注释中出现\u,后面如果
跟的不是4个16进制的数字,也会报错)"表示将字符转换成对应的unicode编 码;也可以用字符来赋值如: char c="\u0000" ,char的默认初始化值,unicode的null字符
基本类型的后缀:
long : l 或 L
float: f 或 F;
double: d 或 D
二、类型转换
正如前面所说的,类型由大到小,是必需强制转换。但这并不意味着需要用户手动强制转换 —— 也就是 隐式转换。隐式转换 说的透彻点就是由编译器来进行强制转换,不需要用户再去写强制转换的代码。下面的前两个小点所说的便是特殊的隐式类型转换。
本小节所讨论的类型转换是不包括 类型由小到大的转换,讨论的是其他比较容易让人迷惑的类型转换
1. int类型的字面常量转换成比int类型低的变量类型
所谓的字面常量就是值的本身,如 5、7、“aa”等等。我们先看个例子:
public static void main(String[] args) {
int a = 8; //8是字面常量
byte b = 9; //9是字面常量
char c = 9+5;//常量表达式
short s = (short) (c+10); //变量表达式,需要显式强制转换
}
上面的代码是经过编译的,是正确的。b是byte类型,但b=9
不需要显式地手动强制转换,这是因为9是字面常量,是由JVM自动完成。
我们再来看一下c=9+5
,c是char类型,9+5
得到结果是int类型,但也不需要显式地手动强制转换。这是因为 9+5
是常量表达式,所以在编译期间已经由编译器计算出结果了,即经过编译后,相当于 c=14
,也是字面常量,所以可以隐式转换。同理,short s = (short) (c+10);
子所以不能隐式转换,就是因为表达式不是常量表达式,包含了变量,只能在运行期间完成,所以就要手动强制转换。
整形字面常量隐式转换的限制:
- 整形字面常量的大小超出目标类型所能表示的范围时,要手动强制类型转换。
byte b = 128;//编译错误,128超出byte类型所能表示的范围
byte c = (byte)128;//编译通过
- 对于传参数时,必须要显式地进行强制类型转换,明确转换的类型
编译器子所以这样要求,其实为了避免 方法重载出现的隐式转换 与 小类型自动转大类型 发生冲突。
public static void main(String[] args) {
shortMethod(8);//编译错误
shortMethod((short)8); //编译通过
longMethod(8);//编译通过,因为这是小类型变成大类型,是不需要强制类型转换的
}
public static void shortMethod(short c){
System.out.println(c);
}
public static void longMethod(short l){
System.out.println(l);
}
- char类型的特殊情况 :下面再细讲
2. 复合运算符的隐式转换
复合运算符(+=、-=、*=、/=、%=)是可以将右边表达式的类型自动强制转换成左边的类型
public static void main(String[] args) {
int a = 8;
short s = 5;
s += a;
s += a+5;
}
s+=a
、s+=a+5;
的表达式计算结果都是int类型,但都不需要手动强制转换。其实,如果是反编译这段代码的class文件,你会发现s+=a;
,其实是被编译器处理成了
s=(short)(s+a)
也就是说对于所有的复合运算的隐式类型转换,其实是编译器自动添加类型转换的代码。
所以,相对于整形字面常量的隐式转换,复合运算符的隐式转换则没有任何限制因为前者只能在编译器期间发生,后者则是编译器实实在在的补全了类型转换的代码。
3. 特殊的char类型
char类型在基本类中是一个比较特殊的存在。这种特殊性在于char类型是一个无符号类型,所以char类型与其他基本类型不是子集与父集间的关系(其他类型都是有符号的类型)。也就是说,char类型与byte、short之间的转换都需要显式的强制类型转换(小类型自动转换成大类型失败)。
同时,由于char类型是一个无符号类型,所以对于整形字面常量的隐式转换的限制,不仅包括字面常量数值的大小不能超出2个字节,还包括字面常量数值不能为负数
byte b = 2;
char c = 2;//编译通过
c = 100000000000;//编译不通过,超出char类型的范围
char d = -2//字面常量为负数,编译不通过
d = (char)-100;//编译通过
char f = (char)b; //编译通过,必须显式的强制类型转换
f = b;//编译不通过,不能隐式转换
int i = c;//编译通过,可以不需要强制类型转换
short s = (short) c;//编译通过,必须显式地强制类型转换
char类型是无符号的类型,这种无符号也体现在在其转换成int类型时,也就是说,char类型在扩展时,也是按无符号的方式扩展,扩展位填0。我们来看一个例子:
public static void main(String[] args) {
short s = -5;
char c = (char)s;
System.out.println(c==s); //false
System.out.println("(int)c = "+(int)c); //转换成int类型,值为65531
System.out.println("(short)c = "+(short)c); //-5
System.out.println("(int)s = "+(int)s);//-5
}
运行结果:
false
(int)c = 65531
(short)c = -5
(int)s = -5
从上面的结果发现,char类型的c 与 short类s其实存储字节码内容是一样的,但由于前者是无符号,所以扩展成int类型的结果是 65531,而不是 -5。运算符==
比较的就是他们扩展成int类型的值,所以为fasle。
对char类型的类型转换,可以总结成以下几点:
- char类型与byte、short的相互转换,都需要显式地强类型制转换。
- 对于数值是负数的,都需要进行显式地强制类型转换,特别是在整形字面常量的隐式转换中。
- char类型转换成int、long类型是符合 小类型转大类型的规则,即无需要强制类型转换。
4. 运算结果的类型
在Java中,一个运算结果的类型是与表达式中类型最高的相等,如:
char cc = 5;
float dd = 0.6f+cc;//最高类型是float,运算结果是float
float ee = (float) (0.6d+cc);//最高类型是double,运算结果也是double
int aa = 5+cc;//最高类型是int,运算结果也为int
但是,对于最高类型是byte、short、char的运算来说,则运行结果却不是最高类型,而是int类型。看下面的例子,c、d运算的最高类型都是char,但运算结果却是int,所以需要强制类型转换。
byte b = 2;
char a = 5;
char c = (char) (a+b);//byte+char,运算结果的类型为int,需要强制类型转换
int e = a+b;//编译通过,不需要强制类型转换,可以证明是int
char d = (char) (a+c);//char+char,
short s1 = 5;
short s2 = 6;
short s3 =(short)s1+s2;
综上所述,java的运算结果的类型有两个性质:
- 运算结果的类型必须是int类型或int类型以上。
- 最高类型低于int类型的,运算结果都为int类型。否则,运算结果与表达式中最高类型一致。
三、浮点数类型
1. 浮点类型的介绍
我们都知道,long类型转换成float类型是不需要强制类型转换的,也就是说相对于flaot类型,long类型是小类型,存储的范围要更小。然而flaot只占了4个字节,而long却占了8个字节,long类型的存储空间要比float类型大。这究竟是怎么一回事,我们接下来将细细分析。
浮点数使用 IEEE(电气和电子工程师协会)格式。 浮点数类型使用 符号位、指数、有效位数(尾数)来表示。要注意一下,尾数的最高
在java中,float 和 double 的结构如下:
类 型 | 符 号 位 | 指 数 域 | 有效位域 |
---|---|---|---|
float | 1位 | 8位 | 23位 |
double | 1位 | 11位 | 52位 |
符号位: 0为正,1为负;
指数域: 无符号的,float的偏移量为127(即float的指数范围是-126~127,),double
有效位域 无符号的;
2. 浮点类型的两个需要注意的地方
1)存储的小数的数值可能是模糊值
public static void main(String[] args) {
double d1 = 0.1;
double d2 = 0.2;
System.out.println(d1+d2 == 0.3);
System.out.println(d1+d2);
}
运行结果:
false
0.30000000000000004
上述的运算结果并不是错误。这是因为无法用二进制来准确地存储的0.3,这是一个无限循环的值,与10进制的1/3很相似。不只是0.3,很多小数都是无法准确地用浮点型表示,其实这是由 小数的十进制转成二进制的算法所决定的,十进制的小数要不断乘2,知道最后的结果为整数才是最后的二进制值,但这有可能怎么也得不到整数,所以最后得到的结果可能是一个 无限值 ,浮点型就无法表示了
但是对于 整数 来说,在浮点数的有效范围内,则都是精确的。同样,也是由于转换算法:十进制的整数转成二进制的算法是不断对2求余数,所以 不会存在无限值的情况;
2)浮点数的有效位及精度
浮点型所能表示的有效位是有限的,所以哪怕是整数,只要超出有效位数,也只能存储相似值,也就是该数值的最低有效位将会丢失,从而造精度丢失。
float类型的二进制有效位是24位,对应十进制的7 ~ 8位数字;double类型的二进制53位,对应十进制的10 ~ 11位数字。
double、float类型 所能表示的范围比int、long类型表示的范围要广,也浮点类型属于大类型。但是,并不能完美地表整形,浮点类型的精度丢失会造成一些问题。
public static void main(String[] args) {
int a = 3000000;
int b = 30000000;
float f1 = a;
float f2 = b;
System.out.println("3000000==3000001 "+(f1==f1+1));
System.out.println("30000000==30000001 "+(f2==f2+1));
System.out.println("3000000的有效二进制位数:"+ Integer.toBinaryString(a).length());
System.out.println("30000000的有效二进制位数:"+ Integer.toBinaryString(b).length());
}
运行结果:
3000000 == 3000001 false
30000000 == 30000001 true
3000000的有效二进制位数: 22
30000000的有效二进制位数: 25
上面的例子很好体现了精度丢失所带来的后果:30000000==30000001
的比较居然为true了。而造成这种结果的原因就是 30000000的有效二进制位数是25位,超出了float所能表示的有效位24位,最后一位就被舍去,所以就造成在刚加的1也被舍去,因此30000000的加一操作前后的浮点型表示是一样的。
当然,并不是超出浮点型的有效位就不能精确表示,其实,主要看的是最高有效位与最低非0有效位之间的 “间隙”,如果间隙的在浮点型的有效位数内,自然可以精确表示,因为舍去的低有效位都是0,自然就无所谓了。如果上面的例子的浮点型用的是double就不会丢失精度了,因为double的精度是52位。
3)解决浮点型精度丢失的问题
浮点型带来精度丢失的问题是很让人头痛的,所以一般情况下,在程序中是不会使用float、double来存储比较大的数据。而商业计算往往要求结果精确。《Effactive Java》书中有一句话:
float和double类型的主要设计目标是为了科学计算和工程计算
JDK为此提供了两个高精度的大数操作类给我们:BigInteger、BigDecimal。
java基础(一) 深入解析基本类型的更多相关文章
- Java基础知识➣环境搭建与类型整理(一)
概述 公司业务需要,产品既要有.NET又需要Java,没得选择,只能业余时间学习Java,整体觉得Java也.NET还是很相似的,只是语法有差别,差别也不是很大,这就将学习Java的基础知识整理下,以 ...
- Java 基础【09】 日期类型
java api中日期类型的继承关系 java.lang.Object --java.util.Date --java.sql.Date --java.sql.Time --java.sql.Time ...
- 你必须掌握的Java基础:JSON解析工具-json-lib
一.简介 json-lib是一个Java类库,提供将Java对象,包括beans,maps,collections,java arrays和xml等转换成JSON,或者反向转换的功能. 二.准备 在 ...
- java基础(9) - 泛型解析
泛型 定义简单的泛型类 泛型方法 /** * 1.定义一个泛型类 * 在类名后添加类的泛型参数 <T> * 泛型类里面的所有T会根据创建泛型类时传入的参数确定类型 * 2.定义泛型方法 * ...
- JAVA基础-XML的解析
一.XML的概述 XML的全名为可扩展标记语言(Extensible Markup Language),XML的作用为:1.传输,2.存取数据,3.软件的配置文件.传输现在都用更轻量的Json,而存储 ...
- java基础(八) 深入解析常量池与装拆箱机制
引言 本文将介绍常量池 与 装箱拆箱机制,之所以将两者合在一起介绍,是因为网上不少文章在谈到常量池时,将包装类的缓存机制,java常量池,不加区别地混在一起讨论,更有甚者完全将这两者视为一个整体, ...
- Java 基础【12】 日期类型
java api中日期类型的继承关系 java.lang.Object --java.util.Date --java.sql.Date --java.sql.Time --java.sql.Time ...
- Java基础知识点1:基本类型包装类
基本类型的包装类 简介 通常来说我们在程序中经常会使用元类型,比如 int data = 1; float data = 2.1F; 但是在有些场景中不能直接使用元类型,比如如果我们想要建立一个int ...
- 【java基础】 合并两个类型相同的list
将两个类型相同的list合并,可以用 addAll(Collection<? extends E> c) import java.util.ArrayList; import java.u ...
随机推荐
- c#的托管代码和非托管代码的理解
理解托管和非托管代码的前提之下,要先了解CLR(公共语言运行库) .Net Framework 是由彼此独立又相关的两部分组成:CLR 和 类库, CLR是它为我们提供的服务,类库是它实现的功能. . ...
- 深度优先搜索(DFS)专题讲座PPT截图【需要原稿的请留言或私信】
以下是今晚我在bilibili直播讲DFS算法的时候的ppt截图,ppt搞了一下午,水平有限,只能做成这个样子,供大家参考!(如果需要原稿,请在评论区留言或私信告诉我,我会发到你的邮箱里),感谢各位的 ...
- Zabbix安装客户端agent(windows和Centos7)
上一篇简单的介绍了怎么搭建Zabbix监控服务端,接下来给大家介绍怎么在windows和Centos7上安装zabbix_agent客户端. Zabbix是一个基于WEB界面的提供分布式系统监视以及网 ...
- c++(hash表)
hash表,有时候也被称为散列表.个人认为,hash表是介于链表和二叉树之间的一种中间结构.链表使用十分方便,但是数据查找十分麻烦:二叉树中的数据严格有序,但是这是以多一个指针作为代价的结果.hash ...
- for语句,你真正搞懂了吗?
今天看书时,无意间看到了这个知识点,啥知识点?也许在各位大神看来,那是再简单不过的东西了. 说来惭愧.原来直到今天我才真正搞懂for语句. for语句的结构如下所示: for(语句A;语句B;语句C) ...
- 浏览器与CDN缓存行为
@地址栏回车 1. 未过期: 浏览器拦截,直接返回: (expires/cache-control两个参数决定,如果两个参数都有,cache-control覆盖expires); 2. 已过期: et ...
- java if与for循环的题
//打印一个4*5的空心长方形 /* for (int i = 0; i < 5;i++ ) { if (i == 0 | i == 4) { ...
- windows server 2008使用nginx转发API异常解决办法
公司比较传统,一直使用的JSP做项目,没有遇到过跨域问题. 最近因为公司接到一个微信spa项目,因为考虑到项目需要调用老接口,斗胆选择nginx(1.12.1)做接口转发服务, 开发环境使用的win1 ...
- destoon分页
<?php //控制分页//分页$pagesize=4;$pagesql="SELECT COUNT(*) AS num FROM `{$DT_PRE}` company"; ...
- [机器学习]模型评价参数,准确率,召回率,F1-score
很久很久以前,我还是有个建筑梦的大二少年,有一天,讲图的老师看了眼我的设计图,说:"我觉得你这个设计做得很紧张".当时我就崩溃,对紧张不紧张这样的评价标准理解无能.多年后我终于明白 ...