CodeGym /Java 博客 /随机的 /Java 中的访问修饰符
John Squirrels
第 41 级
San Francisco

Java 中的访问修饰符

已在 随机的 群组中发布
你好!在今天的课程中,我们将熟悉访问修饰符的概念,并考虑如何使用它们的示例。当然,说“熟悉”并不完全正确:您已经从之前的课程中熟悉其中的大部分内容。为了以防万一,让我们回顾一下最重要的一点。修饰符访问通常是关键字,用于调节对代码不同部分的访问。为什么是“最经常”?因为其中之一是默认设置的,没有使用关键字 :) Java 有四个访问修饰符。我们按照从最严格到最“宽松”的顺序列出它们:
  • 私人的;
  • 默认(包可见);
  • 受保护;
  • 民众。
让我们看一下它们中的每一个,并确定它们何时可能有用。我们将举例说明 :)

私有修饰符

访问修饰符。 私有、受保护、默认、公共 - 2private是最严格的访问修饰符。它将数据和方法的可见性限制在单个类中。您从关于 getter 和 setter 的课程中​​知道了这个修饰符。还记得这个例子吗?

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;
   }
}
我们在上一课中考虑过它。我们在这里犯了一个严重的错误:我们公开了我们的数据,这使得其他程序员可以直接访问这些字段并更改它们的值。更重要的是......这些值是在没有任何检查的情况下分配的。这意味着我们的程序可以创建一只名为“”的猫,年龄为-1000 岁,体重为 0。为了解决这个问题,我们使用了 getter 和 setter,还使用了 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) {
       // input parameter check
       this.name = name;
   }

   public int getAge() {
       return age;
   }

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

   public int getWeight() {
       return weight;
   }

   public void setWeight(int weight) {
       // input parameter check
       this.weight = weight;
   }
}
基本上,限制对字段的访问和实现 getter 和 setter 是最常见的私有化示例会用到实际工作中。也就是说,这个修饰符的主要目的是在程序中实现封装。顺便说一句,这不仅适用于字段。想象一下,在您的程序中有一个方法可以实现一些非常复杂的功能。我们可以举个例子吗?假设您的 readDataFromCollider() 方法接受数据地址作为输入,以字节格式从大型强子对撞机读取数据,将此数据转换为文本,将其写入文件并打印。连方法的描述看起来都吓人,更不用说代码了:) 为了使代码更具可读性,最好不要将所有方法的复杂逻辑都写在一个地方。相反,我们应该将功能分解为单独的方法。例如,readByteData()方法负责读取数据,convertBytesToSymbols()方法将从collider读取的数据转换为文本,saveToFile()方法将接收到的文本保存到文件中,printColliderData ()方法打印我们的数据文件。最后,我们的readDataFromCollider()方法会简单得多:

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) {

       // Converts bytes to characters
   }

   public File saveToFile(String[] colliderData) {

       // Saves read data to a file
   }

   public void printColliderData(File fileWithColliderData) {

       // Prints data from the file
   }
}
但是,正如您从有关接口的课程中所记得的那样,用户只能访问外部接口。而我们的4个方法不在其中。它们是辅助方法:我们创建它们是为了提高代码的可读性,而不是将四个不同的任务塞进一个方法中。您不需要授予用户访问这些方法的权限。如果用户在使用碰撞器时可以访问convertBytesToSymbols()方法,他们很可能只是对该​​方法感到困惑,并想知道它的用途。转换了哪些字节?哪儿来的呢?为什么要将它们转换为文本?在此方法中执行的逻辑不是向用户公开的界面的一部分。只有readDataFromCollider()方法是接口的一部分。那么我们如何处理这四种“内部”方法呢?正确的!使用private修饰符来限制对它们的访问。这样做允许他们在类中和平地执行他们的工作,而不会混淆用户,用户不需要知道每个单独方法的逻辑。

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) {
       // Converts bytes to characters
   }

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

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

受保护修饰符

下一个最严格的修饰符是protected受保护访问修饰符。 私有、受保护、默认、公共 - 3访问修饰符标记的字段和方法将可见:
  • 在与我们相同的包中包含的所有类中;
  • 在继承我们类的所有类中。
