java bit mask,【JDK源码剖析】Java数值类型的包装类

概述

Java是一种强类型语言,必须为每一种变量声明一种类型.在Java中一共有8种基本类型(primitive type),其中有4中整型,2种浮点类型,1中用于表示Unicode编码的字符单元的字符类型char和一种用于真值表示的boolean类型

之前曾写过几篇博文

这些博文大都是在JVM或者计算机组成原理相关角度来看待的。

最近要开始阅读JDK的源码了,希望能够从源码角度回顾这些内容

下面会从这8种基本类型(primitive type)对应的包装器类型进行解析

AAffA0nNPuCLAAAAAElFTkSuQmCC

布尔类型之所以未定 是因为JVM中没有boolean类型

下面会从这8种基本类型(primitive type)对应的包装器类型进行解析

public final class Integer extends Number implements Comparable

public final class Double extends Number implements Comparable

public final class Float extends Number implements Comparable

public final class Long extends Number implements Comparable

public final class Byte extends Number implements Comparable

public final class Short extends Number implements Comparable

public final class Boolean implements Serializable, Comparable

public final class Character implements java.io.Serializable, Comparable

数值类型的包装器都继承了Number抽象类且实现了Comparable的接口方法

而对于Boolean和Character,它们都实现了Serializable和Comparable的接口方法

java.io.Serializable和Serializable是同一个接口

如果要剖析它们的包装类 首先要从Number抽象类和Comparable接口入手

Comparable接口

Comparable是内部比较器,常用作自然排序接口,需要实现内部的compareTo方法

源代码

package java.lang;

import java.util.List;

public interface Comparable {

int compareTo(T o);

}

内部比较器的特点是嵌入式的 , 其比较行为必须在待比较对象内部实现。

一个类如果实现了Comparable接口,就意味着“该类本身支持排序”,并且可以直接通过Arrays.sort()或Collections.sort()进行排序

当然,一个类如果没有实现Comparable接口,也可以挂载外部比较器Comparator进行排序

一般来说

通过 x.compareTo(y) 来“比较x和y的大小

返回“负数”,意味着“x

返回“零”,意味着“x==y”

返回“正数”,意味着“x>y”

具体的实现要结合后面的源代码

Number抽象类

Number 类定义了一些抽象方法,以各种不同数字格式返回对象的值。如 xxxValue() 方法,它将 Number 对象转换为 xxx 数据类型的值并返回,其中 doubleValue() 方法返回 double 类型的值,floatValue() 方法返回 float 类型的值。

该抽象类声明了各种包装类型的拆箱方法

package java.lang;

import java.io.Serializable;

// 数值类型包装类的共同祖先,声明了各种包装类型的拆箱方法

public abstract class Number implements Serializable {

private static final long serialVersionUID = -8742448824652078965L;

// 以byte形式返回当前对象的值

public byte byteValue() {

return (byte) intValue();

}

// 以short形式返回当前对象的值

public short shortValue() {

return (short) intValue();

}

// 以int形式返回当前对象的值

public abstract int intValue();

// 以long形式返回当前对象的值

public abstract long longValue();

// 以float形式返回当前对象的值

public abstract float floatValue();

// 以double形式返回当前对象的值

public abstract double doubleValue();

}

包装类

这里以Integer类为例进行解析,其他数值类型的包装类与此类似

字段部分

@Native

private static final long serialVersionUID = 1360826667806852920L;

// 相当于int.class

@SuppressWarnings("unchecked")

public static final Class TYPE = (Class) Class.getPrimitiveClass("int");

关于@SuppressWarnings注解

作用:告诉编译器忽略指定的警告,不用在编译完成后出现警告信息。

其中 @SuppressWarnings(“unchecked”),告诉编译器忽略 unchecked 警告信息,如使用List,ArrayList等未进行参数化产生的警告信息。

代码中注释 “相当于int.class”

实际上是这样的 ,为了获取基本数据类型int

可以通过Class.getPrimitiveClass(“int”)获取int.class类型

@Native

public static final int MIN_VALUE = 0x80000000; // int最小值 0

//二进制为 10000000 00000000 00000000 00000000

@Native

public static final int MAX_VALUE = 0x7fffffff; // int最大值

//二进制为 01111111 11111111 11111111 11111111

@Native

public static final int SIZE = 32; // 当前类型所占bit[位]数

