JAVA之旅(八)——多态的体现,前提,好处,应用,转型,instanceof,多态中成员变量的特点,多态的案例

JAVA之旅(八)——多态的体现,前提,好处,应用,转型,instanceof,多态中成员变量的特点,多态的案例


学习是不能停止的

一.多态

我们今天又要学习一个新的概念了,就是多态,它是面向对象的第三个特征,何谓多态?

  • 定义

某一类事物的多种存在方式

  • 比如

动物中的猫狗,人类中的男人,女人

我们可以把多态理解为事物存在的多种体现形态

当我们new一个猫类的时候,和new 一个动物,其实是一样的,多种形态变现

所以我们可以分这几部分分析

    1. 多态的体现
    1. 多态的前提
  • 3.多态的好处
  • 4.多态的应用

我们定义一个需求,描述动物,正常的逻辑应该是这样描述的

//公共的   类   类名
public class HelloJJAVA {
    // 公共的 静态 无返回值 main方法 数组
    public static void main(String[] str) {
        /**
         * 动物: 猫,狗
         */
        Cat c = new Cat();
        c.eat();
        dog d = new dog();
        d.eat();
    }
}

/**
 * 动物
 *
 * @author LGL
 *
 */
abstract class Animal {

    // 吃什么不确定,抽象
    abstract void eat();
}

/**
 * 猫
 *
 * @author LGL
 *
 */
class Cat extends Animal {

    @Override
    void eat() {
        System.out.println("猫吃鱼");
    }

}

/**
 * 狗类
 *
 * @author LGL
 *
 */
class dog extends Animal {

    @Override
    void eat() {
        System.out.println("狗吃骨头");
    }

}

这个体系我们展现出来一个为题,我们为了使用猫吃东西和狗吃东西,得new两个对象,要是多来几只小动物,我不还得new死,所以我们要想一个解决办法,他们有一个共性,就是都是动物,我们可以这样转换

Animal a = new Cat();
a.eat();

因为也是动物类型,我们输出

这就是多态在程序中的表现

  • 父类的引用指向了自己的子类对象,这就是多态的代码体现形式,人 = new 男人,换句话说,父类的引用也可以接收子类的对象,所以我们可以这样定义一个方法
//公共的   类   类名
public class HelloJJAVA {
    // 公共的 静态 无返回值 main方法 数组
    public static void main(String[] str) {
        /**
         * 动物: 猫,狗
         */
        AnimalEat(new Cat());
        AnimalEat(new dog());
    }

    public static void AnimalEat(Animal a) {
        a.eat();
    }
}

这样就方便了,这样也就体现了多态的好处:

  • 多态的出现大大的提升了程序的扩展性

但是有前提的

  • 必须类与类之间有关系,要么继承,要么实现
  • 通常,还有一个前提就是存在覆盖

不过,有利有弊,还是会存在弊端的

  • 提高了扩展性,但是只能使用父类的引用访问父类的成员,这是局限性,但是我们侧重扩展性

我们再返回前面说多态的转型,我们看这段代码

//类型提升
Animal a = new Cat();
a.eat();

我们也叫作向上转型,

如果想要调属性,该如何操作(向下转型)?

  • 强制将父类的引用转为子类类型
        Animal a = new Cat();
        a.eat();

        Cat c = (Cat)a;
        c.sleep();

也就是说,转型是强制将父类的引用,转为子类类型,向下转型。千万不要将父类对象转成子类对象,我们能转换的是父类引用指向子类对象的子类,多态自始至终都是子类对象在做着变化

那么你会了强转之后,你就说,我可以这样做

//公共的   类   类名
public class HelloJJAVA {
    // 公共的 静态 无返回值 main方法 数组
    public static void main(String[] str) {
        /**
         * 动物: 猫,狗
         */

        AnimalEat(new Cat());
        AnimalEat(new dog());

    }

    public static void AnimalEat(Animal a) {
        a.eat();

        Cat c = (Cat) a;
        c.sleep();
    }
}

这样是不是可以?我们看结果