起初,很难想象什么时候可能需要这样做。不要感到惊讶:protected的用例远少于private 的用例,而且它们非常具体。想象一下,我们有一个AbstractSecretAgent抽象类,它表示某个情报服务中的秘密代理人,以及一个包含此类及其后代的top_secret包。FBISecretAgentMI6SecretAgentMossadSecretAgent等具体类都继承了它。在抽象类内部,我们要实现一个代理计数器。当在程序某处创建新代理时,它会增加。包绝密;

public abstract class AbstractSecretAgent {

   public static int agentCount = 0;
}
但我们的特工是保密的!这意味着他们而不是其他人应该知道其中有多少存在。我们可以轻松地将protected修饰符添加到agent_counter字段。然后其他秘密特工类和位于我们的top_secret包中的其他类的实例可以获取它的值。

public abstract class AbstractSecretAgent {

   protected static int agent_counter = 0;
}
这就是需要protected修饰符 的专门任务:)

包可见修饰符

列表中的下一个是默认修饰符,也称为包可见修饰符。它不是由关键字指示的,因为 Java 默认将它应用于所有字段和方法。如果您在代码中编写以下内容:

int x = 10
x 变量将具有此包可见访问权限。很容易记住它的作用。基本上,default = protected inheritance :) 和protected修饰符一样,它的应用是有限的。大多数情况下,默认访问用于包含一些实用程序类的包中,这些实用程序类未实现包中所有其他类的功能。让我们举个例子。想象一下,我们有一个“服务”包。它包含各种与数据库一起工作的类。比如有一个从数据库中读取用户数据的UserService类,一个CarService从同一数据库和其他类读取汽车数据的类,每个类都使用特定类型的对象并从数据库中读取相应的数据。

package services;

public class UserService {
}

package services;

public class CarService {
}
但是数据库中的数据很容易是一种格式,而我们需要另一种格式。假设用户的生日在数据库中存储为 <TIMESTAMP WITH TIME ZONE>...

2014-04-04 20:32:59.390583+02
...相反,我们需要最简单的对象 — java.util.Date。为了解决这个问题,在services包里面,我们可以创建一个特殊的Mapper类。它将负责将数据从数据库转换为我们熟悉的 Java 对象。一个简单的帮助类。我们通常将所有类都声明为public class ClassName,但这不是必需的。我们可以将我们的助手类简单地声明为class Mapper在这种情况下,它仍然可以正常工作,但服务包之外的任何人都看不到它!

package services;

class Mapper {
}


package services;

public class CarService {

   Mapper mapper;
}
这是基本的推理:为什么包外的任何人都需要看到一个仅适用于该包中的类的助手类?

公共修饰符

最后但同样重要的是,公共修饰符!您在学习 CodeGym 的第一天第一次运行public static void main(String[] args) 时遇到了这个修饰符。 访问修饰符。 私有、受保护、默认、公共 - 4现在您已经学习了有关接口的课程,其目的对您来说是显而易见的 :) 毕竟,创建public修饰符是为了向用户提供一些东西。例如,您的程序的界面。假设您编写了一个可以将俄语文本翻译成英语的翻译程序。您创建了一个实现所有必要逻辑的translate(String textInRussian)方法。您用public这个词标记了这个方法,现在它是接口的一部分:

public class Translator {

   public String translate(String textInRussian) {

       // Translates text from Russian to English
   }
}
您可以将此方法绑定到屏幕上的“翻译”按钮,您就完成了!任何人都可以使用它。标有public修饰符的代码部分供最终用户使用。举一个真实的例子,private是针对电视内部发生的所有进程,而public是针对遥控器上用于管理电视的按钮。更重要的是,用户不需要知道电视是如何制造的或它是如何工作的。遥控器是一组公共方法:on()off()nextChannel()previousChannel()increaseVolume()decreaseVolume()等。 为了巩固您所学的知识,我们建议您观看我们的 Java 课程中的视频课程
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION