Java出道之时,自诩为“纯面向对象的语言”,意思是之前的所谓“面向对象语言”不纯。

但是,有人指责Java也不纯——8种基本类型并非类类型。为此,Java为他们提供可对应的类类型,是为“包装类”。

包装类

Java的八种基本数据类型用起来很方便,但不支持面向对象的编程机制,不属于Object继承体系,没有成员方法可调用。某些场合下,只能使用对象类型,不能使用基本类型,因此基本类型需要对应的包装类。

比如集合的定义:List<Integer> list;

写为List<int> list;就错了

Java提供了基本类型对应的包装类(Wrapper Class):

包装类一般就是把基本类型的首字母小写变为大写,但是int和char除外,它们的包装类要用全称。

下表中将int和char的写法加粗。

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

另有一种说法,说Java中有9种基本类型,还要加一个void,其包装类是Void,但这种说法没有被普遍接受。

装箱和拆箱的概念

基本类型→(转为)→包装类,是为装箱

包装类→(转为)→基本类型,是为拆箱

JDK 1.5开始就提供了自动装箱、自动拆箱功能。借助该功能,开发者可以把基本类型当做对象使用,也可以把包装类的实例当做基本类型变量使用。

public class Test包装类 {
public static void main(String[] args) {
int a1 = 1000;// 定义基本类型
Integer objA = a1; // 自动装箱:Integer←int
int a2 = objA; // 自动拆箱:int←Integer
System.out.println(a2);
}
}

上述代码的解析:

int a1 = 1000;
自动装箱 Integer objA =a1; Integer←int 本质上调用了Integer.valueOf(...)
自动拆箱 int a2 = objA; int←Integer 本质上调用了objA.intValue()

包装类可以通过new实例化来构造

除Character类外,其它的包装类都有parseXxx方法:字符串→基本数据类型

包装类有valueOf方法:字符串→包装类对象

示例代码(比较枯燥,瞅一眼就行):

public class Test构造包装类 {
public static void main(String[] args) {
构造包装类();
parseXxx_str_to_基本类型();
valueOf_str_to_Wrapper();
}
static void 构造包装类() {
System.out.println("---new 包装类---");
Boolean objBool = new Boolean(true);
Character objChar = new Character('X');
Byte objByte = new Byte((byte) 10);
Short objS = new Short((short) 50);
Integer objInt = new Integer(100);
Long objLong = new Long(1000);
Float objF = new Float(3.14);
Double objD = new Double(3.1415);
System.out.println(objBool);
System.out.println(objChar);
System.out.println(objByte);
System.out.println(objS);
System.out.println(objInt);
System.out.println(objLong);
System.out.println(objF);
System.out.println(objD);
}
static void parseXxx_str_to_基本类型() {
String str = "123";
System.out.println("---除Character类外,包装类都有parseXxx方法");
System.out.println("---parseXxx:字符串→基本数据类型值");
byte b = Byte.parseByte(str);
short s = Short.parseShort(str);
int i = Integer.parseInt(str);
long l = Long.parseLong(str);
float f = Float.parseFloat(str);
double d = Double.parseDouble(str);
boolean bl = Boolean.parseBoolean("TruE");
System.out.println(i);
System.out.println(s);
System.out.println(b);
System.out.println(l);
System.out.println(f);
System.out.println(d);
System.out.println(bl);
}
static void valueOf_str_to_Wrapper() {
String str = "123";
System.out.println("---valueOf方法:字符串→包装类对象");
Byte objByte = Byte.valueOf(str);
Short objShort = Short.valueOf(str);
Integer objInt = Integer.valueOf(str);
Long objLong = Long.valueOf(str);
Float objF = Float.valueOf(str);
Double objD = Double.valueOf(str);
Boolean objB = Boolean.valueOf("true");
Character obkChar = Character.valueOf('C');
System.out.println(objByte);
System.out.println(objShort);
System.out.println(objInt);
System.out.println(objLong);
System.out.println(objF);
System.out.println(objD);
System.out.println(obkChar);
System.out.println(objB);
}
}

Java中100等于100,1000不等于1000

public class Java1000 {
public static void main(String[] args) {
Integer a1 = 100;
Integer a2 = 100;
System.out.println(a1 + "==" + a2 + ":" + (a1 == a2)); a1 = 1000;
a2 = 1000;
System.out.println(a1 + "==" + a2 + ":" + (a1 == a2));
}
}

