Java开发网 Java开发网
注册 | 登录 | 帮助 | 搜索 | 排行榜 | 发帖统计  

您没有登录

» Java开发网 » Java SE 综合讨论区  

按打印兼容模式打印这个话题 打印话题    把这个话题寄给朋友 寄给朋友    该主题的所有更新都将Email到你的邮箱 订阅主题
flat modethreaded modego to previous topicgo to next topicgo to back
作者 JAVA面试题解惑系列(八)——聊聊基本类型(内置类型)
臧圩人





发贴: 63
积分: 15
于 2008-07-25 10:38 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
------------------------------------------------------------------------------------
我想出一本名为《JAVA面试题解惑系列》的书籍,详情请见:
http://rmyd.group.javaeye.com/group/topic/6193
目前网络连载中:http://zangweiren.javaeye.com/
请大家多关注,多提宝贵意见!
------------------------------------------------------------------------------------

作者:臧圩人(zangweiren)
网址:http://zangweiren.javaeye.com

>>>转载请注明出处!<<<

基本类型,或者叫做内置类型,是JAVA中不同于类的特殊类型。它们是我们编程中使用最频繁的类型,因此面试题中也总少不了它们的身影,在这篇文章中我们将从面试中常考的几个方面来回顾一下与基本类型相关的知识。

基本类型共有八种,它们分别都有相对应的包装类。关于它们的详细信息请看下表:



基本类型可以分为三类,字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double。数值类型又可以分为整数类型byte、short、int、long和浮点数类型float、double。JAVA中的数值类型不存在无符号的,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变。实际上,JAVA中还存在另外一种基本类型void,它也有对应的包装类java.lang.Void,不过我们无法直接对它们进行操作。对于数值类型的基本类型的取值范围,我们无需强制去记忆,因为它们的值都已经以常量的形式定义在对应的包装类中了。请看下面的例子:
Java代码

public class PrimitiveTypeTest {
public static void main(String[] args) {
// byte
System.out.println("基本类型:byte 二进制位数:" + Byte.SIZE);
System.out.println("包装类:java.lang.Byte");
System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE);
System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE);
System.out.println();

// short
System.out.println("基本类型:short 二进制位数:" + Short.SIZE);
System.out.println("包装类:java.lang.Short");
System.out.println("最小值:Short.MIN_VALUE=" + Short.MIN_VALUE);
System.out.println("最大值:Short.MAX_VALUE=" + Short.MAX_VALUE);
System.out.println();

// int
System.out.println("基本类型:int 二进制位数:" + Integer.SIZE);
System.out.println("包装类:java.lang.Integer");
System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE);
System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE);
System.out.println();

// long
System.out.println("基本类型:long 二进制位数:" + Long.SIZE);
System.out.println("包装类:java.lang.Long");
System.out.println("最小值:Long.MIN_VALUE=" + Long.MIN_VALUE);
System.out.println("最大值:Long.MAX_VALUE=" + Long.MAX_VALUE);
System.out.println();

// float
System.out.println("基本类型:float 二进制位数:" + Float.SIZE);
System.out.println("包装类:java.lang.Float");
System.out.println("最小值:Float.MIN_VALUE=" + Float.MIN_VALUE);
System.out.println("最大值:Float.MAX_VALUE=" + Float.MAX_VALUE);
System.out.println();

// double
System.out.println("基本类型:double 二进制位数:" + Double.SIZE);
System.out.println("包装类:java.lang.Double");
System.out.println("最小值:Double.MIN_VALUE=" + Double.MIN_VALUE);
System.out.println("最大值:Double.MAX_VALUE=" + Double.MAX_VALUE);
System.out.println();

// char
System.out.println("基本类型:char 二进制位数:" + Character.SIZE);
System.out.println("包装类:java.lang.Character");
// 以数值形式而不是字符形式将Character.MIN_VALUE输出到控制台
System.out.println("最小值:Character.MIN_VALUE="
+ (int) Character.MIN_VALUE);
// 以数值形式而不是字符形式将Character.MAX_VALUE输出到控制台
System.out.println("最大值:Character.MAX_VALUE="
+ (int) Character.MAX_VALUE);
}
}


运行结果:

1、基本类型:byte 二进制位数:8
2、包装类:java.lang.Byte
3、最小值:Byte.MIN_VALUE=-128
4、最大值:Byte.MAX_VALUE=127
5、
6、基本类型:short 二进制位数:16
7、包装类:java.lang.Short
8、最小值:Short.MIN_VALUE=-32768
9、最大值:Short.MAX_VALUE=32767
10、
11、基本类型:int 二进制位数:32
12、包装类:java.lang.Integer
13、最小值:Integer.MIN_VALUE=-2147483648
14、最大值:Integer.MAX_VALUE=2147483647
15、
16、基本类型:long 二进制位数:64
17、包装类:java.lang.Long
18、最小值:Long.MIN_VALUE=-9223372036854775808
19、最大值:Long.MAX_VALUE=9223372036854775807
20、
21、基本类型:float 二进制位数:32
22、包装类:java.lang.Float
23、最小值:Float.MIN_VALUE=1.4E-45
24、最大值:Float.MAX_VALUE=3.4028235E38
25、
26、基本类型:double 二进制位数:64
27、包装类:java.lang.Double
28、最小值:Double.MIN_VALUE=4.9E-324
29、最大值:Double.MAX_VALUE=1.7976931348623157E308
30、
31、基本类型:char 二进制位数:16
32、包装类:java.lang.Character
33、最小值:Character.MIN_VALUE=0
34、最大值:Character.MAX_VALUE=65535

Float和Double的最小值和最大值都是以科学记数法的形式输出的,结尾的“E+数字”表示E之前的数字要乘以10的多少倍。比如3.14E3就是3.14×1000=3140,3.14E-3就是3.14/1000=0.00314。

大家将运行结果与上表信息仔细比较就会发现float、double两种类型的最小值与Float.MIN_VALUE、Double.MIN_VALUE的值并不相同,这是为什么呢?实际上Float.MIN_VALUE和Double.MIN_VALUE分别指的是float和double类型所能表示的最小正数。也就是说存在这样一种情况,0到±Float.MIN_VALUE之间的值float类型无法表示,0到±Double.MIN_VALUE之间的值double类型无法表示。这并没有什么好奇怪的,因为这些范围内的数值超出了它们的精度范围。

基本类型存储在栈中,因此它们的存取速度要快于存储在堆中的对应包装类的实例对象。从Java5.0(1.5)开始,JAVA虚拟机(Java Virtual Machine)可以完成基本类型和它们对应包装类之间的自动转换。因此我们在赋值、参数传递以及数学运算的时候像使用基本类型一样使用它们的包装类,但这并不意味着你可以通过基本类型调用它们的包装类才具有的方法。另外,所有基本类型(包括void)的包装类都使用了final修饰,因此我们无法继承它们扩展新的类,也无法重写它们的任何方法。

各种数值类型之间的赋值与转换遵循什么规律呢?我们来看下面这个例子:
Java代码

public class PrimitiveTypeTest {
public static void main(String[] args) {
// 给byte类型变量赋值时,数字后无需后缀标识
byte byte_a = 1;
// 编译器会做范围检查,如果赋予的值超出了范围就会报错
// byte byte_b = 1000;
// 把一个long型值赋值给byte型变量,编译时会报错,即使这个值没有超出byte类型的取值范围
// byte byte_c = 1L;

// 给short类型变量赋值时,数字后无需后缀标识
short short_a = 1;
// 编译器会做范围检查,如果赋予的值超出了范围就会报错
// short short_b = 70000;
// 把一个long型值赋值给short型变量,编译时会报错,即使这个值没有超出short类型的取值范围
// byte short_c = 1L;

// 给short类型变量赋值时,数字后无需后缀标识
int int_a = 1;
// 编译器会做范围检查,如果赋予的值超出了范围就会报错
// int int_b = 2200000000;
// 把一个long型值赋值给int型变量,编译时会报错,即使这个值没有超出int类型的取值范围
// int int_c = 1L;

// 可以把一个int型值直接赋值给long型变量,数字后无需后缀标识
long long_a = 1;
// 如果给long型变量赋予的值超出了int型值的范围,数字后必须加L(不区分大小写)标识
long long_b = 2200000000L;
// 编译器会做范围检查,如果赋予的值超出了范围就会报错
// long long_c = 9300000000000000000L;

// 可以把一个int型值直接赋值给float型变量
float float_a = 1;
// 可以把一个long型值直接赋值给float型变量
float float_b = 1L;
// 没有F(不区分大小写)后缀标识的浮点数默认为double型的,不能将它直接赋值给float型变量
// float float_c = 1.0;
// float型数值需要有一个F(不区分大小写)后缀标识
float float_d = 1.0F;
// 把一个double型值赋值给float型变量,编译时会报错,即使这个值没有超出float类型的取值范围
// float float_e = 1.0D;
// 编译器会做范围检查,如果赋予的值超出了范围就会报错
// float float_f = 3.5000000E38F;

// 可以把一个int型值直接赋值给double型变量
double double_a = 1;
// 可以把一个long型值直接赋值给double型变量
double double_b = 1L;
// 可以把一个float型值直接赋值给double型变量
double double_c = 1F;
// 不带后缀标识的浮点数默认为double类型的,可以直接赋值
double double_d = 1.0;
// 也可以给数字增加一个D(不区分大小写)后缀标识,明确标出它是double类型的
double double_e = 1.0D;
// 编译器会做范围检查,如果赋予的值超出了范围就会报错
// double double_f = 1.8000000000000000E308D;

// 把一个double型值赋值给一个byte类型变量,编译时会报错,即使这个值没有超出byte类型的取值范围
// byte byte_d = 1.0D;
// 把一个double型值赋值给一个short类型变量,编译时会报错,即使这个值没有超出short类型的取值范围
// short short_d = 1.0D;
// 把一个double型值赋值给一个int类型变量,编译时会报错,即使这个值没有超出int类型的取值范围
// int int_d = 1.0D;
// 把一个double型值赋值给一个long类型变量,编译时会报错,即使这个值没有超出long类型的取值范围
// long long_d = 1.0D;

// 可以用字符初始化一个char型变量
char char_a = 'a';
// 也可以用一个int型数值初始化char型变量
char char_b = 1;
// 把一个long型值赋值给一个char类型变量,编译时会报错,即使这个值没有超出char类型的取值范围
// char char_c = 1L;
// 把一个float型值赋值给一个char类型变量,编译时会报错,即使这个值没有超出char类型的取值范围
// char char_d = 1.0F;
// 把一个double型值赋值给一个char类型变量,编译时会报错,即使这个值没有超出char类型的取值范围
// char char_e = 1.0D;
// 编译器会做范围检查,如果赋予的值超出了范围就会报错
// char char_f = 70000;
}
}


从上面的例子中我们可以得出如下几条结论:

1、未带有字符后缀标识的整数默认为int类型;未带有字符后缀标识的浮点数默认为double类型。
2、如果一个整数的值超出了int类型能够表示的范围,则必须增加后缀“L”(不区分大小写,建议用大写,因为小写的L与阿拉伯数字1很容易混淆),表示为long型。
3、带有“F”(不区分大小写)后缀的整数和浮点数都是float类型的;带有“D”(不区分大小写)后缀的整数和浮点数都是double类型的。
4、编译器会在编译期对byte、short、int、long、float、double、char型变量的值进行检查,如果超出了它们的取值范围就会报错。
5、int型值可以赋给所有数值类型的变量;long型值可以赋给long、float、double类型的变量;float型值可以赋给float、double类型的变量;double型值只能赋给double类型变量。

下图显示了几种基本类型之间的默认逻辑转换关系:



图中的实线表示无精度损失的转换,而虚线则表示这样的转换可能会损失一定的精度。如果我们想把一个能表示更大范围或者更高精度的类型,转换为一个范围更小或者精度更低的类型时,就需要使用强制类型转换(Cast)了。不过我们要尽量避免这种用法,因为它常常引发错误。请看下面的例子,如果不运行代码,你能预测它的结果吗?
Java代码

