2011-07-10 26 views
45

Làm cách nào tôi có thể sử dụng các phương pháp thiết lập và nhận và tại sao tôi nên sử dụng chúng? Họ có thực sự hữu ích không? Và bạn cũng có thể cho tôi ví dụ về các phương thức thiết lập và nhận được không?Đặt và nhận các phương thức trong java?

+0

Bạn đang hỏi về Java Bean. – Rudy

+3

Khái niệm này chắc chắn không giới hạn ở hạt Java. –

+0

Bạn có thể đọc một số http://www.google.com/search?q=javabeans+tutorial kết quả 717K này. –

Trả lời

51

Đặt và nhận các phương thức là mẫu bao gói dữ liệu. Thay vì truy cập trực tiếp vào các biến thành viên lớp, bạn định nghĩa các phương thức get để truy cập các biến này và các phương thức set để sửa đổi chúng. Bằng cách đóng gói chúng theo cách này, bạn có quyền kiểm soát giao diện công cộng, bạn cần phải thay đổi các hoạt động bên trong của lớp trong tương lai.

Ví dụ, đối với một biến thành viên:

Integer x; 

Bạn có thể có phương pháp:

Integer getX(){ return x; } 
void setX(Integer x){ this.x = x; } 

chiccodoro cũng đề cập đến một điểm quan trọng. Nếu bạn chỉ muốn cho phép truy cập đọc vào trường cho bất kỳ lớp học nước ngoài nào, bạn có thể làm điều đó bằng cách chỉ cung cấp phương thức công khai get và giữ riêng tư set hoặc không cung cấp set.

+0

từ giao diện của nó, nếu tôi sử dụng thiết lập và có được phương pháp nó sẽ được dễ dàng hơn để khắc phục lỗi? tôi có đúng không – user759630

+0

có, và để tránh chúng ở nơi đầu tiên. –

+2

Có, ví dụ, bạn có thể thiết lập các điểm ngắt trong các phương thức này để xem khi nào mã còn lại cố truy cập biến thành viên cơ bản –

6

Có phương pháp truy cập được ưu tiên truy cập trực tiếp vào trường, vì nó kiểm soát cách truy nhập trường (có thể áp đặt kiểm tra dữ liệu v.v.) và phù hợp với giao diện (giao diện không thể yêu cầu trường hiện diện).

+4

gee ... một ví dụ về getter và setter. Tôi không biết rằng sẽ thêm nhiều giá trị kể từ khi các bài viết khác đã làm điều đó – Bohemian

5

Bộ định tuyến và getters được sử dụng để thay thế trực tiếp các biến thành viên truy cập từ các lớp bên ngoài. nếu bạn sử dụng một setter và getter trong việc tiếp cận một thuộc tính, bạn có thể bao gồm khởi tạo, kiểm tra lỗi, biến đổi phức tạp, vv Một số ví dụ:

private String x; 

public void setX(String newX) { 
    if (newX == null) { 
     x = ""; 
    } else { 
     x = newX; 
    } 
} 

public String getX() { 
    if (x == null) { 
     return ""; 
    } else { 
     return x; 
    } 
} 
+0

Thú vị, vì 'x' không thể là null vì' setX', vì vậy 'getX' không cần phải kiểm tra nó. Nhưng điểm được tạo ra, và bất cứ ai hiểu nhận xét này đều nhận được toàn bộ quan điểm về getters và setters. +1 –

+0

X sẽ là null nếu getX được gọi trước khi gọi đến setX. – g051051

+1

Tại sao không phải 'x' vừa được khởi tạo thành' "" '? Sau đó, bạn lưu kiểm tra trong 'getX'. –

21

tôi muốn thêm vào câu trả lời khác mà setters có thể được sử dụng để ngăn chặn việc đưa đối tượng ở trạng thái không hợp lệ.

Ví dụ: giả sử rằng tôi đã đặt Mã số thuế, được mô hình hóa dưới dạng Chuỗi. Phiên bản đầu tiên của setter có thể thực hiện như sau:

private String taxId; 

public void setTaxId(String taxId) { 
    this.taxId = taxId; 
} 

Tuy nhiên chúng ta nên ngăn chặn việc sử dụng để thiết lập các đối tượng với một taxId không hợp lệ, vì vậy chúng tôi có thể giới thiệu một tấm séc:

private String taxId; 

public void setTaxId(String taxId) throws IllegalArgumentException { 
    if (isTaxIdValid(taxId)) { 
     throw new IllegalArgumentException("Tax Id '" + taxId + "' is invalid"); 
    } 
    this.taxId = taxId; 
} 

Các bước tiếp theo, để cải thiện tính mô đun của chương trình, là làm cho chính đối tượng TaxId như một đối tượng, có thể tự kiểm tra.

