public 访问修饰符
public 是 Java 中最宽松的访问修饰符,当您将一个成员(变量、方法或构造函数)声明为 public 时,它意味着:
该成员可以被任何其他类访问,无论这些类位于同一个包中,还是位于不同的包中。
public 在继承中的具体表现
继承的核心是“is-a”(是一个)关系,子类会继承父类的所有成员,但访问权限会受到修饰符的限制。public 成员是其中最容易访问的。
继承 public 方法
这是最常见的情况,子类会继承父类的 public 方法,并且这些方法在子类中仍然是 public 的,子类可以直接调用这些方法,也可以选择重写它们。
示例代码:
// 父类 Animal.java
package com.example.inheritance;
public class Animal {
// 这是一个 public 方法
public void eat() {
System.out.println("This animal is eating.");
}
public void sleep() {
System.out.println("This animal is sleeping.");
}
}
// 子类 Dog.java,与 Animal 在同一个包中
package com.example.inheritance;
public class Dog extends Animal {
// Dog 类继承了 Animal 的所有 public 方法
// 我们可以直接调用它们
public void bark() {
System.out.println("The dog is barking.");
}
}
// 另一个包中的类 Main.java
package com.example.test;
// 需要导入父类所在的包
import com.example.inheritance.Animal;
import com.example.inheritance.Dog;
public class Main {
public static void main(String[] args) {
// 创建 Dog 的实例
Dog myDog = new Dog();
// 因为 eat() 是 public 的,所以可以在任何地方被调用
myDog.eat(); // 输出: This animal is eating.
myDog.sleep(); // 输出: This animal is sleeping.
myDog.bark(); // 输出: The dog is barking.
}
}
分析:
即使 Main 类和 Animal、Dog 不在同一个包中,只要通过 import 语句导入了 Animal,就可以创建 Dog 的实例并直接调用其从 Animal 继承来的 public 方法。
继承 public 字段(成员变量)
子类同样会继承父类的 public 字段,并且这些字段在子类中也是 public 的。
示例代码:
// 父类 Vehicle.java
package com.example.inheritance;
public class Vehicle {
// 这是一个 public 字段
public String brand;
public Vehicle(String brand) {
this.brand = brand;
}
}
// 子类 Car.java
package com.example.inheritance;
public class Car extends Vehicle {
public int numberOfDoors;
public Car(String brand, int doors) {
// 使用 super 调用父类的构造函数来初始化继承来的 brand 字段
super(brand);
this.numberOfDoors = doors;
}
public void displayInfo() {
// 可以直接访问继承来的 public 字段 brand
System.out.println("Car Brand: " + this.brand);
System.out.println("Number of Doors: " + this.numberOfDoors);
}
}
// 测试类 Main.java
package com.example.test;
import com.example.inheritance.Car;
public class Main {
public static void main(String[] args) {
Car myCar = new Car("Toyota", 4);
// 直接访问 public 字段 brand
System.out.println("Brand from outside: " + myCar.brand); // 输出: Brand from outside: Toyota
myCar.displayInfo();
// 输出:
// Car Brand: Toyota
// Number of Doors: 4
}
}
分析:
Main 类可以直接访问 Car 实例的 brand 字段,因为它继承自 Vehicle 并且是 public 的,这通常被认为是不好的实践,因为它破坏了封装性(Encapsulation),更好的做法是通过 public 的 getter 和 setter 方法来访问和修改私有字段。
public 与其他继承相关修饰符的对比
为了更好地理解 public 在继承中的角色,我们把它和 protected、默认(包私有)以及 private 进行对比。
假设有一个父类 Parent:
package com.example.parent;
public class Parent {
public int publicVar = 1;
protected int protectedVar = 2;
int defaultVar = 3; // 默认,包私有
private int privateVar = 4;
}
和一个子类 Child:
package com.example.child; // 不同的包
import com.example.parent.Parent;
public class Child extends Parent {
public void accessParentMembers() {
System.out.println("publicVar: " + publicVar); // 可以访问
System.out.println("protectedVar: " + protectedVar); // 可以访问
// System.out.println("defaultVar: " + defaultVar); // 编译错误!不在同一个包
// System.out.println("privateVar: " + privateVar); // 编译错误!父类私有成员无法继承
}
}
| 修饰符 | 在同一个包的子类 | 在不同包的子类 | 在非子类中 | 说明 |
|---|---|---|---|---|
public |
可以访问 | 可以访问 | 可以访问 | 权限最广,任何地方都可以访问。 |
protected |
可以访问 | 可以访问 | 不可以访问 | 提供给子类和同包类访问的“受保护”权限。 |
| 默认 (无修饰符) | 可以访问 | 不可以访问 | 不可以访问 | 仅限于同一个包内的类访问。 |
private |
不可以访问 | 不可以访问 | 不可以访问 | 仅在声明它的类内部可见,不能被继承。 |
- 最高权限:
public是 Java 中访问权限最高的修饰符。 - 完全可继承:父类的
public成员(方法和字段)会被子类完整地继承下来,并且在子类中仍然是public的。 - 跨包访问:
public成员是唯一一个允许在不同包的类中被直接访问的成员(除了protected,但它对非子类有限制)。 - 实践建议:虽然
public字段可以被子类和外部类直接访问,但这会破坏封装性,在良好的面向对象设计中,通常将字段设为private,然后提供public的getter和setter方法来控制对它们的访问,这样可以在方法内部添加验证逻辑,确保对象状态的完整性。
简单记:
- 想让一个成员在整个项目中都能被使用(包括被所有子类使用),就把它声明为
public。 - 想让一个成员只在“有血缘关系”(子类)和“住在一个小区”(同包)的类中使用,就把它声明为
protected。 - 想让一个成员只在“住在一个小区”(同包)的类中使用,就使用默认修饰符。
- 想让一个成员只在“自己家”(本类)里使用,就把它声明为
private。
