Java继承、多态

继承


继承是一种关系,继承者拥有被继承者的特征关系,一个大群体包含一个小群体,这时我们就可以用到继承

语法

Java中如果一个类继承于另一个类,使用extends关键字 : class A extends B
示例:

public class Animal{
	public String name;
	public int age;
	public String color;
	public void eat(){
		System.out.println("吃东西");
	}
}

//继承关系
public class dog extends Animal{
	public void dark(){
		System.out.println("狗在汪汪的叫");
	}	
}

通过继承,子类可以拥有父类所有的属性和方法,上例中Dog类创建的对象具有父类Animal类的特征

Dog dog = new dog();
dog.name;
dog.eat();
dog.dark();

并不会报错

继承的作用

主要作用为使用继承能够对代码进行重用,它也是多态的一种
根据上面的Animal父类 我们可以省略大部分重复代码,因为动物具有许多相同特征

public class Cat extends Animal{
	public void catchMouse(){
		System.out.println("猫正在抓老鼠");
	}
}

Cat类和Dog类一样,都具有名字,年龄,颜色,所以都可以使用一个父类的属性
父类更加通用,抽象,而子类更加具体
继承的三个价值:

  1. 重用代码,简化代码和工作量,重用能够增加代码的可用价值
  2. 扩展功能,细化类型,详细描述对象的类型
  3. 实现对象的多种形态,即多态

继承的注意事项

  1. 单一继承原则 :子类只允许继承一个父类,不能有多继承
  2. 单方向继承原则:只允许子类获得父类的非私有成员
  3. 父类private私有特征子类不能继承!只有public/protected属性方法可以被子类访问
  4. 所有类的默认父类均为Object,因此都具有Object的一些方法

super关键字

在类中可以使用this关键字代表自己,而对于继承的子类,可以使用super表示父类

public class A{
	public int a1;
	public void a2(){}
}

public classe B extends A{
	public B(){
		super();  //调用父类的构造函数
		super.a = 100; //父类属性,用this也可调用
		super.a2(); //父类方法
	}
	public void b(){
		this.a = 10;
	}
}

实际上,继承在Java中子类在使用new创建对象使用时会先把父类new创建出来,子类在调用构造方法的第一行,会先调用父类的构造方法,即隐式调用了父类构造 super() 方法,父类实例化后再子类实例化

public class A{
	public A(){
		System.out.println("aaa");
	}
}
public class B extends A {
	public B(){
		System.out.println("bbb");
	}
}

//测试
B b = new B(); //输出aaa bbb

当然如果父类有多个构造方法,我们可以在子类中运用super改变自动调用的情况

调用关系

由上可知,this 和 super 有相同的作用,super 只有在子类和父类属性或者方法调用冲突的时候才必须使用
假设子类有属性 name,调用该属性时

  • 如果 name 是自己没有的,那么就往父类寻找,父类没有继续往上找到为止
  • 如果 name 自己有,那么就会调用自己的
  • 如果都有,那么就用 super.name 和 this.name 进行区分
  • 如果父类有子类没有,用 this.name 和 super.name 都能调用

组合优先于继承

如果一个类中有多个方法可以使用,如果要扩展这个类,有两种方案:继承和组合
如:

class A{
    public void a1() { }
    public void a2() { }
    public void a3() { }
}// 使用继承
class B1 extends A{
    // 自动继承父类方法
    
    // 重写扩展父类方法
    @Override 
    public void a1() { 
        super.a1(); 
    }
    // 添加其他扩展方法
    public void b() { }
}// 使用组合
class B2{
    // 依赖于A对象
    private A a = new A();
    // 通过A对象实现的中介方法
    public void a1() { 
        this.a.a1(); 
    }
    // 扩展方法
    public void a2() { 
        this.a.a2(); 
    }
    // 添加其他扩展方法
    public void b() { }
}

优先使用继承还是组合

  1. 需要使用多态时优先考虑继承
  2. 结构稳定,继承关系层次简单可以使用

组合与继承的区别

组合继承
has-a 的关系is-a 的关系
运行期决定编译器决定
不破坏封装破坏封装,子类依赖于父类
支持扩展,随意增加只能单继承,包含所有父类方法
动态选择组合类方法全盘复用父类方法

多态


引用类型转换

基本数据类型中
从小空间到大空间:

  • 类型必须兼容,除Boolean以外都兼容
  • 自动转换(隐式转换)
  • 发生在进行赋值的时候

从大空间到小空间

  • 强制转换(显示转换)
  • 可能产生精度丢失的情况

引用数据类型中
在继承过程中,有父类和子类,是大空间包含小空间的情况

  • 向上转型:也叫隐式转换,自动转换,从子类小群体对象到父类大群体对象是自动类型转换,比如Animal a = new Cat()
  • 反之为向下转型 如Cat a = new Animal(),会报错

