protected 和默认,都能被子类访问吗
在 Java 中,protected
和默认(包级私有,无显式修饰符)的成员能否被子类访问,取决于子类与父类是否在同一个包中。以下是具体规则和对比:
一、protected
修饰符
protected
成员的访问范围:
-
同包内的所有类(包括非子类)可以访问。
-
不同包中的子类(无论是否直接继承)可以访问。
关键点:protected
允许跨包的子类访问父类成员。
示例:跨包子类访问 protected
成员
// 父类在包 com.example.parent
package com.example.parent;public class Parent {protected String protectedField = "protected 字段";protected void protectedMethod() {System.out.println("protected 方法");}
}// 子类在包 com.example.child(不同包)
package com.example.child;import com.example.parent.Parent;public class Child extends Parent {public void accessProtected() {System.out.println(protectedField); // 允许访问(跨包子类)protectedMethod(); // 允许访问(跨包子类)}
}
结果:子类 Child
可以正常访问父类的 protected
字段和方法。
二、默认修饰符(包级私有)
默认修饰符(无显式关键字,如 String defaultField;
)的成员访问范围:
-
仅同包内的类(包括子类)可以访问。
-
不同包中的子类无法访问(即使子类继承了父类)。
示例:跨包子类无法访问默认成员
// 父类在包 com.example.parent
package com.example.parent;public class Parent {String defaultField = "默认字段"; // 默认修饰符void defaultMethod() { // 默认修饰符System.out.println("默认方法");}
}// 子类在包 com.example.child(不同包)
package com.example.child;import com.example.parent.Parent;public class Child extends Parent {public void accessDefault() {// System.out.println(defaultField); // 编译错误:无法访问默认字段// defaultMethod(); // 编译错误:无法访问默认方法}
}
结果:子类 Child
(跨包)无法访问父类的默认修饰符成员。
三、同包子类的情况
如果子类与父类在同一个包中:
-
protected
和默认修饰符的成员都可以被访问(因为默认修饰符允许同包访问)。
示例:同包子类访问两种成员
// 父类和子类都在包 com.example.same
package com.example.same;public class Parent {protected String protectedField = "protected 字段";String defaultField = "默认字段";
}public class Child extends Parent {public void accessMembers() {System.out.println(protectedField); // 允许(protected)System.out.println(defaultField); // 允许(默认,同包)}
}
结果:同包子类可以访问父类的 protected
和默认成员。
四、总结对比表
修饰符 | 同包子类访问 | 跨包子类访问 | 同包非子类访问 |
---|---|---|---|
| ✅ 允许 | ✅ 允许 | ✅ 允许 |
默认(包级) | ✅ 允许 | ❌ 不允许 | ✅ 允许 |
五、实际开发建议
-
如果希望子类(无论是否跨包)能访问父类成员,用
protected
。 -
如果仅希望同包内的子类或类访问,用默认修饰符(限制更严格)。
-
抽象类中定义公共逻辑时,若子类可能跨包,优先用
protected
修饰需要被子类使用的方法或字段(如之前提到的依赖注入字段)。
结论:
-
protected
成员可以被所有子类(无论是否跨包)访问。 -
默认修饰符成员只能被同包子类访问,跨包子类无法访问。