private final TaxId taxId = new TaxId() 

public void setTaxId(String taxIdString) throws IllegalArgumentException { 
    taxId.set(taxIdString); //will throw exception if not valid 
} 

Tương tự như vậy với getter, nếu chúng ta chưa có giá trị thì sao? Có thể chúng tôi muốn có một con đường khác, chúng tôi có thể nói:

public String getTaxId() throws IllegalStateException { 
    return taxId.get(); //will throw exception if not set 
} 
+0

-1 Ví dụ đầu tiên là tuyệt vời. Xóa toàn bộ phần "cải thiện tính mô đun của chương trình" và tôi sẽ thay đổi thành +1. –

+1

Thực ra tôi đồng ý với Kent Pugh, như trong cuốn sách Prefactoring: "Treat String như một kiểu dữ liệu nguyên thủy. Mô tả các thuộc tính với các kiểu dữ liệu trừu tượng, thay vì là Strings." - Ví dụ trong một lớp khách hàng điển hình có thể có một vài trong số các kiểu trừu tượng này và một số có thể có các quy tắc xác nhận phức tạp, bao gồm một số dòng mã (đôi khi là hàng trăm). Đó là chính xác những gì tôi đã làm, tôi tạo ra một số [datatypes] này (https://github.com/stivlo/obliquid-lib/tree/master/src/main/java/org/obliquid/datatype) và chúng đủ chung tôi có thể tái sử dụng chúng thông qua các dự án. – stivlo

+2

Tôi sẽ cố gắng giải thích điều này tốt hơn. Trong một chương trình hướng đối tượng, một cách tốt để suy nghĩ ở một lớp học có thể là một cách nhân cách hóa. Một chuyên gia miền trong một miền, nó phải làm điều gì đó rất tốt và chỉ có một điều. Vì vậy, một lớp Khách hàng phải là chuyên gia trong Khách hàng, không phải trong mã bưu điện, Mã Vat, Id thuế, Đô thị và không nên biết cách định dạng số điện thoại. Tất cả những mối quan tâm này là các tên miền nhỏ riêng biệt và phải có chuyên gia tên miền cho từng tên miền đó. Chúng tôi không muốn mã này gây ô nhiễm cho lớp học chính của chúng tôi. – stivlo

2

chỉ vì quy tắc OOP: Ẩn và đóng gói dữ liệu. Đó là một thực tế rất xấu để tuyên bố một đối tượng là công khai và thay đổi nó trên bay trong hầu hết các tình huống. Ngoài ra còn có nhiều lý do khác, nhưng gốc là Encapsulation trong OOP. và "mua một cuốn sách hoặc đọc về lập trình hướng đối tượng", bạn sẽ hiểu mọi thứ về điều này sau khi bạn đọc bất kỳ cuốn sách nào trên OOP.

+0

-1 OP được yêu cầu một cách rõ ràng về các ví dụ. –

2

Các câu trả lời ở trên tóm tắt vai trò của getters và setters tốt hơn tôi có thể, tuy nhiên tôi muốn thêm rằng mã của bạn nên được cấu trúc lý tưởng để giảm sử dụng getters tinh khiết và setters, tức là những người không có công trình phức tạp, xác nhận, và vân vân, khi chúng phá vỡ đóng gói. Điều này không có nghĩa là bạn không bao giờ có thể sử dụng chúng (câu trả lời của stivlo cho thấy một ví dụ về việc sử dụng tốt các getters và setters), chỉ cần cố gắng giảm thiểu tần suất bạn sử dụng chúng.

Vấn đề là getters và setters có thể hoạt động như một giải pháp để truy cập trực tiếp dữ liệu cá nhân. Dữ liệu cá nhân được gọi là riêng tư vì nó không có nghĩa là được chia sẻ với các đối tượng khác; nó có nghĩa là đại diện cho trạng thái của đối tượng. Cho phép các đối tượng khác truy cập vào các trường riêng của đối tượng sẽ đánh bại toàn bộ mục đích của việc đặt nó ở vị trí đầu tiên. Hơn nữa, bạn giới thiệu khớp nối cho mỗi getter hoặc setter bạn viết. Hãy xem xét điều này, ví dụ:

private String foo; 

public void setFoo(String bar) { 
    this.foo = bar; 
} 

Điều gì sẽ xảy ra nếu, ở đâu đó trên đường, bạn quyết định không cần foo nữa, hoặc bạn muốn biến thành số nguyên? Mỗi đối tượng sử dụng phương thức setFoo bây giờ cần được thay đổi cùng với foo.

1

Những lợi ích của get() set() phương pháp như sau ..

  1. Bạn có thể serialize quý vị phản đối một cách dễ dàng.
  2. Bạn có thể tạo đối tượng liên tục từ lớp chứa.
  3. Bạn có thể dễ dàng chuyển đổi thuộc tính sang JSON.
  4. Trong lớp DAO (Khung như Hibernate), bạn có thể lưu trực tiếp đối tượng vào DB.
  5. Dễ hiểu về khái niệm hướng đối tượng.
  6. Cần có tất cả các mẫu thiết kế ngoại trừ có thể trong mẫu âm đơn.
  7. Bảo mật cho các thuộc tính bảo vệ quyền truy cập trực tiếp.
  8. Đa hình, đóng gói có thể dễ dàng được hiểu và thực hiện bởi loại lớp này.

Ví dụ:

private String personName; 
private int personId; 

    public void setPersonName(String name) throws Exception{ 
    if(!(name.equals("")||name=="")){ 
     this.personName = name; 
    } 
    } 
    public String getPersonName(){ 
    return this.personName; 
    } 
    public void setPersonId(int id) throws Exception{ 
    this.personId = id; 
    } 
    public int getPersonId(){ 
    return this.personId; 
    } 
+0

hoạt động này hoạt động như thế nào? đây là lần đầu tiên tôi gặp phải một câu lệnh name.equals ("") " – user759630

+0

Xem http://leepoint.net/notes-java/data/expressions/22compareobjects.html –

1

Trên câu trả lời tất cả các giả định rằng đối tượng trong câu hỏi là một đối tượng với hành vi. Một chiến lược nâng cao trong OOP là tách các đối tượng dữ liệu (làm zip, chỉ có các trường) và các đối tượng hành vi.

Với các đối tượng dữ liệu, tốt nhất là bỏ qua các getters và thay vào đó có các trường công khai. Họ thường không có người định cư, vì họ thường không thay đổi - các lĩnh vực của họ được thiết lập thông qua các nhà thầu, và không bao giờ một lần nữa. Hãy xem qua số Clean Code hoặc Pryce và Freeman's Growing OO Software... để biết chi tiết.

7

Tôi nghĩ rằng bạn muốn một cái gì đó như thế này:

public class Person { 

    private int age; 

    //public method to get the age variable 
    public int getAge(){ 
     return this.age 
    } 

    //public method to set the age variable 
    public void setAge(int age){ 
     this.age = age; 
    } 
} 

Bạn đang chỉ đơn giản là gọi một phương thức như vậy trên một trường hợp đối tượng. Những phương pháp này rất hữu ích, đặc biệt nếu thiết lập một thứ gì đó được cho là có tác dụng phụ. Ví dụ.nếu bạn muốn để phản ứng với các sự kiện nhất định như:

public void setAge(int age){ 

     this.age = age; 

     double averageCigarettesPerYear = this.smokedCigarettes * 1.0/age; 

     if(averageCigarettesPerYear >= 7300.0) { 
      this.eventBus.fire(new PersonSmokesTooMuchEvent(this)); 
     } 
    } 

Tất nhiên điều này có thể nguy hiểm nếu ai đó quên để gọi setAge(int) nơi ông nên và đặt age trực tiếp sử dụng this.age.

+0

Đây là cách tốt nhất để nói" không "tôi –

0

Câu trả lời này được hợp nhất từ ​​một câu hỏi khác.

Phương thức getAge() của bạn được gọi là phương pháp thể hiện trong Java.

Để gọi phương thức thể hiện, bạn nên có đối tượng của Lớp mà phương thức này được xác định.

Ví dụ, Nếu phương pháp này trong một lớp gọi là Person, sau đó

  1. Tạo một đối tượng Person sử dụng toán tử new

    Person p = new Person(); 
    
  2. Để có được tuổi của một đối tượng Person, sử dụng này phương pháp

    p.getAge() 
    
+0

Đã bỏ phiếu trong vòng một giây. Không chắc họ đánh giá như thế nào. –

0

đây là mã cho phương thức thiết lập

public void setAge(int age){ 
    this.age = age; 
} 
1
public class Person{ 

private int age; 

public int getAge(){ 
    return age; 
} 

public void setAge(int age){ 
    this.age = age; 
} 
} 

tôi nghĩ rằng đây là bạn muốn .. và điều này cũng được gọi là POJO

0

Dường như bạn cố gắng để làm một cái gì đó tương tự như C# nếu bạn muốn phương thức createAge create
setAge(int age){ this.age = age;}

0

Tôi không thấy câu trả lời đơn giản cho câu hỏi thứ hai (tại sao) tại đây. Vì vậy, ở đây đi.

Giả sử bạn có trường công khai được sử dụng rất thường xuyên trong mã của bạn. Bất cứ khi nào bạn quyết định bạn cần phải làm một cái gì đó thêm trước khi bạn đưa ra hoặc thiết lập lĩnh vực này, bạn có một vấn đề. Bạn phải tạo một getter đặc biệt và setter cho trường này và thay đổi mã hoàn chỉnh của bạn từ việc sử dụng trường trực tiếp để sử dụng getter và setters.

Bây giờ hãy tưởng tượng bạn đang phát triển một thư viện được nhiều người sử dụng. Khi bạn cần thực hiện thay đổi như trên và đặt quyền truy cập trực tiếp của trường thành riêng, mã của tất cả những người đang sử dụng trường này sẽ bị ngắt.

Sử dụng getters và setters là về lập kế hoạch tương lai của mã, nó làm cho nó linh hoạt hơn. Tất nhiên bạn có thể sử dụng các trường công cộng, đặc biệt là đối với các lớp đơn giản chỉ giữ một số dữ liệu. Nhưng nó luôn luôn là một ý tưởng tốt để chỉ làm cho các lĩnh vực tư nhân và mã một phương pháp nhận và thiết lập cho nó.

4

Một số lợi ích của việc sử dụng getter và setter (được gọi là encapsulation hoặc data-hiding):

(ban đầu đã trả lời here)

1.Các trường của một lớp có thể được thực hiện chỉ đọc (bằng cách chỉ cung cấp bộ thu thập) hoặc chỉ ghi (chỉ bằng cách cung cấp trình thiết lập). Điều này cho phép lớp kiểm soát toàn bộ những người được truy cập/sửa đổi các trường của nó.

Ví dụ:

class EncapsulationExample { 
    private int readOnly = -1; // this value can only be read, not altered 
    private int writeOnly = 0; // this value can only be changed, not viewed 
    public int getReadOnly() { 
     return readOnly; 
    } 
    public int setWriteOnly(int w) { 
     writeOnly = w; 
    } 
} 

2. Người sử dụng của một lớp không cần phải biết làm thế nào lớp thực sự lưu trữ các dữ liệu. Điều này có nghĩa là dữ liệu được tách ra và tồn tại độc lập với người dùng, do đó cho phép mã được sửa đổi và bảo trì dễ dàng hơn. Điều này cho phép người bảo trì thực hiện các thay đổi thường xuyên như sửa lỗi, thiết kế và cải tiến hiệu suất, tất cả trong khi không ảnh hưởng đến người dùng.

Hơn nữa, tài nguyên đóng gói có thể truy cập thống nhất cho mỗi người dùng và có hành vi giống nhau độc lập với người dùng vì hành vi này được xác định nội bộ trong lớp.

Ví dụ (nhận được một giá trị):

class EncapsulationExample { 
    private int value; 
    public int getValue() {  
     return value; // return the value 
    } 
} 

Bây giờ những gì nếu tôi muốn trở lại hai lần giá trị để thay thế? Tôi chỉ có thể thay đổi getter của tôi và tất cả các mã được sử dụng ví dụ của tôi không cần phải thay đổi và sẽ nhận được gấp đôi giá trị:

class EncapsulationExample { 
    private int value; 
    public int getValue() { 
     return value*2; // return twice the value 
    } 
} 

3. Làm cho mã sạch hơn, dễ đọc hơn và dễ dàng hơn để hiểu.

Dưới đây là một ví dụ:

Không đóng gói:

class Box { 
    int widthS; // width of the side 
    int widthT; // width of the top 
    // other stuff 
} 

// ... 
Box b = new Box(); 
int w1 = b.widthS; // Hm... what is widthS again? 
int w2 = b.widthT; // Don't mistake the names. I should make sure I use the proper variable here! 

Với đóng gói:

class Box { 
    private int widthS; // width of the side 
    private int widthT; // width of the top 
    public int getSideWidth() { 
     return widthS; 
    } 
    public int getTopWIdth() { 
     return widthT; 
    } 
    // other stuff 
} 

// ... 
Box b = new Box(); 
int w1 = b.getSideWidth(); // Ok, this one gives me the width of the side 
int w2 = b.getTopWidth(); // and this one gives me the width of the top. No confusion, whew! 

Nhìn cách kiểm soát nhiều hơn bạn có trên thông tin mà bạn đang nhận được và điều này rõ ràng hơn bao nhiêu trong ví dụ thứ hai. Tâm trí bạn, ví dụ này là tầm thường và trong thực tế cuộc sống các lớp học bạn sẽ được đối phó với rất nhiều tài nguyên được truy cập bởi nhiều thành phần khác nhau. Vì vậy, việc đóng gói các tài nguyên làm cho nó rõ ràng hơn những gì chúng ta đang truy cập và theo cách nào (nhận hoặc thiết lập).

Đây là good SO thread về chủ đề này.

Đây là good read về đóng gói dữ liệu.

Các vấn đề liên quan