03.封装继承多态
# 01.封装
- 作用:
- 封装是将数据(变量)和操作数据的方法(函数)打包在一起,形成一个类(Class)
- 封装的目的是隐藏对象的内部细节,仅暴露出必要的操作接口
- 这样可以减少外部对对象内部的直接访问,降低耦合度,提高安全性和易用性
public class BankAccount {
private double balance; // 账户余额,私有属性,封装
public BankAccount(double initialBalance) {
balance = initialBalance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public void withdraw(double amount) {
if (amount > 0 && balance >= amount) {
balance -= amount;
}
}
public double getBalance() {
return balance;
}
public static void main(String[] strings) {
double balance = 19999.9;
BankAccount ba = new BankAccount(balance);
System.out.println( ba.getBalance() );
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 02.继承
- Java 中的继承为单一继承,也就是说,一个子类只能拥有一个父类,一个父类可以拥有多个子类
- 另外,所有的 Java 类都继承自
Java.lang.Object
,所以Object
是所有类的祖先类 - 子类一旦继承父类,就会继承父类所有开放的特征,不能选择性地继承父类特征
# 1、基本使用
- 重写方法的
参数列表
应该与原方法完全相同 返回值类型
应该和原方法的返回值类型一样或者是它在父类定义时的子类型- 重写方法访问级别限制不能比原方法高
- 例如:如果父类方法声明为公有的,那么子类中的重写方法不能是私有的或是保护的
- 方法定义为
final
,将不能被重写(final
关键字将在本节后面讲到) - 一个方法被定义为
static
,将使其不能被重写,但是可以重新声明 - 和父类在一个包中的子类能够重写任何没有被声明为 private 和 final 的父类方法
- 和父类不在同一个包中的子类只能重写 non-final 方法或被声明为 public 或 protected 的方法
- 一个重写方法能够抛出任何运行时异常,不管被重写方法是否抛出异常
- 构造方法不能重写
package day01;
class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void say() {
System.out.println(name + " say 基类 Animal");
}
public void sayHi() {
System.out.println(name + " sayHi 基类 Animal");
}
}
class Dog extends Animal {
// 子类会继承父类的所有非私有(public和protected)属性和方法
protected int age;
// 子类不继承父类构造器,可通过super关键字调用父类构造器
public Dog(String name, int age) {
super(name);
this.name = name;
this.age = age;
}
// 子类可以直接使用这些方法和属性,也可以覆盖(override)这些方法
@Override
public void say() {
System.out.println(name + age + " Dog 继承 Animal");
}
public void eat() {
System.out.println(name + " eat ...");
}
}
public class Test {
public static void main(String[] args) {
Dog myDog = new Dog("阿黄", 11);
myDog.sayHi(); // 阿黄 sayHi 基类 Animal
myDog.say(); // 阿黄11 Dog 继承 Animal
myDog.eat(); // 阿黄 eat ...
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 2、 四种修饰符
1、private
:私有的,只允许在本类中访问2、protected
:受保护的,允许在同一个类、同一个包以及不同包的子类中访问3、默认的
:允许在同一个类,同一个包中访问4、public
:公共的,可以再任何地方访问
访问控制修饰符 | 同一个类 | 同一个包 | 不同包的子类 | 不同包的非子类 |
---|---|---|---|---|
private(私有的) | ✓ | ✕ | ✕ | ✕ |
default(默认的) | ✓ | ✓ | ✕ | ✕ |
protected(受保护的) | ✓ | ✓ | ✓ | ✕ |
public(公共的) | ✓ | ✓ | ✓ | ✓ |
# 1、src/cls/Parent.java
package cls;
// 父类
class Parent {
// 私有的,只允许在本类中访问
private String privateField = "private field";
// 受保护的,允许在同一个类、同一个包以及不同包的子类中访问
protected String protectedField = "protected field";
// 允许在同一个类,同一个包中访问
String defaultField = "default field";
// 公共的,可以再任何地方访问
public String publicField = "public field";
// 私有的,只允许在本类中访问
private void privateMethod() {
System.out.println("private method in Parent");
}
// 受保护的,允许在同一个类、同一个包以及不同包的子类中访问
protected void protectedMethod() {
System.out.println("protected method in Parent");
}
// 允许在同一个类,同一个包中访问
void defaultMethod() {
System.out.println("default method in Parent");
}
// 公共的,可以再任何地方访问
public void publicMethod() {
System.out.println("public method in Parent");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 2、src/cls/Child.java
package cls;
// 子类,不同包中的子类
class Child extends cls.Parent {
public void accessFieldsAndMethods() {
// System.out.println(privateField); // 编译错误,无法访问父类的private字段
System.out.println(protectedField);
System.out.println(defaultField);
System.out.println(publicField);
// privateMethod(); // 编译错误,无法访问父类的private方法
protectedMethod();
defaultMethod();
publicMethod();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 3、src/cls/Test.java
package cls;
public class Test {
public static void main(String[] args) {
Child child = new Child();
child.accessFieldsAndMethods();
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 3、super与this
super
是用在子类中的,目的是**访问直接父类
**的变量或方法- super 关键字只能调用父类的
public
以及protected
成员 - super 关键字可以用在子类构造方法中调用父类构造方法
- super 关键字不能用于静态 (
static
) 方法中
- super 关键字只能调用父类的
this
关键字指向**当前类对象的引用
**,它的使用场景为- 访问当前类的成员属性和成员方法
- 访问当前类的构造方法
- 不能在静态方法中使用
package cls;
class Parent {
String name;
public Parent(String name) {
this.name = name;
}
public void greet() {
System.out.println("Parent.greet " + this.name);
}
}
class Child extends Parent {
public Child(String name) {
super(name);
this.name = name;
}
@Override
public void greet() {
System.out.println("Child.greet " + this.name);
}
public void greetBoth() {
this.greet(); // Outputs: Child.greet Tom
super.greet(); // Outputs: Parent.greet Tom
}
}
public class Test {
public static void main(String[] args) {
Child child = new Child("Tom");
child.greetBoth();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 4、final
- 当父类中方法不希望被重写时,可以将该方法标记为
final
class SuperClass {
public final void finalMethod() {
System.out.println("我是final方法");
}
}
class SubClass extneds SuperClass {
// 被父类标记为final的方法不允许被继承,编译会报错
@Override
public void finalMethod() {
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 03.多态
多态意味着允许不同类的对象对同一消息做出不同的响应
例如
- 火车类和飞机类都继承自交通工具类,这些类下都有各自的
run()
方法 - 而火车的
run()
方法输出火车会跑,飞机的run()
方法则输出飞机会飞 - 火车和飞机都继承父类的
run()
方法,但是对于不同的对象,拥有不同的操作
- 火车类和飞机类都继承自交通工具类,这些类下都有各自的
# 1、多态举例
public class Test{
public static void main(String args[]){
Animal dog = new Dog();
Animal cat = new Cat();
dog.eat();
cat.eat();
}
}
class Animal {
// 定义方法 eat
public void eat() {
System.out.println("宠物吃东西");
}
}
class Dog extends Animal { // 继承父类
// 重写父类方法 eat
public void eat() {
System.out.println("狗狗吃狗粮");
}
}
class Cat extends Animal { // 继承父类
// 重写父类方法 eat
public void eat() {
System.out.println("猫猫吃猫粮");
}
}
/*
狗狗吃狗粮
猫猫吃猫粮
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 2、向下转型
- 向上转型是父类引用指向子类实例,那么如何让子类引用指向父类实例呢?使用向下转型就可以实现
- 我们为
Dog
类新增了一个run
方法,此时我们无法通过Animal
类型的dog
实例调用到其下面特有的run
方法 - 需要向下转型,通过
(Dog)dog
将Animal
类型的对象强制转换为Dog
类型,这个时候就可以调用run
方法了
package cls;
public class Test{
public static void main(String[] args){
Animal d = new Dog();
d.eat();
// dog.run() // 这个调用就是错误的
((Dog) d).run();
}
}
class Animal {
// 定义方法 eat
public void eat() {
System.out.println("宠物吃东西");
}
}
class Dog extends Animal { // 继承父类
// 重写父类方法 eat
public void eat() {
System.out.println("狗狗吃狗粮");
}
public void run() {
System.out.println("狗狗跑得快");
}
}
/*
狗狗吃狗粮
狗狗跑得快
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 3、instanceof
instanceof
运算符用来检查对象引用是否是类型的实例,或者这个类型的子类,并返回布尔值
package com.case_01;
public class Test{
public static void main(String args[]){
Animal animal = new Dog();
if (animal instanceof Dog){
// 将父类转换成子类
Dog dog = (Dog) animal;
dog.run();
}
}
}
class Animal {
// 定义方法 eat
public void eat() {
System.out.println("宠物吃东西");
}
}
class Dog extends Animal { // 继承父类
// 重写父类方法 eat
public void eat() {
System.out.println("狗狗吃狗粮");
}
public void run() {
System.out.println("狗狗跑得快");
}
}
/*
狗狗跑得快
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 04.abstract抽象类
# 1、作用
abstract 是一个关键字,用来
创建抽象类和抽象方法
抽象类
抽象类是的,
只能作为其他类的父类
抽象类可以
包含抽象方法和非抽象方法
抽象方法
抽象方法
是只有声明,没有实现的方法
包含抽象方法的类必须被声明为抽象类
子类必须实现父类的所有抽象方法,除非子类也是抽象类
# 2、举例
- 在这个例子中,
Animal
是一个抽象类 - 它有一个抽象方法
makeSound()
和一个非抽象方法eat()
Dog
和Cat
是Animal
的子类,它们都实现了makeSound()
方法我们可以看到- 即使
Dog
和Cat
没有定义eat()
方法,但是它们仍然可以调用eat()
方法 - 因为这个方法是从
Animal
类继承来的
package cls;
public class Test{
public static void main(String[] args){
Dog myDog = new Dog(); // 创建 Dog 对象
myDog.makeSound(); // 调用 Dog 的 makeSound() 方法
myDog.eat(); // 调用 Animal 的 eat() 方法
Cat myCat = new Cat(); // 创建 Cat 对象
myCat.makeSound(); // 调用 Cat 的 makeSound() 方法
myCat.eat(); // 调用 Animal 的 eat() 方法
}
}
// 抽象类
abstract class Animal {
// 抽象方法
abstract void makeSound();
// 非抽象方法
public void eat() {
System.out.println("The animal eats");
}
}
// Dog 类继承 Animal 类
class Dog extends Animal {
// 实现 makeSound 方法
public void makeSound() {
System.out.println("The dog barks");
}
}
// Cat 类继承 Animal 类
class Cat extends Animal {
// 实现 makeSound 方法
public void makeSound() {
System.out.println("The cat meows");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
上次更新: 2024/5/31 11:18:42