//JVM中int类型为4个字节 32位

public static final int BYTES = SIZE / Byte.SIZE; // 当前类型所占字节数

private final int value; // 当前类包装的值

// 进制

static final 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'

};

// 个位数

static final byte[] 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 final byte[] 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',

};

// Left here for compatibility reasons, see JDK-8143900.

//出于兼容性的原因留在这里

static final int[] sizeTable = {9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, Integer.MAX_VALUE};

构造方法

@Deprecated(since = "9")

public Integer(int value) {

this.value = value;

}

@Deprecated(since = "9")

public Integer(String s) throws NumberFormatException {

this.value = parseInt(s, 10);

}

注解 @Deprecated 可以标记 Java API 状态,可以是以下几种:

使用它存在风险,可能导致错误

可能在未来版本中不兼容

可能在未来版本中删除

一个更好和更高效的方案已经取代它。

Java 9 中注解增加了两个新元素:since 和 forRemoval。

since: 元素指定已注解的API元素已被弃用的版本。

forRemoval: 元素表示注解的 API 元素在将来的版本中被删除,应该迁移 API。

AAffA0nNPuCLAAAAAElFTkSuQmCC

普通方法

装箱

int --> Integer 默认的装箱行为

第一段 代码体现了享元设计模式

@HotSpotIntrinsicCandidate

public static Integer valueOf(int i) {

if(i >= IntegerCache.low && i<=IntegerCache.high)

return IntegerCache.cache[i + (-IntegerCache.low)];

return new Integer(i);

}

//这里的IntegerCache见下面

//这段代码体现了享元设计模式

// 按10进制形式将字符串s解析为int值,随后再装箱

public static Integer valueOf(String s) throws NumberFormatException {

return Integer.valueOf(parseInt(s, 10));

}

// 按radix进制形式将字符串s解析为int值,随后再装箱

public static Integer valueOf(String s, int radix) throws NumberFormatException {

return Integer.valueOf(parseInt(s, radix));

}

如果你对JVM解释执行和即时编译有了解,那么对于HotSpotIntrinsicCandidate注解很容易就能理解,表示这是段热点代码

可以参考【Java核心技术卷】谈谈对Java平台的理解

注意这里的valueOf方法 为下面的 decode等方法做了一些字符串转化成整型的准备

IntegerCache是属于Integer的静态内部类

它是Integer缓存,默认缓存了-128~127之间的Integer对象

如果想增加缓存数字的上限,比如将缓存范围改为[-128, 200],

则可以设置运行参数:

-XX:AutoBoxCacheMax=200

-Djava.lang.Integer.IntegerCache.high=200

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 = VM.getSavedProperty("java.lang.Integer.IntegerCache.high");

//java.lang.Integer.IntegerCache.high是用来设置HotSpot VM上Integer的autobox(自动装箱缓存大小配置)范围的

//使用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); // [low, high]的个数不能超过Integer.MAX_VALUE

} 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[k] = new Integer(j++);

}

// range [-128, 127] must be interned (JLS7 5.1.7)

assert IntegerCache.high >= 127;

}

private IntegerCache() {

}

}

}

将字符串nm解析为int,随后再装箱

采用哪种进制解析nm取决于nm的格式:

0x、0X、#开头,代表按16进制解析

0开头,代表按8进制解析

其他情形默认按10进制解析

public static Integer decode(String nm) throws NumberFormatException {

int radix = 10; //进制

int index = 0; //标记字符串开始比较的位置

boolean negative = false; //negative的意思是负数 false代表为正

Integer result; //结果封装成变量名为result的Integer对象

//判断是否为空字符串

if(nm.length() == 0)

throw new NumberFormatException("Zero length string");

//解析第一位 判断正负

char firstChar = nm.charAt(0);

if(firstChar == '-') {

negative = true;

index++;

} else if(firstChar == '+')

index++;

// Handle radix specifier, if present

//判断开头

//startWith(String s,int t) 测试在指定索引处t开始的此字符串的子字符串是否以指定的前缀s开头。

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;

}

拆箱

这里是重写了Number抽象类的方法 原理很简单 进行强制类型转换

// 以byte形式返回当前对象的值

public byte byteValue() {

return (byte) value;

}

// 以short形式返回当前对象的值

public short shortValue() {

return (short) value;

}

// Integer-->int 默认的拆箱行为