100100:true

10001000:false


原因:JDK源码的Integer类中,将-128~127做了缓存处理。

看看这段缓存:

package java.lang;
……
public final class Integer extends Number implements Comparable<Integer> {
……
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[]; static {
// high value may be configured by property
int h = 127;
……
high = h;
……
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
……
}

改改这段缓存:(看懂大概即可)

import java.lang.reflect.Field;
import java.util.Arrays;
public class TestInteger {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
// 说明:IntegerCache是Integer中的一个内部类
// 源码:private static class IntegerCache{...}
// 1.取出Integer中定义的内部类(包括公共、私有、保护)
Class<?>[] classes = Integer.class.getDeclaredClasses();
System.out.println("Class数组:" + Arrays.toString(classes));
Class<?> classCache = classes[0];
System.out.println("IntegerCache:" + classCache);
// 2.取成员变量:cache
// 源码:static final Integer cache[];
Field fieldCache = classCache.getDeclaredField("cache");
System.out.println("Integer cache[]:" + fieldCache);
fieldCache.setAccessible(true);
// 3.取出cache的值
// field.get(obj):返回指定对象上由此Field表示的字段的值
Integer[] newCache = (Integer[]) fieldCache.get(classCache);
System.out.println("Integer[]:" + Arrays.toString(newCache));
// 0 : -128
// 1 : -127
// 2 : -126
// ...
// 127 : -1
// 128 : 0
// 129 : 1
// 130 : 2
// 131 : 3
// 132 : 4
// 133 : 5
newCache[132] = newCache[133];
int a = 2;
int b = a + a;
// public PrintStream printf(String format, Object ... args)
// 用的是Object类型,取包装类
System.out.println("println:" + a + "+" + a + "=" + b); // 2+2=4
System.out.printf("printf:%d + %d = %d\n", a, a, b); // 2+2=5
newCache[132] = 1999;
System.out.println("println:b = " + b);// println:正常的4
System.out.printf("printf:b = %d", b);// printf:新值1999
}
}

为什么System.out.printf的结果都是我们修改的值呢?可以推测,printf一定是到缓存中去取值了。

看看printf的源码:

public PrintStream printf(String format, Object ... args)

第二个参数是Object类型的(还是个可变参数),包装类是Object的子类,这里正是用的多态,用Object代表包装类的对象,取的正是Integer中的值,在-128~127范围内,取的正是缓存里的值。

最大值和最小值

通过包装类,我们可以取出数值类型的最大值和最小值,这些值在范围判断的时候很重要,但是非天才是记不住的,包装类可以帮我们快速找出来。

public class MAX_MIN {
public static void main(String[] args) {
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MIN_VALUE);
System.out.println(Long.MAX_VALUE);
System.out.println(Long.MIN_VALUE);
System.out.println(Double.MAX_VALUE);
System.out.println(Double.MIN_VALUE);
}
}

2147483647

-2147483648

9223372036854775807

-9223372036854775808

1.7976931348623157E308

4.9E-324

*Java7增加的包装类功能:compare比较值的大小

public class TestIntegercompare {
public static void main(String[] args) {
Integer a1 = 100;
Integer a2 = 100;
System.out.println(a1 + "==" + a2 + ":" + (a1 == a2));// FALSE a1 = 1000;
a2 = 1000;
System.out.println(a1 + "==" + a2 + ":" + (a1 == a2));// FALSE // 包装类.compare方法:比较值的大小(大于:1/等于:0/小于:-1)
System.out.println(a1 + "==" + a2 + ":" + Integer.compare(a1, a2));
System.out.println("1 VS 2 : " + Integer.compare(1, 2));
System.out.println("2 VS 1 : " + Integer.compare(2, 1));
System.out.println("1 VS 1 : " + Integer.compare(1, 1));
}
}

*Java8增强的包装类,主要是支持无符号运算。

无符号数的最高位不再被当做符号位(不支持负数,最小值为0)

public class Java8Wapper {
public static void main(String[] args) {
byte b = -1;
int unsignedInt = Byte.toUnsignedInt(b);
System.out.println(unsignedInt); long unsignedLong = Byte.toUnsignedLong(b);
System.out.println(unsignedLong);
}
}

255

255

