黑马程序员-java多态

---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------



面向对象编程有三个特征,即封装、继承和多态

封装隐藏了类的内部实现机制,从而可以在不影响使用者的前提下改变类的内部结构,同时保护数据。

继承是为了重用父类代码,同时为实现多态性做准备。

下面我们介绍多态。


多态的体现:

父类型的引用可以指向子类型的对象。如,

Parent p=new Child(); //Child类继承了Parent类


多态的好处:

大大提高程序的扩展性。因为java只允许单继承,这样虽然保证了继承关系的简单明了,但也势必在功能上有很大的限制。多态的引入用于弥补这点不足,另外,抽象类和接口也是解决单继承规定限制的重要手段。

多态的弊端:

虽然提高了扩展性,但是只能使用父类的引用访问父类中的成员。


下面用例子来讲解多态中几个重要的概念

例1:

public class PolyDemo
{
    public static void main(String[] args)
    {
        
        Animal a1=new Cat();  //自动向上类型转换
        Animal a2=new Dog();
		//调用子父类共有方法
		a1.eat();             //动态绑定
		a2.eat();
		//调用子类特有方法
		//a1.catchMouse();    //错误,父类中没有catchMouse()方法
		Cat c=(Cat)a1;	      //强制向下类型转换
		Dog d=(Dog)a2;        
		c.catchMouse();       
		d.guardHouse();   

        //Animal a3 = new animal();
        //Cat c2 = (Cat)a3;   //错误,不能将父类对象转成子类类型
    }
}
class Animal
{
    public void eat()
    {
        System.out.println("Animal is eating!");
    }
}
class Dog extends Animal
{
    public void eat()
    {
        System.out.println("Dog is eating!");   //Dog类重写了eat()方法
    }
	public void guardHouse()                //Dog类特有的方法
	{
		System.out.println("Dog is guarding house!");
	}
}
class Cat extends Animal
{
    public void eat()
    {
        System.out.println("Cat is eating!");
    }
    public void catchMouse()
    {
        System.out.println("Cat is catching mouse!");
    }
}

输出结果:

Cat is eating!
Dog is eating!
Cat is catching mouse!
Dog is guarding house!
由此例,我们讲解以下几个概念:
1、类型转换

1)自动向上类型转换(Upcast):将子类型转为父类型

对于向上的类型转换,不需要显示指定转换类型,类型自动提升

2)强制向下类型转换(Downcast):将父类型转化为子类型

对于向下的类型转换,必须要显示指定转换类型,即必须使用强制类型转换

注意:由上例可知,我们能转换的是父类引用指向子类对象时,该引用既可以被提升,也可以被强制转换。多态自始至终都是子类对象在做着变化


2、多态时成员的特点

1)成员函数:

当父类引用指向子类对象时,该引用变量可以调用子父类共有的成员方法,而不能调用子类中定义但父类中没有的成员方法(否则会编译失败)。

同时,对于父类中定义的成员方法,如果子类重写了该方法,那么父类引用将会调用子类中的该方法,而这就是动态绑定

简单总结:成员方法在多态调用时,编译时期参阅引用变量所属类中是否有调用的方法,如果有则通过,否则编译失败;在运行时期参阅被引用对象所属的类中的成员方法。

2)成员变量:

无论编译时期还是运行时期,都参阅引用变量所属类中的成员变量。

3)静态成员方法:

无论编译时期还是运行时期,都参阅引用变量所属类中的静态成员方法。


下面我们再来看一个例子,以便更好的理解java的多态性

例2:

class PolyDemo 
{
	public static void main(String[] args) 
	{
		A a1 = new A();  
		A a2 = new B();  
        B b = new B();  
        C c = new C();   
        D d = new D();   
        System.out.println(a1.show(b));     
        System.out.println(a1.show(c));    
        System.out.println(a1.show(d));    
        System.out.println(a2.show(b));    
        System.out.println(a2.show(c));   
        System.out.println(a2.show(d));    
        System.out.println(b.show(b));     
        System.out.println(b.show(c));     
        System.out.println(b.show(d)); 
	}
}
class A 
{  
	public String show(D obj)
	{  
		return ("A and D");  
    }   
    public String show(A obj)
	{  
        return ("A and A");  
    }   
}   
class B extends A
{  
    public String show(B obj)
	{  
        return ("B and B");  
    }  
    public String show(A obj)
	{  
        return ("B and A");  
    }   
}  
class C extends B{}   
class D extends B{} 
输出结果:

A and A
A and A
A and D
B and A
B and A
A and D
B and B
B and B
A and D

在分析结果前,我们先讲一下 方法调用的优先问题,优先级由高到低依次为:

this.show(O)>super.show(O)>this.show((super)O)>super.show((super)O)

现在我们来分析结果。1~3的结果应该很好理解。

以4为例,引用变量为a2,类型是A,则this是a2。于是它先在类A中寻找show(B obj)方法,未找到;然后到A的super类(父类)中找,然而A没有父类;于是它转到第三优先级this.show((super)obj),此时this为a2,而O(即B)的父类为A,故在A中寻找show(A obj),类A有此方法。但因为a2引用的是B的一个对象b,而B中重写了A的show(A obj)方法,根据动态绑定,故最终调用的是B中的show(A obj)方法,输出“B and A”。

例5~9同理可得。


下面讲一些多态的应用

需求:电脑运行实例

/*未考虑多态的思考方式(不好)*/
class MainBoard
{
	public void run()
	{
		System.out.println("主板运行!");
	}
	public void useNetCard(NetCard c)    //加载一个网卡,则添加一段调用网卡的代码;若还要加载声卡等,
	{                                    //则再添加调用声卡的代码。扩展性极差。
			c.open();
			c.close();	
	}
}
class NetCard
{
	public void open()
	{
		System.out.println("网卡打开!");
	}
	public void close()
	{
		System.out.println("网卡关闭!");
	}
}


/*考虑多态的思考方式*/
class MainBoard
{
	public void run()
	{
		System.out.println("主板运行!");
	}
	public void usePCI(PCI p)
	{
		if (p!=null)
		{
			p.open();
			p.close();
		}
		
	}
}
interface PCI
{
	public abstract void open();
	public abstract void close();
}
class NetCard implements PCI
{
	public void open()
	{
		System.out.println("网卡打开!");
	}
	public void close()
	{
		System.out.println("网卡关闭!");
	}
}



---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------详细请查看:www.itheima.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值