@HotSpotIntrinsicCandidate

public int intValue() {

return value;

}

// 以long形式返回当前对象的值

public long longValue() {

return (long) value;

}

// 以float形式返回当前对象的值

public float floatValue() {

return (float) value;

}

// 以double形式返回当前对象的值

public double doubleValue() {

return (double) value;

}

从属性中解析值

从系统属性中获取值,然后再装箱

其中,nm为某个系统属性,val为备用值

比如:

System.setProperty(“age”, “20”);

Integer x = getInteger(“age”, 25);

如果属性age存在(被提前设置),x的值为20。

如果属性age不存在,则x的值为备用值25。

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;

}

// 从系统属性中获取值,然后再装箱。如果取不到值,选用val

public static Integer getInteger(String nm, int val) {

Integer result = getInteger(nm, null);

return (result == null) ? Integer.valueOf(val) : result;

}

// 从系统属性中获取值,然后再装箱。如果取不到值,返回null。

public static Integer getInteger(String nm) {

return getInteger(nm, null);

}

java的System.getProperty()方法可以获取的值

AAffA0nNPuCLAAAAAElFTkSuQmCC

逆字符串化

功能分为:

按radix进制形式将字符串s解析为int值

按10进制形式将字符串s解析为int值

按radix进制形式将字符序列s的[beginIndex, endIndex)部分解析为int值

按radix进制形式将无符号整型字符串s解析为有符号整型值

按10进制形式将无符号整型字符串s解析为有符号整型值

按radix进制形式将无符号整型字符序列s的[beginIndex, endIndex)部分解析为有符号整型值

// 按radix进制形式将字符串s解析为int值

public static int parseInt(String s, int radix) throws NumberFormatException {

if(s == null) {

throw new NumberFormatException("null");

}

if(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");

}

boolean negative = false;

int i = 0, len = s.length();

int limit = -Integer.MAX_VALUE;

if(len>0) {

char firstChar = s.charAt(0);

if(firstChar

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++;

}

int multmin = limit / radix;

int result = 0;

while(i

// Accumulating negatively avoids surprises near MAX_VALUE

int digit = Character.digit(s.charAt(i++), radix);

if(digit<0 || result

throw NumberFormatException.forInputString(s);

}

result *= radix;

if(result

throw NumberFormatException.forInputString(s);

}

result -= digit;

}

return negative ? result : -result;

} else {

throw NumberFormatException.forInputString(s);

}

}

// 按10进制形式将字符串s解析为int值

public static int parseInt(String s) throws NumberFormatException {

return parseInt(s, 10);

}

// 按radix进制形式将字符序列s的[beginIndex, endIndex)部分解析为int值

public static int parseInt(CharSequence s, int beginIndex, int endIndex, int radix) throws NumberFormatException {

s = Objects.requireNonNull(s);

if(beginIndex<0 || beginIndex>endIndex || endIndex>s.length()) {

throw new IndexOutOfBoundsException();

}

if(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");

}

boolean negative = false;

int i = beginIndex;

int limit = -Integer.MAX_VALUE;

if(i

char firstChar = s.charAt(i);

if(firstChar

if(firstChar == '-') {

negative = true;

limit = Integer.MIN_VALUE;

} else if(firstChar != '+') {

throw NumberFormatException.forCharSequence(s, beginIndex, endIndex, i);

}

i++;

if(i == endIndex) { // Cannot have lone "+" or "-"

throw NumberFormatException.forCharSequence(s, beginIndex, endIndex, i);

}

}

int multmin = limit / radix;

int result = 0;

while(i

// Accumulating negatively avoids surprises near MAX_VALUE

int digit = Character.digit(s.charAt(i), radix);

if(digit<0 || result

throw NumberFormatException.forCharSequence(s, beginIndex, endIndex, i);

}

result *= radix;

if(result

throw NumberFormatException.forCharSequence(s, beginIndex, endIndex, i);

}

i++;

result -= digit;

}

return negative ? result : -result;

} else {

throw NumberFormatException.forInputString("");

}

}

// 按radix进制形式将无符号整型字符串s解析为有符号整型值

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);

}

}

// 按10进制形式将无符号整型字符串s解析为有符号整型值

public static int parseUnsignedInt(String s) throws NumberFormatException {

return parseUnsignedInt(s, 10);

}

// 按radix进制形式将无符号整型字符序列s的[beginIndex, endIndex)部分解析为有符号整型值

