Java多态初了解

一、多态的定义:

面向对象程序设计的三大特性是封装、继承和多态

多态是同一个行为具有多个不同表现形式或形态的能力。

多态就是同一个接口,使用不同的实例而执行不同的操作。

用更通俗的话来概况多态,那就是具体问题具体分析

二、实现多态的必要条件

1、 首先我们来看一段基于继承实现多态的代码:

public class Test {
    public static void main(String[] args) {
        util a = new util();
        a.use();
        keyboard b = new keyboard();
        b.use();
        util c = new mouse();
        c.use();
        util d = new computer();    //向上转型
        d.use();
        d.notUse();
        mouse f = (mouse) c;        //向下转型
        f.use();
        f.notUse();
        f.click();
        
        computer k = (computer) c;  //错误的写法
        k.use();                    //因为c此时指向的是子类mouse
    }
}

/** 父类 */
class util {
    public void use() {
        System.out.println("使用工具");
    }
    public void notUse() {
        System.out.println("不使用工具");
    }
}

/** 三个子类 */
class keyboard extends util{
    public void use() {
        System.out.println("使用键盘");
    }
}

class mouse extends util{
    public void use() {
        System.out.println("使用鼠标");
    }
    public void click() {
        System.out.println("点击");
    }
}

class computer extends util{
    public void use() {
        System.out.println("使用电脑");
    }
}

具体输出结果如下:
在这里插入图片描述
在这段代码中,我们有一个父类,叫做util。

以及还有三个子类,分别是keyboard,mouse,computer,他们都隶属于util这个大类。

而且,我们会发现他们都有一个相同的方法名叫做use。

但现在如果要你在不修改父类的程序代码前提下,同时我们又需要在不同的情况下使用同一个方法名,那该怎么做呢?

如果我们直接删除某个子类的use函数会怎么样呢?结果就是直接调用了父类的use函数并且输出了“使用工具”,这就是继承,但也就达不到输出具体实例需要的效果了。

这个时候就需要多态性,即不修改程序代码就可以改变程序运行时所绑定的具体代码,也可以让程序选择多个运行状态来达到不同的效果。

所以,我们可以得出实现多态的三个必要条件

1、继承
子类首先要继承父类。

2、重写
为了实现具体实例的不同效果,子类需要对继承于父类的同一个方法进行重写,比如代码中的每个子类对父类use方法的重写。

3、转型
转型又可以分为向上转型和向下转型

------向上转型 (具体请看代码中变量d的使用)

就是将子类对象转化为父类类型,也可以说父类引用指向子类对象。即 父类类型 对象名称 = new 子类类型()
在这里插入图片描述
变量d重写了父类的use方法,但是仍旧能使用父类的另一个方法notUse,这大大提高了拓展性。

但同时也有缺点,我们不能再调用子类中的方法和属性了。

所以向上转型主要适用于不需要面向子类对象时,用父类的功能即可完成相应操作的情况。
------向下转型 (具体请看代码中变量f和k的使用)

就是将父类类型强制转化为子类类型。即我们先定义了一个父类对象指向了子类类型,然后将这个父类类型强制转化为子类类型。
在这里插入图片描述
在这里插入图片描述
于是向下转型就能够调用子类中的方法,比如变量f的click方法。同时也继承了父类的特点,如图中变量f继承了父类c的use和notUse方法。

所以向下转型主要适用于需要使用子类的功能的情况。
但前提这个子类必须是你这个父类引用时指向的那个子类对象

也就是说你原本是mouse,那你肯定不能变成computer啊。

否则就会出现无法强制转化类型的错误,即出现如下图所示的报错。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2、 我们再来看一段基于接口实现多态的代码:

/** 接口方法创建 */
interface Operation {
	public void add();
	public void delete();
}
 
/** 接口实现类 */
class InterfaceOfUtil implements Operation {
	public void add() { 
		System.out.println("添加工具");
	}
 
	public void delete() {
		System.out.println("删除工具");
	}
}

class InterfaceOfMouse implements Operation {
    public void add() { 
		System.out.println("添加鼠标");
    }
    
	public void delete() {
		System.out.println("删除鼠标");
	}
}

/** 测试类 */
public class Test {
	public static void main(String[] args) {
        Operation op1 = new InterfaceOfUtil();
        Operation op2 = new InterfaceOfMouse();
        op1.add();
        op1.delete();
        op2.add();
        op2.delete();
    }
}

