JavaRush /Blog Java /Random-VI /Truy cập các công cụ sửa đổi. Riêng tư, được bảo vệ, mặc ...

Truy cập các công cụ sửa đổi. Riêng tư, được bảo vệ, mặc định, công khai

Xuất bản trong nhóm
Xin chào! Trong bài giảng hôm nay, chúng ta sẽ làm quen với khái niệm “ bộ điều chỉnh quyền truy cập ” và xem các ví dụ về cách làm việc với chúng. Truy cập các công cụ sửa đổi.  Riêng tư, được bảo vệ, mặc định, công khai - 1Mặc dù từ “chúng ta hãy làm quen” sẽ không hoàn toàn chính xác: bạn đã quen thuộc với hầu hết chúng từ các bài giảng trước. Để đề phòng, chúng ta hãy làm mới trí nhớ của chúng ta về điều chính. Công cụ sửa đổi quyền truy cập thường là các từ khóa quy định mức độ truy cập vào các phần khác nhau trong mã của bạn. Tại sao "thường xuyên nhất"? Bởi vì một trong số chúng được đặt theo mặc định và không được chỉ định bởi từ khóa :) Có tổng cộng bốn công cụ sửa đổi truy cập trong Java. Chúng tôi liệt kê chúng theo thứ tự từ nghiêm ngặt nhất đến “mềm” nhất:
  • riêng tư;
  • được bảo vệ;
  • mặc định (gói hiển thị);
  • công cộng
Hãy xem xét từng điều trong số chúng, quyết định khi nào chúng có thể hữu ích cho chúng ta và đưa ra ví dụ :)

Công cụ sửa đổi riêng tư

Truy cập các công cụ sửa đổi.  Riêng tư, được bảo vệ, mặc định, công khai - 2Private— công cụ sửa đổi quyền truy cập hạn chế nhất. Nó giới hạn khả năng hiển thị của dữ liệu và phương thức trong một lớp. Bạn biết công cụ sửa đổi này từ bài giảng về getters và setters. Bạn có nhớ ví dụ này không?
public class Cat {

   public String name;
   public int age;
   public int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";
       cat.age = -1000;
       cat.weight = 0;
   }
}
Chúng tôi đã xem xét nó trong một trong những bài viết trước đó. Ở đây, chúng tôi đã mắc một sai lầm nghiêm trọng: chúng tôi đã mở dữ liệu của mình, do đó các lập trình viên đồng nghiệp có quyền truy cập trực tiếp vào các trường lớp và thay đổi giá trị của chúng. Hơn nữa, các giá trị này được chỉ định mà không cần kiểm tra, do đó trong chương trình của chúng tôi có thể tạo ra một con mèo có tuổi -1000 năm, tên "" và trọng lượng bằng 0. Để giải quyết vấn đề này, chúng tôi đã sử dụng getters và setters , đồng thời cũng hạn chế quyền truy cập vào dữ liệu bằng công cụ sửa đổi private.
public class Cat {

   private String name;
   private int age;
   private int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       // checking the input parameter
       this.name = name;
   }

   public int getAge() {
       return age;
   }

   public void setAge(int age) {
       // checking the input parameter
       this.age = age;
   }

   public int getWeight() {
       return weight;
   }

   public void setWeight(int weight) {
       // checking the input parameter
       this.weight = weight;
   }
}
Trên thực tế, việc hạn chế quyền truy cập vào các trường và triển khai getters-setters là ví dụ phổ biến nhất về việc sử dụng privatetrong công việc thực tế. Nghĩa là, việc thực hiện đóng gói trong một chương trình là mục đích chính của công cụ sửa đổi này. Nhân tiện, điều này không chỉ áp dụng cho các trường. Hãy tưởng tượng rằng trong chương trình của bạn có một phương thức thực hiện một số chức năng RẤT phức tạp. Để lấy ví dụ này làm ví dụ... Giả sử phương thức của bạn readDataFromCollider()lấy một địa chỉ có dữ liệu làm đầu vào, đọc dữ liệu từ Máy Va chạm Hadron Lớn ở định dạng byte, chuyển đổi dữ liệu này thành văn bản, ghi nó vào một tệp và in nó. Ngay cả phần mô tả của phương thức cũng trông rùng rợn chứ chưa nói đến mã :) Để tăng khả năng đọc mã, tốt nhất là không nên viết logic phức tạp của phương thức ở một nơi mà ngược lại, hãy phá vỡ chức năng thành các phương pháp riêng biệt. Ví dụ: phương thức này readByteData()chịu trách nhiệm đọc dữ liệu, convertBytesToSymbols()chuyển đổi dữ liệu đọc được từ trình thu thập dữ liệu thành văn bản, saveToFile()lưu văn bản kết quả vào một tệp và printColliderData()in tệp dữ liệu của chúng tôi. Phương pháp readDataFromCollider()cuối cùng sẽ đơn giản hơn nhiều:
public class ColliderUtil {