public static int parseUnsignedInt(CharSequence s, int beginIndex, int endIndex, int radix) throws NumberFormatException {

s = Objects.requireNonNull(s);

if(beginIndex<0 || beginIndex>endIndex || endIndex>s.length()) {

throw new IndexOutOfBoundsException();

}

int start = beginIndex, len = endIndex - beginIndex;

if(len>0) {

char firstChar = s.charAt(start);

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, start, start + len, radix);

} else {

long ell = Long.parseLong(s, start, start + len, 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 new NumberFormatException("");

}

}

内容字符串化

//最简单的形式

public String toString() {

return toString(value);

}

//静态方法 将将整型转化为字符串

@HotSpotIntrinsicCandidate

public static String toString(int i) {

// 统计整数i中包含的符号数量(包括负号),即计算整数i转为字符串后的长度

int size = stringSize(i);

if(COMPACT_STRINGS) {

byte[] buf = new byte[size];

getChars(i, size, buf);

return new String(buf, LATIN1);

} else {

byte[] buf = new byte[size * 2];

StringUTF16.getChars(i, size, buf);

return new String(buf, UTF16);

}

}

// 静态方法将将整型转化为字符串 返回整型值i的radix形式

public static String toString(int i, int radix) {

if(radixCharacter.MAX_RADIX)

radix = 10;

/* Use the faster version */

if(radix == 10) {

return toString(i);

}

if(COMPACT_STRINGS) {

byte[] buf = new byte[33];

boolean negative = (i<0);

int charPos = 32;

if(!negative) {

i = -i;

}

while(i<=-radix) {

buf[charPos--] = (byte) digits[-(i % radix)];

i = i / radix;

}

buf[charPos] = (byte) digits[-i];

if(negative) {

buf[--charPos] = '-';

}

return StringLatin1.newString(buf, charPos, (33 - charPos));

}

return toStringUTF16(i, radix);

}

// 静态方法将将整型转化为字符串 返回整型值i的二进制形式

public static String toBinaryString(int i) {

return toUnsignedString0(i, 1);

}

// 静态方法将将整型转化为字符串 返回整型值i的八进制形式

public static String toOctalString(int i) {

return toUnsignedString0(i, 3);

}

// 静态方法将将整型转化为字符串 返回整型值i的十六进制形式

public static String toHexString(int i) {

return toUnsignedString0(i, 4);

}

// 静态方法将将整型转化为字符串 返回当前int的无符号形式的值的

public static String toUnsignedString(int i) {

return Long.toString(toUnsignedLong(i));

}

// 静态方法将将整型转化为字符串 返回当前int的无符号形式的值的radix进制形式

public static String toUnsignedString(int i, int radix) {

return Long.toUnsignedString(toUnsignedLong(i), radix);

}

/**

* Convert the integer to an unsigned number.

*/

// 返回整型值val的2^shift进制形式

private static String toUnsignedString0(int val, int shift) {

// assert shift > 0 && shift <=5 : "Illegal shift value";

int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);

int chars = Math.max(((mag + (shift - 1)) / shift), 1);

if(COMPACT_STRINGS) {

byte[] buf = new byte[chars];

formatUnsignedInt(val, shift, buf, 0, chars);

return new String(buf, LATIN1);

} else {

byte[] buf = new byte[chars * 2];

formatUnsignedIntUTF16(val, shift, buf, 0, chars);

return new String(buf, UTF16);

}

}

// 返回整型值i的radix形式,UTF16版本

private static String toStringUTF16(int i, int radix) {

byte[] buf = new byte[33 * 2];

boolean negative = (i<0);

int charPos = 32;

if(!negative) {

i = -i;

}

while(i<=-radix) {

StringUTF16.putChar(buf, charPos--, digits[-(i % radix)]);

i = i / radix;

}

StringUTF16.putChar(buf, charPos, digits[-i]);

if(negative) {

StringUTF16.putChar(buf, --charPos, '-');

}

return StringUTF16.newString(buf, charPos, (33 - charPos));

}

