面向对象
继承
在 Java 中,子类能继承父类的以下内容:
- 成员变量:子类会继承父类中所有非私有(
private)的成员变量。这意味着子类可以直接访问和使用这些变量,就好像它们是在子类中定义的一样。例如,父类Animal中有一个protected修饰的成员变量name,子类Dog继承自Animal,那么Dog类的对象就可以访问和修改name变量。 - 成员方法:子类会继承父类中所有非私有(
private)的成员方法。子类可以直接调用这些方法,也可以根据需要在子类中对其进行重写。例如,父类Animal中有一个public方法eat(),子类Cat继承自Animal,那么Cat类的对象就可以调用eat()方法。如果Cat类有自己独特的进食方式,还可以重写eat()方法来实现具体的逻辑。 - 构造方法:子类不能直接继承父类的构造方法。但是,子类的构造方法可以通过
super关键字来调用父类的构造方法,以初始化从父类继承来的成员变量和执行其他必要的初始化操作。 - 接口实现和抽象方法:如果父类实现了某个接口或者包含抽象方法,子类也会继承这些接口实现和抽象方法。子类必须实现父类中所有未实现的抽象方法,除非子类本身也是抽象类。
多态
多态实现条件 在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方法来实现狗叫和猫叫的具体逻辑。
接口
接口就是一种规则,是对行为的抽象
适配器设计模式
内部类
成员内部类
- 成员内部类是最普通的内部类,它作为外部类的一个成员存在,与外部类的其他成员(如字段、方法)处于同一层次。
- 可以直接访问外部类的所有成员,包括私有成员。
- 要创建成员内部类的对象,必须先有外部类的对象。例如:
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);
}
}
内部类的优点包括:可以更好地实现封装,将相关的类放在一起,提高代码的可读性和可维护性;