这里报错了,提示的是狗类型不行转换成猫类型,的确,不能随便乱转。我们价格判断,怎么判断呢?条件语句该怎么写呢?这里我们又有一个关键字了instanceof

//公共的   类   类名
public class HelloJJAVA {
    // 公共的 静态 无返回值 main方法 数组
    public static void main(String[] str) {
        /**
         * 动物: 猫,狗
         */

        AnimalEat(new Cat());
        AnimalEat(new dog());

    }

    public static void AnimalEat(Animal a) {
        a.eat();

        //如果a的类型是Cat就执行
        if(a instanceof Cat){
            Cat c = (Cat) a;
            c.sleep();
        }

    }
}

这样我们加了判断之后,我们就可以知道

既然多态说了这么多,我们来看看多态的应用吧,还是以一个需求开始去分析

//公共的   类   类名
public class HelloJJAVA {
    // 公共的 静态 无返回值 main方法 数组
    public static void main(String[] str) {

        /**
         * 需求:幼儿园有两个班 大班: 学习,睡觉 小班: 学习,睡觉 可以将两类事物进行抽取
         */
        SmallClass s = new SmallClass();
        s.study();
        s.sleep();

        BigClass b = new BigClass();
        b.study();
    }

}

/**
 * 学生类
 *
 * @author LGL
 *
 */
abstract class Student {
    // 学习的内容不一样,抽象
    public abstract void study();

    // 睡觉
    public void sleep() {
        System.out.println("躺着睡");
    }
}

/**
 * 大班
 *
 * @author LGL
 *
 */
class BigClass extends Student {

    @Override
    public void study() {
        System.out.println("学习大班知识");
    }

}

/**
 * 小班
 *
 * @author LGL
 *
 */
class SmallClass extends Student {

    @Override
    public void study() {
        System.out.println("学习小班知识");
    }

    @Override
    public void sleep() {
        System.out.println("卧着睡");
    }

}

这个例子输出

你拿到一想,是不是根据上面的方法直接复用父类对象的引用?这里我们可以拿到一个单独的类去复用封装

/**
 * 封装工具类
 *
 * @author LGL
 *
 */
class DoStudent {
    public void dosome(Student s) {
        s.study();
        s.sleep();
    }
}

这样我们使用

        DoStudent dos = new DoStudent();
        dos.dosome(new BigClass());
        dos.dosome(new SmallClass());

得到的结果

我们再来看下多态的代码特点,我们举个例子

//公共的   类   类名
public class HelloJJAVA {
    // 公共的 静态 无返回值 main方法 数组
    public static void main(String[] str) {
        zi z = new zi();
        z.method1();
        z.method2();
        z.method3();
    }
}

class Fu {
    void method1() {
        System.out.println("fu method1");
    }

    void method2() {
        System.out.println("fu method2");
    }
}

class zi extends Fu {
    void method1() {
        System.out.println("zi method1");
    }

    void method3() {
        System.out.println("zi method3");
    }

}

你能告诉我打印的结果吗?

我们现在用多态的思想去做

你会知道,3是引用不了的,我现在把报错的的地方注释掉,然后你能告诉我运行的结果吗

我们可以总结出特点(在多态中成员函数的特点)

  • 在编译时期。参阅引用型变量所属的类是否有调用的方法,如果由,编译通过。如果没有编译失败
  • 在运行时期,参阅对象所属的类中是否有调用的方法
  • 简单总结就是成员函数在多态调用时,编译看左边,运行看右边

我们再在子类和父类中都定义一个int值分别是5和8

我们这么输出

        Fu f = new zi();
        System.out.println(f.num);

        zi z = new zi();
        System.out.println(z.num);

输出多少呢?

这里就总结出

  • 在多态中,成员变量的特点:无论编译和运行,都参考左边(引用型变量所属)
  • 在多态中,静态成员变量的特点:无论编译和运行,都参考左边

我们把学到的应用在案例上

//公共的   类   类名
public class HelloJJAVA {
    // 公共的 静态 无返回值 main方法 数组
    public static void main(String[] str) {

        /**
         * 需求:电脑运行实例,电脑运行基于主板
         */
        MainBoard b = new MainBoard();
        b.run();
    }
}