/*

* 从buf的offset索引处开始,存入变量val在2^shift进制下的后len位

* shift取1、3、4时分别代表二进制、八进制、16进制

* 如果len的长度超过该进制下的有效数位长度,则前面空白部分补0

*

* 举例:

* 十进制数12345的八进制形式为30071

*

* char[] buf = new char[10];

*

* formatUnsignedInt(12345, 3, buf, 0, 5) // buf={'3','0','0','7','1','\0','\0','\0','\0','\0'}

* formatUnsignedInt(12345, 3, buf, 0, 7) // buf={'0','0','3','0','0','7','1','\0','\0','\0'}

* formatUnsignedInt(12345, 3, buf, 2, 7) // buf={'\0','\0','0','0','3','0','0','7','1','\0'}

*/

static void formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {

// assert shift > 0 && shift <=5 : "Illegal shift value";

// assert offset >= 0 && offset < buf.length : "illegal offset";

// assert len > 0 && (offset + len) <= buf.length : "illegal length";

int charPos = offset + len;

int radix = 1 << shift;

int mask = radix - 1;

// 循环len次

do {

buf[--charPos] = Integer.digits[val & mask];

val >>>= shift;

} while(charPos>offset);

}

/** byte[]/LATIN1 version */

// formatUnsignedInt方法的byte[]/LATIN1版本,将数字0到9分别存储为对应的ANSI码,'\0'存储为数字0

static void formatUnsignedInt(int val, int shift, byte[] buf, int offset, int len) {

int charPos = offset + len;

int radix = 1 << shift;

int mask = radix - 1;

do {

buf[--charPos] = (byte) Integer.digits[val & mask];

val >>>= shift;

} while(charPos>offset);

}

/** byte[]/UTF16 version */

// formatUnsignedInt方法的byte[]/UTF16版本,每个char存为两个byte

private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int offset, int len) {

int charPos = offset + len;

int radix = 1 << shift;

int mask = radix - 1;

do {

StringUTF16.putChar(buf, --charPos, Integer.digits[val & mask]);

val >>>= shift;

} while(charPos>offset);

}

/*

* 统计整数i中包含的符号数量(包括负号),为转为字符串做准备

* 比如stringSize(12345)返回5,stringSize(-12345)返回6

*/

//静态方法 统计整数i中包含的符号数量 可以用于整数位数获取

static int stringSize(int x) {

int d = 1;

if(x >= 0) {

d = 0;

x = -x;

}

int p = -10;

for(int i = 1; i<10; i++) {

if(x>p)

return i + d;

p = 10 * p;

}

return 10 + d;

}

// 将整数i中包含的符号转为byte存入buf

static int getChars(int i, int index, byte[] buf) {

int q, r;

int charPos = index;

boolean negative = i<0;

if(!negative) {

i = -i;

}

// Generate two digits per iteration

while(i<=-100) {

q = i / 100;

r = (q * 100) - i;

i = q;

buf[--charPos] = DigitOnes[r];

buf[--charPos] = DigitTens[r];

}

// We know there are at most two digits left at this point.

q = i / 10;

r = (q * 10) - i;

buf[--charPos] = (byte) ('0' + r);

// Whatever left is the remaining digit.

if(q<0) {

buf[--charPos] = (byte) ('0' - q);

}

if(negative) {

buf[--charPos] = (byte) '-';

}

return charPos;

}

无符号化

// 将当前int转换为无符号形式,用long存储

public static long toUnsignedLong(int x) {

return ((long) x) & 0xffffffffL;

}

比较

这里实现了Comparable接口的compareTo方法

// 比较两个int(按自然顺序比较)

public static int compare(int x, int y) {

return (x

}

// 比较两个Integer(按自然顺序比较)

public int compareTo(Integer anotherInteger) {

return compare(this.value, anotherInteger.value);

}

// 以无符号形式比较两个int(按自然顺序比较)

public static int compareUnsigned(int x, int y) {

return compare(x + MIN_VALUE, y + MIN_VALUE);

}

通过 x.compareTo(y) 来“比较x和y的大小

返回“负数”,意味着“x

返回“零”,意味着“x==y”

返回“正数”,意味着“x>y”

位操作

// 返回二进制位中值为1的bit位的数量(把int值i表示为二进制形式)

@HotSpotIntrinsicCandidate

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;

}

// 将i中的bit循环左移distance位

public static int rotateLeft(int i, int distance) {

return (i << distance) | (i >>> -distance);

}

// 将i中的bit循环右移distance位

public static int rotateRight(int i, int distance) {

return (i >>> distance) | (i << -distance);

}

// 以bit为单位逆置bit顺序

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;