Java基础教程——包装类的更多相关文章

  1. Java基础教程:面向对象编程[1]

    Java基础教程:面向对象编程 内容大纲 Java语言概述 Java语言特点 1.Java为纯面向对象的语言,它能够直接反映现实生活中的对象.总之,Everything is object! 2.平台 ...

  2. Java基础教程(18)--继承

    一.继承的概念   继承是面向对象中一个非常重要的概念,使用继承可以从逻辑和层次上更好地组织代码,大大提高代码的复用性.在Java中,继承可以使得子类具有父类的属性和方法或者重新定义.追加属性和方法. ...

  3. Java基础教程(12)--深入理解类

    一.方法的返回值   当我们在程序中调用方法时,虚拟机将会跳转到对应的方法中去执行.当以下几种情况发生时,虚拟机将会回到调用方法的语句并继续向下执行: 执行完方法中所有的语句: 遇到return语句: ...

  4. Java基础教程:注解

    Java基础教程:注解 本篇文章参考的相关资料链接: 维基百科:https://zh.wikipedia.org/wiki/Java%E6%B3%A8%E8%A7%A3 注解基础与高级应用:http: ...

  5. Java基础教程:网络编程

    Java基础教程:网络编程 基础 Socket与ServerSocket Socket又称"套接字",网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个s ...

  6. Java基础教程(5)--变量

    一.变量 1.变量的定义   正如上一篇教程<Java基础教程(4)--面向对象概念>中介绍的那样,对象将它的状态存在域中.但是你可能仍然有一些疑问,例如:命名一个域的规则和惯例是什么?除 ...

  7. Java基础教程:Lambda表达式

    Java基础教程:Lambda表达式 本文部分内容引用自OneAPM:http://blog.oneapm.com/apm-tech/226.html 引入Lambda Java 是一流的面向对象语言 ...

  8. Java基础教程:泛型基础

    Java基础教程:泛型基础 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚 ...

  9. Java基础教程:多线程基础(1)——基础操作

    Java:多线程基础(1) 实现多线程的两种方式 1.继承Thread类 public class myThread extends Thread { /** * 继承Thread类,重写RUN方法. ...

随机推荐

  1. 嵌入式以太网模块的TCP Client模式说明

    嵌入式以太网模块采用TTL电平串口,支持TCP Server,TCP Client,UDP Slave,UDP Master,TCP-ZSD,UDP-ZSD多种通信协议,TCP服务器模式支持多连接,可 ...

  2. 如何在 Debian 9 上搭建 LNMP 环境

    步骤一.安装Nginx Nginx在默认的Debian存储库中可用. 使用以下命令更新软件包索引并安装Nginx: sudo apt update sudo apt install nginx 安装过 ...

  3. 在IIS中部署前后端应用,多么痛的领悟!

    目前手上的Web项目是前后端分离的,所以有时也会倒腾Vue框架. 前后端应用最终以容器形态.在k8s中部署, 为此我搭建了基于Gitlab flow的Devops流程. 在Devops实践中,容器部署 ...

  4. Nginx是什么?有什么用?

    一.Nginx是什么 Nginx ("engine x") 是一个高性能的 HTTP 和反向代理服务器,特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服 ...

  5. canvas生成圆图和微信小程序canvas圆图

    先在HTML中创建 img和canvas并设置id属性 <canvas id="canvas" width="500" height="500& ...

  6. jetson-reference编译出现的问题记录

    问题一: 显示gcc版本过高,需要安装低版本的gcc.g++ sudo apt-get install -y gcc-4.9 sudo apt-get install -y g++-4.9 cd /u ...

  7. HashMap的初始化,到底都做了什么?

    HashMap的初始化,到底都做了什么? HashMap初始化参数都是什么?默认是多少? 为什么建议初始化设置容量? tableSizeFor方法是做什么的? 如何获取到一个key的hash值?及计算 ...

  8. Thinkphp3.2 cms之文章模块

    二.文章模块 <?php namespace Admin\Controller; use Think\Controller; class NewController extends Common ...

  9. 解决git push出现error: failed to push some refs to 错误

    错误截图 背景 码云上创建了空项目 本地项目绑定了远程仓库,尝试git push,然后报了错 解决办法 使用强制命令git pull origin master --allow-unrelated-h ...

  10. 2012年游戏软件开发独立本科段01B0815自考科目教材

    代码-----------教材名----------------------------版本----------作者 03708--------中国近现代史纲要----------------高教08 ...