/**
 * 主板
 *
 * @author LGL
 *
 */
class MainBoard {

    public void run() {
        System.out.println("主板运行了");
    }

}

我们程序这样写, 无疑看出来很多弊端,我想上网,看电影,他却没有这功能,我们要怎么去做,我们重新设计程序,再增加

/**
 * 网卡
 *
 * @author LGL
 *
 */
class NetCard {
    public void open() {
        System.out.println("打开网络");
    }

    public void close() {
        System.out.println("关闭网络");
    }
}

但是这样,还是主板的耦合性是在是太强了,不适合扩展,所以,这个程序一定不是一个好的程序我,我们重新设计,用一个标准的接口

import javax.print.attribute.standard.MediaName;

//公共的   类   类名
public class HelloJJAVA {
    // 公共的 静态 无返回值 main方法 数组
    public static void main(String[] str) {

        /**
         * 需求:电脑运行实例,电脑运行基于主板
         */
        MainBoard m = new MainBoard();
        m.run();
        // 没有设备,有设备的话之类传进去
        m.userPCI(null);

    }
}

/**
 * 扩展接口
 *
 * @author LGL
 *
 */
interface PCI {
    public void open();

    public void close();
}

/**
 * 主板
 *
 * @author LGL
 *
 */
class MainBoard {

    public void run() {
        System.out.println("主板运行了");
    }

    public void userPCI(PCI p) {
        if (p != null) {
            p.open();
            p.close();
        } else {
            System.out.println("没有设备");
        }

    }

}

我们现在不管增加听音乐还是上网的功能,只要实现PCI的接口,就可以实现,我们现在增加一个上网功能,该怎么做?


//公共的   类   类名
public class HelloJJAVA {
    // 公共的 静态 无返回值 main方法 数组
    public static void main(String[] str) {

        /**
         * 需求:电脑运行实例,电脑运行基于主板
         */
        MainBoard m = new MainBoard();
        m.run();
        // 没有设备
        m.userPCI(null);

        // 有设备
        m.userPCI(new NetCard());

    }
}

/**
 * 扩展接口
 *
 * @author LGL
 *
 */
interface PCI {
    public void open();

    public void close();
}

/**
 * 主板
 *
 * @author LGL
 *
 */
class MainBoard {

    public void run() {
        System.out.println("主板运行了");
    }

    public void userPCI(PCI p) {
        if (p != null) {
            p.open();
            p.close();
        } else {
            System.out.println("没有设备");
        }

    }

}

/**
 * 网卡
 *
 * @author LGL
 *
 */
class NetCard implements PCI {
    public void open() {
        System.out.println("打开网络");
    }

    public void close() {
        System.out.println("关闭网络");
    }
}

这样我们运行

现在的主板是不是扩展性特别强,这就是多态的扩展性

OK,我们本节的篇幅就先到这里,如果感兴趣的话,可以加群:555974449

时间: 2024-08-26 19:15:31

JAVA之旅(八)——多态的体现,前提,好处,应用,转型,instanceof,多态中成员变量的特点,多态的案例的相关文章

java中成员变量、代码块、构造函数执行顺序

1.java虚拟机运行程序,首先需要装载类,安装现装载父类,初始化父类的静态代码块和静态成员变量 再load子类.初始化子类静态代码块和成员变量 2.load完毕父类与子类后,从main函数入口执行程序,先输出,接着new实例化Beetle类,则先实例化父类Insect,实例化父类时,先初始化非静态成员变量和非静态代码块,接着执行父类构造方法 再实例化子类,实例化子类时,先初始化非静态成员变量和非静态代码块,接着执行子类构造方法. package it.xiangnan.test; public

谈谈java中成员变量与成员方法继承的问题