return reverseBytes(i);

}

// 以字节为单位逆置字节顺序

@HotSpotIntrinsicCandidate

public static int reverseBytes(int i) {

return (i << 24) | ((i & 0xff00) << 8) | ((i >>> 8) & 0xff00) | (i >>> 24);

}

// 判断i的正负。遇到负数返回-1,正数返回1,0返回0。

public static int signum(int i) {

// HD, Section 2-7

return (i >> 31) | (-i >>> 31);

}

// 返回二进制位中开头连续的0的个数(把int值i表示为二进制形式)

@HotSpotIntrinsicCandidate

public static int numberOfLeadingZeros(int i) {

// HD, Count leading 0's

if(i<=0)

return i == 0 ? 32 : 0;

int n = 31;

if(i >= 1 << 16) {

n -= 16;

i >>>= 16;

}

if(i >= 1 << 8) {

n -= 8;

i >>>= 8;

}

if(i >= 1 << 4) {

n -= 4;

i >>>= 4;

}

if(i >= 1 << 2) {

n -= 2;

i >>>= 2;

}

return n - (i >>> 1);

}

// 返回二进制位中末尾连续的0的个数(把int值i表示为二进制形式)

@HotSpotIntrinsicCandidate

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);

}

// 返回二进制位中开头首次出现的1所占的数位,比如00110100,返回32

public static int highestOneBit(int i) {

return i & (MIN_VALUE >>> numberOfLeadingZeros(i));

}

// 返回二进制位中末尾最后出现的1所占的数位,比如00110100,返回4

public static int lowestOneBit(int i) {

// HD, Section 2-1

return i & -i;

}

简单运算

// 求和

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);

}

// 除法运算,计算结果转为int后返回。计算前需要先将两个int值转换为无符号形式,并用long存储。

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));

}

// 取余运算,计算结果转为int后返回。计算前需要先将两个int值转换为无符号形式,并用long存储。

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));

}

剩余代码

剩下的这三个方法 都是继承自Object 没什么好说的了

@Override

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;

}

自动装箱与自动拆箱

其实自动装箱与拆箱更像是一种障眼法,是编译器帮我们做了一些事情

比如说自动装箱

Integer i = 1;

编译器在编译的时候自动作以下的语法编译:Integer i = Integer.valueOf(1);

自动拆箱,也就是将对象中的基本数据从对象中自动取出。

Integer i = 1; //装箱

int t = i; //拆箱

类似于自动装箱 实际上语法编译为: int t = i.intValue();

关于Integer的自动装箱

// 在-128~127 之内的数

Integer i1 =100;

Integer i2 =100;

System.out.println("i1==i2: "+(i1==i2));

//在-128~127 之外的数

Integer i3 =200;

Integer i4 =200;

System.out.println("i3==i4: "+(i3==i4));

输出的结果是

输出的结果是:

i1==i2: true

i3==i4: false

equals() 比较的是两个对象的值(内容)是否相同。

"==" 比较的是两个对象的引用(内存地址)是否相同,也用来比较两个基本数据类型的变量值是否相等。

结合一下前面的Integer.valueOf(int i)源代码

很容易理解

对于–128到127(默认是127)之间的值,Integer.valueOf(int i) 返回的是缓存的Integer对象(并不是新建对象)

所以范例中,i3 与 i4实际上是指向同一个对象。

而其他值,执行Integer.valueOf(int i) 返回的是一个新建的 Integer对象,所以范例中,i1与i2 指向的是不同的对象。

为什么要说这个问题呢?之前见过一道类似的面试题,当初怎么想也想不明白,如今看过源码之后,茅塞顿开。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/499172.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

_Linux 服务器存在某进程 CPU 过高如何追溯其问题根源?

问题描述&#xff1a;在本人运维的一个省级平台系统中&#xff0c;最近有用户反应系统很卡一直转圈圈. 经初步核查发现某web服务器节点存在JAVA进程cpu占比超过100%的情况。为了不影响用户使用&#xff0c;暂时只能采取简单粗暴的方法"重启服务器"。这其中有如下2个疑…

大数乘加运算然后取模 c++_脚本语言系列之Java | Java中的运算符

