Tại sao chúng ta sử dụng autoboxing và unboxing trong Java?


81

Autoboxing là sự chuyển đổi tự động mà trình biên dịch Java thực hiện giữa các kiểu nguyên thủy và các lớp trình bao bọc đối tượng tương ứng của chúng. Ví dụ, chuyển đổi một số nguyên thành một Số nguyên, một nhân đôi thành một Đôi, v.v. Nếu chuyển đổi diễn ra theo hướng khác, điều này được gọi là unboxing.

Vậy tại sao chúng ta cần nó và tại sao chúng ta sử dụng autoboxing và unboxing trong Java?


1
Về cơ bản cho Generics ..
nachokk

3
IntegerparseIntphương pháp. intkhông có. :)
Vishal Zanzrukia

@VishalZanzrukia Vậy chỉ để có thêm chức năng?

12
Bạn có thể có List<Integer>, nhưng bạn không thể có List<int>.
Vishal Zanzrukia

Yes..exactly..to có được nhiều chức năng hơn
Vishal Zanzrukia

Câu trả lời:


173

Cần có một số ngữ cảnh để hiểu đầy đủ lý do chính đằng sau điều này.

Nguyên thủy so với các lớp

Các biến số nguyên trong Java chứa các giá trị (số nguyên, số nhị phân dấu phẩy động có độ chính xác kép, v.v.). Bởi vì các giá trị này có thể có độ dài khác nhau , các biến chứa chúng cũng có thể có độ dài khác nhau (xem xét floatso với double).

Mặt khác, các biến lớp chứa các tham chiếu đến các thể hiện. Tham chiếu thường được triển khai dưới dạng con trỏ (hoặc thứ gì đó rất giống với con trỏ) trong nhiều ngôn ngữ. Những điều này thường có cùng kích thước, không phụ thuộc vào kích thước của các trường hợp họ tham khảo ( Object, String, Integer, vv).

Thuộc tính này của các biến lớp làm cho các tham chiếu mà chúng chứa có thể hoán đổi cho nhau (ở một mức độ nào đó). Điều này cho phép chúng tôi thực hiện những gì chúng tôi gọi là thay thế : nói một cách rộng rãi, sử dụng một thể hiện của một kiểu cụ thể như một thể hiện của một kiểu liên quan khác ( ví dụ: sử dụng một Stringnhư một Object).

Các biến nguyên thủy không thể hoán đổi cho nhau theo cùng một cách, không với nhau hoặc với Object. Lý do rõ ràng nhất cho điều này (nhưng không phải là lý do duy nhất) là sự khác biệt về kích thước của chúng. Điều này làm cho các kiểu nguyên thủy trở nên bất tiện về mặt này, nhưng chúng tôi vẫn cần chúng trong ngôn ngữ (vì những lý do chủ yếu là giảm hiệu suất).

Generics và loại xóa

Loại chung là loại có một hoặc nhiều tham số loại (số chính xác được gọi là độ hiếm chung ). Ví dụ, định nghĩa kiểu chung List<T> có một tham số kiểu T, có thể là Object(tạo ra một kiểu cụ thể List<Object> ), String( List<String>), Integer( List<Integer>), v.v.

Loại chung phức tạp hơn rất nhiều so với loại không chung. Khi chúng được giới thiệu với Java (sau khi phát hành lần đầu), để tránh thực hiện các thay đổi triệt để đối với JVM và có thể phá vỡ khả năng tương thích với các tệp nhị phân cũ hơn, những người tạo ra Java đã quyết định triển khai các kiểu chung theo cách ít xâm lấn nhất: tất cả các kiểu cụ thể của List<T>trên thực tế, được biên dịch thành (tương đương nhị phân của) List<Object>(đối với các loại khác, ràng buộc có thể là một cái gì đó khác hơn Object, nhưng bạn hiểu rõ). Thông tin tham số kiểu và độ hiếm chung chung bị mất trong quá trình này , đó là lý do tại sao chúng tôi gọi nó là xóa kiểu .

