Khi nào sử dụng lớp wrapper và kiểu nguyên thủy


Câu trả lời:


69

Những người khác đã đề cập rằng một số cấu trúc nhất định như Collectionsđối tượng yêu cầu và đối tượng có chi phí cao hơn so với các đối tác ban đầu của chúng (bộ nhớ và quyền anh).

Một xem xét khác là:

Có thể hữu ích khi khởi tạo Đối tượng nullhoặc gửi nullcác tham số vào một phương thức / hàm tạo để chỉ ra trạng thái hoặc chức năng. Điều này không thể được thực hiện với nguyên thủy.

Nhiều lập trình viên khởi tạo các số thành 0 (mặc định) hoặc -1 để biểu thị điều này, nhưng tùy thuộc vào trường hợp, điều này có thể không chính xác hoặc gây hiểu lầm.

Điều này cũng sẽ thiết lập bối cảnh NullPointerExceptionkhi một thứ gì đó được sử dụng không đúng cách, thân thiện với lập trình viên hơn nhiều so với một số lỗi tùy ý.


15
"Có thể hữu ích khi khởi tạo Đối tượng thành null". Nó không thể hữu ích vì điều này không chính xác, nếu trường là tùy chọn, bạn nên chỉ ra điều này một cách rõ ràng.
Eddie Jamsession

8
lol @EddieJamsession cảm ơn, tôi sẽ không bao giờ khởi tạo thành null nữa. (pfffft)
pstanton

@EddieJamsession Nếu khởi tạo Đối tượng thành null như một cách để chỉ ra lỗi khi thiết lập giá trị thực không thành công, bạn sẽ đề xuất cách nào khác để giải quyết vấn đề này? Ồ, tôi vừa nhận ra khi gõ cái này: ngoại lệ. Một NullPointerException quá chung chung; tốt hơn là sử dụng các ngoại lệ tùy chỉnh rất cụ thể để chỉ ra những gì đã xảy ra. Tốt, tôi sẽ làm điều đó từ bây giờ ...
klaar

1
@EddieJamsession Sau khi đọc xong vấn đề này, tôi đã tìm hiểu khái niệm về một đối tượng Tùy chọn. Đúng.
klaar

18

Nói chung, bạn nên sử dụng các kiểu nguyên thủy trừ khi bạn cần một đối tượng vì lý do nào đó (ví dụ: để đưa vào một bộ sưu tập). Thậm chí sau đó, hãy xem xét một cách tiếp cận khác không yêu cầu đối tượng nếu bạn muốn tối đa hóa hiệu suất số. Điều này được tư vấn bởi tài liệubài viết này trình bày cách tự động đấm bốc có thể gây ra sự khác biệt lớn về hiệu suất.


3
hiệu suất không quá lớn nên tính dễ đọc / độ tin cậy của mã nên lùi lại.
pstanton

2
Đầu tiên, sử dụng các nguyên mẫu một cách thích hợp sẽ không làm cho mã của bạn không đọc được. Thứ hai, hiệu suất đạt được là đáng kể trong một số trường hợp. Thật vô lý khi nói rằng nó không bao giờ là như vậy.
Matthew Flaschen

1
@pstanton: vui lòng giải thích như thế nào Integerlà dễ đọc hơn int.
Stephen C

Trong nhiều trường hợp Số nguyên không dễ đọc hơn int và trong những trường hợp này, tôi sẽ luôn sử dụng int, hoặc nếu tôi biết một biến nào đó sẽ KHÔNG BAO GIỜ là null, tôi sẽ sử dụng int vì int như bạn đã chỉ ra hiệu quả hơn một chút. Tuy nhiên, trong nhiều trường hợp, một lập trình viên khác dễ dàng hiểu được trạng thái của một biến khi một đối tượng được sử dụng, vì nó có thể được khởi tạo thành null để biểu thị rằng nó chưa sẵn sàng. Ví dụ: nếu bạn có một bản ghi cơ sở dữ liệu chưa được lưu có một id số tăng dần duy nhất, thì id này phải là 0, -1 hay null trước khi nó được gán một id hợp lệ? Trong trường hợp đó Đối tượng tốt hơn.
pstanton

liên quan đến hiệu suất - trong những trường hợp đặc biệt, hiệu suất có thể đáng kể, tức là nếu bạn đang tạo vô số Đối tượng này rất nhanh hoặc nếu nhiều đối tượng trong số chúng tích tụ trong một khoảng thời gian. Tuy nhiên, tôi mong đợi một lập trình viên giỏi có thể xác định những trường hợp đặc biệt này để tránh hoặc sửa đổi cho phù hợp. Tôi chưa bao giờ nói rằng nó KHÔNG BAO GIỜ quan trọng, nhưng nói chung, nó không phải vậy.
pstanton

