Java ‘protected’ Access Modifier – Java ‘protected’访问修改器

最后修改: 2019年 10月 20日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In the Java programming language, fields, constructors, methods, and classes can be marked with access modifiers. In this tutorial, we’ll look at protected access.

在Java编程语言中,字段、构造函数、方法和类都可以用访问修饰符标记。在本教程中,我们将讨论受保护的访问。

2. The protected Keyword

2.受保护的关键词

While elements declared as private can be accessed only by the class in which they’re declared, the protected keyword allows access from sub-classes and members of the same package.

虽然声明为private的元素只能被其声明的类所访问,protected关键字允许来自同一包的子类和成员的访问。

By using the protected keyword, we make decisions about which methods and fields should be considered internals of a package or class hierarchy, and which are exposed to outside code.

通过使用protected关键字,我们决定哪些方法和字段应被视为包或类层次结构的内部成员,而哪些则暴露给外部代码。

3. Declaring protected Fields, Methods, and Constructors

3.声明保护的域、方法和构造器

First, let’s create a class named FirstClass containing a protected field, method, and constructor:

首先,让我们创建一个名为FirstClass的类,包含一个受保护字段、方法和构造函数。

public class FirstClass {

    protected String name;

    protected FirstClass(String name) {
        this.name = name;
    }

    protected String getName() {
        return name;
    }
}

With this example, by using the protected keyword, we’ve granted access to these fields to classes in the same package as FirstClass and to sub-classes of FirstClass.

在这个例子中,通过使用protected关键字,我们授权与FirstClass处于同一包的类以及FirstClass的子类访问这些字段。

4. Accessing protected Fields, Methods, and Constructors

4.访问受保护的域、方法和构造器

4.1. From the Same Package

4.1.来自同一软件包

Now, let’s see how we can access protected fields by creating a new GenericClass declared in the same package as FirstClass:

现在,让我们看看如何通过创建一个新的GenericClassFirstClass在同一个包中声明来访问受保护的字段。

public class GenericClass {

    public static void main(String[] args) {
        FirstClass first = new FirstClass("random name");
        System.out.println("FirstClass name is " + first.getName());
        first.name = "new name";
    }
}

As this calling class is in the same package as FirstClass, it’s allowed to see and interact with all the protected fields, methods, and constructors.

由于这个调用类与FirstClass在同一个包中,它被允许看到并与所有受保护的字段、方法和构造函数互动。

4.2. From a Different Package

4.2.来自不同的软件包

Let’s now try to interact with these fields from a class declared in a different package from FirstClass:

现在,让我们尝试从一个与FirstClass不同包中声明的类中与这些字段进行交互。

public class SecondGenericClass {

    public static void main(String[] args) {
        FirstClass first = new FirstClass("random name");
        System.out.println("FirstClass name is "+ first.getName());
        first.name = "new name";
    }
}

As we can see, we get compilation errors:

我们可以看到,我们得到了编译错误

The constructor FirstClass(String) is not visible
The method getName() from the type FirstClass is not visible
The field FirstClass.name is not visible

That’s exactly what we were expecting by using the protected keyword.  This is because SecondGenericClass is not in the same package as FirstClass and does not subclass it.

这正是我们通过使用protected关键字所期望的。 这是因为SecondGenericClassFirstClass不在同一个包中,也没有对它进行子类化。

4.3. From a Sub-Class

4.3.来自一个子类

Let’s now see what happens when we declare a class extending FirstClass but declared in a different package:

现在让我们看看当我们声明一个扩展FirstClass但在不同的包中声明的类会发生什么

public class SecondClass extends FirstClass {
    
    public SecondClass(String name) {
        super(name);
        System.out.println("SecondClass name is " + this.getName());
        this.name = "new name";
    } 
}

As expected, we can access all the protected fields, methods, and constructors. This is because SecondClass is a sub-class of FirstClass.

正如所料,我们可以访问所有受保护的字段、方法和构造函数。这是因为SecondClassFirstClass的一个子类。

5. protected Inner Class

5.受保护的内类

In the previous examples, we saw protected fields, methods, and constructors in action. There is one more particular case — a protected inner class.