public class PrimitiveTypeTest {
public static void main(String[] args) {
int a = 123456;
short b = (short) a;
// b的值会是什么呢?
System.out.println(b);
}
}


运行结果:

1、-7616

运算符对基本类型的影响

当使用+、-、*、/、%运算符对基本类型进行运算时,遵循如下规则:

1、只要两个操作数中有一个是double类型的,另一个将会被转换成double类型,并且结果也是double类型;
2、否则,只要两个操作数中有一个是float类型的,另一个将会被转换成float类型,并且结果也是float类型;
3、否则,只要两个操作数中有一个是long类型的,另一个将会被转换成long类型,并且结果也是long类型;
4、否则,两个操作数(包括byte、short、int、char)都将会被转换成int类型,并且结果也是int类型。

当使用+=、-=、*=、/=、%=、运算符对基本类型进行运算时,遵循如下规则:

1、运算符右边的数值将首先被强制转换成与运算符左边数值相同的类型,然后再执行运算,且运算结果与运算符右边数值类型相同。

了解了这些,我们就能解答下面这个常考的面试题了。请看:

short s1=1;s1=s1+1;有什么错?short s1=1;s1+=1;有什么错?


乍一看,觉得它们都应该没有错误,可以正常运行。我们来写个例子试试:
Java代码

public class PrimitiveTypeTest {
public static void main(String[] args) {
short s1 = 1;
// 这一行代码会报编译错误
// s1 = s1 + 1;
// 这一行代码没有报错
s1 = 1 + 1;
// 这一行代码也没有报错
s1 += 1;
}
}


从例子中我们可以看出结果了。利用上面列举的规律,也很容易解释。在s1=s1+1;中,s1+1运算的结果是int型,把它赋值给一个short型变量s1,所以会报错;而在s1+=1;中,由于是s1是short类型的,所以1首先被强制转换为short型,然后再参与运算,并且结果也是short类型的,因此不会报错。那么,s1=1+1;为什么不报错呢?这是因为1+1是个编译时可以确定的常量,“+”运算在编译时就被执行了,而不是在程序执行的时候,这个语句的效果等同于s1=2,所以不会报错。前面讲过了,对基本类型执行强制类型转换可能得出错误的结果,因此在使用+=、-=、*=、/=、%=等运算符时,要多加注意。

Math.round()方法

java.lang.Math类里有两个round()方法,它们的定义如下:
Java代码

public static int round(float a) {
//other code
}

public static long round(double a) {
//other code
}


它们的返回值都是整数,且都采用四舍五入法。运算规则如下:

1、如果参数为正数,且小数点后第一位>=5,运算结果为参数的整数部分+1。
2、如果参数为负数,且小数点后第一位>5,运算结果为参数的整数部分-1。
3、如果参数为正数,且小数点后第一位<5;或者参数为负数,且小数点后第一位<=5,运算结果为参数的整数部分。

我们可以通过下面的例子来验证:
Java代码

public class MathTest {
public static void main(String[] args) {
System.out.println("小数点后第一位=5");
System.out.println("正数:Math.round(11.5)=" + Math.round(11.5));
System.out.println("负数:Math.round(-11.5)=" + Math.round(-11.5));
System.out.println();

System.out.println("小数点后第一位<5");
System.out.println("正数:Math.round(11.46)=" + Math.round(11.46));
System.out.println("负数:Math.round(-11.46)=" + Math.round(-11.46));
System.out.println();

System.out.println("小数点后第一位>5");
System.out.println("正数:Math.round(11.68)=" + Math.round(11.68));
System.out.println("负数:Math.round(-11.68)=" + Math.round(-11.68));
}
}


运行结果:

1、小数点后第一位=5
2、正数:Math.round(11.5)=12
3、负数:Math.round(-11.5)=-11
4、
5、小数点后第一位<5
6、正数:Math.round(11.46)=11
7、负数:Math.round(-11.46)=-11
8、
9、小数点后第一位>5
10、正数:Math.round(11.68)=12
11、负数:Math.round(-11.68)=-12

根据上面例子的运行结果,我们还可以按照如下方式总结,或许更加容易记忆:

1、参数的小数点后第一位<5,运算结果为参数整数部分。
2、参数的小数点后第一位>5,运算结果为参数整数部分绝对值+1,符号(即正负)不变。
3、参数的小数点后第一位=5,正数运算结果为整数部分+1,负数运算结果为整数部分。

switch语句

哪些类型可以用于switch语句的判断呢?我们做个测试就知道了:
Java代码

