第二章 Java语言基础
2.1 八大基本数据类型
2.1.1 byte、short、int、long、float、double、boolean、char

对应包装类
Byte、Short、Integer、Long、Float、Double、Boolean、Character
2.1.2 自动装箱和自动拆箱机制 (jdk 1.5开始引入)
Integer obj = 100; // 自动装箱 - int 到 Integer 的转换
Integer obj = new Integer(100); int num = obj; // 自动拆箱 - Integer 到 int 的转换
2.1.3 包装类研究
2.1.3.1 探索Serializable接口(支持序列化)
public interface Serializable {
}
为什么实现 Serializable 接口就支持序列化?
- 标记接口:Serializable 是一个标记接口(Marker Interface),它不包含任何方法声明或常量。它的唯一目的是告诉Java虚拟机(JVM)这个类的对象是可以被序列化的。当一个类实现了 Serializable 接口,就意味着该类及其所有非瞬态(non-transient)和非静态(non-static)字段都可以被序列化。
- 默认序列化机制:Java提供了默认的序列化机制。当你使用 ObjectOutputStream 来序列化一个对象时,如果该对象所属的类实现了 Serializable 接口,那么JVM会自动调用默认的序列化逻辑来处理对象的所有可序列化字段。同样地,ObjectInputStream 可以用来反序列化对象。
- 控制序列化过程:虽然Java提供了默认的序列化机制,但你也可以通过实现特定的方法来定制序列化过程:
- private void writeObject(ObjectOutputStream out) throws IOException: 允许自定义序列化过程。
- private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException: 允许自定义反序列化过程。
- readResolve() 和 writeReplace(): 这些方法允许你在序列化和反序列化过程中替换对象。
- 安全性与版本控制:通过实现 Serializable 接口并提供一个 serialVersionUID 字段,你可以更好地控制类的版本管理。如果你没有显式地定义 serialVersionUID,Java会根据类的各种属性生成一个默认的UID。如果类的结构发生变化而没有更新 serialVersionUID,则可能导致反序列化失败。
demo1
package com.test;
import lombok.Data;
import java.io.*;
@Data // lombok工具,使用该注解生成setter和getter方法
public class demo implements Serializable {
private static final long serialVersionUID = 1L; // 建议显式定义
private String name;
private int age;
private String sex;
@Override
public String toString() {
return "demo{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
public static void main(String[] args) {
demo d = new demo();
d.setName("张三");
d.setAge(18);
d.setSex("男");
// 序列化
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/demo.txt"));
oos.writeObject(d);
} catch (IOException e) {
e.printStackTrace();
}
// 反序列化
try {
demo d2 = (demo) new ObjectInputStream(new FileInputStream("d:/demo.txt")).readObject();
System.out.println(d2);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
运行结果
demo2
package com.test;
import lombok.Data;
import java.io.*;
@Data
public class Demo implements Serializable {
private static final long serialVersionUID = 1L; // 建议显式定义
private String name;
private int age;
private String sex;
@Override
public String toString() {
return "Demo{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
private void writeObject(ObjectOutputStream oos) throws IOException {
// 加密 name 字段后序列化
if (this.name != null) {
this.name = encrypt(this.name);
}
// 使用默认方式序列化所有非 transient 字段
oos.defaultWriteObject();
}
// 模拟加密函数
private String encrypt(String str) {
return new StringBuilder(str).reverse().toString(); // 简单反转字符串作为加密
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// 使用默认方式反序列化所有非 transient 字段
ois.defaultReadObject();
// 反序列化并解密 name 字段
if (!this.getName().isEmpty()) {
this.name = decrypt(this.getName());
} else {
this.name = null;
}
}
// 模拟解密函数
private String decrypt(String str) {
return new StringBuilder(str).reverse().toString(); // 同样反转还原
}
public static void main(String[] args) {
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("demo.txt"));
Demo demo = new Demo();
demo.setName("张三");
demo.setAge(18);
demo.setSex("男");
// 序列化
oos.writeObject(demo);
// 反序列化
ois = new ObjectInputStream(new FileInputStream("demo.txt"));
Demo demo1 = (Demo) ois.readObject();
System.out.println(demo1);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (oos != null) {
oos.close();
}
if (ois != null) {
ois.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果
总结: 在进行序列化与反序列化时,我们可以自定义一些加密解密逻辑
当执行 oos.writeObject(demo);
会去调用private void writeObject(ObjectOutputStream oos) throws IOException这个方法
当执行 Demo demo1 = (Demo) ois.readObject();
会去调用private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException这个方法
2.1.3.2 探索Number抽象类
package java.lang;
public abstract class Number implements java.io.Serializable { // 抽象类
public abstract int intValue();
public abstract long longValue();
public abstract float floatValue();
public abstract double doubleValue();
public byte byteValue() {
return (byte)intValue();
}
public short shortValue() {
return (short)intValue();
}
private static final long serialVersionUID = -8742448824652078965L;
}
Number 抽象类是各种数值类型的超类。这是一种适配器模式。
为什么 Number 的方法不全部设置为默认实现,而是部分需要改成抽象方法?
因为 每个子类内部存储数据的方式不同,无法用统一的方式来实现这些转换方法。
例如:
public final class Double extends Number implements Comparable<Double>{
...
private final double value;
public int intValue() {
return (int)value;
}
}
public final class Integer extends Number implements Comparable<Integer>{
...
private final int value;
public int intValue() {
return value;
}
}
对于Double和Integer类,这两个类均继承了 Number 类,但是两者底层存储数据的数据类型并不一致,在计算机中的存储结构也不一致。故不能用统一的方式来实现这些转换方法。
2.1.3.3 探索Comparable接口
package java.lang;
import java.util.*;
public interface Comparable<T> {
public int compareTo(T o);
}
该接口比较简单,但很常用。通过泛型来实现其通用性。其他类可以通过实现该接口并重写方法来实现比较逻辑。可以规范返回值的含义。比如返回 负数 表示小于,返回 0 表示等于,返回 正数 表示大于
2.1.3.4 探索Byte类
源码
package java.lang;
public final class Byte extends Number implements Comparable<Byte> {
public static final byte MIN_VALUE = -128;
public static final byte MAX_VALUE = 127;
public static final Class<Byte> TYPE = (Class<Byte>) Class.getPrimitiveClass("byte");
public static String toString(byte b) {
return Integer.toString((int)b, 10);
}
private static class ByteCache {
private ByteCache(){}
static final Byte cache[] = new Byte[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Byte((byte)(i - 128));
}
}
public static Byte valueOf(byte b) {
final int offset = 128;
return ByteCache.cache[(int)b + offset];
}
public static byte parseByte(String s, int radix)
throws NumberFormatException {
int i = Integer.parseInt(s, radix);
if (i < MIN_VALUE || i > MAX_VALUE)
throw new NumberFormatException(
"Value out of range. Value:\"" + s + "\" Radix:" + radix);
return (byte)i;
}
public static byte parseByte(String s) throws NumberFormatException {
return parseByte(s, 10);
}
public static Byte valueOf(String s, int radix)
throws NumberFormatException {
return valueOf(parseByte(s, radix));
}
public static Byte valueOf(String s) throws NumberFormatException {
return valueOf(s, 10);
}
public static Byte decode(String nm) throws NumberFormatException {
int i = Integer.decode(nm);
if (i < MIN_VALUE || i > MAX_VALUE)
throw new NumberFormatException(
"Value " + i + " out of range from input " + nm);
return valueOf((byte)i);
}
private final byte value;
public Byte(byte value) {
this.value = value;
}
public Byte(String s) throws NumberFormatException {
this.value = parseByte(s, 10);
}
public byte byteValue() {
return value;
}
public short shortValue() {
return (short)value;
}
public int intValue() {
return (int)value;
}
public long longValue() {
return (long)value;
}
public float floatValue() {
return (float)value;
}
public double doubleValue() {
return (double)value;
}
public String toString() {
return Integer.toString((int)value);
}
public int hashCode() {
return Byte.hashCode(value);
}
public static int hashCode(byte value) {
return (int)value;
}
public boolean equals(Object obj) {
if (obj instanceof Byte) {
return value == ((Byte)obj).byteValue();
}
return false;
}
public int compareTo(Byte anotherByte) {
return compare(this.value, anotherByte.value);
}
public static int compare(byte x, byte y) {
return x - y;
}
public static int toUnsignedInt(byte x) {
return ((int) x) & 0xff;
}
public static long toUnsignedLong(byte x) {
return ((long) x) & 0xffL;
}
public static final int SIZE = 8;
public static final int BYTES = SIZE / Byte.SIZE;
private static final long serialVersionUID = -7183698231559129828L;
}
代码分析
public final class Byte extends Number implements Comparable<Byte>
类定义表明
- 该类不是抽象类且不能被继承
- 继承了Number抽象类,必须重写对应的抽象方法
- 实现了Comparable接口,必须重写里面的compareTo方法
public static final byte MIN_VALUE = -128; // 最小值,不可变,也就是 -2^7
public static final byte MAX_VALUE = 127; // 最大值,不可变,也就是 -1 + 2^7
public static final Class<Byte> TYPE = (Class<Byte>) Class.getPrimitiveClass("byte");
Byte.TYPE 是一个表示原始类型 byte 的 Class 对象
验证: System.out.println(Byte.TYPE == byte.class); // 输出: true
public static String toString(byte b) {
return Integer.toString((int)b, 10);
}
利用Integer类的toString方法进行字符串转换
private static class ByteCache { // 私有静态内部类
private ByteCache(){} // 构造函数私有化,这里将这个类当做工具类处理
static final Byte cache[] = new Byte[-(-128) + 127 + 1]; // 缓存 -128 ~ +127 这些数的Byte对象
static { // 利用静态代码块初始化
for(int i = 0; i < cache.length; i++)
cache[i] = new Byte((byte)(i - 128));
}
}
public static Byte valueOf(byte b) {
final int offset = 128;
return ByteCache.cache[(int)b + offset];
}
返回对应的缓存对象
public static byte parseByte(String s, int radix)
throws NumberFormatException {
int i = Integer.parseInt(s, radix);
if (i < MIN_VALUE || i > MAX_VALUE)
throw new NumberFormatException(
"Value out of range. Value:"" + s + "" Radix:" + radix);
return (byte)i;
}
使用Integer类的parseInt方法获取值
判断值是否在byte类型的最大值和最小值之间
不是则抛异常
是则返回转换后的数值
public static byte parseByte(String s) throws NumberFormatException {
return parseByte(s, 10);
}
这个方法是上一个方法的简化版,默认10进制转换
public static Byte valueOf(String s, int radix)
throws NumberFormatException {
return valueOf(parseByte(s, radix));
}
public static Byte valueOf(String s) throws NumberFormatException {
return valueOf(s, 10);
}
使用valueOf的好处就是不用重复创建Byte对象,直接使用了缓存对象
public static Byte decode(String nm) throws NumberFormatException {
int i = Integer.decode(nm);
if (i < MIN_VALUE || i > MAX_VALUE)
throw new NumberFormatException(
"Value " + i + " out of range from input " + nm);
return valueOf((byte)i);
}
这个方法的作用是将字符串数字转化为byte
先通过Integer类的decode方法转换
如果数值不在byte范围内,抛出异常
否则返回缓存对象
private final byte value; // 维护的byte数据
public Byte(byte value) {
this.value = value;
}
public Byte(String s) throws NumberFormatException {
this.value = parseByte(s, 10);
}
两种构造方式。不过推荐使用valueOf方法来获取缓存对象。
在现在的编译器优化下,执行 Byte a = 10;默认走的就是valueOf方法获取缓存对象。
public int hashCode() { // 重写超级父类Object的hashCode方法
return Byte.hashCode(value);
}
public static int hashCode(byte value) {
return (int)value;
}
这里说明我们用Byte对象获取其hashCode时,就是它自身的值。
public boolean equals(Object obj) { // 重写超级父类Object的equals方法
if (obj instanceof Byte) {
return value == ((Byte)obj).byteValue();
}
return false;
}
使用instance关键字进行类型判断,类型匹配则判断值是否相等
类型不匹配直接返回false
public byte byteValue() {
return value;
}
public short shortValue() {
return (short)value;
}
public int intValue() {
return (int)value;
}
public long longValue() {
return (long)value;
}
public float floatValue() {
return (float)value;
}
public double doubleValue() {
return (double)value;
}
这里的方法是重写Number类的方法,直接返回维护的byte类型的value的强转结果
public int compareTo(Byte anotherByte) { // 重写 Comparable接口的方法
return compare(this.value, anotherByte.value);
}
public static int compare(byte x, byte y) {
return x - y;
}
返回负数表示小于
返回 0 表示等于
返回正数表示大于
public static int toUnsignedInt(byte x) {
return ((int) x) & 0xff;
}
public static long toUnsignedLong(byte x) {
return ((long) x) & 0xffL;
}
利用位运算将byte转为无符号int类型和无符号long类型
public static final int SIZE = 8; // 比特数
public static final int BYTES = SIZE / Byte.SIZE; // 字节数
private static final long serialVersionUID = -7183698231559129828L; // 序列号
2.1.3.5 探索Short类
源码
package java.lang;
public final class Short extends Number implements Comparable<Short> {
public static final short MIN_VALUE = -32768;
public static final short MAX_VALUE = 32767;
public static final Class<Short> TYPE = (Class<Short>) Class.getPrimitiveClass("short");
public static String toString(short s) {
return Integer.toString((int)s, 10);
}
public static short parseShort(String s, int radix)
throws NumberFormatException {
int i = Integer.parseInt(s, radix);
if (i < MIN_VALUE || i > MAX_VALUE)
throw new NumberFormatException(
"Value out of range. Value:\"" + s + "\" Radix:" + radix);
return (short)i;
}
public static short parseShort(String s) throws NumberFormatException {
return parseShort(s, 10);
}
public static Short valueOf(String s, int radix)
throws NumberFormatException {
return valueOf(parseShort(s, radix));
}
public static Short valueOf(String s) throws NumberFormatException {
return valueOf(s, 10);
}
private static class ShortCache {
private ShortCache(){}
static final Short cache[] = new Short[-(-128) + 127 + 1];
static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Short((short)(i - 128));
}
}
public static Short valueOf(short s) {
final int offset = 128;
int sAsInt = s;
if (sAsInt >= -128 && sAsInt <= 127) { // must cache
return ShortCache.cache[sAsInt + offset];
}
return new Short(s);
}
public static Short decode(String nm) throws NumberFormatException {
int i = Integer.decode(nm);
if (i < MIN_VALUE || i > MAX_VALUE)
throw new NumberFormatException(
"Value " + i + " out of range from input " + nm);
return valueOf((short)i);
}
private final short value;
public Short(short value) {
this.value = value;
}
public Short(String s) throws NumberFormatException {
this.value = parseShort(s, 10);
}
public byte byteValue() {
return (byte)value;
}
public short shortValue() {
return value;
}
public int intValue() {
return (int)value;
}
public long longValue() {
return (long)value;
}
public float floatValue() {
return (float)value;
}
public double doubleValue() {
return (double)value;
}
public String toString() {
return Integer.toString((int)value);
}
public int hashCode() {
return Short.hashCode(value);
}
public static int hashCode(short value) {
return (int)value;
}
public boolean equals(Object obj) {
if (obj instanceof Short) {
return value == ((Short)obj).shortValue();
}
return false;
}
public int compareTo(Short anotherShort) {
return compare(this.value, anotherShort.value);
}
public static int compare(short x, short y) {
return x - y;
}
public static final int SIZE = 16;
public static final int BYTES = SIZE / Byte.SIZE;
public static short reverseBytes(short i) {
return (short) (((i & 0xFF00) >> 8) | (i << 8));
}
public static int toUnsignedInt(short x) {
return ((int) x) & 0xffff;
}
public static long toUnsignedLong(short x) {
return ((long) x) & 0xffffL;
}
private static final long serialVersionUID = 7515723908773894738L;
}
代码分析
public final class Short extends Number implements Comparable<Short>
类定义表明
- 该类不是抽象类且不能被继承
- 继承了Number抽象类,必须重写对应的抽象方法
- 实现了Comparable接口,必须重写里面的compareTo方法
public static final short MIN_VALUE = -32768; // 最小值,不可变,也就是 -2^15
public static final short MAX_VALUE = 32767; // 最大值,不可变,也就是 -1 + 2^15
public static final Class<Short> TYPE = (Class<Short>) Class.getPrimitiveClass("short");
Short.TYPE 是一个表示原始类型 short 的 Class 对象
验证: System.out.println(Short.TYPE == short.class); // 输出: true
public static String toString(short s) {
return Integer.toString((int)s, 10);
}
使用Integer类的toString方法
public static short parseShort(String s, int radix)
throws NumberFormatException {
int i = Integer.parseInt(s, radix);
if (i < MIN_VALUE || i > MAX_VALUE)
throw new NumberFormatException(
"Value out of range. Value:"" + s + "" Radix:" + radix);
return (short)i;
}
public static short parseShort(String s) throws NumberFormatException {
return parseShort(s, 10);
}
先将字符串转为int
判断是否在范围内,不在抛出异常
在则返回值
public static Short valueOf(String s, int radix)
throws NumberFormatException {
return valueOf(parseShort(s, radix));
}
public static Short valueOf(String s) throws NumberFormatException {
return valueOf(s, 10);
}
本质上还是利用Integer类的进制转换功能
private static class ShortCache { // 静态内部类
private ShortCache(){} // 构造函数私有化,此处看做工具类
static final Short cache[] = new Short[-(-128) + 127 + 1]; // -128 ~ + 127 的值对应的Short对象
static { // 利用静态代码块初始化
for(int i = 0; i < cache.length; i++)
cache[i] = new Short((short)(i - 128));
}
}
public static Short valueOf(short s) {
final int offset = 128;
int sAsInt = s;
if (sAsInt >= -128 && sAsInt <= 127) { // must cache
return ShortCache.cache[sAsInt + offset];
}
return new Short(s);
}
如果在范围内,直接返回缓存对象
否则返回新对象
public static Short decode(String nm) throws NumberFormatException {
int i = Integer.decode(nm);
if (i < MIN_VALUE || i > MAX_VALUE)
throw new NumberFormatException(
"Value " + i + " out of range from input " + nm);
return valueOf((short)i);
}
利用Integer类的decode方法将字符串转换
private final short value; // 维护的short类型数据
public Short(short value) {
this.value = value;
}
public Short(String s) throws NumberFormatException {
this.value = parseShort(s, 10);
}
两种构造方式
public byte byteValue() {
return (byte)value;
}
public short shortValue() {
return value;
}
public int intValue() {
return (int)value;
}
public long longValue() {
return (long)value;
}
public float floatValue() {
return (float)value;
}
public double doubleValue() {
return (double)value;
}
重写的Number类的方法
public String toString() {
return Integer.toString((int)value);
}
利用Integer类的toString方法
public int hashCode() {
return Short.hashCode(value);
}
public static int hashCode(short value) {
return (int)value;
}
重写Object类的hashCode方法
直接返回维护的value值
public boolean equals(Object obj) {
if (obj instanceof Short) {
return value == ((Short)obj).shortValue();
}
return false;
}
重写Object类的equals方法
先判断类型是否匹配,匹配判断维护的short值是否相等
不匹配直接返回false
public int compareTo(Short anotherShort) {
return compare(this.value, anotherShort.value);
}
public static int compare(short x, short y) {
return x - y;
}
重写了Comparable接口的compareTo方法
public static final int SIZE = 16; // 比特数
public static final int BYTES = SIZE / Byte.SIZE; // 字节数
public static short reverseBytes(short i) { // 高八位和第八位互换
return (short) (((i & 0xFF00) >> 8) | (i << 8));
}
public static int toUnsignedInt(short x) { // 转化为 unsignedInt
return ((int) x) & 0xffff;
}
public static long toUnsignedLong(short x) { // 转化为unsignedLong
return ((long) x) & 0xffffL;
}
private static final long serialVersionUID = 7515723908773894738L; // 序列化号
2.1.3.6 探索Integer类
源码
package java.lang;
import java.lang.annotation.Native;
public final class Integer extends Number implements Comparable<Integer> {
@Native public static final int MIN_VALUE = 0x80000000;
@Native public static final int MAX_VALUE = 0x7fffffff;
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
final static char[] digits = {
'0' , '1' , '2' , '3' , '4' , '5' ,
'6' , '7' , '8' , '9' , 'a' , 'b' ,
'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
'o' , 'p' , 'q' , 'r' , 's' , 't' ,
'u' , 'v' , 'w' , 'x' , 'y' , 'z'
};
public static String toString(int i, int radix) {
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
/* Use the faster version */
if (radix == 10) {
return toString(i);
}
char buf[] = new char[33];
boolean negative = (i < 0);
int charPos = 32;
if (!negative) {
i = -i;
}
while (i <= -radix) {
buf[charPos--] = digits[-(i % radix)];
i = i / radix;
}
buf[charPos] = digits[-i];
if (negative) {
buf[--charPos] = '-';
}
return new String(buf, charPos, (33 - charPos));
}
public static String toUnsignedString(int i, int radix) {
return Long.toUnsignedString(toUnsignedLong(i), radix);
}
static void getChars(int i, int index, char[] buf) {
int q, r;
int charPos = index;
char sign = 0;
if (i < 0) {
sign = '-';
i = -i;
}
// Generate two digits per iteration
while (i >= 65536) {
q = i / 100;
// really: r = i - (q * 100);
r = i - ((q << 6) + (q << 5) + (q << 2));
i = q;
buf [--charPos] = DigitOnes[r];
buf [--charPos] = DigitTens[r];
}
// Fall thru to fast mode for smaller numbers
// assert(i <= 65536, i); for (;;) {
q = (i * 52429) >>> (16+3);
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
buf [--charPos] = digits [r];
i = q;
if (i == 0) break;
}
if (sign != 0) {
buf [--charPos] = sign;
}
}
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };
static int stringSize(int x) {
for (int i=0; ; i++)
if (x <= sizeTable[i])
return i+1;
}
public static int parseInt(String s, int radix)
throws NumberFormatException
{
/*
* WARNING: This method may be invoked early during VM initialization
* before IntegerCache is initialized. Care must be taken to not use
* the valueOf method.
*/
if (s == null) {
throw new NumberFormatException("null");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
int multmin;
int digit;
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,10);
}
public static int parseUnsignedInt(String s, int radix)
throws NumberFormatException {
if (s == null) {
throw new NumberFormatException("null");
}
int len = s.length();
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar == '-') {
throw new
NumberFormatException(String.format("Illegal leading minus sign " +
"on unsigned string %s.", s));
} else {
if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
(radix == 10 && len <= 9) ) { // Integer.MAX_VALUE in base 10 is 10 digits
return parseInt(s, radix);
} else {
long ell = Long.parseLong(s, radix);
if ((ell & 0xffff_ffff_0000_0000L) == 0) {
return (int) ell;
} else {
throw new
NumberFormatException(String.format("String value %s exceeds " +
"range of unsigned int.", s));
}
}
}
} else {
throw NumberFormatException.forInputString(s);
}
}
public static int parseUnsignedInt(String s) throws NumberFormatException {
return parseUnsignedInt(s, 10);
}
public static Integer valueOf(String s, int radix) throws NumberFormatException {
return Integer.valueOf(parseInt(s,radix));
}
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
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;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
private final int value;
public Integer(int value) {
this.value = value;
}
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
public byte byteValue() {
return (byte)value;
}
public short shortValue() {
return (short)value;
}
public int intValue() {
return value;
}
public long longValue() {
return (long)value;
}
public float floatValue() {
return (float)value;
}
public double doubleValue() {
return (double)value;
}
public String toString() {
return toString(value);
}
public int hashCode() {
return Integer.hashCode(value);
}
public static int hashCode(int value) {
return value;
}
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
public static Integer getInteger(String nm) {
return getInteger(nm, null);
}
public static Integer getInteger(String nm, int val) {
Integer result = getInteger(nm, null);
return (result == null) ? Integer.valueOf(val) : result;
}
public static Integer getInteger(String nm, Integer val) {
String v = null;
try {
v = System.getProperty(nm);
} catch (IllegalArgumentException | NullPointerException e) {
}
if (v != null) {
try {
return Integer.decode(v);
} catch (NumberFormatException e) {
}
}
return val;
}
public static Integer decode(String nm) throws NumberFormatException {
int radix = 10;
int index = 0;
boolean negative = false;
Integer result;
if (nm.length() == 0)
throw new NumberFormatException("Zero length string");
char firstChar = nm.charAt(0);
// Handle sign, if present
if (firstChar == '-') {
negative = true;
index++;
} else if (firstChar == '+')
index++;
// Handle radix specifier, if present
if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) {
index += 2;
radix = 16;
}
else if (nm.startsWith("#", index)) {
index ++;
radix = 16;
}
else if (nm.startsWith("0", index) && nm.length() > 1 + index) {
index ++;
radix = 8;
}
if (nm.startsWith("-", index) || nm.startsWith("+", index))
throw new NumberFormatException("Sign character in wrong position");
try {
result = Integer.valueOf(nm.substring(index), radix);
result = negative ? Integer.valueOf(-result.intValue()) : result;
} catch (NumberFormatException e) {
// If number is Integer.MIN_VALUE, we'll end up here. The next line
// handles this case, and causes any genuine format error to be // rethrown. String constant = negative ? ("-" + nm.substring(index))
: nm.substring(index);
result = Integer.valueOf(constant, radix);
}
return result;
}
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
public static int compareUnsigned(int x, int y) {
return compare(x + MIN_VALUE, y + MIN_VALUE);
}
public static long toUnsignedLong(int x) {
return ((long) x) & 0xffffffffL;
}
public static int divideUnsigned(int dividend, int divisor) {
// In lieu of tricky code, for now just use long arithmetic.
return (int)(toUnsignedLong(dividend) / toUnsignedLong(divisor));
}
public static int remainderUnsigned(int dividend, int divisor) {
// In lieu of tricky code, for now just use long arithmetic.
return (int)(toUnsignedLong(dividend) % toUnsignedLong(divisor));
}
@Native public static final int SIZE = 32;
public static final int BYTES = SIZE / Byte.SIZE;
public static int highestOneBit(int i) {
// HD, Figure 3-1
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >>> 1);
}
public static int lowestOneBit(int i) {
// HD, Section 2-1
return i & -i;
}
public static int numberOfLeadingZeros(int i) {
// HD, Figure 5-6
if (i == 0)
return 32;
int n = 1;
if (i >>> 16 == 0) { n += 16; i <<= 16; }
if (i >>> 24 == 0) { n += 8; i <<= 8; }
if (i >>> 28 == 0) { n += 4; i <<= 4; }
if (i >>> 30 == 0) { n += 2; i <<= 2; }
n -= i >>> 31;
return n;
}
public static int numberOfTrailingZeros(int i) {
// HD, Figure 5-14
int y;
if (i == 0) return 32;
int n = 31;
y = i <<16; if (y != 0) { n = n -16; i = y; }
y = i << 8; if (y != 0) { n = n - 8; i = y; }
y = i << 4; if (y != 0) { n = n - 4; i = y; }
y = i << 2; if (y != 0) { n = n - 2; i = y; }
return n - ((i << 1) >>> 31);
}
public static int bitCount(int i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
public static int rotateLeft(int i, int distance) {
return (i << distance) | (i >>> -distance);
}
public static int rotateRight(int i, int distance) {
return (i >>> distance) | (i << -distance);
}
public static int reverse(int i) {
// HD, Figure 7-1
i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
i = (i << 24) | ((i & 0xff00) << 8) |
((i >>> 8) & 0xff00) | (i >>> 24);
return i;
}
public static int signum(int i) {
// HD, Section 2-7
return (i >> 31) | (-i >>> 31);
}
public static int reverseBytes(int i) {
return ((i >>> 24) ) |
((i >> 8) & 0xFF00) |
((i << 8) & 0xFF0000) |
((i << 24));
}
public static int sum(int a, int b) {
return a + b;
}
public static int max(int a, int b) {
return Math.max(a, b);
}
public static int min(int a, int b) {
return Math.min(a, b);
}
@Native private static final long serialVersionUID = 1360826667806852920L;
}
代码分析
public final class Integer extends Number implements Comparable<Integer>
类定义表明
- 该类不是抽象类且不能被继承
- 继承了Number抽象类,必须重写对应的抽象方法
- 实现了Comparable接口,必须重写里面的compareTo方法
public static final int MIN_VALUE = 0x80000000; // 最小值,不可变,也就是 -2^31
public static final int MAX_VALUE = 0x7fffffff; // 最大值,不可变,也就是 -1 + 2^31
public static final Class<Integer> TYPE = (Class<Integer>) Class.getPrimitiveClass("int");
Integer.TYPE 是一个表示原始类型 int 的 Class 对象
验证: System.out.println(Integer.TYPE == int.class); // 输出: true
final static char[] digits = {
'0' , '1' , '2' , '3' , '4' , '5' ,
'6' , '7' , '8' , '9' , 'a' , 'b' ,
'c' , 'd' , 'e' , 'f' , 'g' , 'h' ,
'i' , 'j' , 'k' , 'l' , 'm' , 'n' ,
'o' , 'p' , 'q' , 'r' , 's' , 't' ,
'u' , 'v' , 'w' , 'x' , 'y' , 'z'
}
这里其实就是每一位可以使用的数,不同的进制数组范围不同,比如10进制的每一个数位就是digits[0] ~ digits[9]中的一个字符。16进制的每一个数位就是digits[0] ~ digits[15]中的1个字符。
所以从这里可以看出,Integer类进行进制转换,最多支持36进制。因为只有'0' ~ '9' 和 'a' ~ 'z' 一共36个字符表示。
public static String toString(int i, int radix) {
// 范围判断,判断进制数是否在 2~36之间
if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
radix = 10;
/* Use the faster version */
if (radix == 10) {
return toString(i); // 进制为10时,使用了一种快速转换方法
}
char buf[] = new char[33]; // 最多33,一个符号位 + int类型完整32位数,不一定全部会用到
boolean negative = (i < 0); // 判断非负性
int charPos = 32; // 下标,32~0 对应 低位 ~ 高位
if (!negative) { // 将数字转为负数统一处理
i = -i;
}
while (i <= -radix) { // 使用短除法进行进制转换
buf[charPos--] = digits[-(i % radix)]; // 将余数查表显示字符
i = i / radix;
}
buf[charPos] = digits[-i]; // 最高位处理
if (negative) { // 带上标志位
buf[--charPos] = '-';
}
return new String(buf, charPos, (33 - charPos)); // 根据实际长度去构造String,而不是完整33位
}
这个方法就是进制转换,但进制为10进制时,提供了一个高效率的方法
public static String toString(int i) { // 进制为10时的toString方法
// 最小值特殊处理,直接返回,因为最小值的相反数比最大值大1,不处理会溢出
if (i == Integer.MIN_VALUE)
return "-2147483648";
int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); // 通过stringSize快速获取数字位数
char[] buf = new char[size];
getChars(i, size, buf); // 核心高效方法
return new String(buf, true);
}
final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
99999999, 999999999, Integer.MAX_VALUE };
// Requires positive x
static int stringSize(int x) {
for (int i=0; ; i++) // 直接根据数值在哪一个区间返回对应的长度
if (x <= sizeTable[i])
return i+1;
}
final static char [] DigitTens = {
'0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
'1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
'2', '2', '2', '2', '2', '2', '2', '2', '2', '2',
'3', '3', '3', '3', '3', '3', '3', '3', '3', '3',
'4', '4', '4', '4', '4', '4', '4', '4', '4', '4',
'5', '5', '5', '5', '5', '5', '5', '5', '5', '5',
'6', '6', '6', '6', '6', '6', '6', '6', '6', '6',
'7', '7', '7', '7', '7', '7', '7', '7', '7', '7',
'8', '8', '8', '8', '8', '8', '8', '8', '8', '8',
'9', '9', '9', '9', '9', '9', '9', '9', '9', '9',
} ;
final static char [] DigitOnes = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
} ;
static void getChars(int i, int index, char[] buf) {
int q, r; // 商和余数
int charPos = index;
char sign = 0;
if (i < 0) { // 判断符号位
sign = '-';
i = -i;
}
// Generate two digits per iteration
while (i >= 65536) { // 这个方法快在一次可以确定两位
q = i / 100; // 商
// really: r = i - (q * 100);
// 相当于 i - q * 64 - q * 32 - q * 4 ,也就是 i - q * 100
r = i - ((q << 6) + (q << 5) + (q << 2)); // 余数
i = q; // 更新数值
buf [--charPos] = DigitOnes[r]; // 查个位表填充
buf [--charPos] = DigitTens[r]; // 查十位表填充
}
// Fall thru to fast mode for smaller numbers
// assert(i <= 65536, i);
for (;;) {
q = (i * 52429) >>> (16+3); // 这里相当于 i / 10,使用位运算快一些
r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ...
buf [--charPos] = digits [r]; // 已经知道是10进制了,直接查 digits表
i = q; // 更新数值
if (i == 0) break; // 数值为 0 退出
}
if (sign != 0) { // 判断是否为负数
buf [--charPos] = sign;
}
}
public static String toUnsignedString(int i, int radix) {
return Long.toUnsignedString(toUnsignedLong(i), radix);
}
利用Long类的方法进行转换
public static String toHexString(int i) {
return toUnsignedString0(i, 4);
}
这里的4代表4个比特位,因为是转16进制,4个比特位代表 1个16进制位
public static String toOctalString(int i) {
return toUnsignedString0(i, 3);
}
这里的3代表3个比特位,因为是转8进制,3个比特位代表 1个8进制位
public static String toBinaryString(int i) {
return toUnsignedString0(i, 1);
}
这里的1代表1个比特位,因为是转2进制,1个比特位代表 1个2进制位