Gắn kết cả hai lại với nhau

Bây giờ vấn đề là sự kết hợp của các thực tế trên: nếu List<T>trở thành List<Object>trong mọi trường hợp, thì Tluôn phải là một kiểu có thể được gán trực tiếp choObject . Bất cứ điều gì khác không được phép. Kể từ đó, như chúng tôi đã nói trước đây, int, floatdoublekhông được hoán đổi với Object, có thể không phải là một List<int>, List<float>hoặc List<double>(trừ khi thực hiện đáng kể phức tạp hơn của Generics tồn tại trong JVM).

Nhưng Mời Java loại thích Integer, FloatDoubleđó quấn những nguyên thủy trong trường lớp, làm cho chúng có hiệu quả thể thay thế như Object, do đó cho phép các loại tổng quát để gián tiếp làm việc với các nguyên thủy cũng (vì bạn có thểList<Integer>, List<Float>, List<Double>và vân vân).

Quá trình tạo ra một Integertừ an int, a Floattừ a float, v.v., được gọi là quyền anh . Ngược lại được gọi là mở hộp . Bởi vì việc phải đóng hộp các nguyên bản mỗi khi bạn muốn sử dụng chúng Objectlà điều bất tiện, nên có những trường hợp ngôn ngữ thực hiện điều này tự động - được gọi là autoboxing .


Theo giải thích của bạn, chúng tôi cần các lớp này Integer, String, ... để triển khai generics. Có lý do nào khác không?
Bishwas Mishra

1
@BishwasMishra Chúng tôi có chúng để chúng tôi có thể sử dụng các giá trị này làm Objectphiên bản. Generics thông qua xóa loại là một trong những ứng dụng đó.
Theodoros Chatzigiannakis

16

Auto Boxing được sử dụng để chuyển đổi các kiểu dữ liệu nguyên thủy sang các đối tượng lớp bao bọc của chúng. Lớp Wrapper cung cấp một loạt các chức năng được thực hiện trên các kiểu nguyên thủy. Ví dụ phổ biến nhất là:

int a = 56;
Integer i = a; // Auto Boxing

Nó là cần thiết vì các lập trình viên dễ dàng có thể trực tiếp viết mã và JVM sẽ đảm nhận phần Boxing và Unboxing.

Auto Boxing cũng rất hữu ích khi chúng ta làm việc với các loại java.util.Collection. Khi chúng ta muốn tạo Bộ sưu tập kiểu nguyên thủy, chúng ta không thể trực tiếp tạo Bộ sưu tập kiểu nguyên thủy, chúng ta chỉ có thể tạo Bộ sưu tập gồm các đối tượng. Ví dụ :

ArrayList<int> al = new ArrayList<int>(); // not supported 

ArrayList<Integer> al = new ArrayList<Integer>(); // supported 
al.add(45); //auto Boxing 

Các lớp gói

Mỗi kiểu trong số 8 kiểu nguyên thủy của Java (byte, short, int, float, char, double, boolean, long) có một lớp Wrapper riêng biệt Được liên kết với chúng. Lớp Wrapper này có các phương thức được xác định trước để định dạng trước các hoạt động hữu ích trên các kiểu dữ liệu nguyên thủy.

Sử dụng các lớp gói

String s = "45";
int a = Integer.parseInt(s); // sets the value of a to 45.

Có rất nhiều chức năng hữu ích mà các lớp Wrapper cung cấp. Kiểm tra tài liệu java tại đây

Unboxing trái ngược với Auto Boxing ở đó chúng ta chuyển đổi đối tượng lớp wrapper trở lại kiểu nguyên thủy của nó. Điều này được thực hiện tự động bởi JVM để chúng ta có thể sử dụng một lớp bao bọc cho một số hoạt động nhất định và sau đó chuyển đổi chúng trở lại các kiểu nguyên thủy vì nguyên thủy dẫn đến quá trình xử lý nhanh hơn. Ví dụ :

