继承与多态
1.为什么会出现继承呢?
因为平时在写代码的时候会出现许多的相同的代码,这就出现了代码的冗余,这时候用继承就可以解决这个问题。
public 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 {
public String name;
public Cat(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
}
class Bird {
public String name;
public Bird(String name) {
this.name = name;
}
public void eat(String food) {
System.out.println(this.name + "正在吃" + food);
}
public void fly()
{
System.out.println(this.name + "正在飞 ︿( ̄︶ ̄)︿");
}
}
这时候用继承就会减少你的代码量
这个代码我们发现其中存在了大量的冗余代码.
仔细分析, 我们发现 Animal 和 Cat 以及 Bird 这几个类中存在一定的关联关系:
1.这三个类都具备一个相同的 eat 方法, 而且行为是完全一样的.
2.这三个类都具备一个相同的 name 属性, 而且意义是完全一样的.
3.从逻辑上讲, Cat 和 Bird 都是一种 Animal (is - a 语义). 此时我们就可以让 Cat 和 Bird 分别继承 Animal 类, 来达到代码重用的效果.
此时, Animal 这样被继承的类, 我们称为 父类 , 基类 或 超类, 对于像 Cat 和 Bird 这样的类, 我们称为 子类, 派生类
和现实中的儿子继承父亲的财产类似, 子类也会继承父类的字段和方法, 以达到代码重用的效果
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();
}
}
使用** extends **指定父类.
Java 中一个子类只能继承一个父类 (而C++/Python等语言支持多继承).
子类会继承父类的所有 public 的字段和方法. 对于父类的 private 的字段和方法, 子类中是无法访问的.
子类的实例中, 也包含着父类的实例. 可以使用 super 关键字得到父类实例的引用.
子类继承父类除了构造方法的所有属性和方法,子类要调用父类的构造方法,并且写在首部。
多态的认知
多态必须要有继承和方法的重写,还有父类引用子类对象
也就是向上转型
为啥叫 “向上转型”? 在面向对象程序设计中, 针对一些复杂的场景(很多类, 很复杂的继承关系), 程序猿会画一种 UML 图的方式来表 示类之间的关系. 此时父类通常画在子类的上方. 所以我们就称为 “向上转型” , 表示往父类的方向转.
运行时绑定————多态
在 Java 中, 调用某个类的方法, 究竟执行了哪段代码 (是父类方法的代码还是子类方法的代码) , 要看究竟这个引 用指向的是父类对象还是子类对象. 这个过程是程序运行时决定的(而不是编译期), 因此称为 动态绑定
下面是多态的关于向上转型的代码
class Animal{
public String name;
public int age;
public Animal(){
}
public Animal(String name,int age){
this.name=name;
this.age=age;
System.out.println("hhhhh");
}
public void eat(){
System.out.println("吃吃");
}
}
class Cat extends Animal{
public String sex;
public Cat(){
}
public Cat(String name,int age,String sex){
super(name,age);
this.sex=sex;
System.out.println("sssss");
}
public void jump(){
System.out.println(this.name+"跳跳");
}
public void eat(){
System.out.println("吃吃吃吃");
}
}
class Bird extends Animal{
public String yumao;
public void fly() {
System.out.println("飞飞");
}
}
下面可以看一下关于多态的理解与应用
class Shape {
public void draw() {
// 啥都不用干
}
}
class Cycle extends Shape {
@Override public void draw() {
System.out.println("○");
}
}
class Rect extends Shape {
@Override public void draw() {
System.out.println("□");
}
}
class Flower extends Shape {
@Override public void draw() {
System.out.println("♣");
}
}
public class Test {
public static void main(String[] args) {
Shape shape1 = new Flower();
Shape shape2 = new Cycle();
Shape shape3 = new Rect();
drawMap(shape1);
drawMap(shape2);
drawMap(shape3);
} // 打印单个图形
public static void drawShape(Shape shape) {
shape.draw();
}
}
当类的调用者在编写 drawMap 这个方法的时候, 参数类型为 Shape (父类), 此时在该方法内部并不知道, 也不关注当 前的 shape 引用指向的是哪个类型(哪个子类)的实例. 此时 shape 这个引用调用 draw 方法可能会有多种不同的表现 (和 shape 对应的实例相关), 这种行为就称为 多态。
向上转型,也就是父类引用子类对象,并且重写了父类的方法且调用
向下转型,就是把父类向子类转,但是必须要先进行向上转型,不然的话就会出出现类型转换错误
必须检查这个对象是不是父类的实例,不是的话就不能进行向下转型
if(animal instanceof Cat ) {
Cat cat = (Cat)animal ;
cat.jump();
}
就以这个为例,Cat明显不是Animal的实例,因此不能向下转型。
使用多态的好处是什么?
- 类调用者对类的使用成本进一步降低. 封装是让类的调用者不需要知道类的实现细节. 多态能让类的调用者连这个类的类型是什么都不必知道, 只需要知道这个对象具有某个方法即可.
继承与多态就说这些了