本文主要介绍java中的常见运算符&#xff0c;如算术运算符、赋值运算符、比较运算符、逻辑运算符、位运算符、三目运算符等。一、几个概念int a 3 4; 、就是操作符&#xff0c;是算术运算符&#xff0c;我们还有其他很多的运算符 3&#xff0c;4就是参与运算的操作数 3 4整体…

visio形成数据字典_入职数据产品经理第一天,同事问了我3个问题

什么是数据产品经理&#xff1f;数据产品经理有什么能力要求&#xff1f;数据产品经理的未来发展什么&#xff1f;文章围绕这三个问题进行陈述分析&#xff0c;希望看完能对你有所帮助。最近&#xff0c;前同事老曹跳槽到去了一家初具规模的互联网公司&#xff0c;作为刚入职公…

电脑硬盘内存不足怎么办_电脑内存不足怎么办?三招帮你轻松解决

熟悉PC硬件的小伙伴都知道&#xff0c;内存相对于电脑来说是一个相当重要的部件&#xff0c;内存可以说是相当于CPU的“工作室”&#xff0c;因为PC所有运行的程序都是在内存中运行&#xff0c;它决定了多少、多大的程序能即时运行&#xff0c;如若执行程序过大或者过多就会导致…

ad敷铜后还有部分飞线_种草!车厘子红组合高柜,除了颜美,还有什么好?

最近上新君在AD线下体验店遇到个忍不住一定要推荐的牌子~它是谁呢&#xff1f;卖个关子猜一猜&#xff1a;「家居达人等级测试」开始⏰「线索一」线下店进门右手边这组红色柜子&#x1f446;「线索二」它是乐高“母国”丹麦的收纳家具品牌&#xff0c;花了37年&#xff0c;就做…

宝塔php开启zip组建,宝塔面板如何开启php扩展

宝塔面板如何开启php扩展&#xff1f;宝塔面板的PHP安装路径为/www/server/php/ 且支持多个PHP版本共存&#xff0c;所以&#xff0c;安装PHP扩展的方法与网上那些示例略有不同。下们通过安装oauth扩展来说明一下如何安装第三方PHP扩展。安装之前&#xff0c;请先到软件列表 –…

win7局域网共享设置_分享几个简单实用的局域网共享设置工具

发现很多朋友对于局域网共享设置都不是很熟悉&#xff0c;特别是现在Windows 10已经越来越普遍&#xff0c;很多用户可能熟悉Windows XP、Winodws7的文件共享、打印机共享比较熟悉&#xff0c;但是一到Windows是就感觉懵逼了&#xff01;确实Windows 10在共享权限设置这块需要更…

dataframe保存为txt_TxtToMy下载-TxtToMy((txt导入myql数据库))v3.7免费版

TxtToMy是一个数据转换软件&#xff0c;帮助数据库用户导入CSV (TXT)数据到MySQL数据库。用户能够通过TxtToMy更好地将文本(csv)文件数据导入Mysql&#xff0c;十分实用&#xff0c;感兴趣的用户可以自行下载体验。基本简介TxtToMy(txt导入myql数据库)是一款十分优秀的TXT导入到…

外星人台式电脑_推荐|外星人笔记本、主机、台式电脑多少钱?(价格)到底怎么样呢?(双十一)...

自外星人电脑爆火至今&#xff0c;关于它的争议就一直没有断过。有人说外星人电脑是超好用的高配电脑&#xff0c;也有人说买外星人电脑的都是人傻钱多&#xff0c;前段时间我还看到有人还因为这个问题吵了起来。说实话&#xff0c;这真的没有吵架的必要。每个人的消费观念不同…

bpmn流程图_几款流程图制作工具

在流程设计、思路展示、网络布线、工作汇报、简介说明、设计程序等工作中&#xff0c;都少不了要用流程图来形象清晰地说明问题。因此&#xff0c;我们经常需要易用的流程图软件来帮助我们绘制流程图&#xff0c;今天&#xff0c;小编就在这里介绍几款流程图软件。Microsoft Vi…

gdb 没有那个文件或目录_阿黛尔暴瘦变回粉丝喜爱的那个她,依然那样楚楚动人...

阿黛尔(Adele)在《第六夜现场》(Saturday Night Live)主持中首次亮相&#xff0c;穿搭风格再次让人眼前一亮参加15届格莱美奖得主阿黛尔出生于伦敦&#xff0c;已经32岁了&#xff0c;她的R&B音乐获得了两项格莱美奖&#xff0c;在获奖后在表示&#xff0c;她真的不敢相信她…

