面向对象编程
面向对象编程的几大特性:
-
继承
-
封装
-
组合
-
多态
一、继承
- 含义:继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
- 目的:代码重用、类的重用。
- 关键字:extends
- 继承的作用:
a. 代码复用的一种手段
b. 用来实现多态 - java中的继承是单继承,不支持多继承。
- 在new子类实例时,会先在子类中创建一个父类实例。
- 每个类都有构造方法,若无显示的创建,编译器将自动生成一个无参的构造方法。若父类中有带参构造方法时,子类new子类实例时,需在子类的构造方法中显示的调用父类的构造方法,并进行传参。若父类中有多个构造方法,子类构造方法中就需显示决定使用哪一个构造方法。(使用super()进行传参)
- 创建子类实例时,需先执行父类的构造方法逻辑(先构造父类对象),再执行子类构造方法逻辑(再构造子类对象)。即显示调用父类构造方法时,需将父类构造方法放到代码的第一行。
class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
class Cat extends Animal {
public Cat(String name) {
// 使用 super 调用父类的构造方法.
super(name);
}
}
class Bird extends Animal {
public Bird(String name) {
super(name);
}
public void fly() {
System.out.println(this.name + "正在飞 ︿( ̄︶ ̄)︿");
}
}
public class Test {
public static void main(String[] args) {
Cat cat = new Cat("小黑");
cat.eat("猫粮");
Bird bird = new Bird("圆圆");
bird.fly();
}
}
二、封装
-
含义: 对象的属性和操作(或服务)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。
-
封装的优点:
①良好的封装能够减少耦合。
②类内部的结构可以自由修改。
③可以对成员变量进行更精确的控制。
④隐藏信息,实现细节。 -
访问权限控制符
①public
②private
③default
④protected
类前面只能加public或者不加。
属性前面四种均可加。
三、组合
一个类的成员可以是其他类。
public class Student {
...
}
public class Teacher {
...
}
public class School {
public Student[] students;
public Teacher[] teachers; }
组合表示 has - a :一个学校中 "包含" 若干学生和教师.
继承表示 is - a :一只猫也 "是" 一种动物.
四、多态
含义: 多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作。
多态性是对象多种表现形式的体现。
好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。
多态具体语法体现:
- 向上转型
- 动态绑定
- 方法重写
1、向上转型
含义:使用一个父类的引用指向一个子类的实例。
eg:Animal animal = new Cat();//此处Anlmal是父类,Cat是子类。
Bird bird = new Bird("圆圆");
Animal bird2 = bird;
// 或者写成下面的方式
Animal bird2 = new Bird("圆圆");
//此时 bird2 是一个父类 (Animal) 的引用, 指向一个子类 (Bird) 的实例.
//这种写法称为 向上转型
向上转型发生的时机:
①直接赋值
②方法传参
③方法返回
方法传参:
此时形参 animal 的类型是 Animal (基类), 实际上对应到 Bird (父类) 的实例.
public class Test {
public static void main(String[] args) {
Bird bird = new Bird("圆圆");
feed(bird);
}
public static void feed(Animal animal) {
animal.eat("谷子");
}
}
// 执行结果
圆圆正在吃谷子
方法返回:
此时方法 findMyAnimal 返回的是一个 Animal 类型的引用, 但是实际上对应到 Bird 的实例.
public static void main(String[] args) {
Animal animal = findMyAnimal();
}
public static Animal findMyAnimal() {
Bird bird = new Bird("圆圆");
return bird;
}
}
// Animal.java
public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println("我是一只小动物");
2、动态绑定
含义:父类中包含的方法在其子类中有对应同名同参的方法,会进行动态绑定。
(运行时确定调用的是哪个方法)在 Java 中, 调用某个类的方法, 究竟执行了哪段
代码(是父类方法的代码还是子类方法的代码) , 要看这个引用指向的是父类对象还是
子类对象. 这个过程是程序运行时决定的(而不是编译期), 因此称为动态绑定.
// Animal.java
public class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println("我是一只小动物");
System.out.println(this.name + "正在吃" + food);
}
}
// Bird.java
public class Bird extends Animal {
public Bird(String name) {
super(name);
}
public void eat(String food) {
System.out.println("我是一只小鸟");
System.out.println(this.name + "正在吃" + food);
}
}
// Test.java
public class Test {
public static void main(String[] args) {
Animal animal1 = new Animal("圆圆");
animal1.eat("谷子");
Animal animal2 = new Bird("扁扁");
animal2.eat("谷子");
}
}
// 执行结果
我是一只小动物
圆圆正在吃谷子
我是一只小鸟
扁扁正在吃谷子
- animal1 和 animal2 虽然都是 Animal 类型的引用, 但是 animal1 指向 Animal 类型的实例,animal2 指向 Bird 类型的实例.
- 针对 animal1 和 animal2 分别调用 eat 方法, 发现 animal1.eat() 实际调用了父类的方法, 而animal2.eat() 实际调用了子类的方法.
3、方法重写
含义:子类实现父类的同名方法, 并且参数的类型和个数完全相同,
这种情况称为 覆写/重写/覆盖(Override).
重写规则:
- 普通方法可以重写, static 修饰的静态方法不能重写.
- 重写中子类的方法的访问权限不能低于父类的方法访问权限.
- 重写的方法返回值类型不一定和父类的方法相同(但是建议最好写成相同, 特殊情况除外).
重载与重写的区别:
重载:同一作用域中,方法名相同,参数不同(参数个数不同 / 参数类型不同)。
重写:父类与子类之间,存在同名的方法(参数相同)。此时通过父类引用来调用该方法
时,会触发重写,具体执行父类中的方法还是子类中的方法由动态绑定规划来决定。