java的多态

继承

一、概念:

使用类来对同一类型的对象建模,不同的类可能会有一些共同的特征和行为,我们可以先定义一个通用的类,然后再定义一个特定的类去继承通用类。
通用类——父类 超类 基类
特定类——子类 继承类 派生类
子类从父类中继承可访问的数据域和方法,另外可以添加新的数据域和方法。私有数据域同样被子类继承,但子类不可以访问

public class cat extends animals{}  //extends作为关键字,告诉编译器cat继承自animals类

一个子类可能继承于多个父类,叫做多重继承,java是不允许多重继承的,java通过接口来实现,而c++允许多重继承

二、super关键字

关键词super指代父类,主要用于两种途径:

1、调用父类的构造方法:

父类的构造方法不会被子类继承,只能使用super从子类的构造方法中调用,且该调用必须是构造方法的第一条语句:

public Circle(double radius,String color,boolean filled){
	super(color,filled);   //调用父类有参构造方法  super()无参构造
	this->radius=radius;
}

在构造一个子类的对象时,子类会先调用父类的构造方法,如果没有代码中没有显式的调用,编译器会自动增加super()作为子类构造方法中的第一条语句

2、调用父类的普通方法

通过super调用父类中的普通方法:
super.方法名(参数);

三、方法重写和方法重载

1、方法重写:

有时子类除了继承父类方法,还需要修改父类中定义的方法的实现
重写的方法必须与被重写的方法具有一样的签名,一样或者兼容的返回类型。(兼容:重写方法的返回类型可以是被重写方法的返回类型的子类型)
私有方法不可以被重写,静态方法也不能被重写

2、方法重载:

方法重载是使用相同的方法名,但不同签名来定义多个方法,而方法重写是在子类中提供一个对父类方法的新的实现。

为了容易分辨,可以使用一种特殊的Java语法,“重写标注”,在子类方法前面加一个**@Override**
如果进行标注了,那必须重写父类的一个方法,否则编译报错

多态

子类是父类的特殊化,每个子类的实例都是其父类的实例,但反过来不成立。比如说:每个圆都是一个几何对象,但并非每个几何对象都是圆。因此,使用父类对象都可以使用子类对象去代替,多态意味着父类的变量可以引用子类的变量。

动态绑定:

animal m = new cat();
//父类: animal  子类: cat  多态:父类的变量可以引用子类的变量
// 相当于m = &(cat类型的一个实例) m是一个引用类型变量
System.out.println(m.toString());

一个变量必须被声明为某种类型。变量的这个类型称为它的声明类型。此处m的声明类型为animal
一个引用类型变量可以是一个null值,或者是对一个声明类型实例的引用。该实例可以使用声明类型或它的子类型的构造方法创建。这样的变量有实际类型,即被变量引用的对象的实际类。此处cat是m的实际类型。
m调用哪个toString()方法是由m的实际类型决定,称为动态绑定
引用变量的声明类型决定了编译时匹配哪个方法,实际类型决定了动态绑定方法的实现


class Animal{
	public Animal(){
		System.out.println("Animal的构造函数调用");
	}
	public void speak() {
		System.out.println("动物会说话");
	}
}

class Cat extends Animal{
	public Cat(){
		//super();  //编译器会默认加上该行,在子类自己构造方法实现之前会先实现父类构造方法
		System.out.println("Cat的构造函数调用");
	}
	@Override
	public void speak() {
		System.out.println("小猫会说话");
		//super.speak()  可以调用父类的speak方法,输出动物会说话
	}
}

public class TestCat {
	public static void main(String[] args) {
		m(new Animal());
		m(new Cat());   调用方法参数是cat的那个m方法
		//q(new Animal());  子类不可以引用父类
		n(new Cat());   虽然按照声明类型调用了方法参数是Animal的n方法,但是最后由实际类型cat绑定方法实现,输出小猫会说话
	}
	public static void m(Animal a) {
		a.speak();
	}
	public static void m(Cat c) {		构建重载方法,通过声明类型决定编译时匹配哪个方法
		c.speak();
	}
	public static void n(Animal a) {		//Animal a = new Cat();
		c.speak();
	}
	public static void q(Cat q){
		q.speak();
	}
	
}

输出:
Animal的构造函数调用
动物会说话
Animal的构造函数调用
Cat的构造函数调用
小猫会说话
Animal的构造函数调用
Cat的构造函数调用
小猫会说话

对象转换和instanceof操作符

对象转换:一个对象的引用可以类型转换为对另外一个对象的引用
向上转换:可以将一个子类的实例转换为一个父类的变量 可以隐式转换

结合上文:
n(new Cat());   该语句将对象new Cat()赋值给了Animal类型的参数a,等价于:
Animal a = new Cat();   
n(a);

向下转换:将一个父类的实例转换为它的子类变量,必须使用转换标记“(子类名)”进行显示转换。为了转换成功,必须确保要转换的对象是子类的一个实例。如果父类对象不是子类的一个实例,就会出现一个运行时异常,比如说上文那个错误。所以在尝试转换之前确保该对象是另一个对象的实例,可以利用instanceof来实现

Animal cat = new Cat();
if(cat instanceof Cat) {
	q((Cat)cat);
}

对基本类型值进行转换不同于对对象引用进行转换:转换一个基本类型值会返回一个新的值,而转换一个对象引用不会创建一个新的对象,转换前后的变量都会指向同一个变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值