zoukankan      html  css  js  c++  java
  • 多态

    Java作为面向对象的语言,可以描述一个事物的多种形态。如Student类继承了Person类,一个Student的对象便既是Student,又是Person。

    Java中多态的代码体现在一个子类对象(实现类对象)既可以给这个子类(实现类对象)引用变量赋值,又可以给这个子类(实现类对象)的父类(接口)变量赋值。

    定义:父类引用变量指向子类对象

    多态的前提:必须有子父类关系 或者 类实现接口关系,否则无法完成多态。

    在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。

    1定义与使用格式

      父类类型  变量名 = new 子类类型();

      变量名.方法名(); 

    例:普通类多态:

    public class Fu {
    	int a=1;
    	
    	public void method(){
    		System.out.println("这是父类方法");
    	}
    }
    
    public class Zi extends Fu{
    	int a=2;
    	public void method(){
    		System.out.println("这是子类方法");
    	}
    	public void zi(){
    		System.out.println("这是子类方法2");
    	}
    }
    
    public class Test {
    	public static void main(String[] args) {		
    		Fu f=new Zi();
    		System.out.println(f.a);		
    		f.method();		
    	}
    }
    

    抽象类多态:

    public abstract class Animal {
    	public abstract void sleep();
    }
    
    public class Dog extends Animal{
    	public void sleep(){
    		System.out.println("狗趴着睡觉");
    	};
    }
    

      

    public class Test {
    	public static void main(String[] args) {
    		Animal an=new Dog();
    		an.sleep();
    	}
    }
    

    接口多态:

    public interface JiDu {
    	public abstract void jidu(); 
    }
    
    public class Pig implements JiDu{	
    	public void jidu() {
    		System.out.println("缉毒猪在缉毒");		
    	}	
    }
    

      

    public class Test {
    	public static void main(String[] args) {		
    		JiDu jd=new Pig();
    		jd.jidu();		
    	}
    }
    

    自己理解: 

    JiDu jd=new Pig();

    正常建对象是 Pig p=new Pig();

    这样jd和p都引用了Pig()的地址,也可以说pig()有了两种状态,这就是多态。

    多态--成员的特点

    2.1多态中成员变量的特点:

    当子父类中出现同名的成员变量时,多态调用该变量时:

    编译时期:参考的是引用型变量所属的类中是否有被调用的成员变量。没有,编译失败。(看父)

    运行时期:调用引用型变量所属的类中的成员变量。(看父)

    简单记:编译和运行都参考等号的左边。编译运行看左边

    2.2多态中成员方法的特点:

    同一个父类的方法会被不同的子类重写。在调用方法时,调用的为各个子类重写后的方法。

    编译时期:参考引用变量所属的类,如果类中没有调用的方法,编译失败。(看父)

    运行时期:参考引用变量所指的对象所属的类,并运行对象所属类中的成员方法。(调用子)。子类独有的方法无法调用。

    简单记:编译看左边,运行看右边

    3 instanceof关键字

    可以通过instanceof关键字来判断某个对象是否属于某种数据类型。

    例:

    public class Animal{}  //动物类
    
    public class Cat extends Animal{} //猫类
    
    public class Person extends Animal{} //人类
    
    public class Pot{} //锅类
    
    public class Test {
    	public static void main(String[] args) {
    		Animal an=new Person();
    		System.out.println(an instanceof Cat);
    		System.out.println(an instanceof Person);		
    		System.out.println(an instanceof Object);
    	}
    }
    

    但是如果

    System.out.println(an instanceof Pot); 就编译失败

     

    所以只有同体系才能比较,不同的直接编译失败。

    4多态转型

    4.1向上转型

    当有子类对象赋值给一个父类引用时,便是向上转型,多态本身就是向上转型的过程

    格式:

      父类类型  变量名 = new 子类类型();

    个人理解:double b=100;(小转大)与这个同理

    4.2向下转型

    一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用转为子类引用,这个过程是向下转型。

    如果是直接创建父类对象,是无法向下转型的(先向上转了,才能向下转

    格式:

      子类类型 变量名 = (子类类型) 父类类型的变量; 

    例:

    public abstract class Animal{
    	public abstract void eat();
    }
    
    public class Cat extends Animal{	
    	public void eat() {		
    		System.out.println("猫吃鱼");
    	}
    	public void cathMouse(){
    		System.out.println("猫抓老鼠");
    	}	
    }
    
    public class Dog extends Animal{	
    	public void eat() {
    		System.out.println("狗吃骨头");		
    	}
    	public void lookhome(){
    		System.out.println("狗看家");
    	}	
    }
    
    public class Test {
    	public static void main(String[] args) {
    		Animal d=new Dog();
    		d.eat();		
    		Animal c=new Cat();
    		c.eat();			
    		
    		Dog d2=(Dog)d;
    		Cat c2=(Cat)c;
    		d2.lookhome();
    		c2.cathMouse();		
    	}
    }
    

    但是如果写成这样:

    Cat c2=(Cat)d;

    可以编译,但会出现异常:

     

    所以,向下转时,必须用instanceof加个判断

    public class Test {
    	public static void main(String[] args) {
    		Animal d=new Dog();
    		d.eat();		
    		Animal c=new Cat();
    		c.eat();
    		
    		method(d);		
    		method(c);	
    		
    	}
    	public static void method(Animal an){
    		if(an instanceof Dog){
    			Dog d2=(Dog)an;
    			d2.lookhome();
    		}else if(an instanceof Cat){
    			Cat c2=(Cat)an;
    			c2.cathMouse();
    		}
    	}
    }
    

    5多态的好处与弊端

    好处:隐藏了子类类型,提高了代码的扩展性

    弊端:只能使用父类共性的内容,而无法使用子类特有功能,功能有限制。

    6 什么时候使用

    6.1什么时候使用向上转型:

    当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作,这时就可以使用向上转型。

    6.2什么时候使用向下转型

    当要使用子类特有功能时,就需要使用向下转型。

    向下转型的好处:可以使用子类特有功能。

    向下转型的弊端:需要面对具体的子类对象;在向下转型时容易发生ClassCastException类型转换异常。在转换之前必须做类型判断。

    7多态举例

    7.1传参

      

    public interface USB {
    	public abstract void openUsb();
    	public abstract void closeUsb();
    }
    
    public class Notebook{
    	public void run(){
    		System.out.println("笔记本运行");
    	}
    	public void shutdown(){
    		System.out.println("笔记本关机");
    	}
    	
    	//usb方法,传一个usb对象
    	public void useUsb(USB u){
    		u.openUsb();
    		u.closeUsb();
    	}
    }
    
    public class Mouse implements USB{	
    	public void openUsb() {
    		System.out.println("插上鼠标");		
    	}	
    	public void closeUsb() {
    		System.out.println("拔下鼠标");		
    	}	
    }
    
    public class Keyboard implements USB{	
    	public void openUsb() {
    		System.out.println("插上键盘");		
    	}	
    	public void closeUsb() {
    		System.out.println("拔下键盘");		
    	}
    }
    
    public class Test {
    	public static void main(String[] args) {
    		Notebook n=new Notebook();
    		Mouse m=new Mouse();
    		Keyboard k=new Keyboard();
    		
    		n.run();
    		n.shutdown();
    		n.useUsb(m);
    		n.useUsb(k);		
    	}
    }
    

    分析:这里最关键的就是:public void useUsb(USB u){}

    这里参数是传一个USB类型的对象

    假设当传值时,传入一个鼠标对象m(Mouse m=new Mouse();)

    那么调用方法的同时,相当于实现了一个多态:

    USB u=new Mouse();

    这是多态最常见的应用。

    之前集合ArrayList的方法Add(Object obj),参数是一个Object类型的对象,但是实际用时,是传入一个集合中存放的对象的类型的对象(就是存什么,就传什么),这也是一种多态。

    7.2 返回值

    如果一个方法的返回值类型是父类,那么可以返回一个子类对象。

    例:

    public class Father {
    	public void test(){
    		System.out.println("父类方法");
    	}
    }
    
    public class Son extends Father{
    	public void test(){
    		System.out.println("子类方法");
    	}
    }
    
    public class Test {
    	public static void main(String[] args) {		
    		Father f=methods();
    		f.test();
    		System.out.println(f instanceof Son);
            System.out.println(f instanceof Father);
    	}
    	
    	public static Father methods(){ //返回值是父类
    		return new Son();	//返回子类对象
    	}
    }
    

    8 总结:封装、继承、多态的作用

    封装:把对象的属性与方法的实现细节隐藏,仅对外提供一些公共的访问方式

    继承:子类会自动拥有父类所有可继承的属性和方法。(抽象类,接口都体现了继承)

    多态:父类引用变量指向子类对象。配合继承与方法重写提高了代码的复用性与扩展性;如果没有方法重写,则多态同样没有意义。

    扩展:java面试题,可以经常看看,例:

    https://blog.csdn.net/linzhiqiang0316/article/details/80473906

  • 相关阅读:
    CDQ分治
    2-sat
    整体二分
    apache性能优化
    apache反向代理出现502调整
    hadoop学习笔记肆--元数据管理机制
    ssh 免密码登录配置,及其原理
    extjs 中的一些鲜为人知的属性(深渊巨坑)
    hadoop学习笔记叁--简单应用
    hadoop学习笔记贰 --HDFS及YARN的启动
  • 原文地址:https://www.cnblogs.com/hzhjxx/p/10054271.html
Copyright © 2011-2022 走看看