12

Theo ý kiến ​​của tôi, nếu các thành viên trong lớp của tôi là biến trình bao bọc, thì nó không dựa trên các giá trị mặc định, đó là hành vi thân thiện với nhà phát triển.

1.

class Person {
   int SSN ; // gets initialized to zero by default 
}

2.

class PersonBetter {
  Integer SSN; //gets initialized to null by default
}

Trong trường hợp đầu tiên, bạn không thể giữ giá trị SSN chưa khởi tạo. Nó có thể bị tổn thương nếu bạn không kiểm tra xem giá trị đã được đặt trước khi bạn cố gắng sử dụng nó hay chưa.

Trong trường hợp thứ hai, bạn có thể giữ SSN được khởi tạo bằng null. Điều này có thể dẫn đến NullPointerException nhưng tốt hơn là vô tình chèn các giá trị mặc định (không) dưới dạng SSN vào cơ sở dữ liệu bất cứ khi nào bạn cố gắng sử dụng nó mà không khởi tạo trường SSN.


3
Mẫu xây dựng có nghĩa là để giải quyết vấn đề này. Trong trường hợp này, bạn tạo một PersonBuilderngoại lệ nếu SSN không được đặt trước khi gọi "build" để lấy Personphiên bản. Tôi nghĩ điều này là quá đáng, nhưng đó là điều mà ngôn ngữ Java thúc đẩy để tạo ra các mẫu phù hợp.
Sandy Chapman

8

Tôi sẽ chỉ sử dụng các loại trình bao bọc nếu bạn phải.

Khi sử dụng chúng, bạn không thu được nhiều, ngoài thực tế là chúng đang có Objects.

Và, bạn mất chi phí sử dụng bộ nhớ và thời gian dành cho quyền anh / mở hộp.


4
bạn có thể không đạt được nhiều, nhưng bạn cũng không mất nhiều. trừ khi bạn đang chạy trên một phi công cọ của năm 1990.
pstanton

Thực tế là chúng là các Đối tượng cũng cung cấp cho chúng nhiều ngữ cảnh và tính đóng gói hơn là một nguyên bản đơn thuần. Vì vậy, bạn thực sự có thể thu được nhiều lợi ích tùy thuộc vào những nguyên thủy đó dùng để làm gì và chúng được sử dụng ở đâu.
aberrant 80

4

Thực tế, tôi đã gặp một tình huống mà việc sử dụng lớp wrapper có thể được giải thích.

Tôi đã tạo một lớp dịch vụ có một longbiến kiểu

  1. Nếu biến thuộc loại long- khi không được khởi tạo, nó sẽ được đặt thành 0 - điều này sẽ gây nhầm lẫn cho người dùng khi hiển thị trong GUI
  2. Nếu biến thuộc loại Long- khi không được khởi tạo, nó sẽ được đặt thành null- giá trị null này sẽ không hiển thị trong GUI.

Điều này cũng áp dụng cho Booleannhững nơi giá trị có thể gây nhầm lẫn hơn khi chúng ta sử dụng nguyên thủy boolean(vì giá trị mặc định là sai).


3

Các tập hợp là trường hợp điển hình cho các đối tượng trình bao bọc Java đơn giản. Tuy nhiên, bạn có thể cân nhắc việc cung cấp cho Wrapper một ý nghĩa cụ thể hơn trong mã (đối tượng giá trị).

IMHO hầu như luôn luôn có lợi khi sử dụng các đối tượng giá trị khi nó tóm tắt về khả năng đọc và duy trì mã. Việc bao bọc các cấu trúc dữ liệu đơn giản bên trong các đối tượng khi chúng có những trách nhiệm nhất định thường đơn giản hóa mã. Đây là điều rất quan trọng trong Thiết kế theo hướng miền .

Tất nhiên là có vấn đề về hiệu suất, nhưng tôi có xu hướng bỏ qua điều đó cho đến khi tôi có khả năng đo lường hiệu suất với dữ liệu thích hợp và thực hiện các hành động trực tiếp hơn đối với khu vực có vấn đề. Nó cũng có thể dễ hiểu hơn về vấn đề hiệu suất nếu mã cũng dễ hiểu.


3

hiệu suất của các ứng dụng bị chi phối bởi các tính toán số có thể được hưởng lợi rất nhiều từ việc sử dụng các nguyên thủy.

