一、数据类型
- 定义:
- 数据类型=数据结构+数据操作,即数据类型包括明确数据的结构以及定义在这组数据所允许的操作。
- 例如:
- 我们经常使用int来定义整型数据,那么就必须明确以下三点,当然这些我们已经形成了一种惯性思维。
A.数据集合:-2147483648~2147483647,范围内所有整数
B.数据关系:负数正数大,二比三小。
C.数据操作:2+1等于3,除数不能为0,等四则运算操作。
数据集合与数据关系用来描述数据结构,数据结构+数据操作用来描述数据类型。因此在使用一个类型前,我们必须明确这三点。
- 类型与变量:
- 变量就是类型的实例它包含类型定义的所有特征,类型确定了变量在内存所占的字节数,以及数据存储所表示的含义,而变量就是内存的一段单元,
- 不同类型的变量本质都是一段内存的存储单元,存储的都二进制数,不同的是占用的字节数,数据存储所表示的含义不同而已。
二、类型转换
- 类型转换:
A.数据类型兼容的两种数据类型之间可以进行自动类型和强制类型转换。
B.注意:前提是数据类型兼容才能进行类型转换。
- 类型兼容:
- 决定不同类型的数据能否进行转换的前提。
A.数值类型:所有整型,浮点型,字符型都是相兼容的。
B.引用类型:在同一个树状继承结构上存在的两个引用类型是相兼容的(即两个引用类型在同一个族谱中)。
- 自动类型转换
- 自动类型转换是由编绎系统进行,无需使用仍何特殊语法,必须满足类型兼容。
- 自动类型转换常发生在使用双目运算符对数据进行运算和赋值过程中。双目运算符要求左右两侧的类型必须一致,否则将进行自动类型转换。
- 数值类型转换规则:数据集合范围小的类型向数据集合范围大的类型转换
- 双目运算符要求左右两侧类型相同,如果不能则进行自动类型转换,结果也与转换后的结果类型相同。
byte->->int->long->float->double
char->int->long->float->double
short-> int->long->float->double
注意:byte、char与short任意两种组合之间进行运算,都需要先转化为int类型,然后进行运算。
代码示例:
public class Test { public static void main(String[] args) { byte bytes = 0; short shorts = 0; char chars = 0; int ints = 0; long longs = 0; float floats = 0f; double doubles = 0; ints = ints + chars + shorts; // 正确,int+chars将chars转int结果为int,再与shorts进行运算,将shorts转换为int,结果为int // shorts=chars;//错误,chars会自动转换为int类型,不能赋值给short类型 ints = chars;// 正确,int类型的取值范围比char大可以转换。 // bytes=shorts+chars;//错误,结果为int类型,不能赋值给byte类型 ints = bytes + chars;// 正确,结果为int类型 // longs=floats;//错误,float类型虽然占用的字节数比long类型小,但数据取值范围比它大,不是由占用字节数决定的。 floats = longs;// 正确,long类型数据取值范围比float类型小,自动类型转换。 floats = bytes + shorts + chars + ints + longs + floats; // 正确,float类型最大,结果为float doubles = bytes + shorts + chars + ints + longs + floats + doubles; // 正确,double类型最大,结果为double int num1=5; int num2=2; doubles=num1/num2; //得不到2.5因为num1,num2都是int类型结果也是int类型2得不到2.5 } }
- 结论:
- byte,short,char,进行运算时一般都转化为int类型,然后才能进行运算
- 数据取值范围小的自动转换为数据取值范围大的类型,不是由占用字节大小决定。
- 运算结果的类型与操作类型最大的那个相同。
- 强制类型转换
- 强制类型转换一般会造精度和信息(引用类型之间)的丢失。需要使用特殊的语法进行确认。
- 只需使用强制类型转换符就会发生。
- 无转换规则,但必须满足两种类型相兼容。
- 语法:
(类型名)(表达式)
- 注意:
- 类型名的括号不可以省略,当表达式只有一个数据的时候括号可以省略。要明确转化的目标是谁。
int num1=(int)(3+2*3.14);//正确,将3+2*3.14表达式的运算结果转换为int类型。
int num2=(int)3+2*3.14;//错误,只是将3转化为int,但表达式中仍有double类型的数据,结果为double
2.强制类型转换只是将目标类型的值转换为目标类型的中间值,目标类型并未发生改变。
double d=3.14;
int i=(int)d;//d仍然为double类型
三、常量的数据类型(重点)
- 为什么常量要有类型?
在编写代码的过程中,常量的取值如何确定呢?一个整型常量值可以无限大吗?这个常量可以进行那些操作呢?
如果将一个3赋值给一个int类型的变量。那么我们就要讨论这个过程是如何进行的。这也是许多新手所困惑的。
- 分析:
试想一个3如何存放到一个int类型的变量中,计算机是不能直接存放一个3这个字符的,不能存放到内存,就不能被计算机操作。
于是,计算机先将3看作一个int类型的数据,为他分配4个字节的空间,以二进制的形式存到内存的常量区。
由于不同类型的常量的存储方式,所能执行的操作不同,前面已经提过,如果确定了变量类型,那么数据集合、数据关系、数据操作就可以确定
于是计算机就必须先确定常量的类型,与编程语言可用的类型进行适配。确定了常量的类型,就可以像普通变量一样在计算机中存储,参与运算。
- 结论:
常量也有类型,在内存中也占存储空间,可以存放数据,可以参与运算,那么我们要考虑的就是确定常量的类型。
常量的赋值过程是先匹配这个常量对应得类型,然后再存放这个常量,然后再将这个常量存放到其他变量中。
long longs=99999999999999;
系统先将99999999999999用一个int类型的空间去存放,然后再将存放到内存中的值赋值给longs。显然int类型的空间存不下,强行运行的话,也到不到正确的结果,系统用int类型的空间保存99999999999999第4个字节的部分(发生截取)
然后将截取之后的结果赋值给longs变量,因此的不到正确的结果。
- 常量类型适配规则:
- 计算机将所有的整数默认看作int类型。
- 计算机将所有带小数点的实数,看作double类型。
- 计算机将所有用单引号括起来的单个字符,看作char类型。
- 计算机将所有用双引号括起来的字符,看作string类型。
意义:
public class Test { public static void main(String[] args) { //short shorts=3;//错误,3是int类型不能赋值给short //int ints=99999999999999;//错误,99999999999999是int类型不能超过:-2147483648~2147483647 //long longs=99999999999999;//错误,99999999999999是int类型,系统分配4个字节,然而4个字节存不下,即使在C语言中不报错,但也得不到99999999999999因为系统先用int类型的空间存放,存不下就截取第4个字节然后再赋值给long,但是存到longs变量中已经不是99999999999999 //float floats=3.14;//错误,3.14是double类型,不能赋值给float类型 double doubles=5/2;//错误,得不到2.5,因为5,2是int类型,结果也是int类型2 } }
可以看出确定了常量的类型就可以确定避免许多的错误。
解决应为类型的问题而造成的错误:
public class Test { public static void main(String[] args) { short shorts=(short)3;//把3强转为short类型,注意是将3转化产生一个short类型的一个中间值转化为short类型3还是int类型 long longs1=99999999999999L;//在常量后面加L系统就会先用long类型的空间去存放它,以得到正确的结果 float floats=3.14f;//在小数后面加f告诉系统这个常用是float类型的,用float类型的空间存放它 float floats1=(float)3.14;//还是用double类型的空间存放3.14,然后把3.14转化为为float类型,将得到的中间值赋值给float double doubles=5/2f;//告诉系统2是一个float类型的数据,由于/右边是float类型,系统会将5也转化为float类型,结果也是float类型2.5 } }