public class MathTest {
// 枚举类型,Java5.0以上版本可用
static enum enum_e {
A, B
}

public static void main(String[] args) {
// byte
byte byte_n = 0;
switch (byte_n) {
case 0:
System.out.println("byte可以用于switch语句");
break;
}

// Byte类
Byte byte_m = 0;
// 需要Java5.0(1.5)以上版本支持
switch (byte_m) {
case 0:
System.out.println("Byte类可以用于switch语句");
System.out.println();
break;
}

// char
char char_n = 0;
switch (char_n) {
case 0:
System.out.println("char可以用于switch语句");
break;
}

// Character类
Character char_m = 0;
// 需要Java5.0(1.5)以上版本支持
switch (char_m) {
case 0:
System.out.println("Character类可以用于switch语句");
System.out.println();
break;
}

// short
short short_n = 0;
switch (short_n) {
case 0:
System.out.println("short可以用于switch语句");
break;
}

// Short
Short short_m = 0;
// 需要Java5.0(1.5)以上版本支持
switch (short_m) {
case 0:
System.out.println("Short类可以用于switch语句");
System.out.println();
break;
}

// int
int int_n = 0;
switch (int_n) {
case 0:
System.out.println("int可以用于switch语句");
break;
}

// Integer类
Integer int_m = 0;
// 需要Java5.0(1.5)以上版本支持
switch (int_m) {
case 0:
System.out.println("Integer类可以用于switch语句");
System.out.println();
break;
}

// long
long long_n = 0;
// 编译错误,long型不能用于switch语句
// switch (long_n) {
// case 0:
// System.out.println("long可以用于switch语句");
// break;
// }

// Long类
Long long_m = 0L;
// 编译错误,Long类型不能用于switch语句
// switch (long_m) {
// case 0:
// System.out.println("Long类可以用于switch语句");
// System.out.println();
// break;
// }

// float
float float_n = 0.0F;
// 编译错误,float型不能用于switch语句
// switch (float_n) {
// case 0.0F:
// System.out.println("float可以用于switch语句");
// break;
// }

// Float类
Float float_m = 0.0F;
// 编译错误,Float类型不能用于switch语句
// switch (float_m) {
// case 0.0F:
// System.out.println("Float类可以用于switch语句");
// System.out.println();
// break;
// }

// double
double double_n = 0.0;
// 编译错误,double型不能用于switch语句
// switch (double_n) {
// case 0.0:
// System.out.println("double可以用于switch语句");
// break;
// }

// Double类
Double double_m = 0.0;
// 编译错误,Double类型不能用于switch语句
// switch (double_m) {
// case 0.0:
// System.out.println("Double类可以用于switch语句");
// System.out.println();
// break;
// }

// boolean
boolean bool_b = true;
// 编译错误,boolean型不能用于switch语句
// switch (bool_b) {
// case true:
// System.out.println("boolean可以用于switch语句");
// break;
// }

// Boolean类
Boolean bool_l = true;
// 编译错误,Boolean类型不能用于switch语句
// switch (bool_l) {
// case true:
// System.out.println("Boolean类可以用于switch语句");
// System.out.println();
// break;
// }

// String对象
String string_s = "Z";
// 编译错误,long型不能用于switch语句
// switch (string_s) {
// case "Z":
// System.out.println("String可以用于switch语句");
// System.out.println();
// break;
// }

// enum(枚举类型,Java5.0以上版本可用)
switch (MathTest.enum_e.A) {
case A:
System.out.println("enum可以用于switch语句-A");
break;
case B:
System.out.println("enum可以用于switch语句-B");
break;
}
}
}


运行结果如下:

1、byte可以用于switch语句
2、Byte类可以用于switch语句
3、
4、char可以用于switch语句
5、Character类可以用于switch语句
6、
7、short可以用于switch语句
8、Short类可以用于switch语句
9、
10、int可以用于switch语句
11、Integer类可以用于switch语句
12、
13、enum可以用于switch语句-A

结果已经出来了,我们来总结一下:

1、byte、char、short、int四种基本类型以及它们的包装类(需要Java5.0/1.5以上版本支持)都可以用于switch语句。
2、long、float、double、boolean四种基本类型以及它们的包装类(在Java所有版本中)都不能用于switch语句。
3、enum类型,即枚举类型可以用于switch语句,但是要在Java5.0(1.5)版本以上才支持。
4、所有类型的对象(包括String类,但在Java5.0/1.5以上版本中,该项要排除byte、char、short、int四种基本类型对应的包装类)都不能用于switch语句。



我的博客:http://zangweiren.javaeye.com
JAVA面试题解惑系列:http://zangweiren.javaeye.com/category/34977
作者 Re:JAVA面试题解惑系列(八)——聊聊基本类型(内置类型) [Re:臧圩人]
JiafanZhou



版主


发贴: 736
积分: 61
于 2008-08-02 16:39 user profilesend a private message to usersend email to JiafanZhousearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
- the first image does not display anything.

- the second image does not display.

- This is a much more basic article than the rest of the articles you have written so far. You seem to adopt a random order to write your article, which is not a good idea. I suggest that this article should be labeled as the (1) or (2) in terms of index.
Maybe the author should think about the total domain of the writing and give priority to writing in terms of difficulty.

- My opinion is that the article is more *language syntax* rather than the practical questions in the interview. e.g. I would not ask the range of all the primitive types, because they the basic of basics.



When I was a kid I used to pray every night for a new bike. Then I realized that The Lord doesn't work that way, so I stole one and asked him to forgive me.
作者 Re:JAVA面试题解惑系列(八)——聊聊基本类型(内置类型) [Re:臧圩人]
臧圩人





发贴: 63
积分: 15
于 2008-08-03 17:40 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
回复HenryShanley:

说的有道理,谢谢你的建议,看来我要调整一下写作的顺序了,呵呵



我的博客:http://zangweiren.javaeye.com
JAVA面试题解惑系列:http://zangweiren.javaeye.com/category/34977
作者 Re:JAVA面试题解惑系列(八)——聊聊基本类型(内置类型) [Re:臧圩人]
uriesijsif





发贴: 9
积分: 0
于 2008-08-10 09:16 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
臧圩人 wrote:
------------------------------------------------------------------------------------
我想出一本名为《JAVA面试题解惑系列》的书籍,详情请见:
http://rmyd.group.javaeye.com/group/topic/6193
目前网络连载中:http://zangweiren.javaeye.com/
请大家多关注,多提宝贵意见!
------------------------------------------------------------------------------------

作者:臧圩人(zangweiren)
网址:http://zangweiren.javaeye.com

>>>转载请注明出处!<<<

基本类型,或者叫做内置类型,是JAVA中不同于类的特殊类型。它们是我们编程中使用最频繁的类型,因此面试题中也总少不了它们的身影,在这篇文章中我们将从面试中常考的几个方面来回顾一下与基本类型相关的知识。

基本类型共有八种,它们分别都有相对应的包装类。关于它们的详细信息请看下表:



基本类型可以分为三类,字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double。数值类型又可以分为整数类型byte、short、int、long和浮点数类型float、double。JAVA中的数值类型不存在无符号的,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变。实际上,JAVA中还存在另外一种基本类型void,它也有对应的包装类java.lang.Void,不过我们无法直接对它们进行操作。对于数值类型的基本类型的取值范围,我们无需强制去记忆,因为它们的值都已经以常量的形式定义在对应的包装类中了。请看下面的例子:
Java代码

