Java 是一种面向对象的编程语言,面向对象编程(Object-Oriented Programming,OOP)是一种编程范式,它将数据和操作数据的方法封装在一起,形成对象,通过对象之间的交互来实现程序的功能
在 Java 中,类是面向对象编程的核心概念,它是创建对象的蓝图和模板。
类的定义
在 Java 里,类的定义使用 class
关键字,基本语法如下:
修饰符 class 类名 {
// 类的成员
// 成员变量(属性)
// 成员方法(行为)
// 构造方法
}
访问控制修饰符
public
- 含义:
public
是最宽松的访问修饰符。使用public
修饰的类可以被任何其他类访问,无论这些类位于哪个包中。
package com.example.pkg1;
public class PublicClass {
public void display() {
System.out.println("This is a public class.");
}
}
在任何包的 Java 类中,都可以创建 PublicClass
的实例并调用其方法:
package com.example.pkg2;
import com.example.pkg1.PublicClass;
public class AnotherClass {
public static void main(String[] args) {
PublicClass obj = new PublicClass();
obj.display();
}
}
默认(无修饰符)
- 含义:如果一个类没有使用任何访问修饰符,那么它具有默认的访问权限,也称为包级私有。这意味着该类只能被同一个包中的其他类访问。
去掉上例中的 public。
把AnotherClass移动到pkg1下。就又可以正常访问了
非访问控制修饰符
final
- 含义:当
final
修饰类时,表示该类是最终类,不能被其他类继承。这常用于确保类的实现不会被修改,例如 Java 中的String
类就是final
类。 - 示例
// 定义一个 final 类
final class FinalClass {
public void printInfo() {
System.out.println("This is a final class.");
}
}
// 以下代码会编译错误,因为 FinalClass 不能被继承
// class SubFinalClass extends FinalClass { }
abstract
- 含义:
abstract
修饰的类是抽象类。抽象类不能被实例化,主要用于作为其他类的基类,为子类提供公共的方法和属性定义。抽象类中可以包含抽象方法(只有方法声明,没有方法体)和具体方法。 - 示例
// 定义一个抽象类
abstract class AbstractClass {
// 抽象方法
public abstract void abstractMethod();
// 具体方法
public void concreteMethod() {
System.out.println("This is a concrete method in an abstract class.");
}
}
// 子类继承抽象类并实现抽象方法
class SubAbstractClass extends AbstractClass {
@Override
public void abstractMethod() {
System.out.println("Implementing the abstract method.");
}
}
可以创建 SubAbstractClass
的实例,但不能创建 AbstractClass
的实例:
public class Main {
public static void main(String[] args) {
// AbstractClass obj = new AbstractClass(); // 编译错误
SubAbstractClass subObj = new SubAbstractClass();
subObj.abstractMethod();
subObj.concreteMethod();
}
}
其他修饰符组合
一个类可以同时使用多个修饰符,但要遵循一定的规则。例如,abstract
和 final
不能同时修饰同一个类,因为 abstract
类需要被继承来实现抽象方法,而 final
类不能被继承。常见的合法组合有 public abstract
(定义公共的抽象类)、public final
(定义公共的最终类)等。
// 定义一个公共的抽象类
public abstract class PublicAbstractClass {
public abstract void doSomething();
}
// 定义一个公共的最终类
public final class PublicFinalClass {
public void printMessage() {
System.out.println("This is a public final class.");
}
}
Public 类的唯一性限制
-
单文件仅允许一个 public 类
每个.java
文件最多只能有一个public
修饰的类,且 文件名必须与 public 类名完全一致(包括大小写)。这是 Java 编译器强制要求的规则,否则会触发编译错误。 -
设计目的
- 类加载效率:JVM 通过文件名快速定位公共类的字节码文件,若允许多个 public 类存在,会导致类加载器需遍历多个文件,降低效率。
- 接口单一性:每个文件作为编译单元,public 类代表对外暴露的接口,强制唯一性可确保代码结构清晰。
非 Public 类的灵活性
-
允许存在多个非 public 类
同一文件中可定义任意数量的非 public 类(如abstract
、final
或无修饰符类),这些类的命名不受文件名限制。 -
作用域限制
非 public 类仅在当前包内可见,无法被其他包中的代码直接引用。这种设计有助于实现模块化封装。
底层实现逻辑
-
编译生成规则
每个类(无论是否为 public)在编译后均生成独立的.class
文件。例如,若Demo.java
包含public class Demo
和class Helper
,编译后将产生Demo.class
和Helper.class
-
入口方法兼容性
主方法public static void main(String[] args)
可定义在非 public 类中,但需通过指定类名运行(如java NonPublicClassName
)。
设计哲学与最佳实践
-
代码可维护性
单一文件对应单一公共类的规则,符合面向对象的 单一职责原则,便于代码阅读和维护。 -
避免命名冲突
强制文件名与 public 类名一致,可减少不同开发者间的类名重复风险,尤其在大型项目中 -
Java 通过限制单文件的 public 类数量,优化了类加载机制,并强化了代码结构的规范性。若需多类协作,可通过内部类或包级私有类实现,而非违反文件组织规则
类的成员
成员变量(属性)
成员变量用于描述类的状态,定义在类中方法之外。可以为成员变量指定数据类型和初始值。
public class Person {
// 成员变量
String name;
int age;
}
成员方法(行为)
成员方法用于描述类的行为,定义在类中。可以有参数和返回值。
public class Person {
String name;
int age;
// 成员方法
public void sayHello() {
System.out.println("Hello, my name is " + name + ", I'm " + age + " years old.");
}
}
构造方法
构造方法是一种特殊的方法,用于创建对象时初始化对象的状态。构造方法的名称必须与类名相同,且没有返回值类型(连 void
都不能有)。
public class Person {
String name;
int age;
// 构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello() {
System.out.println("Hello, my name is " + name + ", I'm " + age + " years old.");
}
}
可以通过以下方式创建 Person
对象:
public class Main {
public static void main(String[] args) {
Person person = new Person("Alice", 20);
person.sayHello();
}
}
访问修饰符
Java 提供了四种访问修饰符,用于控制成员变量和成员方法的访问权限:
public
:公共的,任何类都可以访问。private
:私有的,只有本类内部可以访问。protected
:受保护的,本类、同一个包中的类以及不同包中的子类可以访问。- 默认(不写修饰符):同一个包中的类可以访问。
public class Person {
private String name; // 私有成员变量
protected int age; // 受保护的成员变量
String address; // 默认访问修饰符的成员变量
public void sayHello() {
System.out.println("Hello!");
}
}
封装(Encapsulation) 是面向对象编程的核心特性之一,其核心思想是 隐藏对象的内部状态和实现细节,仅对外暴露必要的接口。通过封装,可以控制对数据的访问、提高代码的安全性和可维护性。
将对象的属性和行为包装在类中,外部只需关注如何调用接口,无需了解内部实现。
通过限制直接访问成员变量,防止无效或非法数据破坏对象状态。
外部代码仅依赖类的公共接口,内部实现的修改不会影响调用方。
案例:
class BankAccount {
//封装私有属性,不让外部做不合理的操作
private double balance;
// 通过方法控制余额增加,防止负数的出现
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
// 通过方法验证扣除金额在合理范围之内
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
}
}
}