有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java保护的构造函数和可访问性

如果一个类的子类在不同的包中,为什么我们不能用受保护的构造函数实例化它呢?如果可以访问受保护的变量和方法,为什么同样的规则不适用于受保护的构造函数

pack1:

package pack1;

public class A {
    private int a;
    protected int b;
    public int c;

    protected A() {    
        a = 10;
        b = 20;
        c = 30;
    }
}

pack2:

package pack2;

import pack1.A;

class B extends A {
    public void test() {
        A obj = new A(); // gives compilation error; why?
        //System.out.println("print private not possible :" + a);
        System.out.println("print protected possible :" + b);
        System.out.println("print public possible :" + c);
    }
}

class C {
    public static void main(String args[]) {
        A a = new A(); // gives compilation error; why?
        B b = new B();
        b.test();
    }
}

共 (5) 个答案

  1. # 1 楼答案

    If protected variables and methods can be accessed, why doesn't the same rule also apply for a protected constructor?

    只有当另一个包中的子类扩展了包含受保护变量和方法的类时,才能访问受保护变量和方法。 您可以访问子类b中的变量“b”,因为您扩展了类A。您将无法访问类C中的变量“b”,因为它没有扩展类A

    访问子类中受保护构造函数的唯一方法是使用父类引用变量和子类对象

    package pack2;
    
    import pack1.A;
    
    class B extends A {
        public void test() {
            A obj = new B(); // will execute protected constructor
            System.out.println("print protected possible :" + b);
        }
    }
    
  2. # 2 楼答案

    我同意之前的海报,不知道为什么要这样做(在扩展类中以这种方式实例化父对象),但你甚至可以这样做:

    public void test() {
        A obj = new A(){}; // no compilation error; why? you use anonymous class 'override'
        ...
    
  3. # 3 楼答案

    根据Java规范(https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6.2.2

    6.6.2.2. Qualified Access to a protected Constructor

    Let C be the class in which a protected constructor is declared and let S be the innermost class in whose declaration the use of the protected constructor occurs. Then:

    • If the access is by a superclass constructor invocation super(...), or a qualified superclass constructor invocation E.super(...), where E is a Primary expression, then the access is permitted.

    • If the access is by an anonymous class instance creation expression new C(...){...}, or a qualified anonymous class instance creation expression E.new C(...){...}, where E is a Primary expression, then the access is permitted.

    • If the access is by a simple class instance creation expression new C(...), or a qualified class instance creation expression E.new C(...), where E is a Primary expression, or a method reference expression C :: new, where C is a ClassType, then the access is not permitted. A protected constructor can be accessed by a class instance creation expression (that does not declare an anonymous class) or a method reference expression only from within the package in which it is defined.

    在您的情况下,通过调用super()B访问受保护的A构造函数将是合法的。然而,使用new进行访问是不合法的

  4. # 4 楼答案

    JLS 6.6.7回答了您的问题。子类只访问其父类的受保护成员,如果它涉及其父类的实现。因此,如果父构造函数受保护且位于不同的包中,则不能在子类中实例化父对象

    6.6.7 Example: protected Fields, Methods, and Constructors Consider this example, where the points package declares:

    package points;
    public class Point {
        protected int x, y;
        void warp(threePoint.Point3d a) {
            if (a.z > 0)        // compile-time error: cannot access a.z
                a.delta(this);
        }
    }
    

    and the threePoint package declares:

    package threePoint;
    import points.Point;
    public class Point3d extends Point {
        protected int z;
        public void delta(Point p) {
            p.x += this.x;      // compile-time error: cannot access p.x
            p.y += this.y;      // compile-time error: cannot access p.y
        }
        public void delta3d(Point3d q) {
            q.x += this.x;
            q.y += this.y;
            q.z += this.z;
        }
    }
    

    which defines a class Point3d. A compile-time error occurs in the method delta here: it cannot access the protected members x and y of its parameter p, because while Point3d (the class in which the references to fields x and y occur) is a subclass of Point (the class in which x and y are declared), it is not involved in the implementation of a Point (the type of the parameter p). The method delta3d can access the protected members of its parameter q, because the class Point3d is a subclass of Point and is involved in the implementation of a Point3d. The method delta could try to cast (§5.5, §15.16) its parameter to be a Point3d, but this cast would fail, causing an exception, if the class of p at run time were not Point3d.

    A compile-time error also occurs in the method warp: it cannot access the protected member z of its parameter a, because while the class Point (the class in which the reference to field z occurs) is involved in the implementation of a Point3d (the type of the parameter a), it is not a subclass of Point3d (the class in which z is declared).

  5. # 5 楼答案

    为什么类中需要A obj=new A();,而类b的对象本身就是class A

    在c类中,它给出了错误,因为你正在访问A类的受保护属性,它是构造函数

    在这种情况下,要获取类A的对象,必须在类A中使用此函数

    static A getInstance()
    {
       A obj = new A(); // create obj of type A.
       return obj; // returns that object by this method. No need to use 'New' kind of instantiation.
    }