public class PrimitiveTypeTest {
public static void main(String[] args) {
// byte
System.out.println("基本类型:byte 二进制位数:" + Byte.SIZE);
System.out.println("包装类:java.lang.Byte");
System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE);
System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE);
System.out.println();

// short
System.out.println("基本类型:short 二进制位数:" + Short.SIZE);
System.out.println("包装类:java.lang.Short");
System.out.println("最小值:Short.MIN_VALUE=" + Short.MIN_VALUE);
System.out.println("最大值:Short.MAX_VALUE=" + Short.MAX_VALUE);
System.out.println();

// int
System.out.println("基本类型:int 二进制位数:" + Integer.SIZE);
System.out.println("包装类:java.lang.Integer");
System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE);
System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE);
System.out.println();

// long
System.out.println("基本类型:long 二进制位数:" + Long.SIZE);
System.out.println("包装类:java.lang.Long");
System.out.println("最小值:Long.MIN_VALUE=" + Long.MIN_VALUE);
System.out.println("最大值:Long.MAX_VALUE=" + Long.MAX_VALUE);
System.out.println();

// float
System.out.println("基本类型:float 二进制位数:" + Float.SIZE);
System.out.println("包装类:java.lang.Float");
System.out.println("最小值:Float.MIN_VALUE=" + Float.MIN_VALUE);
System.out.println("最大值:Float.MAX_VALUE=" + Float.MAX_VALUE);
System.out.println();

// double
System.out.println("基本类型:double 二进制位数:" + Double.SIZE);
System.out.println("包装类:java.lang.Double");
System.out.println("最小值:Double.MIN_VALUE=" + Double.MIN_VALUE);
System.out.println("最大值:Double.MAX_VALUE=" + Double.MAX_VALUE);
System.out.println();

// char
System.out.println("基本类型:char 二进制位数:" + Character.SIZE);
System.out.println("包装类:java.lang.Character");
// 以数值形式而不是字符形式将Character.MIN_VALUE输出到控制台
System.out.println("最小值:Character.MIN_VALUE="
+ (int) Character.MIN_VALUE);
// 以数值形式而不是字符形式将Character.MAX_VALUE输出到控制台
System.out.println("最大值:Character.MAX_VALUE="
+ (int) Character.MAX_VALUE);
}
}


运行结果:

1、基本类型:byte 二进制位数:8
2、包装类:java.lang.Byte
3、最小值:Byte.MIN_VALUE=-128
4、最大值:Byte.MAX_VALUE=127
5、
6、基本类型:short 二进制位数:16
7、包装类:java.lang.Short
8、最小值:Short.MIN_VALUE=-32768
9、最大值:Short.MAX_VALUE=32767
10、
11、基本类型:int 二进制位数:32
12、包装类:java.lang.Integer
13、最小值:Integer.MIN_VALUE=-2147483648
14、最大值:Integer.MAX_VALUE=2147483647
15、
16、基本类型:long 二进制位数:64
17、包装类:java.lang.Long
18、最小值:Long.MIN_VALUE=-9223372036854775808
19、最大值:Long.MAX_VALUE=9223372036854775807
20、
21、基本类型:float 二进制位数:32
22、包装类:java.lang.Float
23、最小值:Float.MIN_VALUE=1.4E-45
24、最大值:Float.MAX_VALUE=3.4028235E38
25、
26、基本类型:double 二进制位数:64
27、包装类:java.lang.Double
28、最小值:Double.MIN_VALUE=4.9E-324
29、最大值:Double.MAX_VALUE=1.7976931348623157E308
30、
31、基本类型:char 二进制位数:16
32、包装类:java.lang.Character
33、最小值:Character.MIN_VALUE=0
34、最大值:Character.MAX_VALUE=65535

Float和Double的最小值和最大值都是以科学记数法的形式输出的,结尾的“E+数字”表示E之前的数字要乘以10的多少倍。比如3.14E3就是3.14×1000=3140,3.14E-3就是3.14/1000=0.00314。

大家将运行结果与上表信息仔细比较就会发现float、double两种类型的最小值与Float.MIN_VALUE、Double.MIN_VALUE的值并不相同,这是为什么呢?实际上Float.MIN_VALUE和Double.MIN_VALUE分别指的是float和double类型所能表示的最小正数。也就是说存在这样一种情况,0到±Float.MIN_VALUE之间的值float类型无法表示,0到±Double.MIN_VALUE之间的值double类型无法表示。这并没有什么好奇怪的,因为这些范围内的数值超出了它们的精度范围。

基本类型存储在栈中,因此它们的存取速度要快于存储在堆中的对应包装类的实例对象。从Java5.0(1.5)开始,JAVA虚拟机(Java Virtual Machine)可以完成基本类型和它们对应包装类之间的自动转换。因此我们在赋值、参数传递以及数学运算的时候像使用基本类型一样使用它们的包装类,但这并不意味着你可以通过基本类型调用它们的包装类才具有的方法。另外,所有基本类型(包括void)的包装类都使用了final修饰,因此我们无法继承它们扩展新的类,也无法重写它们的任何方法。

各种数值类型之间的赋值与转换遵循什么规律呢?我们来看下面这个例子:
Java代码