kiểu nguyên thủy, người ta sử dụng toán tử ==, nhưng đối với trình bao bọc, lựa chọn ưu tiên là gọi phương thức equals ().

"Các kiểu nguyên thủy được coi là có hại" vì chúng trộn lẫn "ngữ nghĩa thủ tục vào một mô hình hướng đối tượng thống nhất khác.

Nhiều lập trình viên khởi tạo các số thành 0 (mặc định) hoặc -1 để biểu thị điều này, nhưng tùy thuộc vào trường hợp, điều này có thể không chính xác hoặc gây hiểu lầm.


1

Nếu bạn muốn sử dụng Bộ sưu tập, bạn phải sử dụng các lớp Wrapper.

Các kiểu nguyên thủy, được sử dụng cho các mảng. Ngoài ra, để đại diện cho dữ liệu không có hành vi, ví dụ: bộ đếm hoặc điều kiện boolean.

Kể từ khi autoboxing, biên giới "khi nào sử dụng nguyên thủy hoặc trình bao bọc" đã trở nên khá mờ nhạt.

Nhưng hãy nhớ rằng, Wrappers là các đối tượng, vì vậy bạn sẽ có được tất cả các tính năng Java ưa thích. Ví dụ: bạn có thể sử dụng phản xạ để tạo các đối tượng Số nguyên, nhưng không sử dụng giá trị int. Các lớp gói cũng có các phương thức như valueOf.


Ngoài các bộ sưu tập, tôi không nên sử dụng các lớp trình bao bọc? Làm thế nào về việc sử dụng nó cho khai báo thông thường như Integer i = new Integer (10); Làm như thế này có tốt không?
Gopi

autoboxing cho phép bạn thực hiện Integer i = 10;
Tom

1
Không, Sri. Nếu bạn không có yêu cầu rằng tôi phải là một đối tượng, đừng biến nó thành một đối tượng.
Matthew Flaschen

Autoboxing sẽ bỏ hộp i đã khai báo ở trên thành int i = 10 hay Integer i = 10?
Gopi

3
int pi = new Integer (10); làm. Số nguyên oi = 10; làm. int ni = null; không hoạt động. LHS được chuyển đổi thành bất cứ thứ gì mà RHS yêu cầu.
pstanton

0

Nếu bạn muốn tạo một loại giá trị. Một cái gì đó như ProductSKU hoặc AirportCode.

Khi một kiểu nguyên thủy (chuỗi trong các ví dụ của tôi) xác định bình đẳng, bạn sẽ muốn ghi đè bình đẳng.


5
chuỗi không phải là một nguyên thủy
pstanton

2
vẫn có những lý do chính đáng để bọc một kiểu giá trị có chứa một chuỗi làm đối tượng cơ sở.
Chris Missal

câu trả lời của bạn không có ý nghĩa. tôi không chắc bạn đang nói gì. Tuy nhiên, tôi đồng ý với nhận xét của bạn, các lớp trình bao bọc là một ý tưởng hay nếu chúng cải thiện tính dễ đọc.
pstanton

Loại giá trị hoặc đối tượng giá trị phải được tạo và không thay đổi. Ví dụ: sẽ không hợp lý nếu tạo một đối tượng "CountryCode" như: new CountryCode ("USA") sau đó tạo một đối tượng khác theo cách tương tự, sau này chúng khác nhau. Chúng chỉ là chuỗi để bắt đầu, nhưng chúng có ý nghĩa đằng sau chúng. Bằng cách sử dụng các chuỗi, bạn có thể sửa đổi chúng (bằng cách bổ sung thêm dữ liệu, v.v.) nhưng chúng sẽ không còn bằng nhau nữa. Xem bài viết này cho một mô tả tốt hơn về những gì tôi đang cố gắng để giải thích :) Tôi hy vọng làm cho này cảm c2.com/cgi/wiki?ValueObject
Chris Sách Lễ

0

Các giá trị nguyên thủy trong Java không phải là đối tượng. Để thao tác các giá trị này với tư cách là đối tượng, gói java.lang cung cấp một lớp trình bao bọc cho mỗi kiểu dữ liệu nguyên thủy.

Tất cả các lớp Wrapper là cuối cùng. Đối tượng của tất cả các lớp trình bao bọc có thể được khởi tạo là bất biến có nghĩa là không thể thay đổi giá trị trong đối tượng trình bao bọc.

Mặc dù, lớp void được coi là một lớp bao bọc nhưng nó không bọc bất kỳ giá trị nguyên thủy nào và không thể khởi tạo. Nó không có hàm tạo công khai, nó chỉ biểu thị một đối tượng lớp đại diện cho từ khóa void.

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.