目录
友情提醒
先看文章目录,大致了解知识点结构,直接点击文章目录可以跳转到文章指定位置。
一、Java面向对象的三大特性之多态
1.1)理解多态
①联系生活实际,相类似的事物/行为使用统一的称呼和准则。
例1:手机支付,现金支付,以物易物等等我们统一用支付称呼这类不同的交易行为。
例2:苹果,香蕉,哈密瓜等等我们统一用水果称呼这些不同的果子。
②联系Java代码,不同子类继承了同一个父类。当我们统一用父类引用变量去调用这些不同的子类对象中的方法时,我们称为多态。
1.2)多态的前提
①多态的使用必须在继承的体系中。了解继承可以看这篇博客—》三大特性之继承性
②子类必须重写父类的方法
③实例化对象的时候父类的引用变量指向子类的对象(向上转型): Fu f = new Zi();
多态格式:父类 对象名=new 子类();
二、多态的体现
2.1)接口中的多态
注意:实现类中独有的成员,多态中接口无法直接调用访问。可以先进行强制向下转型,才能访问实现类独有属性和方法。
public interface FlyAnimal {
//抽象方法
public abstract void fly();
}
//----------------------分割--------------------------------
class bird implements FlyAnimal{
@Override
public void fly(){
System.out.println("鸟在飞");
}
}
class Cow implements FlyAnimal{
@Override
public void fly(){
System.out.println("牛在飞");
}
}
//----------------------分割--------------------------------
class Test{
public static void main(String[] args) {
//子类对象变量调用自己的方法
bird b1 = new bird();
Cow c1 = new Cow();
b1.fly();
c1.fly();
//使用多态,父类对象变量调用子类方法
FlyAnimal b2 = new bird();
FlyAnimal c2 = new Cow();
b2.fly();
c2.fly();
}
}
2.2)抽象类的多态
注意:子类中独有的成员,多态中父类无法直接调用访问。可以先进行强制向下转型,才能访问子类独有属性和方法。
public abstract class FlyAnimal {
//抽象方法
public abstract void fly();
}
class bird extends FlyAnimal{
@Override
public void fly(){
System.out.println("鸟在飞");
}
}
//----------------------分割--------------------------------
class Cow extends FlyAnimal{
@Override
public void fly(){
System.out.println("牛在飞");
}
}
//--------------------分割----------------------------------
class Test{
public static void main(String[] args) {
//子类对象变量调用自己的方法
bird b1 = new bird();
Cow c1 = new Cow();
b1.fly();
c1.fly();
//使用多态,父类对象变量调用子类方法
FlyAnimal b2 = new bird();
FlyAnimal c2 = new Cow();
b2.fly();
c2.fly();
}
}
2.3)多态应用场景
下面的例子中:Kite,Plane,BirdFly都实现了Able接口,此时可以使用多态数组存储。
public class TestInter {
public static void main(String[] args) {
//Kite,Plane,BirdFly都实现了Able接口,
//创建FlyAble数组,长度为3
FlyAble[] fa = new FlyAble[3]; //多态数组
fa[0] = new Kite(); //多态了
fa[1] = new Plane(); //多态了
fa[2] = new Bird(); //多态了
//遍历fas数组元素,调用fly方法执行
for(FlyAble f : fa){
f.fly();
}
}
}
2.4)多态的好处和弊端
好处:降低冗余度,有良好的扩展性和阅读性,并可以对所有类的对象进行通用处理。下面的例子中:lookAnimal这个方法复用度大大提高,一个方法可以看无数个动物
public abstract class FlyAnimal {
//抽象方法
public abstract void fly();
}
//--------------------分割----------------------------------
class Bird extends FlyAnimal{
@Override
public void fly(){
System.out.println("动物园鸟在飞");
}
}
//--------------------分割----------------------------------
class Cow extends FlyAnimal{
@Override
public void fly(){
System.out.println("动物园牛在飞");
}
}
//--------------------分割----------------------------------
class Pig extends FlyAnimal{
@Override
public void fly(){
System.out.println("动物园猪在飞");
}
}
//--------------------分割----------------------------------
class Test{
//主方法
public static void main(String[] args) {
//使用多态,lookAnimal这个方法复用度大大提高,一个方法可以看无数个动物
FlyAnimal b1 = new Bird();
FlyAnimal c1 = new Cow();
FlyAnimal p1 = new Pig();
//使用lookAnimal方法
lookAnimal(b1);//传入父类,运行bird子类方法
lookAnimal(c1);//传入父类,运行cow子类方法
lookAnimal(p1);//传入父类,运行pig子类方法
}
//lookAnimal方法
public static void lookAnimal(FlyAnimal f){
f.fly();
};
}
弊端:不能调用子类特有的方法。需要强制向下转型才能调用。
三、多态的类型转换
3.1)自动向上转换
父类 父类对象名=new 子类();
Animal animal =new Dog();
Animal animal = new Cat();
3.2)强制向下转换
子类 子类对象名=(子类类型)父类对象名;
Dog dog = (Dog) animal;
Cat cat = (Cat) animal;
3.3)instanceof关键字
①Cat子类向上转为Animal父类后,怎么知道这个Animal变量名是Cat类转的呢?可以用instanceof关键字来判断。
判断对象本质类型是否属于该数据类型:
格式: 对象名 instanceof 数据类型
①如果是该类型,则返回true
②如果不是该类型,则返回false
abstract class Person{
public abstract void eat();
}
//--------------------分割----------------------------------
class Man extends Person{
@Override
public void eat(){
System.out.println("男的吃饭");
}
}
//--------------------分割----------------------------------
class Woman extends Person{
@Override
public void eat(){
System.out.println("女的吃饭");
}
}
//--------------------分割----------------------------------
class Test {
public static void test(Person ps){
//使用instanof判断
if(ps instanceof Man){
//说明是一个Man,则强转为Man类型
Man m = (Man)ps;
}else if(ps instanceof Woman){
//说明是一个Woman,则强转为Woman类型
Woman w = (Woman)ps;
}
}
}
面试题拓展
结论:
①属性(静态、非静态)都没多态性的展现,静态方法也没有多态性的展现
②非静态方法有多态的展现:编译时检查父类中是否有该方法,如果没有,编译错误;如果有,执行子类重写后的方法。如果子类没有重写该方法,就会调用父类的该方法。总结:编译看左边,运行看右边。
/*
多态性相关的面试内容:
属性(静态、非静态)都没多态性的展现,静态方法也没有多态性的展现
非静态方法有多态的展现编译阶段看看等号左侧运行阶段看等号右侧
*/
class Father{
//静态属性
static int a = 10;
//非静态属性
int b = 20;
//静态方法
public static void func(){
System.out.println("Father...func");
}
//非静态方法
public void method(){
System.out.println("Father...method");
}
}
//--------------------分割----------------------------------
class Son extends Father{
//静态属性
static int a = 100;
//非静态属性
int b = 200;
//静态方法
public static void func(){
System.out.println("Son...func");
}
//非静态方法
public void method(){
System.out.println("Son...method");
}
}
//--------------------分割----------------------------------
class Test{
public static void main(String[] args) {
Father f = new Son(); //多态了
//访问属性(静态、非静态)
System.out.println(f.a);
System.out.println(f.b);
//访问静态方法
f.func();
//访问非静态方法
f.method();
}
}/* 打印结果
10
20
Father...func
Son...method*/