在前面的例子中,我们看到了受保护的字段、方法和构造函数的作用。还有一种特殊情况–受保护的内类。

Let’s create this empty inner class inside our FirstClass:

让我们在我们的FirstClass内创建这个空的内类。

package com.baeldung.core.modifiers;

public class FirstClass {

    // ...

    protected static class InnerClass {

    }
}

As we can see, this is a static inner class, and so can be constructed from outside of an instance of FirstClass. However, as it is protected, we can only instantiate it from code in the same package as FirstClass.

我们可以看到,这是一个静态的内部类,所以可以从FirstClass的实例之外构建。然而,由于它是受保护的我们只能从与FirstClass相同包的代码中实例化它。

5.1. From the Same Package

5.1.来自同一软件包

To test this, let’s edit our GenericClass:

为了测试这一点,让我们编辑我们的GenericClass

public class GenericClass {

    public static void main(String[] args) {
        // ...
        FirstClass.InnerClass innerClass = new FirstClass.InnerClass();
    }
}

As we can see, we can instantiate the InnerClass without any problem because GenericClass is in the same package as FirstClass.

我们可以看到,我们可以毫无问题地实例化InnerClass,因为GenericClassFirstClass在同一个包中。

5.2. From a Different Package

5.2.来自不同的软件包

Let’s try to instantiate an InnerClass from our SecondGenericClass which, as we remember, is outside FirstClass’ package:

让我们试着从我们的SecondGenericClass实例化一个InnerClass,正如我们所记得的,它在FirstClass’包之外。

public class SecondGenericClass {

    public static void main(String[] args) {
        // ...

        FirstClass.InnerClass innerClass = new FirstClass.InnerClass();
    }
}

As expected, we get a compilation error:

正如预期的那样,我们得到一个编译错误

The type FirstClass.InnerClass is not visible

5.3. From a Sub-Class

5.3.来自于一个子类

Let’s try to do the same from our SecondClass:

让我们尝试从我们的SecondClass做同样的事情。

public class SecondClass extends FirstClass {
    
    public SecondClass(String name) {
        // ...
 
        FirstClass.InnerClass innerClass = new FirstClass.InnerClass();
    }     
}

We were expecting to instantiate our InnerClass with ease. However, we are getting a compilation error here too:

我们本以为可以轻松地实例化我们的InnerClass。然而,我们在这里也得到了一个编译错误:

The constructor FirstClass.InnerClass() is not visible

Let’s take a look at our InnerClass declaration:

让我们看一下我们的InnerClass声明。

protected static class InnerClass {
}

The main reason we are getting this error is that the default constructor of a protected class is implicitly protected. In addition, SecondClass is a sub-class of FirstClass but is not a sub-class of InnerClass.  Finally, we also declared SecondClass outside FirstClass’ package.

我们得到这个错误的主要原因是:一个受保护类的默认构造函数是隐含的受保护。此外,SecondClass 是FirstClass的一个子类,但不是InnerClass的一个子类。 最后,我们也声明了SecondClassFirstClass’包之外。

For all these reasons, SecondClass can’t access the protected InnerClass constructor.

由于所有这些原因,SecondClass不能访问protected InnerClass构造函数。

If we wanted to solve this issue and allow our SecondClass to instantiate an InnerClass object, we could explicitly declare a public constructor:

如果我们想解决这个问题并允许我们的SecondClass实例化一个InnerClass对象,我们可以明确地声明一个公共构造函数

protected static class InnerClass {
    public InnerClass() {
    }
}

By doing this, we no longer get a compilation error, and we can now instantiate an InnerClass from SecondClass.

通过这样做,我们不再得到一个编译错误,而且我们现在可以从SecondClass实例化一个InnerClass

6. Conclusion

6.结论

In this quick tutorial, we discussed the protected access modifier in Java. With it, we can ensure exposing only the required data and methods to sub-classes and classes in the same package.

在这个快速教程中,我们讨论了Java中的protected访问修改器。有了它,我们可以确保只将所需的数据和方法暴露给同一包中的子类和类。

As always, the example code is available over on GitHub.

像往常一样,示例代码可在GitHub上获得