小谈基本数据类型包装类

引入包装类

首先我们看一个简单的需求:把十进制100转成二级制。

我们可以这么干,采用"除2取余,逆序排列"的方法,类似于小学数学中讲的“短除法”。

PS:画图工具用的不是很溜,大家凑合着看吧~

可以看出十进制整数100的二进制是1100100。

代码实现示例

package String;

public class WrapperClassTest {

	public static void main(String[] args) {
		int i = 100;
		String result0 = toBinary(0);
		String result1 = toBinary(1);
		String result100 = toBinary(100);
		System.out.println("result0 == " + result0);
		System.out.println("result1 == " + result1);
		System.out.println("result100 == " + result100);
	}

	// 此方法只能求自然数的二进制
	private static String toBinary(int number) {
		if (number == 0) {
			return "0";
		}
		int sum;
		String result = "";
		for (int i = number; i > 0; i = i / 2) {
			if (i % 2 == 0) {
				sum = 0;
			} else {
				sum = 1;
			}
			result = sum + result;
		}
		return result;
	}
}

运行结果:

result0 == 0
result1 == 1
result100 == 1100100

这么看来还不错,但是这个方法只能求某个自然数的二进制,还可能存在未知bug,那么问题来了,如果给的数是负数、小数,我们怎么整?我们都知道java是典型的面向对象编程语言,但其中的8种基本数据类型并不支持面向对象编程,不具备对象的特性——不携带属性、没有方法可调用。如果我们要完成数据的进制转换,或者把一个int数据转成String类型就会很麻烦,为了解决这些问题,java也为每种基本数据类型设计了各自对应的类,称之为包装类(Wrapper Classes)。

基本数据类型及对应的包装类说明
基本数据类型对应的包装类基本数据类型对应的包装类
byteBytecharCharacter
shortShortfloatFloat
intIntegerdoubleDouble
longLongbooleanBoolean


Integer构造方法

ps:基本类型包装类使用方法基本相同,这里我们以Integer为例进行科普。

构造方法摘要
Integer(int value)
          构造一个新分配的 Integer 对象,它表示指定的 int 值。
Integer(String s)
          构造一个新分配的 Integer 对象,它表示 String 参数所指示的 int 值。注意:这个字符串必须是由数字字符组成,否则会抛出
NumberFormatException这个异常

代码示例:

	public static void main(String[] args) {
		int i = 100;
		String str = "100";
		Integer integer = new Integer(i);
		Integer integer2 = new Integer(str);
		System.out.println("integer == " + integer);
		System.out.println("integer2 == " + integer2);
	}

解决进制转换问题

  • 十进制与其他进制之间的转换

本文刚开始通过求十进制100的二进制引入基本类型包装类,那么jdk提供给我们的基本类型包装类又是怎么解决这个问题的?查看API可知,可以通过toBinaryString(int i)这个方法解决,老规矩,先上代码:

public static void main(String[] args) {
	int i = 100;
	Integer integer = new Integer(i);
	String str = integer.toBinaryString(i);
	System.out.println("str == " + str);
}

运行结果:
str == 1100100

其实Integer中还提供了八进制、十六进制、N进制(1<N<37的整数)的转换,look at it!

public static void main(String[] args) {
	int i = 100;
	Integer integer = new Integer(i);
	String str1 = integer.toOctalString(i);// 转成八进制
	String str2 = integer.toHexString(i);// 转成十六进制
	String str3 = integer.toString(i, 0);// 转成零进制
	String str4 = integer.toString(i, 1);// 转成一进制
	String str5 = integer.toString(i, 2);// 转成二进制
	String str6 = integer.toString(i, 36);// 转成三十六进制
	String str7 = integer.toString(i, 37);// 转成三十七进制
	String str8 = integer.toString(i, -1);// 转成负一进制

	System.out.println("str1 ==" + str1);
	System.out.println("str2 ==" + str2);
	System.out.println("str3 ==" + str3);
	System.out.println("str4 ==" + str4);
	System.out.println("str5 ==" + str5);
	System.out.println("str6 ==" + str6);
	System.out.println("str7 ==" + str7);
	System.out.println("str8 ==" + str8);
}

运行结果:
str1 ==144
str2 ==64
str3 ==100
str4 ==100
str5 ==1100100
str6 ==2s
str7 ==100
str8 ==100

我们从运行结果发现,转成零进制、一进制、三十七进制、负一进制,结果都是100,why?

通过查看源码我们看到,进制在小于Character.MIN_RADIX(也就是2)或者大于Character.MAX_RADIX(也就是36)时,就按照十进制处理了,也就是说进制转换的范围是二进制到三十六进制。

二进制这个临界值我们可以理解,那三十六进制这个最大临界值怎么理解?三十七进制怎么就不行了?我们想想,“0~9”、“a~z”加起来是不是刚好是36个,通过查看如下源码,我们也可以找到答案,so,you konow?

  • String数据与N进制之间的转换
public static void main(String[] args) {
	// 字符串数据转成N进制的整数
	System.out.println(Integer.parseInt("100", 10));
	System.out.println(Integer.parseInt("100", 2));
	System.out.println(Integer.parseInt("100", 8));
	System.out.println(Integer.parseInt("100", 16));
	System.out.println(Integer.parseInt("100", 36));
	// java.lang.NumberFormatException 前面的字串必须是能组成后面进制的数据,二进制逢二进 
    //一,“123"明显不符合要求
	// System.out.println(Integer.parseInt("123", 2));
}

上面的Integer.parseInt("100", 10)表示把字符串类型的“100”转换成十进制整型数据,其他以此类推。

基本数据类型与String之间的转换

  • String转int
public static void main(String[] args) {
	String str = "100";
	int number = 66;
	//String转int
	//方式一
	Integer integer = new Integer(str);
	int number1 = integer.intValue();
	System.out.println("number1 == " + number1);
	//方式二(推荐使用)
	int number2 = Integer.parseInt(str);
	System.out.println("number2 == " +number2);
}
  • int转String
public static void main(String[] args) {
	String str = "100";
	int number = 66;
	// int转String
	// 方式一
	String str1 = "" + number;
	System.out.println("str1 == " + str1);
	// 方式二
	Integer integer = new Integer(number);
	String str2 = integer.toString();
	System.out.println("str2 == " + str2);
	// 方式三(推荐使用)
	String str3 = String.valueOf(number);
	System.out.println("str3 == " + str3);
	// 方式四
	String str4 = Integer.toString(number);
	System.out.println("str4 == " + str4);
}

拆装箱

基本类型和对应的包装类可以相互转换。

  • 基本类型向对应的包装类转换称为装箱,比如把int转换成Integer类的对象。
  • 包装类向对应的基本类型转换称为拆箱,比如把Integer类的对象简化为int。
public static void main(String[] args) {
	int i = 100;
	Integer integer = new Integer(i);// 通过构造方法手动装箱
	int j = integer.intValue();// 通过intValue方法手动拆箱
	System.out.println("integer == " + integer);
	System.out.println("j == " + j);
}

JDK1.5之后,有了包装类的自动拆装箱:

public class WrapperClass02 {

	/*
	 * JDK5的新特性 自动装箱:把基本类型转换为包装类类型 自动拆箱:把包装类类型转换为基本类型
	 */
	public static void main(String[] args) {
		// 定义了一个int类型的包装类类型变量i
		// Integer i = new Integer(100);
		Integer ii = 100;
		ii += 200;
		System.out.println("ii == " + ii);
	}
}

可以看到,我直接把int类型数据赋值给Integer对象,按理来说,基本数据类型是不能直接赋值给引用类型的,可是代码并没有报错,why?而且我对int数据和Integer数据做了相加操作,居然也没有报错,这又是为什么?通过反编译class文件,我们发现原来JDK帮我们通过Integer.valueOf()方法将int数据装箱转换成Integer类型之后,才做的赋值;相加的操作是通过intValue()拆箱,将Integer数据转成int数据,做完相加操作之后,再通过Integer.valueOf()方法将int数据装箱成Integer对象,最后完成赋值;字符串的拼接通过实例化StringBuilder对象调用append方法实现。

注意一个小问题:在使用时,Integer  x = null;代码就会出现NullPointerException。建议先判断是否为null,然后再使用。

Integer iii = null;
// NullPointerException
if (iii != null) {
	iii += 1000;
	System.out.println(iii);
}

面试题

根据如下程序,写出程序运行结果:

package String;

/**
 * 看程序写结果
 * 
 * @author Ke_Xiaomiao
 *
 */
public class WrapperClass02 {

	public static void main(String[] args) {
		Integer i1 = new Integer(127);
		Integer i2 = new Integer(127);
		System.out.println(i1 == i2);
		System.out.println(i1.equals(i2));
		System.out.println("------");

		Integer i3 = new Integer(128);
		Integer i4 = new Integer(128);
		System.out.println(i3 == i4);
		System.out.println(i3.equals(i4));
		System.out.println("------");

		Integer i5 = 127;
		Integer i6 = 127;
		System.out.println(i5 == i6);
		System.out.println(i5.equals(i6));
		System.out.println("------");

		Integer i7 = 128;
		Integer i8 = 128;
		System.out.println(i7 == i8);
		System.out.println(i7.equals(i8));
		System.out.println("------");
	}
}

首先我们看第一块,i1和i2都是创建的新对象的引用,所以i1==i2结果是false,又因为它俩值相等,所以i1.equals(i2)结果是true;第二块与第一块原理一样;第三块把127直接赋值给i5和i6,其实我们知道这里做了自动装箱操作,即Integer.valueOf(127),虽然都是把127装进“箱子”里了,可是装进的“箱子”不同,所以我们认为i5==i6结果也是false,又因为它俩值相等,即内容一样,所以i5.equels(i6)结果是true;第四块代码原理与第三块是一样的。我们暂时是这么认为的,对不对我们不知道,且看运行结果:

false
true
------
false
true
------
true
true
------
false
true
------

咦,我怎么发现第三块代码的结果跟我们想的不太一样呢,why?

既然第三块代码存在装箱操作,我们不妨看下Integer.valueOf()的源码:

我们发现这里存在一个IntegerCache,暂且叫它Integer数据缓冲池。如果被装箱的数据在low和high之间,它是直接从缓冲池里取的数据,否则创建新的Integer对象。那么low和high分别是多少,继续追踪源码:

我们可以看到low的值是-128,high的值是127,而且类的注释也说明了缓冲池的范围是-128~127之间(包括-128和127)。so,第三块代码因为是直接从缓冲池取的,所以i5==i6结果是true,而第四块代码中,128超出了缓冲池的范围,得重新创建对象,所以i7==i8结果是false。你学会了吗?学会了点赞留言支持一下,没学会的同学欢迎评论区留言提问,我看到会第一时间回复~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值