Java基本数据类型与包装类

Author Avatar
stormjie 10月 10, 2018
  • 在其它设备中阅读本文章

前几天提到我最近要复习Java基础,所以我又去图书馆借了这本书

刚好过去整整一年,当初我入门Java就是看这本书,今天的我依然是个Java初学者~

这篇的主题是基础中的基础了,所以也很容易被人忽略(包括我也是),最近刷起题来才发现细枝末节的东西很多,还是要理一理。

一、基本数据类型

Java提供了八种基本类型,六种数值类型(四个整型,两个浮点型),一种字符型,还有一种布尔型。

byte:

  • byte 数据类型是8位、有符号的以二进制补码表示的整数;
  • 最小值是 -128(-2^7);
  • 最大值是 127(2^7-1);
  • 默认值是 0;
  • byte 类型用在大型数组中节约空间,主要代替整数,因为 byte 变量占用的空间只有 int 类型的四分之一;
  • 例子:byte a = 100;byte b = -50;

short:

  • short 数据类型是 16 位、有符号的以二进制补码表示的整数;
  • 最小值是 -32768(-2^15);
  • 最大值是 32767(2^15 - 1);
  • Short 数据类型也可以像 byte 那样节省空间。一个short变量是int型变量所占空间的二分之一;
  • 默认值是 0;
  • 例子:short s = 1000;short r = -20000;

int:

  • int 数据类型是32位、有符号的以二进制补码表示的整数;
  • 最小值是 -2,147,483,648(-2^31);
  • 最大值是 2,147,483,647(2^31 - 1);
  • 一般地整型变量默认为 int 类型;
  • 默认值是 0 ;
  • 例子:int a = 100000;int b = -200000;

long:

  • long 数据类型是 64 位、有符号的以二进制补码表示的整数;
  • 最小值是 -9,223,372,036,854,775,808(-2^63);
  • 最大值是 9,223,372,036,854,775,807(2^63 -1);
  • 这种类型主要使用在需要比较大整数的系统上;
  • 默认值是 0L;
  • 例子: long a = 100000L;Long b = -200000L;
    “L”理论上不分大小写,但是若写成”l”容易与数字”1”混淆,不容易分辩。所以最好大写。

float:

  • float 数据类型是单精度、32位、符合IEEE 754标准的浮点数;
  • float 在储存大型浮点数组的时候可节省内存空间;
  • 默认值是 0.0f;
  • 浮点数不能用来表示精确的值,如货币;
  • 例子:float f1 = 234.5f;

double:

  • double 数据类型是双精度、64 位、符合IEEE 754标准的浮点数;
  • 浮点数的默认类型为double类型;
  • double类型同样不能表示精确的值,如货币;
  • 默认值是 0.0d;
  • 例子:double d1 = 123.4;

boolean:

  • boolean数据类型表示1位的信息;
  • 只有两个取值:true 和 false;
  • 这种类型只作为一种标志来记录 true/false 情况;
  • 默认值是 false;
  • 例子:boolean one = true;

char:

  • char类型是一个单一的 16 位 Unicode 字符;
  • 最小值是 \u0000(即为0);
  • 最大值是 \uffff(即为65,535);
  • char 数据类型可以储存任何字符;
  • 例子:char letter = ‘A’;

注:

  • 整型默认为int类型,但如果将一个较小的整数值(在byte或short类型的表数范围内)赋给一个byte或short变量,系统会自动把这个整数值当成byte或者short类型来处理。
  • 如果使用一个很大的整数值(超出int类型的表数范围)时,Java不会自动把这个整数值当成long类型来处理,如果希望把它当成long类型来处理推荐在整数值后加字母L作为后缀。
  • Java整数值有四种表示形式:十进制,二进制(0b或0B开头),八进制(0开头),十六进制(0x或0X开头,其中10~15分别以a~f来表示)。
  • 浮点型默认为较精确的double,如果想使用float应在浮点数后加上尾缀f或F。
  • 浮点型是不精确的,不能对浮点型进行精确比较,也不能作为switch语句判断条件。

二、基本类型的类型转换

1.自动类型转换

注:

  • 基本数据类型中,布尔类型boolean占有一个字节,由于其本身所代码的特殊含义,boolean类型与其他基本类型不能进行类型的转换(既不能进行自动类型的提升,也不能强制类型转换), 否则将编译出错。
  • byte,char,short虽然类型从小到大自动转换,但是byte不能转成char,char也不能转成short。因为byte和short是数值型的变量,char字符型的变量。数值型变量有符号(第一位)而在char中则无正负之分。byte转short自然就是可以的了。
2.强制类型转换

如果将上图箭头右边的值转换为左边的值就需要强制类型转换,原因很简单,右边表示的范围大,左边表示的范围小。 当进行强制类型转换时,类似于把一个大瓶子的水倒入小瓶子,如果大瓶子的水不多还好,但如果大瓶子里的水很多就会引起溢出,造成数据丢失。

《疯狂Java讲义》中有个很好的例子说明强制类型转换后数值是如何改变的,在这贴出来做个记录。

3.表达式类型的自动提升

当一个算术表达式中包含多个基本类型的值时,整个算术表达式的数据类型将发生自动提升。Java定义了如下的自动提升规则。

  • 所有的byte类型、short类型和char类型将被提升到int类型。

  • 整个算术表达式的数据类型自动提升到与表达式中最高等级操作数同样的类型。

面试陷阱

byte b1 = 10;
byte b2 = 11;
//错误: 不兼容的类型: 从int转换到byte可能会有损失
//否则,两个操作数都将转换为int类型。
byte b3 = b1 + b2 //错误
byte b3 = (byte)(b1 + b2); //正确
short s1 = 1; 
s1 = s1 + 1; //错误: 不兼容的类型: 从int转换到short可能会有损失
short s2 = 1; 
s2 += 1; // 等同于short s2 = (short)(s2 + (short)1); //正确

三、包装类

为了满足Java语言面向对象的这一特性,上述基本数据类型中的每一个在java.lang包中都有一个包装类,即将每个基本类型都包装成了一个类。

基本数据类型 包装类
byte Byte
boolean Boolean
short Short
char Character
int Integer
long Long
float Float
double Double

对于包装类说,这些类的用途主要包含三种:

  • 集合不允许存放基本数据类型,故常用包装类。

  • 作为和基本数据类型对应的类类型存在,方便涉及到对象的操作。

  • 包含每种基本数据类型的相关属性如最大值、最小值等,以及相关的操作方法。

1.基本类型与包装类型之间的转换

JDK自从1.5版本以后,就引入了自动拆装箱的语法,也就是在进行基本数据类型和对应的包装类转换时,系统将自动进行,这将大大方便我们的代码书写。使用示例代码如下:

//自动装箱
int m = 10;
Integer in = m;
System.out.println(in); //10

//自动拆箱
Integer inn = new Integer(10);
int n = inn;
System.out.println(n); //10
2.字符串和基本类型之间的转换

(1)基本类型转换成字符串类型

  • 包装类的toString()方法。

  • String 类的valueOf()方法。

  • 空字符串加一个基本类型变量。

(2)字符串类型转换成基本类型

  • 包装类的parseXxx()静态方法。

  • 包装类的valueOf()方法。

3.包装类中“==”与equals的用法比较

值得注意的是,包装类中的equals方法和String类一样,都是重写了Object类中的equals方法,因此比较的是内容而不是地址,而“==”比较的依然是引用变量的地址,只是当包装类型和与之相对应的基本类型进行“==”比较时会先做自动拆箱处理。

public static void equalsTest() {
        // TODO Auto-generated method stub
        Integer a = new Integer(-100);
        Integer b = new Integer(-100);
        int c = -100;
        System.out.println(a == b);//false
        System.out.println(a == c);//true
        System.out.println(b == c);//true

        System.out.println(a.equals(b));//true

        String s1 = new String("hello");
        String s2 = new String("hello");
        System.out.println(s1 == s2);//false
        System.out.println(s1.equals(s2));//true
}
4.包装类的常量池

既然提到String类,必须说说包装类和String类一样,JVM也为其提供了常量池,下面代码具体说明:

/**
 * 8种基本类型的包装类和对象池
 *         包装类:java提供的为原始数据类型的封装类,如:int(基本数据类型),Integer封装类。
 *         对象池:为了一定程度上减少频繁创建对象,将一些对象保存到一个"容器"中。
 * 
 *     Byte,Short,Integer,Long,Character。这5种整型的包装类的对象池范围在-128~127之间,也就是说,
 *     超出这个范围的对象都会开辟自己的堆内存。
 * 
 *  Boolean也实现了对象池技术。Double,Float两种浮点数类型的包装类则没有实现。
 *     String也实现了常量池技术。
 * 
 * 自动装箱拆箱技术
 *     JDK5.0及之后允许直接将基本数据类型的数据直接赋值给其对应地包装类。
 *  如:Integer i = 3;(这就是自动装箱)
 *  实际编译代码是:Integer i=Integer.valueOf(3); 编译器自动转换
 *     自动拆箱则与装箱相反:int i = (Integer)5;
 */
public class Test {
    public static void main(String[] args) {

        //基本数据类型常量池范围-128~127
        Integer n1 = -129;
        Integer n2 = -129;
        Long n3 = 100L;
        Long n4 = 100L;
        Double n5 =  12.0;
        Double n6 = 12.0;
        //false
        System.out.println(n1 == n2);
        //true
        System.out.println(n3 == n4);
        //false
        System.out.println(n5 == n6);

        //String常量池技术,注意:这里String不是用new创建的对象
        String str1 = "abcd";
        String str2 = "abcd";
        //true
        System.out.println(str1 == str2);
    }
}

想深入了解的话可以看看这两篇帖子Java包装类对象比较中存在的问题Java包装类的常量池

这篇Java基本数据类型与包装类到这就更完了,没想到小细节是真得多,最后感谢上述出现过的帖子的作者以及《疯狂Java讲义》的作者李刚先生。