   public void readDataFromCollider(Path pathToData) {
       byte[] colliderData = readByteData(pathToData);
       String[] textData = convertBytesToSymbols(colliderData);
       File fileWithData = saveToFile(textData);
       printColliderData(fileWithData);
   }

   public byte[] readByteData(Path pathToData) {

       // reads data in bytes
   }

   public String[] convertBytesToSymbols(byte[] colliderDataInBytes) {

       // convert bytes to characters
   }

   public File saveToFile(String[] colliderData) {

       // save the read data to a file
   }

   public void printColliderData(File fileWithColliderData) {

       // print data from file
   }
}
Tuy nhiên, như bạn nhớ trong bài giảng về giao diện, người dùng chỉ có quyền truy cập vào giao diện cuối cùng. Và 4 phương pháp của chúng tôi không phải là một phần của nó. Chúng mang tính bổ trợ : chúng tôi tạo ra chúng để cải thiện khả năng đọc mã và tránh nhồi nhét bốn tác vụ khác nhau vào một phương thức. Không cần phải cấp cho người dùng quyền truy cập vào các phương pháp này. Nếu người dùng có quyền truy cập vào phương thức khi làm việc với máy va chạm convertBytesToSymbols(), rất có thể anh ta sẽ không hiểu phương thức này là gì và tại sao nó lại cần thiết. Những byte nào được chuyển đổi? Họ đến từ đâu vậy? Tại sao chuyển đổi chúng thành văn bản? Logic chạy trong phương thức này không phải là một phần của giao diện người dùng. Chỉ có phương thức readDataFromCollider()là một phần của giao diện. Phải làm gì với bốn phương pháp "nội bộ" này? Phải! Hạn chế quyền truy cập vào chúng bằng công cụ sửa đổi private. Bằng cách này, họ có thể dễ dàng thực hiện công việc của mình trong lớp và không gây nhầm lẫn cho người dùng, những người không cần logic của từng người trong số họ một cách riêng biệt.
public class ColliderUtil {

   public void readDataFromCollider(Path pathToData) {
       byte[] colliderData = readByteData(pathToData);
       String[] textData = convertBytesToSymbols(colliderData);
       File fileWithData = saveToFile(textData);
       printColliderData(fileWithData);
   }

   private byte[] readByteData(Path pathToData) {
       // reads data in bytes
   }

   private String[] convertBytesToSymbols(byte[] colliderDataInBytes) {
       // convert bytes to characters
   }

   private File saveToFile(String[] colliderData) {
       // save the read data to a file
   }

   private void printColliderData(File fileWithColliderData) {
       // print data from file
   }
}

Bảo vệ sửa đổi

Công cụ sửa đổi truy cập hạn chế nhất tiếp theo là protected. Truy cập các công cụ sửa đổi.  Riêng tư, được bảo vệ, mặc định, công khai - 3 Các trường và phương thức được chỉ định bằng công cụ sửa đổi truy cập protectedsẽ hiển thị:
  • trong tất cả các lớp nằm trong cùng gói với gói của chúng tôi;
  • trong tất cả các lớp kế thừa của lớp chúng tôi.
Thật khó để tưởng tượng khi nào điều này có thể cần thiết. Đừng ngạc nhiên: protectedcó ít trường hợp áp dụng hơn nhiều privatevà chúng rất cụ thể. Hãy tưởng tượng rằng chúng ta có một lớp trừu tượng AbstractSecretAgentbiểu thị một đặc vụ bí mật của một cơ quan tình báo nào đó, cũng như một gói top_secretchứa lớp này và các hậu duệ của nó. Các lớp cụ thể - FBISecretAgent, MI6SecretAgent, MossadSecretAgentv.v. - được kế thừa từ nó. Bên trong lớp trừu tượng, chúng tôi muốn triển khai bộ đếm tác nhân. Khi một đối tượng tác nhân mới được tạo ở đâu đó trong chương trình, nó sẽ tăng lên.
package top_secret;

public abstract class AbstractSecretAgent {

   public static int agentCount = 0;
}
Nhưng đặc vụ của chúng tôi là bí mật! Điều này có nghĩa là chỉ có họ chứ không ai khác được biết về số lượng của họ. Chúng ta có thể dễ dàng thêm một công cụ sửa đổi protectedvào trường agentCountvà sau đó các đối tượng của các lớp đặc vụ bí mật khác hoặc các lớp nằm trong gói “bí mật” của chúng ta có thể nhận được giá trị của nó top_secret.
public abstract class AbstractSecretAgent {

   protected static int agentCount = 0;
}
Đối với những nhiệm vụ cụ thể như vậy thì cần có một công cụ sửa đổi protected:)

gói sửa đổi hiển thị