private static String toUnsignedString0(int val, int shift) {
// assert shift > 0 && shift <=5 : "Illegal shift value";
int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val); // 减去前导0的个数
// 计算分组显示个数,比如16进制,shift=4,假设有7个前导0,那chars=7,只需要7个字符显示,因为一个字符代表4位。
int chars = Math.max(((mag + (shift - 1)) / shift), 1);
char[] buf = new char[chars];
formatUnsignedInt(val, shift, buf, 0, chars); // 填充buf数组
// Use special constructor which takes over "buf".
return new String(buf, true);
}
// 这个方法用于判断一个数的二进制位的前导0的个数
public static int numberOfLeadingZeros(int i) {
// HD, Figure 5-6
if (i == 0) // 0 那就是32位全是0,直接返回32
return 32;
int n = 1; // 假设最高位是0,不是0的话后面会减一
if (i >>> 16 == 0) { n += 16; i <<= 16; } // 判断高16位是否为0,然后将低16位代替高16位
if (i >>> 24 == 0) { n += 8; i <<= 8; } //判断高8位是否为0,然后将高16位的低8位代替高8位
if (i >>> 28 == 0) { n += 4; i <<= 4; } // 判断高4位是否为0,然后将高8位的低4位代替高4位
if (i >>> 30 == 0) { n += 2; i <<= 2; } // 判断高2位是否为0,然后将高4位的低2位代替高2位
n -= i >>> 31; // 减去最高位,如果前面这个数最高位是1,那if一个都不会中。
return n; // 返回前导0的个数
}
static int formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
int charPos = len;
int radix = 1 << shift;
int mask = radix - 1; // 获取掩码
do {
buf[offset + --charPos] = Integer.digits[val & mask]; // 查表
val >>>= shift; // 右移,这样可以控制几个比特位显示一个字符
} while (val != 0 && charPos > 0);
return charPos;
}
// 这个方法的作用是将字符串 s 看做 radix 进制数,然后转换为10进制数返回
public static int parseInt(String s, int radix)
throws NumberFormatException
{
/*
* WARNING: This method may be invoked early during VM initialization
* before IntegerCache is initialized. Care must be taken to not use
* the valueOf method.
*/
if (s == null) {
throw new NumberFormatException("null");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
// 前面是一些合法性判断
int result = 0; // 存放结果
boolean negative = false; // 默认非负
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE; // 下限,默认条件下防止正数溢出
int multmin; // 辅助下限
int digit; // 每一个数位值
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true; // 更改状态
limit = Integer.MIN_VALUE; // 更改下限
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix); // 获取指定位置数位值
if (digit < 0) { // 合法性判断
throw NumberFormatException.forInputString(s);
}
if (result < multmin) { // 溢出判断,如果小于multmin,再左移一次会溢出
throw NumberFormatException.forInputString(s);
}
result *= radix; // 左移
if (result < limit + digit) { // 判断左移后的值是否能继续累加
throw NumberFormatException.forInputString(s);
}
result -= digit; // 负数累加
}
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result; // 根据正负性返回数值
}
public static int parseInt(String s) throws NumberFormatException {
return parseInt(s,10); // 使用上述方法,默认把 s 的内容当做10进制
}
public static int parseUnsignedInt(String s, int radix)
throws NumberFormatException {
if (s == null) {
throw new NumberFormatException("null");
}
int len = s.length();
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar == '-') { // 无符号数没有符号
throw new
NumberFormatException(String.format("Illegal leading minus sign " +
"on unsigned string %s.", s));
} else {
// len <=5 是因为在最大进制36时,36^5 - 1< Integer.MAX_VALUE, 而 36^6 -1 > Integer.MAX_VALUE,如果len > 5会造成溢出
if (len <= 5 || // Integer.MAX_VALUE in Character.MAX_RADIX is 6 digits
(radix == 10 && len <= 9) ) { // Integer.MAX_VALUE in base 10 is 10 digits
return parseInt(s, radix); // 使用parseInt转换
} else { // 数据可能超出Integer的最大值,只能用Long类的parseLong方法
long ell = Long.parseLong(s, radix);
if ((ell & 0xffff_ffff_0000_0000L) == 0) {
return (int) ell;
} else {
throw new
NumberFormatException(String.format("String value %s exceeds " +
"range of unsigned int.", s));
}
}
}
} else {
throw NumberFormatException.forInputString(s);
}
}
public static int parseUnsignedInt(String s) throws NumberFormatException {
return parseUnsignedInt(s, 10); // 直接调用上述方法
}
public static Integer valueOf(String s, int radix) throws NumberFormatException {
return Integer.valueOf(parseInt(s,radix));
}
public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}
这两个方法都是直接调用已有的方法
private static class IntegerCache {
static final int low = -128; // 缓存最小值
static final int high; // 最大值不确定,但至少为127
static final Integer cache[]; // 缓存数组
static {
// high value may be configured by property
int h = 127; // 理解为high的默认值
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) { // 判断用户是否手动配置最大值
try {
int i = parseInt(integerCacheHighPropValue); // 解析
i = Math.max(i, 127); // 取最大值
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1); // 不能越界
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1]; // 预分配缓存
int j = low;
for(int k = 0; k < cache.length; k++) // 初始化
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {} // 构造函数私有化
}
这里可以配置虚拟机选项 -Djava.lang.Integer.IntegerCache.high
例如配置 -Djava.lang.Integer.IntegerCache.high=256
则
Integer a = 128;
Integer b = 128;
System.out.println(a == b); // true,如果没配置返回的是false
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
如果值在范围内,返回对应值的缓存对象
否则返回新对象
private final int value; // 维护的int类型数据
public Integer(int value) {
this.value = value;
}
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
两种构造方式
public byte byteValue() {
return (byte)value;
}
public short shortValue() {
return (short)value;
}
public int intValue() {
return value;
}
public long longValue() {
return (long)value;
}
public float floatValue() {
return (float)value;
}
public double doubleValue() {
return (double)value;
}
重写Number类的方法
public String toString() {
return toString(value);
}
直接调的前面的toString方法
public int hashCode() {
return Integer.hashCode(value);
}
public static int hashCode(int value) {
return value;
}
重写Object类的hashCode方法
public boolean equals(Object obj) {
if (obj instanceof Integer) { // 判断是否是Integer实例
return value == ((Integer)obj).intValue(); //判断与维护的值是否相等
}
return false;
}
重写Object类的equals方法
public static Integer getInteger(String nm) { // 根据系统属性值获取对象
return getInteger(nm, null);
}
public static Integer getInteger(String nm, int val) { // 根据系统属性值获取对象,不存在则使用指定值的对象
Integer result = getInteger(nm, null);
return (result == null) ? Integer.valueOf(val) : result;
}
public static Integer getInteger(String nm, Integer val) { // 根据系统属性值获取对象,不存在则使用指定对象
String v = null;
try {
v = System.getProperty(nm); // 获取系统属性
} catch (IllegalArgumentException | NullPointerException e) {
}
if (v != null) {
try {
return Integer.decode(v); // 返回结果
} catch (NumberFormatException e) {
}
}
return val; // 返回指定对象
}
public static Integer decode(String nm) throws NumberFormatException {
int radix = 10; // 默认10进制
int index = 0;
boolean negative = false; // 默认非负
Integer result; // 结果
if (nm.length() == 0)
throw new NumberFormatException("Zero length string");
char firstChar = nm.charAt(0);
// Handle sign, if present
if (firstChar == '-') {
negative = true;
index++;
} else if (firstChar == '+')
index++;
// Handle radix specifier, if present
if (nm.startsWith("0x", index) || nm.startsWith("0X", index)) { // 16进制
index += 2;
radix = 16;
}
else if (nm.startsWith("#", index)) { // 16进制
index ++;
radix = 16;
}
else if (nm.startsWith("0", index) && nm.length() > 1 + index) { // 8进制
index ++;
radix = 8;
}
if (nm.startsWith("-", index) || nm.startsWith("+", index))
throw new NumberFormatException("Sign character in wrong position");
// 后面都是调用现有方法
try {
result = Integer.valueOf(nm.substring(index), radix);
result = negative ? Integer.valueOf(-result.intValue()) : result;
} catch (NumberFormatException e) {
// If number is Integer.MIN_VALUE, we'll end up here. The next line
// handles this case, and causes any genuine format error to be // rethrown.
String constant = negative ? ("-" + nm.substring(index))
: nm.substring(index);
result = Integer.valueOf(constant, radix);
}
return result;
}
public int compareTo(Integer anotherInteger) { // 重写Comparable接口方法
return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
public static int compareUnsigned(int x, int y) {
return compare(x + MIN_VALUE, y + MIN_VALUE);
}
public static long toUnsignedLong(int x) {
return ((long) x) & 0xffffffffL; // 位运算
}
为啥还要进行与运算?
假设我们有一个 int x = -1;
,其二进制是:
11111111 11111111 11111111 11111111 (32 个 1)
当你把它强制转成 long:
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111111 (64 位)
所以我们用与运算保留低32位
00000000 00000000 00000000 00000000 11111111 11111111 11111111 11111111
public static int divideUnsigned(int dividend, int divisor) {
// In lieu of tricky code, for now just use long arithmetic.
return (int)(toUnsignedLong(dividend) / toUnsignedLong(divisor));
}
public static int remainderUnsigned(int dividend, int divisor) {
// In lieu of tricky code, for now just use long arithmetic.
return (int)(toUnsignedLong(dividend) % toUnsignedLong(divisor));
}
直接调上述方法
@Native public static final int SIZE = 32; // 比特数
public static final int BYTES = SIZE / Byte.SIZE; // 字节数
// 这是 获取一个整数最高位为 1 的那一位(其余位为 0)的一种高效算法
// 这个方法通过一系列位操作,将输入 int i 中所有比最高位 1 小的位都设置为 1,然后通过减法快速提取出那个最高位的 1。
public static int highestOneBit(int i) {
// HD, Figure 3-1
i |= (i >> 1);
i |= (i >> 2);
i |= (i >> 4);
i |= (i >> 8);
i |= (i >> 16);
return i - (i >>> 1);
}
// Integer.lowestOneBit(i) 通过 i & -i 快速提取出 i 的二进制中最右边的 1,是一个经典的位运算技巧,效率高、用途广。
public static int lowestOneBit(int i) {
// HD, Section 2-1
return i & -i;
}
// 这个方法用来快速计算一个 int 类型整数 二进制表示中最右边的 1 后面有多少个连续的 0。
public static int numberOfTrailingZeros(int i) {
// HD, Figure 5-14
int y;
if (i == 0) return 32;
int n = 31;
y = i <<16; if (y != 0) { n = n -16; i = y; }
y = i << 8; if (y != 0) { n = n - 8; i = y; }
y = i << 4; if (y != 0) { n = n - 4; i = y; }
y = i << 2; if (y != 0) { n = n - 2; i = y; }
return n - ((i << 1) >>> 31);
}
// 这个方法用于 统计一个 int 类型整数中二进制表示中有多少个 1。
public static int bitCount(int i) {
// HD, Figure 5-2
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
// 用于实现 32 位整数的循环左移(rotate left)。
public static int rotateLeft(int i, int distance) {
return (i << distance) | (i >>> -distance);
}
// 用于实现 32 位整数的循环右移(rotate left)。
public static int rotateRight(int i, int distance) {
return (i >>> distance) | (i << -distance);
}
// Integer.reverse(i) 使用了一种高效的"分治+位掩码"算法,通过多轮局部交换,最终完成整个 32 位整数的二进制位反转,是一种典型的高性能位运算技巧。
public static int reverse(int i) {
// HD, Figure 7-1
i = (i & 0x55555555) << 1 | (i >>> 1) & 0x55555555;
i = (i & 0x33333333) << 2 | (i >>> 2) & 0x33333333;
i = (i & 0x0f0f0f0f) << 4 | (i >>> 4) & 0x0f0f0f0f;
i = (i << 24) | ((i & 0xff00) << 8) |
((i >>> 8) & 0xff00) | (i >>> 24);
return i;
}
public static int signum(int i) {
// HD, Section 2-7
return (i >> 31) | (-i >>> 31);
}
返回 -1,如果输入的整数 i 是负数;
返回 0,如果输入的整数 i 是零;
返回 1,如果输入的整数 i 是正数。
// Integer.reverseBytes(i) 使用位运算技巧,将一个 int 类型的四个字节顺序完全反转,适用于网络传输、文件格式转换、底层协议解析等场景。
public static int reverseBytes(int i) {
return ((i >>> 24) ) |
((i >> 8) & 0xFF00) |
((i << 8) & 0xFF0000) |
((i << 24));
}
public static int sum(int a, int b) { // 和
return a + b;
}
public static int max(int a, int b) { // 最大值
return Math.max(a, b);
}
public static int min(int a, int b) { // 最小值
return Math.min(a, b);
}
@Native private static final long serialVersionUID = 1360826667806852920L; // 序列号
2.1.3.7 探索Long类
public static final Class<Long> TYPE = (Class<Long>) Class.getPrimitiveClass("long");
Long.TYPE 是一个表示原始类型 long 的 Class 对象
验证: System.out.println(Long.TYPE == long.class); // 输出: true
Long类和Integer类的方法实现基本差不多,简单总结一下
总结
- 维护的数据不同,Long维护long, Integer 维护 int
- LongCache是对 -128 ~ + 127的值的对象进行预分配,IntegerCache默认也是,但可以通过
-Djava.lang.Integer.IntegerCache.high 进行扩展 - 在将long值转无符号时,会用BigInteger这个类进行处理
2.1.3.8 探索Float、Double类
对于单精度浮点数(32位),格式为
虽然指数字段有 8 位(理论上可以表示 0~255),但由于 0 和 255 是保留值,不能用于规范化数,所以实际用于规范化数的指数字段只能是 1~254,对应的实际指数范围就是 -126 ~ +127。
public static final Class<Float> TYPE = (Class<Float>) Class.getPrimitiveClass("float");
Float.TYPE 是一个表示原始类型 float 的 Class 对象
验证: System.out.println(Float.TYPE == float.class); // 输出: true
对于双精度浮点数(64位),格式为
虽然指数字段有 11 位(理论上可以表示 0~2047),但由于 0 和 2047 是保留值,不能用于规范化数,所以实际用于规范化数的指数字段只能是 1~2046,对应的实际指数范围就是 -1022 ~ +1023。
public static final Class<Double> TYPE = (Class<Double>) Class.getPrimitiveClass("double");
Double.TYPE 是一个表示原始类型 double 的 Class 对象
验证: System.out.println(Double.TYPE == double.class); // 输出: true
注意
- Float.NaN != Float.NaN
- Double.NaN != Double.NaN
- 判断两个浮点数是否相等时,最好不要用 == ,而是使用一个较小的数对比差值
2.1.3.9 探索Boolean类
源码
package java.lang;
public final class Boolean implements java.io.Serializable,
Comparable<Boolean>
{
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
public static final Class<Boolean> TYPE = (Class<Boolean>) Class.getPrimitiveClass("boolean");
private final boolean value;
private static final long serialVersionUID = -3665804199014368530L;
public Boolean(boolean value) {
this.value = value;
}
public Boolean(String s) {
this(parseBoolean(s));
}
public static boolean parseBoolean(String s) {
return ((s != null) && s.equalsIgnoreCase("true"));
}
public boolean booleanValue() {
return value;
}
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
public static Boolean valueOf(String s) {
return parseBoolean(s) ? TRUE : FALSE;
}
public static String toString(boolean b) {
return b ? "true" : "false";
}
public String toString() {
return value ? "true" : "false";
}
public int hashCode() {
return Boolean.hashCode(value);
}
public static int hashCode(boolean value) {
return value ? 1231 : 1237;
}
public boolean equals(Object obj) {
if (obj instanceof Boolean) {
return value == ((Boolean)obj).booleanValue();
}
return false;
}
public static boolean getBoolean(String name) {
boolean result = false;
try {
result = parseBoolean(System.getProperty(name));
} catch (IllegalArgumentException | NullPointerException e) {
}
return result;
}
public int compareTo(Boolean b) {
return compare(this.value, b.value);
}
public static int compare(boolean x, boolean y) {
return (x == y) ? 0 : (x ? 1 : -1);
}
public static boolean logicalAnd(boolean a, boolean b) {
return a && b;
}
public static boolean logicalOr(boolean a, boolean b) {
return a || b;
}
public static boolean logicalXor(boolean a, boolean b) {
return a ^ b;
}
}
代码分析
public final class Boolean implements java.io.Serializable, Comparable<Boolean>
由于Boolean并不属于数值类型,所以Boolean并没有继承Number类,而是直接实现java.io.Serializable接口。其实也可以联想,因为Boolean和Number的其他类型不能进行转换
语法层面就被限定了。
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
这两个对象被经常复用,比如valueOf方法等
public static final Class<Boolean> TYPE = (Class<Boolean>) Class.getPrimitiveClass("boolean");
Boolean.TYPE 是一个表示原始类型 boolean 的 Class 对象
验证: System.out.println(Boolean.TYPE == boolean.class); // 输出: true
private final boolean value; // 维护的boolean类型数据
private static final long serialVersionUID = -3665804199014368530L; // 序列号
public Boolean(boolean value) {
this.value = value;
}
public Boolean(String s) {
this(parseBoolean(s));
}
public static boolean parseBoolean(String s) {
return ((s != null) && s.equalsIgnoreCase("true")); // 忽略大小写
}
两种构造方式
public boolean booleanValue() {
return value; // 返回维护值
}
public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE); // 返回静态对象
}
public static Boolean valueOf(String s) {
return parseBoolean(s) ? TRUE : FALSE; // 返回静态对象
}
public static String toString(boolean b) {
return b ? "true" : "false";
}
public String toString() {
return value ? "true" : "false";
}
一目了然
public int hashCode() { // 重写的Object类的方法
return Boolean.hashCode(value);
}
public static int hashCode(boolean value) {
return value ? 1231 : 1237; // 返回的是固定值,不看的话心里会有各种猜测,其实很简单
}
public boolean equals(Object obj) { // 重写的Object类的方法
if (obj instanceof Boolean) {
return value == ((Boolean)obj).booleanValue();
}
return false;
}
public static boolean getBoolean(String name) { // 通过系统属性获取值
boolean result = false;
try {
result = parseBoolean(System.getProperty(name));
} catch (IllegalArgumentException | NullPointerException e) {
}
return result;
}
public int compareTo(Boolean b) {
return compare(this.value, b.value);
}
public static int compare(boolean x, boolean y) {
return (x == y) ? 0 : (x ? 1 : -1);
}
Boolean的比较我个人基本没用过
public static boolean logicalAnd(boolean a, boolean b) { // 逻辑与
return a && b;
}
public static boolean logicalOr(boolean a, boolean b) { // 逻辑或
return a || b;
}
public static boolean logicalXor(boolean a, boolean b) { // 逻辑异或
return a ^ b;
}
2.1.3.10 探索Character类
这个类的内容有点多,这里只展示了常用部分。
public final class Character implements java.io.Serializable, Comparable<Character>
这个类维护的是字符类型,所以没继承Number类,直接实现序列化接口
public static final int MIN_RADIX = 2; // 可转换的最小进制
public static final int MAX_RADIX = 36;// 可转换的最大进制
在前面的Integer类的进制转换中用到了这两个常量
public static final char MIN_VALUE = '\u0000';
public static final char MAX_VALUE = '\uFFFF';
这里值得一说的是 java中的char是两个字节,而 c/c++中的char 是一个字节
public static final Class<Character> TYPE = (Class<Character>) Class.getPrimitiveClass("char");
Character.TYPE 是一个表示原始类型 char 的 Class 对象
验证: System.out.println(Character.TYPE == char.class); // 输出: true
private final char value; // 维护的char数据
private static final long serialVersionUID = 3786198910865385080L; // 序列化号
private static class CharacterCache {
private CharacterCache(){}
static final Character cache[] = new Character[127 + 1];
static {
for (int i = 0; i < cache.length; i++)
cache[i] = new Character((char)i);
}
}
其实是为Ascii码表的128个字符提供了缓存对象
public static Character valueOf(char c) {
if (c <= 127) { // must cache
return CharacterCache.cache[(int)c];
}
return new Character©;
}
编写 Character a = 'a'; 时,执行的就是这个valueOf方法
判断字符类型
- isLetter(char ch):判断指定字符是否为字母。
- isDigit(char ch):判断指定字符是否为数字。
- isWhitespace(char ch):判断指定字符是否为空白字符。
- isUpperCase(char ch):判断指定字符是否为大写字母。
- isLowerCase(char ch):判断指定字符是否为小写字母。
转换字符大小写 - toUpperCase(char ch):将字符转换为大写形式。
- toLowerCase(char ch):将字符转换为小写形式。
获取字符分类 - getType(char ch):返回指定字符的Unicode类别。每个类别由一个整数表示,例如Character.UPPERCASE_LETTER代表大写字母。
检查字符属性 - isJavaIdentifierStart(char ch):判断字符是否可以作为Java标识符的起始字符。
- isJavaIdentifierPart(char ch):判断字符是否可以作为Java标识符的一部分(除了第一个字符之外)。
比较字符 - compare(char x, char y):比较两个字符的数值顺序,类似于Integer.compare()。
2.2 流程控制(小面经)
2.2.1 小面经问题:switch 能作用在哪些数据类型上?
在Java 5 之前,switch语句的表达式只能是byte、short、char和int类型。这是因为在早期版本中,switch语句的设计主要是为了处理整数类型的值。
从Java 5 开始,Java引入了枚举类型(enum),并且允许switch语句的表达式为枚举类型。这大大增强了switch语句的灵活性,使其能够处理更复杂的逻辑。
从Java 7 开始,switch语句的表达式还可以是字符串类型(String)。这是一个重要的增强,使得switch语句可以用于基于字符串值的分支选择。
2.2.2 小面经问题:break, continue, return 的区别及作用?
break :
作用:跳出当前所在的最内层循环或switch语句,不再执行该循环或switch语句中的剩余代码。如果在嵌套循环中使用,它只会跳出最内层的循环。
continue :
作用:结束本次循环的剩余部分,直接跳到下一次循环的开始条件判断处。也就是说,它会跳过本次循环体中剩余的代码,继续检查循环条件是否满足,以决定是否进行下一次循环。
return :
作用:从当前方法返回,并停止执行该方法中的所有后续代码。对于非void类型的方法,return语句还必须返回一个与方法声明类型相匹配的值。对于void类型的方法,return语句可以省略返回值。
2.3 修饰符(小面经)
2.3.1访问修饰符public、private、protected 和默认(不写任何修饰符)的区别?
public :
可见性:对所有类都可见。
使用对象:可以修饰类、接口、变量、方法。
适用范围:当前类、同一包内、子孙类(无论是否在同一包)、其他包。
private :
可见性:仅在同一类内可见。
使用对象:可以修饰变量、方法。
注意:不能修饰外部类。
适用范围:仅限于当前类。
protected :
可见性:对同一包内的类和所有子类可见。
使用对象:可以修饰变量、方法。
注意:不能修饰外部类。
适用范围:当前类、同一包内、子孙类(无论是否在同一包),但不同包中的子孙类需要通过继承关系访问。
默认 (不写任何修饰符):
可见性:在同一包内可见。
使用对象:可以修饰类、接口、变量、方法。
适用范围:当前类、同一包内。

