你好!在今天的讲座中,我们将熟悉“访问修饰符”的概念并查看使用它们的示例。 尽管“让我们熟悉一下”这个词并不完全正确:您已经从之前的讲座中熟悉了其中的大多数。以防万一,让我们回顾一下主要的事情。 访问修饰符通常是调节对代码不同部分的访问级别的关键字。为什么“最经常”?因为其中之一是默认设置的,并且不是由关键字指示的:) Java中总共有四种访问修饰符。我们按照从最严格到最“软”的顺序列出它们:
- 私人的;
- 受保护;
- 默认(包可见);
- 民众
修饰符私有
Private
——最严格的访问修饰符。它限制了单个类中数据和方法的可见性。您从关于 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) {
// 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;
}
}
实际上,限制对字段的访问和实现 getter-setter 是实际工作中最常见的使用示例private
。 也就是说,在程序中实现封装是该修饰符的主要目的。 顺便说一句,这不仅适用于领域。想象一下,在您的程序中,有一个方法实现了一些非常复杂的功能。以此为例...假设您的方法readDataFromCollider()
采用一个带有数据的地址作为输入,以字节格式从大型强子对撞机读取数据,将该数据转换为文本,将其写入文件并打印。连方法的描述都显得毛骨悚然,更不用说代码了:)为了增加代码的可读性,最好不要把方法的复杂逻辑写在一处,而是相反,破坏功能分成单独的方法。例如,该方法readByteData()
负责读取数据,convertBytesToSymbols()
将从碰撞器读取的数据转换为文本,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) {
// 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
}
}
然而,正如您从界面讲座中所记得的那样,用户只能访问最终界面。而我们的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) {
// 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
}
}
修饰符保护
下一个最严格的访问修饰符是protected
. 使用访问修饰符指定的字段和方法protected
将可见:
- 在与我们的包相同的所有类中;
- 在我们班的所有后继班级中。
protected
应用案例比 少得多private
,而且很具体。想象一下,我们有一个抽象类AbstractSecretAgent
,表示某个情报机构的秘密特工,以及一个top_secret
包含该类及其后代的包。具体类 - FBISecretAgent
、MI6SecretAgent
等MossadSecretAgent
-都是从它继承的。在抽象类中,我们想要实现一个代理计数器。当程序中某处创建新的代理对象时,它会增加。
package top_secret;
public abstract class AbstractSecretAgent {
public static int agentCount = 0;
}
但我们的代理人是秘密的!这意味着只有他们自己才能知道他们的号码。protected
我们可以轻松地向字段添加修饰符agentCount
,然后其他秘密代理类的对象或位于我们的“秘密”包中的那些类都可以获取其值top_secret
。
public abstract class AbstractSecretAgent {
protected static int agentCount = 0;
}
对于此类特定任务,需要修饰符protected
:)
包可见修饰符
我们列表中的下一个是修饰符default
,或者也称为package visible
。它不是由关键字指示的,因为它是 Java 中所有字段和方法的默认设置。如果你在代码中写入 -
int x = 10;
...变量x
将具有相同的package visible
访问权限。如果方法(或变量)未使用任何修饰符进行标记,则视为使用“默认修饰符”进行标记。具有此类修饰符(即根本没有任何修饰符)的变量或方法对于声明它们的包中的所有类都是可见的。并且只对他们而言。它的用途是有限的,就像修饰符一样protected
。最常见的是,default
-access 用于一个包中,其中有一些实用程序类没有实现该包中所有其他类的功能。让我们举个例子。想象一下我们有一个“服务”包。其中包含与数据库一起使用的各种类。例如,有一个类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
. 在这种情况下,它仍然可以完成其工作,但对于包之外的任何人都看不到services
!
package services;
class Mapper {
}
package services;
public class CarService {
Mapper mapper;
}
事实上,这是正确的逻辑:为什么包外的人会看到一个只能与同一包的类一起使用的辅助类?
公共修饰符
最后,但并非最不重要的 - 修饰符public
!您在 JavaRush 学习的第一天就遇到了他,当时他正在启动public static void main(String[] args)
. 现在你已经学习了有关界面的讲座,它的目的对你来说是显而易见的:)毕竟,public
它是为了给用户一些东西而创建的。例如,您的程序的界面。假设您编写了一个翻译程序,它可以将俄语文本翻译成英语。您已经创建了一个方法,translate(String textInRussian)
在该方法中实现了必要的逻辑。您用单词 标记了该方法public
,现在它将成为接口的一部分:
public class Translator {
public String translate(String textInRussian) {
// translates text from Russian to English
}
}
您可以将此方法的调用与程序屏幕上的“翻译”按钮关联起来 - 就是这样!任何人都可以使用它。标有修饰符的部分代码public
是供最终用户使用的。举个生活中的例子,private
这些都是电视工作时内部发生的所有过程,public
这些都是电视遥控器上用户可以控制电视的按钮。同时,他也不需要知道电视的工作原理和工作原理。遥控器是一组public
方法:on()
、off()
、nextChannel()
、previousChannel()
、increaseVolume()
等decreaseVolume()
。
GO TO FULL VERSION