尚硅谷面向对象篇笔记记录

发布于:2025-03-31 ⋅ 阅读:(21) ⋅ 点赞:(0)

第四章 面向对象编程(上)

1. 面向过程 vs. 面向对象

1.1 编程思想

  • 面向过程 (POP, Procedure-Oriented Programming)
    • 强调功能行为,以函数为最小单位,关注如何做
  • 面向对象 (OOP, Object-Oriented Programming)
    • 强调对象,将功能封装进对象,以类/对象为最小单位,关注谁来做
    • 三大特性
      • 封装 (Encapsulation)
      • 继承 (Inheritance)
      • 多态 (Polymorphism)

1.2 示例:人把大象装进冰箱

面向过程 面向对象
1. 打开冰箱 类:打开(冰箱)
2. 放入大象 大象类:进入(冰箱)
3. 关上冰箱 冰箱类:关门()
class{
    void 打开(冰箱 b) { b.开门(); }
    void 操作(大象 e, 冰箱 b) { e.进入(b); }
    void 关闭(冰箱 b) { b.关门(); }
}
class 冰箱 { void 开门() {} void 关门() {} }
class 大象 { void 进入(冰箱 b) {} }

2. Java 语言的基本元素:类与对象

2.1 类与对象

  • 类 (Class):对一类事物的抽象描述,是概念
  • 对象 (Object):类的具体实例,是实际存在的个体。
    • = “人”,对象 = “张三、李四”

2.2 Java 类的成员

  • 属性 (成员变量, Field)
    • 对象的特征,如姓名、年龄
  • 方法 (Method)
    • 对象的行为,如吃饭、跑步
class Person {
    String name;
    int age;
    void eat() { System.out.println(name + " 在吃饭"); }
}

3. 对象的创建与使用

3.1 创建对象

Person p1 = new Person();
  • 访问对象的属性/方法:
p1.name = "张三";
p1.eat();

3.2 内存分配

内存区域 存储内容
栈 (Stack) 局部变量
堆 (Heap) new 出来的对象
方法区 (Method Area) 类信息、静态变量

4. 类的成员之一:属性

4.1 属性的声明

class Person {
    String name; // 实例变量
    int age = 18; // 显式初始化
}
  • 分类
    • 成员变量(属性)
      • 实例变量(不加 static):属于对象,存于堆内存
      • 类变量(加 static):属于类,存于方法区
    • 局部变量
      • 方法、代码块、形参内部声明的变量,存于
类别 声明位置 默认值
成员变量 类中 有默认值
局部变量 方法或代码块中 无默认值,需手动赋值

5. 类的成员之二:方法

5.1 方法的定义

class Person {
    String name;
    void show() { System.out.println("姓名:" + name); }
}
  • 方法声明格式
修饰符 返回值类型 方法名(参数列表) { 方法体; return 返回值; }
  • 方法的分类

    分类 有返回值 无返回值
    无参数 int getAge() void sayHello()
    有参数 int add(int a, int b) void print(String msg)

6. 方法的重载

  • 定义:在同一个类中,多个方法名相同,但参数列表不同
  • 特点
    • 返回值类型无关!
    • 参数类型、个数、顺序至少有一个不同。
class MathUtil {
    int add(int a, int b) { return a + b; }
    double add(double a, double b) { return a + b; }
}

7. 方法的参数传递

  • 值传递
    • 基本数据类型:传递值的副本
    • 引用数据类型:传递地址的副本
void change(int x) { x = 3; } // 不影响原变量
void change(Person p) { p.age = 3; } // 修改对象属性

8. 类的成员之三:构造器

  • 作用:初始化对象。
  • 语法
class Person {
    String name;
    Person(String n) { name = n; }
}
  • 构造器重载
    • 根据不同参数定义多个构造器。

9. 关键字 this

  • 作用
    • 指代当前对象
    • 调用本类的构造器 (this(...))
class Person {
    String name;
    Person(String name) { this.name = name; }
}

10. 关键字 package、import

  • package:声明类所在包
package com.atguigu.oop;
  • import:导入其他包的类
import java.util.Scanner;

11. 面向对象特性之一:封装

  • 封装的作用
    • 隐藏细节,只提供访问接口。
    • 提高安全性,防止外部直接修改属性。
class Person {
    private int age;
    public void setAge(int a) { if (a >= 0 && a <= 130) age = a; }
    public int getAge() { return age; }
}
访问权限 同类 同包 子类 其他包
private
缺省 (default)
protected
public

12. 练习题

  1. 定义 Person 类,封装 age 属性,并提供 setAge()getAge() 方法。
  2. 定义 Circle 类,计算圆的面积。
  3. 定义 Student 数组,按成绩排序。
  4. 编写 AccountCustomer 类,使用 Bank 管理账户信息。

第五章 面向对象编程(中)

1. 面向对象特性之二:继承 (Inheritance)

1.1 继承的概念

  • 作用

    • 减少代码冗余,提高代码复用性。
    • 便于功能扩展,提高程序的维护性。
    • 提供多态的前提,增强灵活性。
  • 语法

    class 子类 extends 父类 { }
    
  • 示例

    class Person {
        String name;
        int age;
        public String getInfo() { return "姓名: " + name + ", 年龄: " + age; }
    }
    
    class Student extends Person {
        String school;
        public String getInfo() { return super.getInfo() + ", 学校: " + school; }
    }
    

1.2 继承的规则

  • 子类继承了父类的 publicprotected 成员。
  • 不能继承 private 成员,但可以通过 getter/setter 访问。
  • Java 只支持单继承,不支持多重继承,但支持多层继承
继承类型 描述
单继承 一个子类只能继承一个父类。
多层继承 子类可以继续被其他类继承。

1.3 继承的示例

class Animal { void eat() { System.out.println("动物在吃饭"); } }
class Dog extends Animal { void bark() { System.out.println("狗在叫"); } }
class Puppy extends Dog { void weep() { System.out.println("小狗在哭"); } }

调用示例:

Puppy myPuppy = new Puppy();
myPuppy.eat();   // 继承自 Animal
myPuppy.bark();  // 继承自 Dog
myPuppy.weep();  // Puppy 自己的方法

2. 方法的重写(Override)

2.1 方法重写的规则

  • 子类必须与父类的方法:
    • 方法名相同
    • 参数列表相同
    • 返回值类型相同或为子类型(Java 5+)。
    • 访问权限不能比父类更严格public > protected > default > private)。
    • 不能重写 privatestatic 方法

示例

class Parent {
    void show() { System.out.println("父类方法"); }
}

class Child extends Parent {
    @Override
    void show() { System.out.println("子类重写方法"); }
}

方法调用

Parent p = new Child();
p.show();  // 输出:子类重写方法

3. 访问权限修饰符

修饰符 类内部 同包 不同包的子类 其他包
private
缺省 (default)
protected
public

示例

class Parent {
    private int a = 1;
    int b = 2;             // 默认(default)
    protected int c = 3;
    public int d = 4;
}

4. 关键字 super

4.1 super 关键字的作用

  • 访问父类的属性
  • 调用父类的方法
  • 调用父类的构造器

示例

class Parent {
    String name = "父类";
    void show() { System.out.println("父类方法"); }
}

class Child extends Parent {
    String name = "子类";
    void display() {
        System.out.println(super.name); // 访问父类的 name
        super.show(); // 调用父类方法
    }
}

调用

Child c = new Child();
c.display();  // 输出:父类  父类方法

4.2 super 调用父类构造器

class Animal {
    Animal(String name) { System.out.println("Animal: " + name); }
}

class Dog extends Animal {
    Dog(String name) {
        super(name);  // 调用父类构造器
        System.out.println("Dog: " + name);
    }
}

5. 面向对象特性之三:多态(Polymorphism)

5.1 多态的定义

  • 同一个引用,指向不同子类的对象
  • 父类引用可以指向子类对象(向上转型)。
  • 方法调用时,执行的是子类重写的方法(动态绑定)。

示例

class Animal {
    void sound() { System.out.println("动物发出声音"); }
}

class Dog extends Animal {
    @Override void sound() { System.out.println("狗叫"); }
}

public class Test {
    public static void main(String[] args) {
        Animal a = new Dog();  // 向上转型
        a.sound();  // 输出:狗叫
    }
}

6. instanceof 关键字

  • 用于判断对象是否属于某个类
if (obj instanceof Dog) {
    System.out.println("obj 是 Dog 类型");
}

7. Object 类的使用

7.1 equals() 方法

  • 默认实现比较引用地址
  • 需要重写以比较内容。
@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (obj instanceof Person) {
        Person p = (Person) obj;
        return this.name.equals(p.name) && this.age == p.age;
    }
    return false;
}

8. 包装类(Wrapper Class)

8.1 基本数据类型与包装类

基本类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

8.2 装箱与拆箱

// 自动装箱
Integer num = 10;

// 自动拆箱
int value = num;