2.3.2 为什么要用 static 关键字?
内存效率 :
静态成员在整个程序执行期间只存在一份副本,被所有对象共享。这意味着无论创建了多少个类的实例,静态变量只会占用一块内存,这有助于节省内存。
访问便利性 :
无需创建类的实例即可访问静态成员,可以直接通过类名调用静态方法或访问静态变量。
组织常量和工具方法 :
适用于那些不依赖于对象状态的方法和值,如数学计算、辅助函数等。
2.3.3 static 方法是否能被重写?
不能被重写 :
从技术上讲,static方法不能被子类重写。如果子类中声明了一个与父类中static方法签名相同的方法,那么这个过程被称为方法隐藏而不是重写。这意味着子类中的static方法会遮蔽父类中的同名static方法,但不会像实例方法重写那样具有动态绑定的特性。
方法调用的行为 :
当你尝试通过一个指向子类对象的父类引用来调用一个静态方法时,编译器会根据引用类型来决定调用哪个版本的静态方法,而不是根据实际的对象类型。这是与实例方法重写的最大区别之一,在实例方法重写的情况下,调用的是运行时对象的实际类型的方法。
2.4 自测
- 如何自定义序列化行为?比如对某些字段加密?
- 八大数据类型是什么?对应的包装类是什么?
- 八大数据类型的包装类哪些具有常量池(缓存对象),常量池的范围?
- Integer类型常量池如何调节?
- Character类有哪些常用方法?
- 如何快速查找二进制数最左边的一个1?最右边一个1?
- 面经理解性记忆?