Tiếp theo trong danh sách của chúng tôi là công cụ sửa đổi defaulthoặc, như nó còn được gọi là, package visible. Nó không được biểu thị bằng từ khóa vì nó được đặt theo mặc định trong Java cho tất cả các trường và phương thức. Nếu bạn viết mã của mình -
int x = 10;
... biến xsẽ có cùng package visiblequyền truy cập này. Nếu một phương thức (hoặc biến) không được đánh dấu bằng bất kỳ công cụ sửa đổi nào, thì nó được coi là được đánh dấu bằng "công cụ sửa đổi mặc định". Các biến hoặc phương thức có công cụ sửa đổi như vậy (tức là không có bất kỳ công cụ sửa đổi nào) sẽ hiển thị đối với tất cả các lớp của gói mà chúng được khai báo. Và chỉ với họ. Công dụng của nó bị hạn chế, giống như công cụ sửa đổi protected. Thông thường, default-access được sử dụng trong gói trong đó có một số lớp tiện ích không triển khai chức năng của tất cả các lớp khác trong gói này. Hãy đưa ra một ví dụ. Hãy tưởng tượng chúng ta có một gói " services ". Bên trong nó có nhiều lớp khác nhau làm việc với cơ sở dữ liệu. Ví dụ: có một lớp UserServiceđọc dữ liệu người dùng từ cơ sở dữ liệu, một lớp CarServiceđọc dữ liệu về ô tô từ cùng một cơ sở dữ liệu và các lớp khác, mỗi lớp làm việc với loại đối tượng riêng và đọc dữ liệu về chúng từ cơ sở dữ liệu.
package services;

public class UserService {
}

package services;

public class CarService {
}
Tuy nhiên, một tình huống có thể dễ dàng xảy ra khi dữ liệu trong cơ sở dữ liệu ở một định dạng nhưng chúng ta lại cần nó ở một định dạng khác. Hãy tưởng tượng rằng ngày sinh của người dùng trong cơ sở dữ liệu được lưu trữ ở định dạng DẤU THỜI GIAN VỚI MÚC THỜI GIAN...
2014-04-04 20:32:59.390583+02
...thay vào đó chúng ta cần đối tượng đơn giản nhất - java.util.Date. Với mục đích này, chúng ta có thể tạo servicesmột lớp đặc biệt bên trong gói Mapper. Anh ta sẽ chịu trách nhiệm chuyển đổi dữ liệu từ cơ sở dữ liệu sang các đối tượng Java mà chúng ta quen thuộc. Một lớp trợ giúp đơn giản. Chúng ta thường tạo tất cả các lớp dưới dạng public class ClassName, nhưng điều này không cần thiết. Chúng ta có thể khai báo lớp người trợ giúp của mình một cách đơn giản là class Mapper. Trong trường hợp này, nó vẫn thực hiện công việc của mình nhưng không ai nhìn thấy được bên ngoài gói services!
package services;

class Mapper {
}


package services;

public class CarService {

   Mapper mapper;
}
Và trên thực tế, đây là logic đúng: tại sao ai đó ở bên ngoài gói lại thấy một lớp phụ trợ chỉ hoạt động với các lớp của cùng một gói?

công cụ sửa đổi công khai

Và cuối cùng trong danh sách nhưng không kém phần quan trọng - công cụ sửa đổi public! Bạn đã gặp anh ấy vào ngày đầu tiên học tại JavaRush, khi ra mắt public static void main(String[] args). Truy cập các công cụ sửa đổi.  Riêng tư, được bảo vệ, mặc định, công khai - 4 Bây giờ bạn đã nghiên cứu các bài giảng về giao diện, bạn đã rõ mục đích của nó :) Suy cho cùng, publicnó được tạo ra để cung cấp thứ gì đó cho người dùng. Ví dụ: giao diện chương trình của bạn. Giả sử bạn đã viết một chương trình dịch và nó có thể dịch văn bản tiếng Nga sang tiếng Anh. Bạn đã tạo một phương thức translate(String textInRussian)trong đó logic cần thiết được triển khai. Bạn đã đánh dấu phương thức này bằng từ public, và bây giờ nó sẽ trở thành một phần của giao diện:
public class Translator {

   public String translate(String textInRussian) {

       // translates text from Russian to English
   }
}
Bạn có thể liên kết cuộc gọi với phương thức này bằng nút “dịch” trên màn hình chương trình - và thế là xong! Bất cứ ai cũng có thể sử dụng nó. Các phần của mã được đánh dấu bằng công cụ sửa đổi publiclà dành cho người dùng cuối. Lấy một ví dụ từ cuộc sống, privateđây là tất cả các quá trình xảy ra bên trong TV khi nó hoạt động và publicđây là các nút trên điều khiển từ xa của TV mà người dùng có thể điều khiển nó. Đồng thời, anh ta không cần biết TV hoạt động như thế nào và hoạt động như thế nào. Điều khiển từ xa là một tập hợp publiccác phương thức: on(), off(), nextChannel(), previousChannel(), increaseVolume(), decreaseVolume()v.v.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION