为什么我们在 Java 中使用自动装箱和拆箱?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27647407/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why do we use autoboxing and unboxing in Java?
提问by
Autoboxing is the automatic conversion that the Java compiler makes between the primitive types and their corresponding object wrapper classes. For example, converting an int to an Integer, a double to a Double, and so on. If the conversion goes the other way, this is called unboxing.
自动装箱是 Java 编译器在原始类型与其对应的对象包装类之间进行的自动转换。例如,将 int 转换为 Integer,将 double 转换为 Double,等等。如果转换以另一种方式进行,则称为拆箱。
So why do we need it and why do we use autoboxing and unboxing in Java?
那么为什么我们需要它,为什么我们在 Java 中使用自动装箱和拆箱?
采纳答案by Theodoros Chatzigiannakis
Some context is required to fully understand the main reason behind this.
需要一些上下文才能完全理解这背后的主要原因。
Primitives versus classes
基元与类
Primitive variables in Java contain values(an integer, a double-precision floating point binary number, etc). Because these values may have different lengths, the variables containing them may also have different lengths (consider float
versus double
).
Java 中的原始变量包含值(整数、双精度浮点二进制数等)。因为这些值可能有不同的长度,包含它们的变量也可能有不同的长度(考虑float
vs double
)。
On the other hand, class variables contain referencesto instances. References are typically implemented as pointers (or something very similar to pointers) in many languages. These things typically have the same size, regardless of the sizes of the instances they refer to (Object
, String
, Integer
, etc).
另一方面,类变量包含对实例的引用。在许多语言中,引用通常被实现为指针(或与指针非常相似的东西)。这些东西通常具有相同的大小,而不管它们指的是(实例的大小Object
,String
,Integer
,等)。
This property of class variables makes the references they contain interchangeable(to an extent). This allows us to do what we call substitution: broadly speaking, to use an instance of a particular type as an instance of another, related type(use a String
as an Object
, for example).
类变量的这个属性使得它们包含的引用可以互换(在一定程度上)。这允许我们做我们所说的替换:广义上讲,将特定类型的实例用作另一个相关类型的实例(例如,将 aString
用作Object
)。
Primitive variables aren't interchangeablein the same way, neither with each other, nor with Object
. The most obvious reason for this (but not the only reason) is their size difference. This makes primitive types inconvenient in this respect, but we still need them in the language (for reasons that mainly boil down to performance).
原始变量不能以相同的方式互换,无论是彼此之间还是与Object
. 最明显的原因(但不是唯一的原因)是它们的大小差异。这使得原始类型在这方面不方便,但我们在语言中仍然需要它们(主要归结为性能的原因)。
Generics and type erasure
泛型和类型擦除
Generic types are types with one or more type parameters(the exact number is called generic arity). For example, the generic type definitionList<T>
has a type parameter T
, which can be Object
(producing a concrete typeList<Object>
), String
(List<String>
), Integer
(List<Integer>
) and so on.
泛型类型是具有一个或多个类型参数的类型(确切的数量称为泛型 arity)。例如,泛型类型定义List<T>
有一个类型参数T
,它可以是Object
(产生一个具体类型List<Object>
)、String
(List<String>
)、Integer
(List<Integer>
)等。
Generic types are a lot more complicated than non-generic ones. When they were introduced to Java (after its initial release), in order to avoid making radical changes to the JVM and possibly breaking compatibility with older binaries, the creators of Java decided to implement generic types in the least invasive way:all concrete types of List<T>
are, in fact, compiled to (the binary equivalent of) List<Object>
(for other types, the bound may be something other than Object
, but you get the point). Generic arity and type parameter information are lost in this process, which is why we call it type erasure.
泛型类型比非泛型复杂得多。当它们被引入 Java 时(在其初始版本之后),为了避免对 JVM 进行根本性的更改并可能破坏与旧二进制文件的兼容性,Java 的创建者决定以最小侵入性的方式实现泛型:所有具体类型的List<T>
事实上,被编译为(二进制等价物)List<Object>
(对于其他类型,界限可能不是Object
,但你明白了)。泛型和类型参数信息在这个过程中丢失了,这就是我们称之为类型擦除的原因。
Putting the two together
将两者放在一起
Now the problem is the combination of the above realities: if List<T>
becomes List<Object>
in all cases, then T
must always be a type that can be directly assigned to Object
. Anything else can't be allowed. Since, as we said before, int
, float
and double
aren't interchangeable with Object
, there can't be a List<int>
, List<float>
or List<double>
(unless a significantly more complicated implementation of generics existed in the JVM).
现在的问题是上述现实的结合:如果在所有情况下都List<T>
变成List<Object>
了,那么T
必须始终是可以直接分配给 的类型Object
。不能允许其他任何事情。因为,正如我们之前所说的,int
,float
和double
不能与 互换Object
,所以不能有List<int>
, List<float>
or List<double>
(除非 JVM 中存在更复杂的泛型实现)。
But Java offers types like Integer
, Float
and Double
which wrap these primitives in class instances, making them effectively substitutable as Object
, thus allowing generic types to indirectly work with the primitivesas well (because you canhave List<Integer>
, List<Float>
, List<Double>
and so on).
但是Java提供喜欢的类型Integer
,Float
以及Double
其在类实例包装这些原语,使他们有效地作为替代Object
,从而使泛型类型与原语间接地工作,以及(因为你可以有List<Integer>
,List<Float>
,List<Double>
等)。
The process of creating an Integer
from an int
, a Float
from a float
and so on, is called boxing. The reverse is called unboxing. Because having to box primitives every time you want to use them as Object
is inconvenient, there are cases where the language does this automatically - that's called autoboxing.
创建一个Integer
from an int
、a Float
from afloat
等等的过程称为装箱。反之称为拆箱。因为每次要使用原语时都必须装箱很不Object
方便,所以在某些情况下语言会自动执行此操作 -这称为自动装箱。
回答by Scott Hunter
Because they are different types, and as a convenience. Performance is likely the reason for having primitive types.
因为它们是不同的类型,并且为了方便。性能可能是使用原始类型的原因。
回答by Gabriel
Some data structures can accept only objects, no primitive types.
一些数据结构只能接受对象,不能接受原始类型。
Example: the key in a HashMap.
示例:HashMap 中的键。
See this question for more: HashMap and int as key
有关更多信息,请参阅此问题:HashMap and int as key
There are other good reasons, such as a "int" field in a database, which could be NULL as well. An int in Java cannot be null ; an Integer reference can. Autoboxing and unboxing provide with a facility to avoid writing extraneous code in the conversions back and forth.
还有其他很好的理由,例如数据库中的“int”字段也可能为 NULL。Java 中的 int 不能为 null ;整数引用可以。自动装箱和拆箱提供了一种便利,可以避免在来回转换中编写无关代码。
回答by hoijui
why do we have (un)boxing?
为什么我们有(取消)拳击?
to make writing code where we mix primitives and their Object Oriented (OO) alternatives more comfortable/less verbose.
使我们在混合原语及其面向对象 (OO) 替代方案的情况下编写代码更舒适/更简洁。
why do we have primitives and their OO alternatives?
为什么我们有原语及其面向对象的替代品?
primitive types are not classes (unlike in C#), thus they are not subclasses of Object
and can not be overridden.
原始类型不是类(与 C# 不同),因此它们不是的子类Object
并且不能被覆盖。
we have primitives like int
for performance reasons, and the Object
alternatives like Integer
for the benefits of OO programming, and as a minor point, to have a good location for utility constants and methods (Integer.MAX_VALUE and Integer.toString(int)
).
int
出于性能原因,我们有原语,而为了 OO 编程的好处,还有Object
替代Integer
方案,作为次要的一点,为实用程序常量和方法(Integer.MAX_VALUE 和Integer.toString(int)
)提供一个良好的位置。
The OO benefits are visible most easily with Generics (List<Integer>
), but are not limited to that, for example:
使用泛型 ( List<Integer>
)最容易看到面向对象的好处,但不仅限于此,例如:
Number getMeSome(boolean wantInt) {
if (wantInt) {
return Integer.MAX_VALUE;
} else {
return Long.MAX_VALUE;
}
}
回答by varun
Auto Boxingis usedto convert primitive data types to their wrapper class objects. Wrapper class provide a wide range of function to be performed on the primitive types. The most common example is :
自动拳击被用来以原始数据类型转换为自己的包装类对象。包装类提供了对基本类型执行的广泛功能。最常见的例子是:
int a = 56;
Integer i = a; // Auto Boxing
It is neededbecause of programmers easy to be able to directly write code and JVM will take care of the Boxing and Unboxing.
之所以需要它,是因为程序员很容易能够直接编写代码,并且 JVM 将负责装箱和拆箱。
Auto Boxing also comes in handy when we are working with java.util.Collection types. When we want to create a Collection of primitive types we cannot directly create a Collection of a primitive type , we can create Collection only of Objects. For Example :
当我们使用 java.util.Collection 类型时,自动装箱也派上用场。当我们想要创建原始类型的集合时,我们不能直接创建原始类型的集合,我们只能创建对象的集合。例如 :
ArrayList<int> al = new ArrayList<int>(); // not supported
ArrayList<Integer> al = new ArrayList<Integer>(); // supported
al.add(45); //auto Boxing
Wrapper Classes
包装类
Each of Java's 8 primitive type (byte,short,int,float,char,double,boolean,long) hava a seperate Wrapper class Associated with them. These Wrapper class have predefined methods for preforming useful operations on primitive data types.
Java 的 8 种原始类型(byte、short、int、float、char、double、boolean、long)中的每一种都有一个单独的 Wrapper 类与它们相关联。这些 Wrapper 类具有预定义的方法,用于对原始数据类型执行有用的操作。
Use of Wrapper Classes
包装类的使用
String s = "45";
int a = Integer.parseInt(s); // sets the value of a to 45.
There are many useful functions that Wrapper classes provide. Check out the java docs here
Wrapper 类提供了许多有用的功能。在此处查看 Java 文档
Unboxingis opposite of Auto Boxing where we convert the wrapper class object back to its primitive type. This is done automatically by JVM so that we can use a the wrapper classes for certain operation and then convert them back to primitive types as primitives result int faster processing. For Example :
拆箱与自动装箱相反,我们将包装类对象转换回其原始类型。这是由 JVM 自动完成的,因此我们可以使用包装类进行某些操作,然后将它们转换回原始类型,因为原始类型会导致更快的处理。例如 :
Integer s = 45;
int a = s; auto UnBoxing;
In case of Collections which work with objects only auto unboxing is used. Here's how :
对于与对象一起使用的集合,仅使用自动拆箱。就是这样 :
ArrayList<Integer> al = new ArrayList<Integer>();
al.add(45);
int a = al.get(0); // returns the object of Integer . Automatically Unboxed .
回答by Joop Eggen
The primitive (non-object) types have there justification in efficiency.
原始(非对象)类型在效率上是有道理的。
The primitive types int, boolean, double
are immediate data, whereas Object
s are references. Hence fields (or variables)
原始类型int, boolean, double
是直接数据,而Object
s 是引用。因此字段(或变量)
int i;
double x;
Object s;
would need local memory 4+8+8? where for the object only the reference (address) to memory is stored.
需要4+8+8的本地内存吗?对于对象,仅存储对内存的引用(地址)。
Using the Object wrappers Integer, Double
and others, one would introduce an indirection, reference to some Integer/Double instance in the heap memory.
使用 Object 包装器Integer, Double
和其他包装器,可以引入一个间接引用,即对堆内存中某个 Integer/Double 实例的引用。
Why boxing is needed?
为什么需要拳击?
That is a question of relative scope. In a future java it is planned to be able to have an ArrayList<int>
, lifting primitive types.
这是一个相对范围的问题。在未来的 java 中,计划能够有一个ArrayList<int>
,提升原始类型。
Answer:For now an ArrayList only works for Object, reserving room for an object reference, and managing garbage collection likewise. Hence generic typesare Object children. So if one wanted an ArrayList of floating point values, one needed to wrap a double in a Double object.
答:目前 ArrayList 仅适用于 Object,为对象引用保留空间,并同样管理垃圾收集。因此泛型类型是 Object 的孩子。因此,如果想要一个浮点值的 ArrayList,则需要将一个 double 包装在一个 Double 对象中。
Here Java differs from the traditional C++ with its templates: C++ classes vector<string>, vector<int>
would create two compilation products. Java design went for having one ArrayList.class, not needing for every parameter type a new compiled product.
在这里,Java 与传统 C++ 的不同之处在于其模板:C++ 类vector<string>, vector<int>
将创建两个编译产品。Java 设计倾向于拥有一个 ArrayList.class,而不需要为每个参数类型都创建一个新的编译产品。
So without boxing to Object one would need to compile classes for every occurrence of a parameter type. In concreto: every collection or container class would need a version for Object, int, double, boolean. The version for Object would handle all child classes.
因此,如果不对 Object 进行装箱,则需要为每次出现的参数类型编译类。具体来说:每个集合或容器类都需要一个 Object、int、double、boolean 版本。Object 的版本将处理所有子类。
In fact, the need for such diversification already existed in Java SE for IntBuffer, CharBuffer, DoubleBuffer, ... which operate on int, char, double. It was solved in a hacky way by generatingthese sources from a common one.
事实上,Java SE 中已经存在对 IntBuffer、CharBuffer、DoubleBuffer 等多样化的需求,它们对 int、char、double 进行操作。通过从一个共同的来源生成这些来源,它以一种hacky的方式解决了。
回答by Amarildo
Starting with JDK 5, java has added two important functions: autoboxing and autounboxing. AutoBoxingis the process for which a primitive type is automatically encapsulated in the equivalent wrapper whenever such an object is needed. You do not have to explicitly construct an object. Auto-unboxingis the process whereby the value of an encapsulated object is automatically extracted from a type wrapper when its value is required. You do not need to call a method such as intValue()or doubleValue().
从JDK 5开始,java增加了两个重要的功能:自动装箱和自动拆箱。AutoBoxing是在需要此类对象时将基本类型自动封装在等效包装器中的过程。您不必显式构造对象。自动拆箱是当需要封装对象的值时,自动从类型包装器中提取其值的过程。您不需要调用诸如intValue()或doubleValue() 之类的方法。
The addition of autoboxing and auto-unboxing greatly simplifies writing algorithms, eliminating the bait manually boxing and unboxing of values. It is also helpful to avoid mistakes. It is also very important for generics, who only operate on objects. Lastly, autoboxing facilitates work with the Collections Framework.
自动装箱和自动拆箱的加入大大简化了算法的编写,消除了手动装箱和拆箱值的诱饵。避免错误也很有帮助。对于只对对象进行操作的泛型也非常重要。最后,自动装箱有助于使用集合框架。
回答by Chhalma Sultana Chhaya
ArrayList does not support primitive types only support class. but we need to use primitive types e.g int, double etc.
ArrayList 不支持原始类型,只支持类。但是我们需要使用原始类型,例如 int、double 等。
ArrayList<String> strArrayList = new ArrayList<String>(); // is accepted.
ArrayList<int> intArrayList = new ArrayList<int>(); // not accepted.
The Integer class wraps a value of the primitive type int in an object.so bellow code is accepted.
Integer 类将原始类型 int 的值包装在一个对象中。因此可以接受以下代码。
ArrayList<Integer> intArrayList = new ArrayList<Integer>(); // is accepted.
we can add a value with add(value) method. To add a String value say "Hello" in strArrayList code is just
我们可以使用 add(value) 方法添加一个值。要添加字符串值,在 strArrayList 代码中说“Hello”只是
strArrayList.add("Hello");
and add a int value say 54 we can write
并添加一个 int 值说 54 我们可以写
intArrayList.add(54);
but when we write intArrayList.add(54); compiler convert to the following line
但是当我们写 intArrayList.add(54); 编译器转换为以下行
intArrayList.add(Integer.valueOf(54));
As intArrayList.add(54) is easy and more acceptable from user side so compiler does the hard job which is `intArrayList.add(Integer.valueOf(54));
it is autoBoxing.
由于 intArrayList.add(54) 很容易并且更容易被用户接受,所以编译器完成了艰巨的工作,intArrayList.add(Integer.valueOf(54));
它是自动装箱。
Similarly to retrieve value we just type
intArrayList.get(0) and compiler convert to <code>intArrayList.get(0).intValue();
which is autoUnboxing.
与检索值类似,我们只需键入 intArrayList.get(0) 并编译器将<code>intArrayList.get(0).intValue();
其转换为 autoUnboxing。
回答by Yash Patel
Autoboxing: Converting a primitive value into an object of the corresponding wrapper class.
自动装箱:将原始值转换为相应包装器类的对象。
Unboxing: Converting an object of a wrapper type to its corresponding primitive value
拆箱:将包装类型的对象转换为其相应的原始值
// Java program to illustrate the concept
// of Autoboxing and Unboxing
import java.io.*;
class GFG
{
public static void main (String[] args)
{
// creating an Integer Object
// with value 10.
Integer i = new Integer(10);
// unboxing the Object
int i1 = i;
System.out.println("Value of i: " + i);
System.out.println("Value of i1: " + i1);
//Autoboxing of char
Character gfg = 'a';
// Auto-unboxing of Character
char ch = gfg;
System.out.println("Value of ch: " + ch);
System.out.println("Value of gfg: " + gfg);
}
}