9. 练习题

  1. 编写 Order 类,重写 equals() 方法,判断 orderId 是否相等。
  2. 定义 GeometricObject(几何形状),子类 CircleMyRectangle,重写 equals()toString()
  3. 利用 Vector 处理学生成绩,找出最高分,并计算等级(A/B/C/D)。

第6章 面向对象编程(下)

6.1 关键字:static

当创建一个类时,只是描述了对象的属性和行为,并没有产生实质上的对象。只有通过new关键字才会创建对象并分配内存空间。有时候,我们希望某些特定的数据无论有多少个对象都只存在一份,这时候就需要使用static关键字。

static修饰的成员变量(类变量)

  • 类变量由该类的所有实例共享
  • 随着类的加载而加载,优先于对象存在
  • 可以通过"类名.类变量"的方式访问,不需要创建对象
  • 存储在方法区的静态域中
class Person {
    private int id;
    public static int total = 0;
    
    public Person() {
        total++;
        id = total;
    }
}

static修饰的方法(类方法)

  • 类方法可以直接通过类名调用,不需要创建对象
  • 在static方法内部只能访问类的static成员(属性和方法)
  • 不能使用this关键字和super关键字
  • 不能被重写

static的使用范围

可以用static修饰:

  • 属性
  • 方法
  • 代码块
  • 内部类

类属性、类方法的设计思想

  • 类属性作为该类各个对象之间共享的变量
  • 在设计类时,分析哪些属性不因对象的不同而改变,将这些属性设置为类属性
  • 如果方法与调用者无关,则可以声明为类方法
静态 vs 非静态成员对比表
特性 静态成员 非静态成员
内存分配时间 类加载时分配 对象实例化时分配
访问方式 类名.成员对象.成员 必须通过对象访问
存储位置 方法区静态域 堆内存对象实例中
是否共享 所有对象共享同一份 每个对象独立
生命周期 与类同生命周期 与对象同生命周期
能否访问非静态成员 ❌ 不能直接访问 ✅ 可以访问

单例(Singleton)设计模式

单例模式确保一个类只有一个实例,并提供一个全局访问点。

饿汉式单例模式
class Singleton {
    // 1.私有化构造器
    private Singleton() {
    }
    // 2.内部提供一个当前类的实例
    // 3.此实例必须静态化
    private static Singleton single = new Singleton();
    // 4.提供公共的静态的方法,返回当前类的对象
    public static Singleton getInstance() {
        return single;
    }
}
懒汉式单例模式
class Singleton {
    // 1.私有化构造器
    private Singleton() {
    }
    // 2.内部提供一个当前类的实例
    // 3.此实例必须静态化
    private static Singleton single;
    // 4.提供公共的静态的方法,返回当前类的对象
    public static Singleton getInstance() {
        if(single == null) {
            single = new Singleton();
        }
        return single;
    }
}

注意:懒汉式单例模式存在线程安全问题,需要在多线程环境下进行修复。

饿汉式 vs 懒汉式对比表
特性 饿汉式 懒汉式(基础版)
对象创建时机 类加载时立即创建 首次调用getInstance()时创建
线程安全 ✅ 安全 ❌ 不安全(需额外处理)
资源利用率 类加载即占用资源 延迟加载,节省资源
实现复杂度 简单 需处理线程安全问题

单例模式优化实现

1. 饿汉式(线程安全)

java

复制

class Singleton {
private static final Singleton INSTANCE = new Singleton();

private Singleton() {}

public static Singleton getInstance() {
    return INSTANCE;
}

}

2. 懒汉式(双重检查锁)

java

复制

class Singleton {
private static volatile Singleton instance;

private Singleton() {}

public static Singleton getInstance() {
    if (instance == null) {                    // 第一次检查
        synchronized (Singleton.class) {      // 同步锁
            if (instance == null) {            // 第二次检查
                instance = new Singleton();
            }
        }
    }
    return instance;
}

}

  • volatile作用:防止指令重排序,保证可见性

  • 双重检查意义:减少同步代码执行次数

单例模式的应用场景

  • 网站的计数器
  • 应用程序的日志应用
  • 数据库连接池
  • 项目中的配置文件读取类
  • Windows的任务管理器
  • Windows的回收站

6.2 理解main方法的语法

main方法是Java程序的入口点,JVM需要调用该方法来启动程序。其特点:

  • 访问权限必须是public
  • 必须是static的(JVM调用时不需要创建对象)
  • 接收一个String[]类型的参数(命令行参数)
  • main方法中不能直接访问非静态成员,需要先创建对象
public class CommandPara {
    public static void main(String[] args) {
        for (int i = 0; i < args.length; i++) {
            System.out.println("args[" + i + "] = " + args[i]);
        }
    }
}