iphonex售价_库克也非常无奈!颁发新规后:依旧未能阻止苹果12的售价大跳水

【11月2日讯】相信大家都知道&#xff0c;苹果在发布了iPhone 12系列手机之后&#xff0c;为了改变以往iPhone手机首发售价就“破发”的尴尬局面&#xff0c;也是直接颁发了新规&#xff0c;限制了国内补贴力度最强的某电商平台—某多多&#xff0c;试图通过重新掌控供应链渠道…

鼠标连点器电脑版_最值得买的鼠标垫推荐-最佳长款桌垫鼠标垫排行榜【2020年10月】...

超大鼠标垫可以将键盘、鼠标都垫着,大而厚实,操作电脑时更方便,不会出现鼠标垫不够用的情况,而且超大鼠标垫还可作为桌垫,美观大方,适合在家使用。今天给大家推荐最佳长款桌垫鼠标垫排行&#xff0c;希望对大家选购鼠标垫有帮助。第一名 美商海盗船|MM300战场风桌垫海盗船的产品…

superoneclick 2.2_减排二氧化碳2.2万吨!“电能替代”助安吉传统产业绿色转型

近日&#xff0c;安吉县孝丰镇丰缘茶场的茶农夏亚红联系上了国网安吉县供电公司的工作人员&#xff0c;希望对方再来指导一下新安装设备的使用和操作。作为安吉县“节能贷”的用户&#xff0c;夏亚红成为该公司推出的茶农专变新服务的首位受益人&#xff0c;她坦言明年炒茶旺季…

c# spire.xls 设置文字为微软雅黑_只要一分钟,给你的PPT文字加上拼音和声调

每天下午一点&#xff0c;PPT技能进步一点做PPT时必不可少的一项就是字体使用合适的字体可以让我们的PPT更加美观见惯了满屏幕的宋体和微软雅黑你也许想要尝试一下其他的方式来装点的文字何不用拼音&#xff1f;都知道在一些低年级的PPT中会给文字添加拼音相信很多看过语文老师…

xgboost 怎么读_南宁日语培训考级怎么选_在线日语学习

摘要&#xff1a; 南宁日语培训考级怎么选_在线日语学习为你介绍口语学习&#xff0c;听力先行。要先有输入&#xff0c;再有输出。要想有一口规范的日语口语发音&#xff0c;有必要先许多做听力练习。当你的耳朵熟悉了每个单词的发音&#xff0c;你才有时机说出规范的日语。听…

glsl shader 雪_深夜食堂里的雪平锅,美味秘诀:手工打造,高效导热,煮煲炸蒸都好用!...

hello&#xff0c;看今天内容之前生活妹给大家推荐一下各种好吃好用的↓↓↓在日本&#xff0c;几乎每个家庭都有一个雪平锅。日本厨师冨田唯介甚至专门为雪平锅撰写了一本书&#xff1a;《雪平锅无油料理》&#xff0c;里面详细讲诉了雪平锅能做的各类美食&#xff0c;从煮物到…

ubuntu 安装GPU黑屏 修改GRUB_Ubuntu升级安装最新内核的方法与注意事项(以18.04为例)...

请关注本头条号&#xff0c;每天坚持更新原创干货技术文章。如需学习视频&#xff0c;请在微信搜索公众号“智传网优”直接开始自助视频学习前言本文主要如何安全地升级Ubuntu内核&#xff0c;以18.04 Server版为例纂写本教程。我们先来了解一下什么是主线内核构建(Mainline Ke…

send tcp char far_TCP/IP之传输层详解

1. 传输层特征传输层位于TCP/IP协议族中的第4层&#xff0c;负责在网络主机中创建虚拟传输控制协议TCP&#xff0c;或用户数据报协议UDP&#xff0c;也叫“Transport Layer”。此层向其主机上运行的应用程序发送和接收数据。传输层将端口号分配给在主机上的应用程序中运行的进程…

python库_Python 基本功: 2. 学会调用库

在完成 基本功教程1 之后&#xff1a;多多教Python&#xff1a;Python 基本功: 1. Hello world​zhuanlan.zhihu.com你已经成功完成了第一个 Python 应用程序&#xff0c;并且运用了三种不同的创作工具。接下来&#xff0c;我们先来从宏观的角度了解一下 Python 宇宙&#xff0…