public class PrimitiveTypeTest {
public static void main(String[] args) {
// 给byte类型变量赋值时,数字后无需后缀标识
byte byte_a = 1;
// 编译器会做范围检查,如果赋予的值超出了范围就会报错
// byte byte_b = 1000;
// 把一个long型值赋值给byte型变量,编译时会报错,即使这个值没有超出byte类型的取值范围
// byte byte_c = 1L;

// 给short类型变量赋值时,数字后无需后缀标识
short short_a = 1;
// 编译器会做范围检查,如果赋予的值超出了范围就会报错
// short short_b = 70000;
// 把一个long型值赋值给short型变量,编译时会报错,即使这个值没有超出short类型的取值范围
// byte short_c = 1L;

// 给short类型变量赋值时,数字后无需后缀标识
int int_a = 1;
// 编译器会做范围检查,如果赋予的值超出了范围就会报错
// int int_b = 2200000000;
// 把一个long型值赋值给int型变量,编译时会报错,即使这个值没有超出int类型的取值范围
// int int_c = 1L;

// 可以把一个int型值直接赋值给long型变量,数字后无需后缀标识
long long_a = 1;
// 如果给long型变量赋予的值超出了int型值的范围,数字后必须加L(不区分大小写)标识
long long_b = 2200000000L;
// 编译器会做范围检查,如果赋予的值超出了范围就会报错
// long long_c = 9300000000000000000L;

// 可以把一个int型值直接赋值给float型变量
float float_a = 1;
// 可以把一个long型值直接赋值给float型变量
float float_b = 1L;
// 没有F(不区分大小写)后缀标识的浮点数默认为double型的,不能将它直接赋值给float型变量
// float float_c = 1.0;
// float型数值需要有一个F(不区分大小写)后缀标识
float float_d = 1.0F;
// 把一个double型值赋值给float型变量,编译时会报错,即使这个值没有超出float类型的取值范围
// float float_e = 1.0D;
// 编译器会做范围检查,如果赋予的值超出了范围就会报错
// float float_f = 3.5000000E38F;

// 可以把一个int型值直接赋值给double型变量
double double_a = 1;
// 可以把一个long型值直接赋值给double型变量
double double_b = 1L;
// 可以把一个float型值直接赋值给double型变量
double double_c = 1F;
// 不带后缀标识的浮点数默认为double类型的,可以直接赋值
double double_d = 1.0;
// 也可以给数字增加一个D(不区分大小写)后缀标识,明确标出它是double类型的
double double_e = 1.0D;
// 编译器会做范围检查,如果赋予的值超出了范围就会报错
// double double_f = 1.8000000000000000E30Cool;

// 把一个double型值赋值给一个byte类型变量,编译时会报错,即使这个值没有超出byte类型的取值范围
// byte byte_d = 1.0D;
// 把一个double型值赋值给一个short类型变量,编译时会报错,即使这个值没有超出short类型的取值范围
// short short_d = 1.0D;
// 把一个double型值赋值给一个int类型变量,编译时会报错,即使这个值没有超出int类型的取值范围
// int int_d = 1.0D;
// 把一个double型值赋值给一个long类型变量,编译时会报错,即使这个值没有超出long类型的取值范围
// long long_d = 1.0D;

// 可以用字符初始化一个char型变量
char char_a = 'a';
// 也可以用一个int型数值初始化char型变量
char char_b = 1;
// 把一个long型值赋值给一个char类型变量,编译时会报错,即使这个值没有超出char类型的取值范围
// char char_c = 1L;
// 把一个float型值赋值给一个char类型变量,编译时会报错,即使这个值没有超出char类型的取值范围
// char char_d = 1.0F;
// 把一个double型值赋值给一个char类型变量,编译时会报错,即使这个值没有超出char类型的取值范围
// char char_e = 1.0D;
// 编译器会做范围检查,如果赋予的值超出了范围就会报错
// char char_f = 70000;
}
}


从上面的例子中我们可以得出如下几条结论:

1、未带有字符后缀标识的整数默认为int类型;未带有字符后缀标识的浮点数默认为double类型。
2、如果一个整数的值超出了int类型能够表示的范围,则必须增加后缀“L”(不区分大小写,建议用大写,因为小写的L与阿拉伯数字1很容易混淆),表示为long型。
3、带有“F”(不区分大小写)后缀的整数和浮点数都是float类型的;带有“D”(不区分大小写)后缀的整数和浮点数都是double类型的。
4、编译器会在编译期对byte、short、int、long、float、double、char型变量的值进行检查,如果超出了它们的取值范围就会报错。
5、int型值可以赋给所有数值类型的变量;long型值可以赋给long、float、double类型的变量;float型值可以赋给float、double类型的变量;double型值只能赋给double类型变量。

下图显示了几种基本类型之间的默认逻辑转换关系:



图中的实线表示无精度损失的转换,而虚线则表示这样的转换可能会损失一定的精度。如果我们想把一个能表示更大范围或者更高精度的类型,转换为一个范围更小或者精度更低的类型时,就需要使用强制类型转换(Cast)了。不过我们要尽量避免这种用法,因为它常常引发错误。请看下面的例子,如果不运行代码,你能预测它的结果吗?
Java代码

public class PrimitiveTypeTest {
public static void main(String[] args) {
int a = 123456;
short b = (short) a;
// b的值会是什么呢?
System.out.printlnBeer;
}
}


运行结果:

1、-7616

运算符对基本类型的影响

当使用+、-、*、/、%运算符对基本类型进行运算时,遵循如下规则:

1、只要两个操作数中有一个是double类型的,另一个将会被转换成double类型,并且结果也是double类型;
2、否则,只要两个操作数中有一个是float类型的,另一个将会被转换成float类型,并且结果也是float类型;
3、否则,只要两个操作数中有一个是long类型的,另一个将会被转换成long类型,并且结果也是long类型;
4、否则,两个操作数(包括byte、short、int、char)都将会被转换成int类型,并且结果也是int类型。

当使用+=、-=、*=、/=、%=、运算符对基本类型进行运算时,遵循如下规则:

1、运算符右边的数值将首先被强制转换成与运算符左边数值相同的类型,然后再执行运算,且运算结果与运算符右边数值类型相同。

了解了这些,我们就能解答下面这个常考的面试题了。请看:

乍一看,觉得它们都应该没有错误,可以正常运行。我们来写个例子试试:
Java代码

public class PrimitiveTypeTest {
public static void main(String[] args) {
short s1 = 1;
// 这一行代码会报编译错误
// s1 = s1 + 1;
// 这一行代码没有报错
s1 = 1 + 1;
// 这一行代码也没有报错
s1 += 1;
}
}


从例子中我们可以看出结果了。利用上面列举的规律,也很容易解释。在s1=s1+1;中,s1+1运算的结果是int型,把它赋值给一个short型变量s1,所以会报错;而在s1+=1;中,由于是s1是short类型的,所以1首先被强制转换为short型,然后再参与运算,并且结果也是short类型的,因此不会报错。那么,s1=1+1;为什么不报错呢?这是因为1+1是个编译时可以确定的常量,“+”运算在编译时就被执行了,而不是在程序执行的时候,这个语句的效果等同于s1=2,所以不会报错。前面讲过了,对基本类型执行强制类型转换可能得出错误的结果,因此在使用+=、-=、*=、/=、%=等运算符时,要多加注意。