6.3 类的成员之四:代码块

代码块(初始化块)用于初始化类或对象,分为两种:

静态代码块

  • 使用static修饰
  • 随着类的加载而加载,且只执行一次
  • 优先于非静态代码块执行
  • 只能访问静态成员
class Person {
    public static int total;
    static {
        total = 100; // 初始化静态变量
        System.out.println("静态代码块执行");
    }
}

非静态代码块

  • 没有static修饰
  • 每次创建对象时都会执行
  • 先于构造器执行
  • 可以访问静态和非静态成员

代码块的执行顺序

  1. 静态成员变量的默认初始化
  2. 静态代码块和静态成员变量的显式初始化(按照它们在类中出现的顺序)
  3. 非静态成员变量的默认初始化
  4. 非静态代码块和非静态成员变量的显式初始化(按照它们在类中出现的顺序)
  5. 构造器的执行

执行顺序示意图

类加载阶段
静态成员默认初始化
静态代码块/静态变量显式初始化
按代码顺序执行
对象实例化阶段
非静态成员默认初始化
非静态代码块/非静态变量显式初始化
构造器执行

典型示例

public class BlockTest {
    static int staticVar = 1;
    int instanceVar = 2;
    
    // 静态代码块
    static {
        System.out.println("静态代码块执行:" + staticVar);
        // System.out.println(instanceVar); // 错误!不能访问非静态成员
    }
    
    // 非静态代码块
    {
        System.out.println("非静态代码块执行:" + instanceVar);
        System.out.println("可以访问静态变量:" + staticVar);
    }
    
    public static void main(String[] args) {
        new BlockTest();
    }
}

6.4 关键字:final

final关键字表示"最终的",在Java中可以用于修饰类、方法和变量。

final修饰类

  • 表示该类不能被继承
  • 提高安全性和程序可读性
  • 例如:String类、System类、StringBuffer类

final修饰方法

  • 表示该方法不能被子类重写
  • 例如:Object类中的getClass()方法

final修饰变量

  • 表示该变量是常量,只能被赋值一次
  • 常量名通常使用大写字母
  • final修饰的成员变量必须在声明时、构造器中或代码块中显式赋值
final double MY_PI = 3.14;

6.5 抽象类与抽象方法

随着继承层次的深入,父类可能会变得越来越抽象,以至于无法创建具体的实例。这种类就称为抽象类。

抽象类的特点

  • 使用abstract关键字修饰
  • 不能被实例化
  • 可以包含抽象方法和非抽象方法
  • 子类必须重写所有抽象方法,否则也必须声明为抽象类

抽象方法的特点

  • 使用abstract关键字修饰
  • 只有方法声明,没有方法体
  • 只能在抽象类中声明

抽象类的限制

  • 不能用abstract修饰变量、代码块、构造器
  • 不能用abstract修饰私有方法、静态方法、final方法、final类

模板方法设计模式

模板方法是一种行为设计模式,它定义了一个算法的骨架,而将一些步骤延迟到子类中实现。

abstract class Template {
    public final void getTime() {
        long start = System.currentTimeMillis();
        code();
        long end = System.currentTimeMillis();
        System.out.println("执行时间是:" + (end - start));
    }
    
    public abstract void code();
}

class SubTemplate extends Template {
    public void code() {
        for (int i = 0; i < 10000; i++) {
            System.out.println(i);
        }
    }
}

模板方法设计模式在各种框架中都有广泛应用,如:

  • 数据库访问的封装
  • Junit单元测试
  • JavaWeb的Servlet
  • Hibernate和Spring框架

6.6 接口(interface)

接口是一种特殊的抽象类,只包含常量和抽象方法的定义。接口代表了一种规范,定义了一组规则,体现了"能不能"的关系。

接口的特点

  • 使用interface关键字定义
  • 所有成员变量默认都是public static final修饰的
  • 所有方法默认都是public abstract修饰的
  • 接口不能有构造器
  • 接口可以多继承
public interface Runner {
    int ID = 1; // 默认为public static final
    void start(); // 默认为public abstract
    void run();
    void stop();
}

类实现接口

  • 使用implements关键字
  • 一个类可以实现多个接口
  • 实现类必须提供接口中所有抽象方法的实现,否则必须声明为抽象类
  • 先写extends,后写implements
class Person implements Runner {
    public void start() {
        // 实现
    }
    
    public void run() {
        // 实现
    }
    
    public void stop() {
        // 实现
    }
}

接口的多重继承