Integer s = 45;
int a = s; auto UnBoxing;

Trong trường hợp Bộ sưu tập hoạt động với các đối tượng, chỉ sử dụng tính năng tự động mở hộp. Đây là cách thực hiện:

ArrayList<Integer> al = new ArrayList<Integer>();
al.add(45);

int a = al.get(0); // returns the object of Integer . Automatically Unboxed . 

4

Các kiểu nguyên thủy (không phải đối tượng) có sự biện minh về hiệu quả.

Các kiểu nguyên thủy int, boolean, doublelà dữ liệu tức thời, trong khi Objects là các tham chiếu. Do đó các trường (hoặc biến)

int i;
double x;
Object s;

sẽ cần bộ nhớ cục bộ 4 + 8 + 8? trong đó đối tượng chỉ có tham chiếu (địa chỉ) tới bộ nhớ được lưu trữ.

Sử dụng các trình bao bọc Đối tượng Integer, Doublevà các trình bao bọc khác, người ta sẽ giới thiệu một hướng dẫn, tham chiếu đến một số cá thể Số nguyên / Đôi trong bộ nhớ heap.

Tại sao quyền anh là cần thiết?

Đó là một câu hỏi thuộc phạm vi tương đối. Trong một java trong tương lai, nó được lên kế hoạch để có thể ArrayList<int>nâng cấp các kiểu nguyên thủy.

Trả lời: Hiện tại một ArrayList chỉ hoạt động cho Đối tượng, dành chỗ cho một tham chiếu đối tượng và quản lý việc thu gom rác cũng như vậy. Do đó, các loại chung là Object con. Vì vậy, nếu người ta muốn một ArrayList các giá trị dấu phẩy động, người ta cần bao bọc một đôi trong một đối tượng Double.

Ở đây Java khác với C ++ truyền thống với các mẫu của nó: các lớp C ++ vector<string>, vector<int>sẽ tạo ra hai sản phẩm biên dịch. Thiết kế Java hướng tới việc có một ArrayList.class, không cần mỗi loại tham số là một sản phẩm đã biên dịch mới.

Vì vậy, không có quyền chọn đối tượng, người ta sẽ cần phải biên dịch các lớp cho mỗi lần xuất hiện của một kiểu tham số. Trong cụ thể: mọi lớp tập hợp hoặc vùng chứa sẽ cần một phiên bản cho Object, int, double, boolean. Phiên bản cho Object sẽ xử lý tất cả các lớp con.

Trên thực tế, nhu cầu đa dạng hóa như vậy đã tồn tại trong Java SE cho IntBuffer, CharBuffer, DoubleBuffer, ... hoạt động trên int, char, double. Nó đã được giải quyết theo một cách khó hiểu bằng cách tạo ra các nguồn này từ một nguồn chung.


4

Bắt đầu với JDK 5, java đã thêm hai chức năng quan trọng: autoboxing và autounboxing. AutoBoxing là quá trình mà một kiểu nguyên thủy được tự động đóng gói trong trình bao bọc tương đương bất cứ khi nào một đối tượng như vậy là cần thiết. Bạn không cần phải xây dựng một đối tượng một cách rõ ràng. Tự động mở hộp là quá trình theo đó giá trị của một đối tượng được đóng gói được tự động trích xuất từ ​​một trình bao bọc kiểu khi giá trị của nó được yêu cầu. Bạn không cần gọi một phương thức như intValue () hoặc doubleValue () .

Việc bổ sung autoboxing và auto-unboxing đơn giản hóa đáng kể các thuật toán viết , loại bỏ mồi câu thủ công quyền anh và mở hộp các giá trị. Nó cũng hữu ích để tránh những sai lầm . Nó cũng rất quan trọng đối với generic , những người chỉ hoạt động trên các đối tượng. Cuối cùng, tính năng tự động đóng hộp tạo điều kiện làm việc với Khung Bộ sưu tập .