谈谈java中成员变量与成员方法继承的问题 关于成员变量和成员方法的的继承问题,我也可以做一个小测试,来看看结果. 首先我们先创建一个父类: 其次再创建一个子类,子类中要比父类中少一个成员方法: 这样我们对子类创建对象,如果不创建对象,我们是无法访问子类的成员变量和成员方法的,因为“无法从静态上下文中引用非静态方法”.我们要输出有: 从以上的数据中,我们就可以得出的输出结果是 这样我们就可以得出结论. 总结: 1.   在结果中可以看出,子类的成员变量和成员方法,与其父类的相同的时候,子类就会覆

多态中成员变量、成员方法等的特点

1 public class Test { 2 public static void main(String[] args) { 3 Parent p = new Son(); 4 p.show(); 5 System.out.println("a的值为:"+p.a); 6 } 7 } 8 9 class Parent { 10 int a=10; 11 public Parent() { 12 System.out.println("父类无参构造,a的值为:"+a

C#的HttpModule中及Java的Servlet中成员变量乱用导致的不易重现的BUG

3年前写的在HttpModule中记录访问日志的代码,在最近使用日志数据分析登录账号的IP情况时,才发现了一个不易重现的BUG——日志中记录的登录账号出现串掉的情况.之所以这个时候才发现该问题,是因为部分用户的IP是固定的,但是日志里却出现了别人的IP.而之所以3年后才发现,是因为这块日志数据一直没怎么用过.回头想想,根本原因还是在用成员变量的时候没考虑到多线程的情况,或者说多用户同时访问的情况.因为HttpModule里的事件,是所有页面实例共用的. 问题代码: string dateBegi

Java多态 实例子类自动调用父类为空的构造方法 成员变量不支持Override 可写,没多态效果

=======子类 实例化的时候 默认调用父类为空的构造方法 即super();可省略. 但是当父类没有为空的构造方法的时候就必须在子类中       调用这个方法先实例父类 才能实例子类. 父类为空的构造方法 默认存在 在子类中默认自动调用. ========父类引用指向子类对象的时候  根据引用变量中 实例所属的类调用不同的类的方法,这种多态只适用于方法不适用与成员变量. 简单的理解为Java不支持属性字段覆盖(override),只支持方法覆盖,属性字段 不可重写. ========实例化

Java 子类初始化父类的构造方法 成员变量不支持多态

class Fu{ int a=2; Fu() { System.out.println("fu run"); }}class Zi extends Fu{ Zi() { System.out.println("zi run"); }} public class Copy { public static void main(String[] args) { Zi zi = new Zi(); System.out.println(zi.a); } } 运行结果为 f

java接口中成员变量和方法的默认修饰符(转)

Java的interface中,成员变量的默认修饰符为:public static final 所以我们在interface中定义成员变量的时候,可以 1:public static final String name = "张三"; 2:String name = "张三"; 以上两种都可以,老司机一般都是第二种.既然是静态最终的变量,也就意味着在外面访问的时候不能修改这个成员变量的值.所以在接口中定义成员变量的,一般都是常量.不会修改的.如果要进行修改的话,定义

java中成员变量、代码块、构造函数运行顺序

1.java虚拟机执行程序,首先须要装载类,安装现装载父类,初始化父类的静态代码块和静态成员变量 再load子类. 初始化子类静态代码块和成员变量 2.load完成父类与子类后,从main函数入口运行程序.先输出,接着new实例化Beetle类,则先实例化父类Insect,实例化父类时.先初始化非静态成员变量和非静态代码块,接着运行父类构造方法 再实例化子类,实例化子类时,先初始化非静态成员变量和非静态代码块,接着运行子类构造方法. package it.xiangnan.test; publi

Java中成员变量和局部变量的区别

java面向对象过程中,最基本的两类变量就是成员变量和局部变量 成员变量是写在类中并且写在方法外部,一般写在每个类的头部,用于初始化或者方法操作,作用域是整个类被实例化到被销毁,中间变量都可以被外部方法(权限为public时)或者内部方法所共享使用,并且可以保持变量的值,就是多个方法可以复用该变量,成员变量一般要加权限修饰符,并且定义成员变量的时候系统会给初始值0 而局部变量作用域只在方法内部,当方法调用完毕,该变量也自动消失,并且只有方法本身可以使用,其他方法或类都不能使用该变量,也就是方法本