JAVA不像PHP,JS,Python,它是一门强类型语言。强类型的语言有以下几个要求:
但是在实际生产中,经常需要在不同类型的值之间进行操作,这就需要一种新的语法来适应这种需要,这个语法就是数据类型转换。作为基础中的基础,今天带大家重温一下:
JAVA基本数据类型:byte,short,int,long为整型;float,double为浮点型;char为字符型;boolean 为布尔类型;
JAVA引用数据类型:类class,接口interface,数组[];
如此,我们也分两大块来讲解类型的转换问题:
在数值处理这部分,计算机和现实的逻辑不太一样。对于现实来说,1和 1.0 没有什么区别,但是对于计算机来说,1 是整数类型,而 1.0 就是浮点类型,其在内存中的存储方式以及占用的空间都不一样,所以类型转换在计算机内部是必须的。
Java 语言中,基本数据类型的转换分两种:
由于基本数据类型中 boolean 类型不是数字型,所以基本数据类型的转换是除了 boolean 类型以外的其它 7 种类型之间的转换。
自动类型转换,也称隐式类型转换,是指不需要书写代码,由系统自动完成的类型转换。由于实际开发中这样的类型转换很多,所以 Java 语言在设计时,没有为该操作设计语法,而是由 JVM 自动完成。
转换规则:从存储范围小的类型到存储范围大的类型;
具体规则为:byte → short(char) → int → long → float → double;
注意问题:
//基本类型:自动类型转换
@Test
public void testAuto() {
//1.JVM首先将b的值转换成short类型,然后再赋值给s;
byte b = 13;
short s = b;
//2.在类型转换的时候也可以跳跃,就是byte也可以自动转换为更高的类型;
int i = b;
double d = b;
//3.虽然b1 b2都是byte型,但是运算的时候首先会转换成int型;
byte b1 = 13;
byte b2 = 14;
byte b3 = (byte)(b1 + b2); //27
//4.整型溢出:此时的 b4+b5 > 127,超出byte表示范围,
// 127 + 1 = -128,再加的话以此类推,环形往复;
byte b4 = 66;
byte b5 = 67;
byte b6 = (byte)(b4 + b5); //-123
//5.浮点型溢出:超出表示范围时会出现INF无穷大;
float f1 = 3.2f/1f; //3.2
float f2 = 3.2f/0; //Infinity(正无穷)
float f3 = -3.2f/0; //-Infinity(负无穷)
}
强制类型转换,也称显式类型转换,是指必须书写代码才能完成的类型转换。该类类型转换很可能存在精度的损失,所以必须书写相应的代码,并且能够忍受该种损失时才进行该类型的转换。
转换规则:从存储范围大的类型到存储范围小的类型。
具体规则为:double → float → long → int → short(char) → byte
语法格式为:(转换到的类型)需要转换的值
//基本类型:强制类型转换
@Test
public void testForced() {
//强制类型转换通常都会存储精度的损失,所以使用时需要谨慎
double d1 = 3.14159265358979;
double d2 = 1227;
float f = (float) d1; //3.1415927 (精度损失)
int i1 = (int) d1; //3 (精度损失)
int i2 = (int) d2; //1227 (精度无损失)
}
Java的字符串String属于一个类,所以它属于引用数据类型。因为在引用数据类型中,只存在String与基本数据类型的互转。因为基本数据类型与String互转原理相同,方法相似,所以这里以int为例,讲解一下规则和原理:
//int -> String :三种方法
@Test
public void testIntToString() {
int num = 20180721;
//1. num + ""
long start = System.currentTimeMillis(); //得到开始运行时系统时间
for(int i=0; i<100000; i++){
String str = num + "";
}
long end = System.currentTimeMillis(); //得到结束运行时系统时间
System.out.println("num + \"\" : " + (end - start));
//2. String.valueOf(num)
start = System.currentTimeMillis();
for(int i=0; i<100000; i++){
String str = String.valueOf(num);
}
end = System.currentTimeMillis();
System.out.println("String.valueOf(num) : " + (end - start));
//3. Integer.toString(num)
start = System.currentTimeMillis();
for(int i=0; i<100000; i++){
String str = Integer.toString(num);
}
end = System.currentTimeMillis();
System.out.println("Integer.toString(num) : " + (end - start));
}
程序执行结果:
可以发现,第一种方式与后面两种方式运行的时间相差比较大,这里简单说一下区别:
num + “”:先将数字toString()转成字符串,然后进行字符串的拼接,效率自然很低,且过程中会产生两个String对象;
Integer.toString():采用Integer.toString()的基础是Object.toString(),因为java.lang.Object类中已有public方法toString(),所以对任何严格意义上的Java对象都可以调用此方法,但使用时需要注意,必须保证object不是null值,否则将会抛出NullPointerException异常;
String.valueOf():直接使用String类的静态方法,只产生一个对象,基础仍是Object.toString()方法,JDK中String.valueOf(object)源码:
public static String valueOf(Object obj){
return (obj==null)?"null":obj.toString();
}
所以使用该方法不必担心object为null的情况,但同时也要注意:当object为null时,该方法返回字符串"null",而非null,此处是个坑!!
//String -> int :两种方法
@Test
public void testStringToInt() {
String s = "20181227";
//1.Integer.parseInt(str)
long start = System.currentTimeMillis(); //得到开始运行时系统时间
for(int i=0; i<100000; i++){
int n = Integer.parseInt(s);
}
long end = System.currentTimeMillis(); //得到结束运行时系统时间
System.out.println("Integer.parseInt(str) : " + (end - start));
//2.Integer.valueOf(str).intValue()
start = System.currentTimeMillis();
for(int i=0; i<100000; i++){
int n = Integer.valueOf(s).intValue();
}
end = System.currentTimeMillis();
System.out.println("Integer.valueOf(str).intValue() : " + (end - start));
}
程序执行结果:
可以发现,两者运行时间差距虽有但不大,可以忽略,但是执行原理确是天差地别,解释一下:
Integer.valueOf(str).intValue():此方法运用了包装类的拆装箱操作,先是将String -> Integer -> int,即将String包装类型转化为Integer包装类型,再将包装类型转化为基本类型, 等价于 new Integer(Integer.parseInt(str)),过程中会产生额外的一个对象。
Integer.parseInt():直接使用String类的静态方法,只产生一个对象;
更多精彩,请关注我的"今日头条号":Java云笔记
随时随地,让你拥有更新,更便捷的掌上云服务