CodeGym/Java 博客/随机的/Java.lang.Integer 类
John Squirrels
第 41 级
San Francisco

Java.lang.Integer 类

已在 随机的 群组中发布
个会员
Java 数据类型可以有条件地分为两个块:原始数据类型和引用(类)。Java中有多种基本数据类型,例如整数(byteshortintlong)、浮点数(floatdouble)、逻辑数据类型(boolean)和字符数据类型(char)。您可能已经知道每种基本数据类型都有自己的包装类。一种引用数据类型,将其原始兄弟“包装”或转变为 Java 对象。Integer 是其名为 int 的原始兄弟的包装类。Integer在英语中的意思是整数。它们可以是正数、负数或 0。不幸的是,Java 中的 Integer 并不表示任何整数。java中的整数是32位的整数。如果您想要更大的数字,欢迎使用 Java Long数字。他们有 64 位可供使用。如果您不幸需要更大的数字,Java 可以为您提供BigInteger

使用整数

作为包装类,Integer提供了各种使用int 的方法,以及许多将int转换为StringString转换为int的方法。该类有两个构造函数:
  • public Integer(int i),其中i是要初始化的原始值。这个创建了一个用int值初始化的Integer对象。

  • public Integer(String s)抛出NumberFormatException。这里s是int值的字符串表示形式。此构造函数创建一个Integer对象,该对象使用字符串表示形式提供的int值进行初始化。

整数对象创建

有不同的Integer对象创建选项。最常用的一种也是最简单的一种。这是一个例子:
Integer myInteger = 5;
这种情况下Integer变量 的初始化与原始 int变量的初始化类似。顺便说一句,您可以使用int的值初始化Integer变量。这是一个例子:
int myInt = 5;
Integer myInteger = myInt;
System.out.println(myInteger);
这里的输出是:
5
事实上,在这里我们可以观察到自动打包。我们还可以使用构造函数和new关键字创建一个Integer对象,就像任何其他对象一样:
Integer myInteger = new Integer(5);
您可以像使用int一样 使用Integer变量(加、减、乘、除、递增、递减)。但是,请务必记住,Integer是一种引用数据类型,并且该类型的变量可以为 null。在这种情况下,最好不要进行此类操作。
Integer myInteger1  = null;
Integer myInteger2 = myInteger1 + 5;
这里我们会得到一个异常:
线程“main”中的异常 java.lang.NullPointerException”

整数类常量

Integer类提供了用于处理整数的各种常量和方法他们来了:
  • SIZE表示int类型占用的两位数系统中的位数

  • BYTES是int类型占用的两位数系统中的字节数

  • MAX_VALUE是int类型可以容纳的最大值

  • MIN_VALUE是int类型可以容纳的最小值

  • TYPEint类型返回Class类型的对象

整数类最有用的方法

现在让我们看一下Integer类最常用的方法。我认为其中最受欢迎的是从String转换数字的方法,反之亦然。
  • static int parseInt(String s)此方法将String转换为int。如果无法进行转换,则会抛出NumberFormatException 。

  • static int parseInt(String s, int radix)此方法还将s参数转换为int。radix参数表示最初编写的数字系统s 。

除了parseInt之外,还有一个非常相似的valueOf方法,有几个变体。但是, valueOf的结果将为Integer,而parseInt的结果将为int
  • static Integer valueOf(int i)返回一个值为i的Integer

  • static Integer valueOf(String s) 的工作方式类似于parseInt(String s),但结果将是Integer,而不是int

  • static Integer valueOf(String s, int radix)的工作方式与parseInt(String s, int radix)相同,但结果是Integer,而不是int

Integer类有什么问题吗?哦,是的,有……

因此,Java 中有两种整数类型(适合 32 位):intInteger。要了解它们的具体情况,我们需要了解有关 JVM 内存模型的以下信息:您声明的所有内容都存储在堆栈内存(特定于每个线程的 JVM 堆栈)或堆空间中。基本类型(intlongfloatbooleandoublecharbyte等)存储在堆栈内存中。所有对象和数组都存储在堆空间中。方法所需的这些对象和数组的引用存储在 Stack 中。所以。我们为什么关心?嗯,你看,Stack 比 Heap 小(缺点),但是在 Stack 中分配值比在 Heap 中分配值要快得多(优点)。让我们从原始类型int开始。它正好占用 32 位。即 32/8=4 字节。因为它是原始类型。现在,让我们考虑Integer。它是一个对象,具有额外的开销和对齐方式。我使用了一个库 jol 来测量它的大小:
public static void main(String[] args) {
 	System.out.println(ClassLayout.parseInstance(Integer.valueOf(1)).toPrintable());
}
结果占用了16个字节:
java.lang.Integer 对象内部:OFF SZ 类型描述值 0 8(对象头:标记)0x000000748c90e301(哈希:0x748c90e3;年龄:0) 8 4(对象头:类)0x000492a0 12 4 int Integer.value 1 实例大小: 16字节
什么?!内存增加了 4 倍!但我们不要就此止步。作为 Java 开发人员,我们通常不会停止使用单个整数。我们真正想要的是使用很多它们。就像按顺序一样。例如,在数组中。或者一个列表。数组和列表一样存储在堆中。因此,分配应该花费大约相同的时间。正确的?但是如果我们需要分配更多内存怎么办?让我们检查一下包含 1000 个原始int值的数组占用了多少空间:
public static void main(String[] args) {
    	int[] array = new int[1000];
    	for (int i = 0; i < 1000; i++) array[i] = i;                System.out.println(ClassLayout.parseInstance(array).toPrintable());
}
结果是 4016 字节:
OFF SZ 类型 描述 值 0 8(对象头:标记) 0x0000000000000001(不可偏置;年龄:0) 8 4(对象头:类) 0x00006c38 12 4(数组长度) 1000 12 4(对齐/填充间隙) 16 4000 int [I.<elements> N/A 实例大小:4016 字节 空间损失:4 字节内部 + 0 字节外部 = 总共 4 字节
好吧,考虑到单个 int 需要 4 个字节,这确实有点道理。包含1000 个整数的ArrayList<Integer>怎么样?我们来看一下:
public static void main(String[] args) {
	List<Integer> list = new ArrayList<>(1000);
	for (int i = 0; i < 1000; i++) list.add(i);
      System.out.println(GraphLayout.parseInstance(list).toFootprint());
}
结果是 20040 字节(又是 4 倍!):
java.util.ArrayList@66d3c617d 足迹:计数平均总和描述 1 4016 4016 [Ljava.lang.Object; 1000 16 16000 java.lang.Integer 1 24 24 java.util.ArrayList 1002 20040(总计)
因此,ArrayList<Integer>占用的内存空间是原来的 4 倍。这不好。但是,列表仍然更容易,因为我们可以添加和删除元素!噢,Java…为什么你需要把所有东西都装箱?!但是,我忘记了,Java 是伟大的,它的伟大之处在于我们可以使用丰富的开源库!Trove4j 就是其中之一。它有TIntArrayList,其内部有一个int[]数据。我们来测量一下它的大小:
public static void main(String[] args) {
	TIntList list = new TIntArrayList(1000);
	for (int i = 0; i < 1000; i++) list.add(i);
	System.out.println(GraphLayout.parseInstance(list).toFootprint());
}
结果是 4040 字节(几乎与int[]相同!):
gnu.trove.list.array.TIntArrayList@7440e464d 足迹:计数平均总和描述 1 4016 4016 [I 1 24 24 gnu.trove.list.array.TIntArrayList 2 4040(总计)
所以,最终,我们可以两全其美!占用 4 倍空间的整数列表。而且这不涉及Integer实例。仅int。我们 Java 开发人员非常关心内存……但我们也关心性能。有一个很棒的微基准测试库,它的名字很适中,可以让我们测量代码的性能。首先我们来比较计算两个随机整数(无论是否装箱)的和的性能: jmh 的配置如下:
benchmark {
	configurations {
    	main {
        	warmups = 5 // number of warmup iterations
        	iterations = 50 // number of iterations
        	iterationTime = 500 // time in seconds per iteration
        	iterationTimeUnit = "ns" // time unit for iterationTime
基准:
private static final Random random = new Random();

@Benchmark
public int testPrimitiveIntegersSum() {
	int a = random.nextInt();
	int b = random.nextInt();
	return a + b;
}

@Benchmark
public Integer testBoxedIntegersSum() {
	Integer a = random.nextInt();
	Integer b = random.nextInt();
	return a + b;
}
结果:
主要:test.SampleJavaBenchmark.testBoxedIntegersSum 5693337.344 ±(99.9%) 1198774.178 ops/s [平均值](最小值、平均值、最大值)=(1092314.989、5693337.344、12001683.428),stdev = 242158 3.144 CI (99.9%): [4494563.166, 6892111.522] (假设正态分布) main: test.SampleJavaBenchmark.testPrimitiveIntegersSum 15295010.959 ±(99.9%) 2555447.456 ops/s [平均值] (min, avg, max) = (4560097.059, 15295010.959, 24283809.447),标准差 = 5162130.283 CI (99.9%): [12739563.502, 17850458.415](假设正态分布)
因此,平均而言,原始整数的分配和求和速度是盒装整数的两倍多。现在,让我们比较一下集合(或 1000 个整数的数组)的创建和计算的性能:
@Benchmark
public int testPrimitiveArray() {
	int[] array = new int[1000];
	for (int i = 0; i < 1000; i++) array[i] = i;
	int sum = 0;
	for (int x : array) sum += x;
	return sum;
}
11933.545 ops/s [Average]


@Benchmark
public int testBoxesArray() {
	Integer[] array = new Integer[1000];
	for (int i = 0; i < 1000; i++) array[i] = i;
	int sum = 0;
	for (int x : array) sum += x;
	return sum;
}
2733.312 ops/s [Average]


@Benchmark
public int testList() {
	List<Integer> list = new ArrayList<>(1000);
	for (int i = 0; i < 1000; i++) list.add(i);
	int sum = 0;
	for (int x : list) sum += x;
	return sum;
}
2086.379 ops/s [Average]


@Benchmark
public int testTroveIntList() {
	TIntList list = new TIntArrayList(1000);
	for (int i = 0; i < 1000; i++) list.add(i);
	int sum = 0;
	for (int i = 0; i < 1000; i++) sum += list.get(i);
	return sum;
}
5727.979 ops/s [Average]
结果:基元数组比装箱值数组( Integer) 快 4 倍以上;比装箱值(Integer)的ArrayList快几乎六倍;速度是TIntArrayList(实际上装饰原始整数数组)的两倍。因此,如果您需要一个数据结构来存储整数值的集合,并且其大小不会改变,请使用 int [];如果大小要改变 - 您可能需要将 tove4j 库与TIntArrayList一起使用。我的文章到此结束,我解释了使用整数类型的缺点。Integer有一些有趣的静态方法,我应该在结束之前讨论一下。 public static Integer getInteger(String nm, int val)并不像人们想象的那样,而是检索系统属性的Integer值。如果未设置此属性,则 Val为默认值。public static String toBinaryString(int i)返回一个带有数字二进制表示形式的字符串。有一些方法可以检索基于 16 的 ( toHexString ) 和基于 8 ( toOctalString ) 的表示形式。有一种方法可以将String解析为int。即使字符串是基于非 10 基数的表示形式。以下是一些示例: Integer.parseInt("-FF", 16)返回 -255 Integer.parseInt("+42", 10)返回 42 Integer.parseInt("1100110", 2)返回 102
评论
  • 受欢迎
你必须先登录才能发表评论
此页面还没有任何评论