2.面向对象
面向对象
一、类基本介绍
| 类 | 对象 |
|---|---|
| 动物 | 猫、狗、鸡 |
| 车 | 奔驰、宝马 |
1. 类的基本结构
- 属性(Field) :也称为成员变量或字段,用于描述对象的状态。
- 方法(Method) :用于定义对象的行为或操作。
- 构造方法(Constructor) :用于创建类的实例,并初始化对象的状态。
- 内部类(Inner Class,可选) :定义在另一个类内部的类。
public class 类名 {
// 字段(属性)
数据类型 属性名;
// 构造器
public 类名(参数列表) {
// 初始化代码
}
// 方法
public 返回值类型 方法名(参数列表) {
// 方法体
}
}
类的访问修饰符有public和默认两种,public是任何类都能访问改类,默认只能在同一个包中访问。
2. 类属性
- 访问修饰符:
-
private:作用范围仅限于定义该成员的类内部 -
default:作用范围仅限于同一包内的类。 -
protected:作用范围包括同一包内的类以及不同包中的子类。 -
public:作用范围对所有类开放,没有任何访问限制。 -
访问范围:
访问修饰符 同一类 同一包 子类(不同包) 其他包 private✔️ ❌ ❌ ❌ default✔️ ✔️ ❌ ❌ protected✔️ ✔️ ✔️ ❌ public✔️ ✔️ ✔️ ✔️ -
代码示例:
public class myCar { private String model; // 私有属性,只能在myCar类中访问 protected int year; // 受保护属性,同一包和子类可访问 String color; // 默认属性,同一包可访问 public double price; // 公共属性,所有类可访问 }
- 其他修饰符:
static:声明为静态字段,属于类本身而非实例。final:声明为常量,值不可修改。
3. 类方法
[访问修饰符] [其他修饰符] 返回值类型 方法名(参数列表) {
// 方法体
}
3.1 方法类型
-
静态方法
-
使用
static修饰符声明的方法 -
属于类本身,可以通过类名直接调用
-
不能直接访问实例字段或实例方法
-
-
非静态方法
-
未使用
static修饰符的方法 -
属于类的实例,必须通过对象调用
-
可以访问非静态字段和其他方法
-
-
构造方法
-
与类同名且没有返回值类型的方法
-
用于创建类的实例并初始化对象的状态
public class Person { private String name; private int age; // 构造方法 public Person(String name, int age) { // 可有参数、可无参数 this.name = name; this.age = age; } }
-
3.2 方法访问修饰符
同类的属性
二、封装、继承、多态
1. 封装
-
定义 :封装是将类的内部实现细节隐藏起来,并通过公共方法(getter 和 setter)提供受控的访问。
-
目的
-
提高安全性
-
通过隐藏字段并提供受控的访问方法,可以防止外部类直接修改字段,从而避免非法操作。
-
可以在 setter 方法中添加校验逻辑,确保字段值的有效性。
-
-
增强可维护性
- 如果需要修改内部实现,只需调整类的内部逻辑,而无需修改外部代码 -> 例如,我要将年龄从int改为String,不用再外部一个一个改了,而是在内部统一处理
public class Person { private String name; private int age; // ...省略name的getter、setter方法 public int getAge() { return age; } public void setAge(int age) { if (age > 0) { // 添加校验逻辑 // this.age = age; this.age = String.valueOf(age); // 若后期需更改 } else { System.out.println("年龄必须为正数!"); } } }
- 如果需要修改内部实现,只需调整类的内部逻辑,而无需修改外部代码 -> 例如,我要将年龄从int改为String,不用再外部一个一个改了,而是在内部统一处理
-
隐藏信息,实现细节
例如性别在数据库中存储为0、1,但要展示为男,女
public String getSexName() { if("0".equals(sex)){ sexName = "女"; } else if("1".equals(sex)){ sexName = "男"; } return sexName; }
-
2. 继承
继承 允许一个类(称为子类或派生类)从另一个类(称为父类或基类)继承属性和方法。通过继承,子类可以复用父类的代码,并且可以在子类中添加新的功能或修改现有的功能。
2.1 继承的特点
-
代码复用 :子类可以直接使用父类的属性和方法,避免了重复编写代码。
-
扩展性 :子类可以在继承父类的基础上,添加新的属性和方法,或者重写父类的方法。
-
多态性 :通过继承,Java支持多态性,即同一个方法可以在不同的子类中有不同的实现。
2.2 继承知识点
-
子类中super.a、super.a()、super() -> 分别拿到了父类属性,调用了父类方法,构造方法
-
子类可重写父类方法(加上@Override更规范,编译器可以帮助我们检查)
-
final方法不能被重写
-
final类不能被继承
-
多态:父类引用指向了子类的对象,会调用该子类重写的方法。
/ 父类 class Parent { int a = 10; // 父类属性 String name = "Parent"; // 父类构造方法 public Parent(int a) { this.a = a; System.out.println("Parent constructor called with a = " + a); } // 父类方法 void greet() { System.out.println("Hello from Parent"); } // final 方法,不能被子类重写 final void finalMethod() { System.out.println("This is a final method in Parent"); } } // 子类继承父类 class Child extends Parent { String name = "Child"; // 子类属性,隐藏了父类的 name 属性 // 子类构造器,显式调用父类构造器 public Child() { super(20); // 调用父类构造器,传入初始值 20 System.out.println("Child constructor called"); } // 重写父类的 greet 方法 @Override void greet() { super.greet(); // 调用父类的 greet 方法 System.out.println("Hello from Child"); } // 子类新增的方法 void printNames() { System.out.println("Child name: " + name); // 访问子类的 name System.out.println("Parent name: " + super.name); // 访问父类的 name } } // 防止继承的类 final class FinalClass { void display() { System.out.println("This is a final class and cannot be extended"); } } // 主类,用于测试继承的知识点 public class InheritanceStudy { public static void main(String[] args) { // 创建子类对象 Child child = new Child(); // 调用子类方法 child.printNames(); child.greet(); // 多态性:父类引用指向子类对象 Parent parentRef = new Child(); parentRef.greet(); // 调用的是子类重写的方法 // 访问父类的属性 System.out.println("Parent's a: " + parentRef.a); // final 方法调用 child.finalMethod(); // 尝试创建 FinalClass 的子类(会报错) // class SubFinalClass extends FinalClass {} // 错误:不能继承 final 类 } }
3. 多态
同一个方法调用在不同的对象上表现出不同的行为。
3.1 前提条件
- 子类继承父类
- 子类重写父类的方法
- 父类引用指向子类的对象
3.2 例子
-
基本表现:父类引用指向子类对象,此时调用父类的方法会优先看子类是否重写此方法
-
向下转型:若父类引用指向子类对象,则可向下转型,将该对象转为子类引用,转型后可以调用父类原本没有的方法。若父类引用指向的是父类对象,则会转型失败。
-
应用场景:统一管理不同类型的对象
-
注意点:父类无法调用子类特有的方法,转型后可以调用
// 父类 class Animal { // 父类方法 void sound() { System.out.println("Animal makes a sound"); } } // 子类 Dog,重写了父类的 sound 方法 class Dog extends Animal { @Override void sound() { System.out.println("Dog barks"); } // 子类特有的方法 void fetch() { System.out.println("Dog fetches the ball"); } } // 子类 Cat,重写了父类的 sound 方法 class Cat extends Animal { @Override void sound() { System.out.println("Cat meows"); } // 子类特有的方法 void scratch() { System.out.println("Cat scratches the furniture"); } } // 主类,用于测试多态 public class PolymorphismStudy { public static void main(String[] args) { // 1. 多态的基本表现:父类引用指向子类对象 Animal myAnimal = new Dog(); // 父类引用指向 Dog 对象 myAnimal.sound(); // 输出 "Dog barks",调用的是子类重写的方法 myAnimal = new Cat(); // 父类引用指向 Cat 对象 myAnimal.sound(); // 输出 "Cat meows",调用的是子类重写的方法 // 2. 多态与类型转换 // 向下转型:将父类引用转换为子类引用 Animal animalRef = new Dog(); // 父类引用指向子类对象 // Animal animalRef = new Animal(); // Dog dog = (Dog) animalRef; 会报错,父类引用指向的是子类对象才能向下转型成功 if (animalRef instanceof Dog) { // 检查实际类型是否是 Dog Dog dog = (Dog) animalRef; // 向下转型 dog.fetch(); // 调用子类特有的方法 } // 3. 多态的应用场景:统一管理不同类型的对象 Animal[] animals = {new Dog(), new Cat()}; // 使用数组存储不同子类的对象 for (Animal animal : animals) { animal.sound(); // 根据实际类型调用相应的方法 } // 4. 注意事项:父类引用无法直接调用子类特有的方法 // animalRef.fetch(); // 错误:父类引用无法调用子类特有的方法 } } -
多态中构造方法的调用顺序
父类构造方法 => 多态方法(但子类变量父类拿不到,初始化为0)=> 子类构造方法 => 子类的方法
public class Dog extends Animal { private int age = 2; public Dog(int age) { this.age = age; System.out.println("I am dog, my age is:" + this.age); } public void sound() { // 子类覆盖父类方法 System.out.println("I am dog, my age is:" + this.age); } public static void main(String[] args) { new Dog(2); // before sound // I am dog, my age is:0 // after sound // I am dog, my age is:2 } } class Animal { int age = 99; Animal () { System.out.println("before sound"); sound(); System.out.println("after sound"); } public void sound() { System.out.println("I am animal"); } }

浙公网安备 33010602011771号