2

tại sao chúng ta có (un) quyền anh?

để làm cho việc viết mã trong đó chúng tôi kết hợp các phần mềm nguyên thủy và các lựa chọn thay thế Hướng đối tượng (OO) của chúng thoải mái hơn / ít dài dòng hơn.

tại sao chúng ta có các nguyên tắc và các lựa chọn thay thế OO của chúng?

các kiểu nguyên thủy không phải là các lớp (không giống như trong C #), do đó chúng không phải là các lớp con của Objectvà không thể bị ghi đè.

chúng tôi có các lựa chọn ban đầu như intvì lý do hiệu suất và các Objectlựa chọn thay thế như Integervì lợi ích của lập trình OO, và như một điểm nhỏ, để có một vị trí tốt cho các hằng và phương thức tiện ích (Integer.MAX_VALUE và Integer.toString(int)).

Các lợi ích của OO có thể nhìn thấy dễ dàng nhất với Generics ( List<Integer>), nhưng không giới hạn ở đó, ví dụ:

Number getMeSome(boolean wantInt) {

    if (wantInt) {
        return Integer.MAX_VALUE;
    } else {
        return Long.MAX_VALUE;
    }
}

0

Bởi vì chúng là các loại khác nhau, và như một sự tiện lợi. Hiệu suất có thể là lý do để có các loại nguyên thủy.


0

Một số cấu trúc dữ liệu chỉ có thể chấp nhận các đối tượng, không có kiểu nguyên thủy.

Ví dụ: khóa trong HashMap.

Xem câu hỏi này để biết thêm: HashMap và int làm khóa

Có những lý do chính đáng khác, chẳng hạn như trường "int" trong cơ sở dữ liệu, cũng có thể là NULL. Một int trong Java không được rỗng; một tham chiếu số nguyên có thể. Tính năng tự động đóng hộp và mở hộp cung cấp một phương tiện để tránh viết mã không liên quan trong các chuyển đổi qua lại.


0

ArrayList không hỗ trợ các kiểu nguyên thủy chỉ hỗ trợ lớp. nhưng chúng ta cần sử dụng các kiểu nguyên thủy như int, double, v.v.

ArrayList<String> strArrayList = new ArrayList<String>(); // is accepted.

ArrayList<int> intArrayList = new ArrayList<int>(); // not accepted.

Lớp Integer bao bọc một giá trị của kiểu nguyên thủy int trong một đối tượng. Vì vậy mã dưới đây được chấp nhận.

ArrayList<Integer> intArrayList = new ArrayList<Integer>(); // is accepted.

chúng ta có thể thêm một giá trị bằng phương thức add (value). Để thêm giá trị Chuỗi, hãy nói "Xin chào" trong mã strArrayList chỉ là

strArrayList.add("Hello");  

và thêm một giá trị int, nói rằng 54 chúng ta có thể viết

intArrayList.add(54);

nhưng khi chúng ta viết intArrayList.add (54); chuyển đổi trình biên dịch sang dòng sau

intArrayList.add(Integer.valueOf(54)); 

Vì intArrayList.add (54) dễ dàng và dễ chấp nhận hơn từ phía người dùng nên trình biên dịch thực hiện công việc khó khăn đó intArrayList.add(Integer.valueOf(54));là autoBoxing.

Tương tự để truy xuất giá trị, chúng ta chỉ cần nhập intArrayList.get (0) và trình biên dịch chuyển đổi thành <code>intArrayList.get(0).intValue();autoUnboxing.


0

Autoboxing: Chuyển đổi một giá trị nguyên thủy thành một đối tượng của lớp trình bao bọc tương ứng.

Unboxing: Chuyển đổi một đối tượng của một loại trình bao bọc thành giá trị nguyên thủy tương ứng của nó

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

    } 
} 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.