Math.round()方法

java.lang.Math类里有两个round()方法,它们的定义如下:
Java代码

public static int round(float a) {
//other code
}

public static long round(double a) {
//other code
}


它们的返回值都是整数,且都采用四舍五入法。运算规则如下:

1、如果参数为正数,且小数点后第一位>=5,运算结果为参数的整数部分+1。
2、如果参数为负数,且小数点后第一位>5,运算结果为参数的整数部分-1。
3、如果参数为正数,且小数点后第一位<5;或者参数为负数,且小数点后第一位<=5,运算结果为参数的整数部分。

我们可以通过下面的例子来验证:
Java代码

public class MathTest {
public static void main(String[] args) {
System.out.println("小数点后第一位=5");
System.out.println("正数:Math.round(11.5)=" + Math.round(11.5));
System.out.println("负数:Math.round(-11.5)=" + Math.round(-11.5));
System.out.println();

System.out.println("小数点后第一位<5");
System.out.println("正数:Math.round(11.46)=" + Math.round(11.46));
System.out.println("负数:Math.round(-11.46)=" + Math.round(-11.46));
System.out.println();

System.out.println("小数点后第一位>5");
System.out.println("正数:Math.round(11.68)=" + Math.round(11.68));
System.out.println("负数:Math.round(-11.68)=" + Math.round(-11.68));
}
}


运行结果:

1、小数点后第一位=5
2、正数:Math.round(11.5)=12
3、负数:Math.round(-11.5)=-11
4、
5、小数点后第一位<5
6、正数:Math.round(11.46)=11
7、负数:Math.round(-11.46)=-11
8、
9、小数点后第一位>5
10、正数:Math.round(11.68)=12
11、负数:Math.round(-11.68)=-12

根据上面例子的运行结果,我们还可以按照如下方式总结,或许更加容易记忆:

1、参数的小数点后第一位<5,运算结果为参数整数部分。
2、参数的小数点后第一位>5,运算结果为参数整数部分绝对值+1,符号(即正负)不变。
3、参数的小数点后第一位=5,正数运算结果为整数部分+1,负数运算结果为整数部分。

switch语句

哪些类型可以用于switch语句的判断呢?我们做个测试就知道了:
Java代码

public class MathTest {
// 枚举类型,Java5.0以上版本可用
static enum enum_e {
A, B
}

public static void main(String[] args) {
// byte
byte byte_n = 0;
switch (byte_n) {
case 0:
System.out.println("byte可以用于switch语句");
break;
}

// Byte类
Byte byte_m = 0;
// 需要Java5.0(1.5)以上版本支持
switch (byte_m) {
case 0:
System.out.println("Byte类可以用于switch语句");
System.out.println();
break;
}

// char
char char_n = 0;
switch (char_n) {
case 0:
System.out.println("char可以用于switch语句");
break;
}

// Character类
Character char_m = 0;
// 需要Java5.0(1.5)以上版本支持
switch (char_m) {
case 0:
System.out.println("Character类可以用于switch语句");
System.out.println();
break;
}

// short
short short_n = 0;
switch (short_n) {
case 0:
System.out.println("short可以用于switch语句");
break;
}

// Short
Short short_m = 0;
// 需要Java5.0(1.5)以上版本支持
switch (short_m) {
case 0:
System.out.println("Short类可以用于switch语句");
System.out.println();
break;
}

// int
int int_n = 0;
switch (int_n) {
case 0:
System.out.println("int可以用于switch语句");
break;
}

// Integer类
Integer int_m = 0;
// 需要Java5.0(1.5)以上版本支持
switch (int_m) {
case 0:
System.out.println("Integer类可以用于switch语句");
System.out.println();
break;
}

// long
long long_n = 0;
// 编译错误,long型不能用于switch语句
// switch (long_n) {
// case 0:
// System.out.println("long可以用于switch语句");
// break;
// }

// Long类
Long long_m = 0L;
// 编译错误,Long类型不能用于switch语句
// switch (long_m) {
// case 0:
// System.out.println("Long类可以用于switch语句");
// System.out.println();
// break;
// }

// float
float float_n = 0.0F;
// 编译错误,float型不能用于switch语句
// switch (float_n) {
// case 0.0F:
// System.out.println("float可以用于switch语句");
// break;
// }

// Float类
Float float_m = 0.0F;
// 编译错误,Float类型不能用于switch语句
// switch (float_m) {
// case 0.0F:
// System.out.println("Float类可以用于switch语句");
// System.out.println();
// break;
// }

// double
double double_n = 0.0;
// 编译错误,double型不能用于switch语句
// switch (double_n) {
// case 0.0:
// System.out.println("double可以用于switch语句");
// break;
// }

// Double类
Double double_m = 0.0;
// 编译错误,Double类型不能用于switch语句
// switch (double_m) {
// case 0.0:
// System.out.println("Double类可以用于switch语句");
// System.out.println();
// break;
// }

// boolean
boolean bool_b = true;
// 编译错误,boolean型不能用于switch语句
// switch (bool_b) {
// case true:
// System.out.println("boolean可以用于switch语句");
// break;
// }

// Boolean类
Boolean bool_l = true;
// 编译错误,Boolean类型不能用于switch语句
// switch (bool_l) {
// case true:
// System.out.println("Boolean类可以用于switch语句");
// System.out.println();
// break;
// }

// String对象
String string_s = "Z";
// 编译错误,long型不能用于switch语句
// switch (string_s) {
// case "Z":
// System.out.println("String可以用于switch语句");
// System.out.println();
// break;
// }

// enum(枚举类型,Java5.0以上版本可用)
switch (MathTest.enum_e.A) {
case A:
System.out.println("enum可以用于switch语句-A");
break;
case B:
System.out.println("enum可以用于switch语句-B");
break;
}
}
}


