[Java 基础]类,面向对象的蓝图
首先需要区分类和对象都是啥?
类:类是一个模板,它描述一类对象的行为和状态,类这个概念更像是下定义,更像是模板(橡皮泥膜具)。
对象:对象(不是女朋友)是类的一个实例,有状态和行为(用橡皮泥膜具倒出来的一个个小人)。
拿狗这个例子来举例,狗这个概念就是类(定义了数据和动作,狗都有年龄、性别、品种等,狗都爱吃骨头、都会汪汪叫等),对象这个概念就指的是具体的一条狗。
类的数据
类中可以通过定义变量来存储数据。一个类可以包含以下类型变量:
局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
类变量:类变量也声明在类中,方法体之外,但必须声明为 static 类型(静态变量)。
public class Person {// 类变量(静态变量)static int personCount = 0;// 成员变量(实例变量)String name;int age;// 构造方法public Person(String name, int age) {// 使用成员变量this.name = name;this.age = age;// 修改类变量personCount++;}// 成员方法public void introduce() {// 局部变量String greeting = "Hello, my name is ";System.out.println(greeting + name + " and I am " + age + " years old.");}// 静态方法public static void showPersonCount() {System.out.println("Total persons created: " + personCount);}// 主方法public static void main(String[] args) {Person p1 = new Person("Alice", 30);Person p2 = new Person("Bob", 25);p1.introduce();p2.introduce();Person.showPersonCount();}
}
类中的成员变量和类变量可以通过访问修饰符来设置这些变量的可见范围:
访问修饰符 | 同一个类中 | 同一个包中 | 子类中(不同包) | 其他包中 |
---|---|---|---|---|
public | ✅ 是 | ✅ 是 | ✅ 是 | ✅ 是 |
protected | ✅ 是 | ✅ 是 | ✅ 是 | ❌ 否(但子类中可访问) |
默认(无修饰符) | ✅ 是 | ✅ 是 | ❌ 否 | ❌ 否 |
private | ✅ 是 | ❌ 否 | ❌ 否 | ❌ 否 |
类的行为
类的行为就是类可以执行哪些操作,这个操作就是方法的概念。方法就是一段可以重复使用的代码,它完成一个特定的任务。你可以把它当成一个“动作”、“功能”或者“操作指令”。
方法
假设你有一个机器人,它什么都不会,除非你教它。
你告诉它:“当我说‘洗衣服’,你就按照我说的步骤来做。”
于是你写下这些步骤:
- 打开洗衣机
- 放衣服
- 加洗衣液
- 按“开始”键
这个“洗衣服”的动作,就是一个方法,你把这套步骤起个名字叫 washClothes()
。
public void washClothes() {System.out.println("打开洗衣机");System.out.println("放衣服");System.out.println("加洗衣液");System.out.println("按开始键");
}
调用洗衣服这个方法,它就自动按照这些洗衣服的步骤执行。
方法的结构如下图所示:
方法的访问修饰符和类中的变量的访问修饰符是一致的,都是用来控制可见范围的,上面讲过了。
这里使用了 static 关键字修饰了方法,表明这个方法是静态方法,这个方法属于类本身,而不是类的任何特定实例(对象)。
构造方法
每个类都有构造方法。如果没有显式地为类定义构造方法,Java 编译器将会为该类提供一个默认构造方法。在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法。
public class Person{public Person(){}public Person(String name){// 这个构造器仅有一个参数:name}
}
上面这个 Person 类有两个构造方法,一个是无参构造方法,一个是有参构造方法。
:::danger
在 Java 中的每个类都至少有一个构造方法。如果在 Java 中没有定义构造方法,系统会自动为这个类创建一个默认的构造方法。这个默认的构造方法没有参数,在其方法体中没有任何代码,即什么也不做。
:::
方法重载
在 Java 中,方法重载 (Method Overloading) 是指在一个类中可以定义多个方法,它们具有相同的名称,但它们的参数列表必须不同。参数列表的不同体现在以下方面:
- 参数的类型不同
- 参数的个数不同
- 参数类型的顺序不同
像上面的构造方法,它就是可以重载的。
public class Calculator {// 两个整数相加public int add(int a, int b) {System.out.println("Adding two integers");return a + b;}// 三个整数相加public int add(int a, int b, int c) {System.out.println("Adding three integers");return a + b + c;}// 两个双精度浮点数相加public double add(double a, double b) {System.out.println("Adding two doubles");return a + b;}// 一个整数和一个双精度浮点数相加(注意参数类型顺序)public double add(int a, double b) {System.out.println("Adding an integer and a double");return a + b;}// 一个双精度浮点数和一个整数相加(注意参数类型顺序)public double add(double a, int b) {System.out.println("Adding a double and an integer");return a + b;}public static void main(String[] args) {Calculator calc = new Calculator();System.out.println(calc.add(5, 10)); // 调用 add(int, int)System.out.println(calc.add(2, 3, 4)); // 调用 add(int, int, int)System.out.println(calc.add(3.5, 2.5)); // 调用 add(double, double)System.out.println(calc.add(10, 5.5)); // 调用 add(int, double)System.out.println(calc.add(7.2, 8)); // 调用 add(double, int)}
}
this 关键字
如果构造方法的入参的参数名和类的成员变量名是一样的,我们需要将入参赋值给成员变量,会导致局部变量和成员变量冲突的问题,需要使用 this 关键字代指当前的对象,通过 this 去访问当前对象的属性。
class Person {int age;public Person (int age) {this.age = age;}public int getAge () {return this.age;}
}
this 关键字代指当前的对象,也可以通过 this 调用成员方法:
class Person {public void openMouth() {...}public void speak() {this.openMouth();}
}
:::danger
这里的 this 关键字可以省略不写
:::
构造方法是在实例化对象时被 Java 虚拟机自动调用的,在程序中不能像调用其他方法一样去调用构造方法,但可以在一个构造方法中使用 “this([参数 1, 参数 2,…])” 的形式来调用其他的构造方法:
class Person {public Person() {System.out.println("无参的构造方法被调用了...");}public Person (String name) {this(); // 调用无参的构造方法System.out.println("有参的构造方法被调用了...");}
}public class Example10 {public static void main (String[] args) {Person p = new Person ("itcast"); // 实例化 Person 对象}
}
静态方法
如果方法使用了 static 关键字修饰了方法,表明这个方法是静态方法,这个方法属于类本身,而不是类的任何特定实例(对象)。
静态代码块
在 Java 类中,使用一对大括号包围起来的若干行代码被称为一个代码块,用 static 关键字修饰的代码块称为静态代码块。当类被加载时,静态代码块会执行,由于类只加载一次,因此静态代码块只执行一次。在程序中,通常会使用静态代码块来对类的成员变量进行初始化。
public class StaticBlockExample {// 静态成员变量static int count;// 静态代码块static {System.out.println("静态代码块执行了!");count = 10; // 初始化静态变量}// 构造方法public StaticBlockExample() {System.out.println("构造方法被调用!");}public static void main(String[] args) {System.out.println("main 方法开始执行");System.out.println("创建第一个对象:");StaticBlockExample obj1 = new StaticBlockExample();System.out.println("count = " + count);System.out.println("\n创建第二个对象:");StaticBlockExample obj2 = new StaticBlockExample();System.out.println("count = " + count);}
}
类的设计
一般来说,类代表的是一种概念的定义,所以,类名一般是名词。
Java 中还有包的概念,包类似于文件夹,一般会将一堆相关联的类文件放到一个包中,包名也一般是名词。
Java 中,一个源文件中只能有一个 public 类,一个源文件可以有多个非 public 类。
源文件的名称应该和 public 类的类名保持一致。例如:源文件中 public 类的类名是 Employee,那么源文件应该命名为 Employee.java。
如果一个类定义在某个包中,那么 package 语句应该在源文件的首行。
如果源文件包含 import 语句,那么应该放在 package 语句和类定义之间。如果没有 package 语句,那么 import 语句应该在源文件中最前面。