具体输出结果如下:
在这里插入图片描述
1. 我们首先定义了一个接口,叫做Operation,里面有两个抽象方法,分别是add、delete,用于添加操作和删除操作。
(注意接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法)

2. 我们通过两个接口实现类: InterfaceOfUtil、InterfaceOfMouse,具体实现了接口中的抽象方法。

3. 然后我们通过测试类: Test将两者的操作都使用了一遍。

在这个过程中,我们会发现util和mouse其实都属于可操作的operation类型,在一种类型下表现出了多种状态,比如util和mouse的名字状态就不一样,当然还可以是价格等其他属性等等,这也体现了多态性

三、接下来是根据经典实例略加修改的一段代码:

public class Test {
    public static void main(String[] args) {
        util father = new util();
        util fatherFromSon = new mouse();
        mouse son = new mouse();
        temp1 t1 = new temp1();
        temp2 t2 = new temp2();

        father.use(son);
        father.use(t1);
        father.use(t2);
        System.out.println("---------");
        fatherFromSon.use(son);
        fatherFromSon.use(t1);
        fatherFromSon.use(t2);
        System.out.println("---------");
        son.use(son);
        son.use(t1);
        son.use(t2);
    }
}
/** 父类 */
class util {
    public void use(temp2 obj) {
        System.out.println("使用工具和temp2");
    }
    public void use(util obj) {
        System.out.println("使用工具和工具");
    }
}

/** 子类 */
class mouse extends util{
    public void use(mouse obj) {
        System.out.println("使用鼠标和鼠标");
    }
    public void use(util obj) {
        System.out.println("使用鼠标和工具");
    }
}

class temp1 extends mouse {
}

class temp2 extends mouse {
}

具体输出结果如下:
在这里插入图片描述
这里我们有四个类,分别是util、mouse和temp1、temp2。

对于第三个操作,因为temp2有明确定义的方法,所以调用的是use(temp2 obj)这个方法。在这里插入图片描述
最难理解的是其他几个操作。例如第四个操作(fatherFromSon.use(son)),fatherFromSon是向上转型的util类型,其use方法重写为son的use方法,按上面的知识点来说,当我们调用use(mouse obj)方法时,应该是输出“使用鼠标和鼠标”的,但结果却是“使用鼠标和工具”,这是为什么呢?

这里就会涉及到继承链中的优先级原则:1.this.use(obj)、2.super.use(obj)、3.this.use((super)obj)、4.super.use((super)obj)。

那么根据下面这张关系图,

1.首先对于fatherFromSon,它是向上转型的util类型,而util类型中并没有use(mouse obj)这个方法。

2.我们会接着去找util类型的super类,util类已经没有super了,那么就会继续判断下一个优先级。

3.this.use((super)mouse),就等价于this.use(util),由于当前的use方法被重写了,所以就会调用mouse类中的use(util obj),也就输出“使用鼠标和工具了”。

我们会发现其他的几个操作也都是符合这个规律的。
在这里插入图片描述
如果我们在父类util里面把每个类型的方法都加上,例如下图:
在这里插入图片描述
那么输出结果就会变成:
在这里插入图片描述
个人理解:如果父类和子类中有相同定义的方法,那么方法就会被成功重写。否则就会按照继承链的优先级来确认方法。

四、多态的优点和缺点:

优点:

1.可替换性(substitutability): 多态对已存在代码具有可替换性。例如,我们可以通过mouse子类重写方法来实现替换util父类的use方法。

2.可扩充性(extensibility): 多态对代码具有可扩充性。比如我们可以继承父类util的方法,然后继续扩充子类mouse的方法。

3.接口性(interface-ability): 多态中的父类可以通过方法,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。

4.灵活性(flexibility): 它在应用中体现了灵活多样的操作,提高了使用效率。

5.简化性(simplicity): 多态简化了类之间的关系,减少了代码量。

------缺点:

  1. 如果不进行向下转型,就无法使用子类的特定功能。

五、总结:

多态是Java中的重要特性。在项目中运用也会有出色的效果,比如在特定的情况下,当某处代码的修改会牵连到很多地方的时候,通过多态的特点来降低耦合度,可以保证程序的拓展性以及降低成本。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值