class Cat extends Animal{
    public void cry(){
        System.out.println("猫在叫:喵喵");
    }
    public void catch(){
        System.out.println("猫能吃老鼠");
    }
}// 入口测试
Animal a = new Cat();
a.catch(); // 编译失败

引用数据类型强制类型转换方法如下

Cat cat = new Cat();
Animal animal = new Cat(); // 向上转型

((Cat)animal).catch(); // 向下转型:强制转换

总结:

  1. 父类 对象 = new 子类() 编译成功
  2. 子类 对象 = new 父类() 编译失败
  3. 子类 对象 = (子类)父类引用子类 强制转换
  4. 父类 对象 = new 子类(); 对象.方法(); 访问的是子类的方法(如果有重写);

多态的概念

多态是同一个行为具有多个不同表现形式或形态的能力,多应用于数组、方法的重写与重载中,使用多态让程序更具有扩展性
相同的行为,由于不同的参数、不同的执行者,导致执行不同的代码,得到的结果也不相同,即多态形式。

Animal a = new Dog();
a.cry();
a = new Dog();
a.cry();

一共有两种方法可以实现多态:

  1. 方法重载:也叫 Overload 行为相同,由于参数不同,得到不同的结果。也称静态多态,在编译期就能知道结果,方法签名已知
  2. 方法重写:也叫 Override 行为相同,由于执行者不同,得到不同的结果。也称动态多态,只有在运行时才知道结果

重载在于同一个类,重写涉及多个类

多态的实现种类

第一种多态:方法重载产生的多态

public class Pig{
    public void pk(){
        System.out.println("猪在pk");
    }
}
public class WhitePig extends Pig{
    public void pk(){
        System.out.println("白猪用锤子打");
    }
}
public class RedPig extends Pig{
    public void pk(){
        System.out.println("红猪用刀打");
    }
}// 测试类,方法重载
public class Game{
    public void control(WhitePig p){
        p.pk();
    }
    public void control(RedPig p){
        p.pk();
    }public static void main(String[] args){
        Game game = new Game();
        Pig p1 = new WhitePig();
        Pig p2 = new RedPig();
        game.control(p1);
        game.control(p2);
    }
}

第二种多态:向上转型和方法重写产生的多态

第三种多态:数组产生的多态

String[] array = new String[] {new A(), new B(), new C()} // 对象数组

第四种多态:方法参数和重写实现多态
(方法重载实现的多态过于麻烦,可以通过父类对象作为参数对方法进行重新设计)

public class Game{
    // 使用父类作为参数
    public void control(Pig p){
        p.pk();
    }
}

第五种多态:由方法返回值不同产生的多态


public Pig createPig(){
    Pig p = null;
    int rand = (new Random()).nextInt(3);
    switch(rand) {
        case 0:
            p = new WhitePig();
            break;
        case 1:
            p = new BlackPig();
            break;
        case 2:
            p = new RedPig();
            break;
    }
    return p;
}

方法的重写

方法重写发生在不同的类中,比如子类不满足于父类方法的实现方式,允许重写父类的方法,实现不一样的需求。
示例:


class Animal{
    public void cry(){
        System.out.println("动物在叫");
    }
}
class Dog extends Animal{
    public void cry(){
        System.out.println("狗在叫:旺旺");
    }
}
class Cat extends Animal{
    public void cry(){
        System.out.println("猫在叫:喵喵");
    }
}// 测试
Animal animal = new Animal();
animal.cry(); // 动物在叫
Dog dog = new Dog();
dog.cry(); // 狗在叫:旺旺
Cat cat = new Cat();
cat.cry(); // 猫在叫:喵喵

上述代码中cry()方法则为重写

  1. 必须有继承关系
  2. 方法名必须完全一样
  3. 发生向上转型,父类型的变量引用子类对象

Override注解

我们重写父类的方法时,一般都在方法前面添加@Override,如:

public class B extends A{
    @Override 
    public void f1(){}

    @Override 
    public void f2(){}
}

重载与重写的区别

重载与重写是为了实现面向对象中的多态

重载重写
位置发生在同一个类中发生在两个有继承关系的类中
方法名方法同名方法同名
参数参数列表必须不同参数列表必须相同
返回值返回类型可以不同,可以相同返回类型必须相同(或者继承关系)
静态方法支持重载不能重写

严格来讲重载的各个方法是完全不同的,重载的方法最终根据参数区分,即给我什么就干什么;

重写实际上是子类重写了父类的方法,重写的方法最终根据当前所操作的对象来区分,即让谁去做就做出什么结果。

方法重载调用时

  1. 如果没有改匹配的类型则自动向上转型
  2. 以类型定义为准,非实际类型
  3. 类型匹配直接调用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

轩尼诗道-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值