面向对象基础

192 阅读6分钟

面向对象

继承

在 Java 中,子类能继承父类的以下内容:

  • 成员变量:子类会继承父类中所有非私有(private)的成员变量。这意味着子类可以直接访问和使用这些变量,就好像它们是在子类中定义的一样。例如,父类Animal中有一个protected修饰的成员变量name,子类Dog继承自Animal,那么Dog类的对象就可以访问和修改name变量。
  • 成员方法:子类会继承父类中所有非私有(private)的成员方法。子类可以直接调用这些方法,也可以根据需要在子类中对其进行重写。例如,父类Animal中有一个public方法eat(),子类Cat继承自Animal,那么Cat类的对象就可以调用eat()方法。如果Cat类有自己独特的进食方式,还可以重写eat()方法来实现具体的逻辑。
  • 构造方法:子类不能直接继承父类的构造方法。但是,子类的构造方法可以通过super关键字来调用父类的构造方法,以初始化从父类继承来的成员变量和执行其他必要的初始化操作。
  • 接口实现和抽象方法:如果父类实现了某个接口或者包含抽象方法,子类也会继承这些接口实现和抽象方法。子类必须实现父类中所有未实现的抽象方法,除非子类本身也是抽象类。

多态

image-20250515164453825.png

多态实现条件 在java中要实现多态,必须要满足如下几个条件,缺一不可:

必须在继承关系上 -> 向上转型 子类和父类必须有同名的 覆盖/重写 方法
通过父类的引用调用重写的方法 完成以上3部分,就会发生动态绑定,而动态绑定是多态的基础。

多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。

2.3 向上转型
向上转型:实际就是创建一个子类对象,将其当成父类对象来使用。

语法格式:父类类型 对象名 = new 子类类型()

比如:Animal animal = new Dog("圆圆",2);

赋值的时候一般要求等号两边的数据类型一样,这里 Dog 类型 可以跟Animal 类型赋值,是因为他们之间构成了父子关系。 animal是父类类型,可以引用一个子类对象,因为是从小范围向大范围的转换。

程序运行时,通过父类的引用调用子类重写的方法,这一过程叫做动态绑定。在代码底层中自主实现。(下面介绍)

【方法重写的规则】

返回值类型 方法名 参数列表 要完全一致。

被重写的方法返回值类型可以不同,但是必须是具有父子关系的。(例如:Animal,Dog 作为 eat()方法的返回值类型,专业术语:协变类型,一般不考) 被重写的方法的访问修饰限定符在子类中要大于等于父类的。private 默认的 protected public例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为 protected 父类被static、private、final修饰的方法、构造方法都不能被重写。 重写的方法,可以使用 @Override 注解来显式指定。有了这个注解能帮我们进行一些合法性校验。 例如不小心将方法名字拼写错了(比如写成 aet),那么此时编译器就会发现父类中没有 aet 方法,就会编译报错,提示无法构成重写。

抽象类

  • 定义:抽象类是一种不能被实例化的类,它通常包含了一些抽象方法和非抽象方法。抽象类的主要作用是作为其他类的基类,为子类提供公共的属性和方法,同时定义一些抽象方法,让子类根据自身的需求去实现这些方法。
  • 特点
    • 抽象类不能被实例化,只能被继承。如果一个类继承了抽象类,那么它必须实现抽象类中的所有抽象方法,除非它本身也是抽象类。
    • 抽象类可以包含抽象方法和非抽象方法。抽象方法只有方法签名,没有方法体;非抽象方法则有具体的方法实现。
    • 抽象类可以有构造方法,用于初始化子类继承的成员变量。
  • 示例

java

abstract class Animal {
    // 抽象方法
    public abstract void makeSound();

    // 非抽象方法
    public void eat() {
        System.out.println("动物在吃东西");
    }
}

抽象方法

  • 定义:抽象方法是一种没有方法体的方法,它只有方法签名,以分号结尾,并且使用abstract关键字修饰。抽象方法必须在抽象类中声明。
  • 特点
    • 抽象方法没有方法体,其实现由子类来完成。子类在继承抽象类时,必须实现抽象类中的所有抽象方法,否则子类也必须声明为抽象类。
    • 抽象方法的主要作用是定义子类必须实现的行为,它为子类提供了一个统一的方法签名,子类根据自身的特点来实现具体的逻辑。
  • 示例:在上述Animal抽象类中,makeSound方法就是抽象方法,它定义了动物发出声音的行为,但不同的动物发出声音的方式不同,所以具体的实现由子类来完成,比如Dog类和Cat类可以分别重写makeSound方法来实现狗叫和猫叫的具体逻辑。

接口

接口就是一种规则,是对行为的抽象

image-20250515192357978.png

image-20250516193848033.png

image-20250516194354659.png

image-20250516195435759.png

image-20250516195911438.png

适配器设计模式

image-20250516195435759.png

内部类

image-20250516195911438.png

成员内部类

  • 成员内部类是最普通的内部类,它作为外部类的一个成员存在,与外部类的其他成员(如字段、方法)处于同一层次。
  • 可以直接访问外部类的所有成员,包括私有成员。
  • 要创建成员内部类的对象,必须先有外部类的对象。例如:
class Outer {
    private int outerField = 10;

    class Inner {
        public void printOuterField() {
            System.out.println(outerField); 
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner();
        inner.printOuterField(); 
    }
}

静态内部类

  • static关键字修饰的内部类。
  • 它不依赖于外部类的实例,不能直接访问外部类的非静态成员。
  • 可以直接通过外部类名来访问静态内部类,例如Outer.Inner inner = new Outer.Inner();

局部内部类

  • 定义在方法或代码块内部的类。
  • 其作用域仅限于所在的方法或代码块。
  • 可以访问所在方法的局部变量,但这些变量必须是final类型(在 Java 8 及以后,实际上可以是隐式final的)。例如:
class Outer {
    public void outerMethod() {
        final int localVar = 20; 
        class Inner {
            public void printLocalVar() {
                System.out.println(localVar); 
            }
        }
        Inner inner = new Inner();
        inner.printLocalVar();
    }
}

public class Main {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.outerMethod();
    }
}

匿名内部类

  • 没有显式的类名的内部类。
  • 通常用于创建一个临时的、只使用一次的类。
  • 一般是在方法调用或表达式中直接定义并使用。例如,在事件处理中经常会用到匿名内部类:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;

public class Main {
    public static void main(String[] args) {
        JFrame frame = new JFrame("Anonymous Inner Class Example");
        JButton button = new JButton("Click me");

        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Button clicked!");
            }
        });

        frame.add(button);
        frame.setSize(300, 200);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

内部类的优点包括:可以更好地实现封装,将相关的类放在一起,提高代码的可读性和可维护性;