接口可以继承多个其他接口。

interface SubInterface extends MyInterface {
    void absM2();
}

接口的应用:代理模式

代理模式是一种设计模式,它为其他对象提供一种代理以控制对这个对象的访问。

interface Network {
    void browse();
}

// 被代理类
class RealServer implements Network {
    @Override
    public void browse() {
        System.out.println("真实服务器上网浏览信息");
    }
}

// 代理类
class ProxyServer implements Network {
    private Network network;
    
    public ProxyServer(Network network) {
        this.network = network;
    }
    
    public void check() {
        System.out.println("检查网络连接等操作");
    }
    
    public void browse() {
        check();
        network.browse();
    }
}

应用场景:

  • 安全代理
  • 远程代理
  • 延迟加载

Java 8中的接口新特性

Java 8为接口引入了两个新特性:

  1. 默认方法(Default Method)
    • 使用default关键字修饰
    • 可以有方法体
    • 可以通过实现类对象调用
public interface AA {
    default void method() {
        System.out.println("北京");
    }
}
  1. 静态方法(Static Method)
    • 使用static关键字修饰
    • 可以通过接口名直接调用
public interface AA {
    public static void method2() {
        System.out.println("hello lambda!");
    }
}
接口默认方法的冲突处理
  • 如果一个类实现了两个接口,这两个接口中有相同的默认方法,实现类必须覆盖该方法
  • 如果一个类继承的父类中有方法与接口默认方法同名,遵循"类优先"原则

6.5 抽象类 vs 6.6 接口

对比表格(Java 8+)

特性 抽象类 接口
成员变量 普通变量或常量 只能是public static final
方法实现 可包含抽象和具体方法 默认方法(default)和静态方法
构造器 ✅ 有 ❌ 无
多继承 ❌ 单继承 ✅ 多实现
设计理念 "是什么"的抽象 "能做什么"的规范
新特性支持 Java 8默认方法 Java 8默认/静态方法

接口新特性示例

public interface SmartDevice {
    // 传统抽象方法
    void connectWifi();
    
    // 默认方法(Java8+)
    default void showBrand() {
        System.out.println("Default Brand");
    }
    
    // 静态方法(Java8+)
    static void printVersion() {
        System.out.println("1.0.0");
    }
}

class SmartWatch implements SmartDevice {
    @Override
    public void connectWifi() {
        System.out.println("智能手表连接WiFi");
    }
    
    // 可选择是否重写默认方法
    @Override
    public void showBrand() {
        System.out.println("Apple Watch");
    }
}

6.7 类的成员之五:内部类

内部类是定义在另一个类内部的类,它可以更好地封装,并且可以直接访问外部类的所有成员。

内部类的分类

  1. 成员内部类
    • 静态成员内部类
    • 非静态成员内部类
  2. 局部内部类
  3. 匿名内部类
内部类
成员内部类
局部内部类
匿名内部类
静态成员内部类
非静态成员内部类

成员内部类

作为外部类成员:

  • 可以被privateprotecteddefaultpublic修饰
  • 可以被static修饰
  • 可以访问外部类的所有成员,包括私有成员

作为一个类:

  • 可以定义属性、方法、构造器等
  • 可以被abstractfinal修饰
class Outer {
    private int s;
    
    public class Inner {
        public void mb() {
            s = 100; // 可以直接访问外部类的私有成员
            System.out.println("在内部类Inner中s=" + s);
        }
    }
    
    public void ma() {
        Inner i = new Inner();
        i.mb();
    }
}

局部内部类

  • 定义在方法或代码块中
  • 只能在定义它的方法或代码块中使用
  • 不能使用publicprotectedprivatestatic修饰符
  • 可以访问外部类的所有成员,包括私有成员
  • 可以访问外部方法的局部变量,但这些变量必须是final

匿名内部类

匿名内部类是没有名字的内部类,必须在创建时继承一个类或实现一个接口。

interface A {
    void fun1();
}

public class Outer {
    public static void main(String[] args) {
        new Outer().callInner(new A() {
            public void fun1() {
                System.out.println("implement for fun1");
            }
        });
    }
    
    public void callInner(A a) {
        a.fun1();
    }
}

特点:

  • 匿名内部类必须继承父类或实现接口
  • 匿名内部类只能有一个对象
  • 匿名内部类对象只能使用多态形式引用
  • 不能定义静态成员和方法

关键总结图表

Java修饰符作用域总览

修饰符 成员变量 方法 代码块 内部类
public
protected
private
static
final
abstract


网站公告

今日签到

点亮在社区的每一天
去签到