运行结果如下:

1、byte可以用于switch语句
2、Byte类可以用于switch语句
3、
4、char可以用于switch语句
5、Character类可以用于switch语句
6、
7、short可以用于switch语句
8、Short类可以用于switch语句
9、
10、int可以用于switch语句
11、Integer类可以用于switch语句
12、
13、enum可以用于switch语句-A

结果已经出来了,我们来总结一下:

1、byte、char、short、int四种基本类型以及它们的包装类(需要Java5.0/1.5以上版本支持)都可以用于switch语句。
2、long、float、double、boolean四种基本类型以及它们的包装类(在Java所有版本中)都不能用于switch语句。
3、enum类型,即枚举类型可以用于switch语句,但是要在Java5.0(1.5)版本以上才支持。
4、所有类型的对象(包括String类,但在Java5.0/1.5以上版本中,该项要排除byte、char、short、int四种基本类型对应的包装类)都不能用于switch语句。



作者 Re:JAVA面试题解惑系列(八)——聊聊基本类型(内置类型) [Re:臧圩人]
uriesijsif





发贴: 9
积分: 0
于 2008-08-10 09:26 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
上面那个发错了,麻烦版主删下,我要问的是:
1、运算符右边的数值将首先被强制转换成与运算符左边数值相同的类型,然后再执行运算,且运算结果与运算符右边数值类型相同。

运算符右边的数值被强制转换成运算符左边的类型后,再执行运算,运算的时候会进行提升吗,比如说二个short型的变量参加算术运算时会提升为 int型,其结果也是int型,而这里 short s=1;s+=1;先把1转换成short型,然后运算,运算的时候会提升吗???
我想应该是这样:1、运算符右边的数值将首先被强制转换成与运算符左边数值相同的类型,然后再执行运算,执行运算的时候会进行提升,但运算结果会强制转换成运算符左边的类型。



作者 Re:JAVA面试题解惑系列(八)——聊聊基本类型(内置类型) [Re:臧圩人]
uriesijsif





发贴: 9
积分: 0
于 2008-08-10 09:45 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
我想应该会进行有符号位提升:
例如:short s=127;
s+=128;//这里128会强制转换成short型也就是-128,再执行127+-128,
//它们会分别进行有符号位的扩展成int型,但运算结果又会强制
//转换成short型,是这样的吗???很迷惑。。。



作者 Re:JAVA面试题解惑系列(八)——聊聊基本类型(内置类型) [Re:臧圩人]
臧圩人





发贴: 63
积分: 15
于 2008-08-10 09:47 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
回复uriesijsif:

1、运算符右边的数值将首先被强制转换成与运算符左边数值相同的类型,然后再执行运算,且运算结果与运算符右边数值类型相同。


这里,最后运算结果应该是与左边的数值类型相同,此处是笔误,新版本中已经修正。

我想应该是这样:1、运算符右边的数值将首先被强制转换成与运算符左边数值相同的类型,然后再执行运算,执行运算的时候会进行提升,但运算结果会强制转换成运算符左边的类型。


我也是这么认为的,请参考这里:

当使用+、-、*、/、%运算符对基本类型进行运算时,遵循如下规则:

1、只要两个操作数中有一个是double类型的,另一个将会被转换成double类型,并且结果也是double类型;
2、否则,只要两个操作数中有一个是float类型的,另一个将会被转换成float类型,并且结果也是float类型;
3、否则,只要两个操作数中有一个是long类型的,另一个将会被转换成long类型,并且结果也是long类型;
4、否则,两个操作数(包括byte、short、int、char)都将会被转换成int类型,并且结果也是int类型。



我的博客:http://zangweiren.javaeye.com
JAVA面试题解惑系列:http://zangweiren.javaeye.com/category/34977
作者 Re:JAVA面试题解惑系列(八)——聊聊基本类型(内置类型) [Re:臧圩人]
uriesijsif





发贴: 9
积分: 0
于 2008-08-10 10:25 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
呵呵,谢了。。


作者 Re:JAVA面试题解惑系列(八)——聊聊基本类型(内置类型) [Re:臧圩人]
uriesijsif





发贴: 9
积分: 0
于 2008-08-10 10:28 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
看了,你写的这些文章学到很多东西,我建议你写下,复制构造函数与克隆之间的区别,,最好是详细解释下深拷贝与浅拷贝的区别。。。最近在学这个,,一直有点迷惑。。。。。。


作者 Re:JAVA面试题解惑系列(八)——聊聊基本类型(内置类型) [Re:uriesijsif]
ditty

负资产小资

CJSDN高级会员


发贴: 1038
积分: 143
于 2008-08-10 16:27 user profilesend a private message to usersend email to dittysearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
嗯,写的比较详细,提个建议:
如果只是网上贴一下,已经很好了,如出书的话,代码篇幅有点过大了,排版困难不说,显得有点罗嗦。最好相信读者举一反三的能力。



内忧外患的时代,洗心革面,阿咪豆腐~
作者 Re:JAVA面试题解惑系列(八)——聊聊基本类型(内置类型) [Re:ditty]
臧圩人





发贴: 63
积分: 15
于 2008-08-11 10:04 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
uriesijsif wrote:
看了,你写的这些文章学到很多东西,我建议你写下,复制构造函数与克隆之间的区别,,最好是详细解释下深拷贝与浅拷贝的区别。。。最近在学这个,,一直有点迷惑。。。。。。

ditty wrote:
嗯,写的比较详细,提个建议:
如果只是网上贴一下,已经很好了,如出书的话,代码篇幅有点过大了,排版困难不说,显得有点罗嗦。最好相信读者举一反三的能力。

非常感谢两位的建议:)



我的博客:http://zangweiren.javaeye.com
JAVA面试题解惑系列:http://zangweiren.javaeye.com/category/34977

flat modethreaded modego to previous topicgo to next topicgo to back
  已读帖子
  新的帖子
  被删除的帖子
Jump to the top of page

   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1
客服电话 18559299278    客服信箱 714923@qq.com    客服QQ 714923