zoukankan      html  css  js  c++  java
  • 09_方法重写丶多态丶抽象类

    Day09笔记

    课程内容

    1、继承中成员方法的关系和方法的重写

    2、final

    3、多态

    4、抽象类

    5、接口

    继承剩余内容

    继承中成员方法的关系

    1、在子父类中,有不同名称的成员方法

            在子类中,可以直接访问父类中定义的成员方法,也可以访问子类中定义的成员方法

    2、在子父类中,有相同声明的方法(方法的返回值类型、方法名称、参数列表)

            称为:方法重写(Override)

            在子父类中,出现了一模一样的方法声明,但是方法的实现却各不相同

            作用:在子类中,【如果】不想改变父类中定义过的方法声明,但是还想改变这个方法的实现内容。

    3、方法重载和方法重写的比较:

            重载:在同一个类中,方法名相同,参数列表不同,与返回值类型无关

            重写:在子父类中,方法名相同,参数列表也相同,与返回值类型有关(相同)

    4、方法重写的说明:

            1、别称:覆写、覆盖、override

            2、注解:@Override

                    作用:检查当前的方法是否在重写父类中的某个方法

            3、在子类中重写父类的方法,只是在改变父类方法的内容,使用的还是父类中的方法定义:子类中被重写的这个方法,所属关系,属于父类的,只是子类重写了内容而已。

            4、如果在子类中,还想访问父类的方法,使用super.方法名称();

    代码示例

    class Demo01_方法的重写 {

             public static void main(String[] args) {

                      DayOne d = new DayOne();

                      d.singRedSong();

                      d.paoNiu();

                      System.out.println("--------");

                      d.test();

             }

    }

     

    class DoubleRiver {

             public void singRedSong() {

                      System.out.println("小小竹筏江中游");

             }

     

             public void paoNiu() {

                      System.out.println("通过唱歌搞定林夕合鸟女士");

             }

    }

     

    class DayOne extends DoubleRiver {

             @Override

             public void paoNiu() {

                      System.out.println("霸王硬上弓");

             }

     

             public void test() {

                      this.paoNiu();

                      super.paoNiu();

             }

    }

    重写的注意事项

    1、私有的方法不能被重写

            父类中的私有方法,在子类中根本就看不到,子类也继承不了父类中的私有成员,也就没有办法重写

            在子类中,仍然可以定义一个和父类私有方法同名的方法,但是这不是对父类方法的重写,而是在子类中心定义了一个方法

    2、方法在重写的时候,权限不能越来越小

            工程上的原因:将来面向父类、面向接口编程,有这些方法的,代码运行的时候是运行子类的方法,方法没有了

            记忆:子类重写父类,必须功能越来越强,权限不能越来越小

    代码示例

    class Demo02_重写的注意事项 {

             public static void main(String[] args) {

                      System.out.println("Hello World!");

             }

    }

     

    class Fu {

             public void test1() {

                      System.out.println("Fu111");

             }

     

             private void test2() {

                      System.out.println("Fu222");

             }

     

             public void test3() {

                      System.out.println("Fu333");

             }

    }

     

    class Zi extends Fu {

             @Override

             public void test1() {

                      System.out.println("Zi111");

             }

     

             /*@Override//私有方法不能重写

             public void test2() {

                      System.out.println("Zi222");

             }

     

             @Override//权限不能越写越小

             private void test3() {

                      System.out.println("Zi333");

             }*/

    }

    final关键字

    概述

    1、final:最后的、最终的、不能改变的

    2、Java中,可以修饰类、方法、变量(局部变量和成员变量)

    3、final修饰类:

            该类不能被继承,类中的任何内容都无法改变,类中的成员方法,都不能被重写了

    4、final修饰方法:

            该方法不能被重写

    5、final修饰变量:

            变量就变成了常量,只能赋值一次

    代码示例1

    class Demo03_final修饰类 {

             public static void main(String[] args) {

                      System.out.println("Hello World!");

             }

    }

     

    final class DoubleRiver {

             public void singRedSong() {

                      System.out.println("小小竹筏江中游");

             }

     

             public void paoNiu() {

                      System.out.println("通过唱歌搞定林夕合鸟女士");

             }

    }

    //编译报错,final修饰之后,不能被继承

    class DayOne extends DoubleRiver {

            

    }

    代码示例2

    class Demo04_final修饰方法 {

             public static void main(String[] args) {

                      System.out.println("Hello World!");

             }

    }

     

    class DoubleRiver {

             public void singRedSong() {

                      System.out.println("小小竹筏江中游");

             }

     

             public final void paoNiu() {

                      System.out.println("通过唱歌搞定");

             }

    }

     

    class DayOne extends DoubleRiver {

             //编译报错,因为父类中的paoNiu是final的,不能被重写

             public void paoNiu() {

                     

             }

     

             public void singRedSong() {

            

             }

    }

    代码示例3

    class Demo05_final修饰变量 {

             public static void main(String[] args) {

                      final int a = 10;

                      System.out.println(a);

                      a = 20;//编译报错,因为a是最终变量,只能赋值一次

                      System.out.println(a);

             }

    }

    final修饰局部变量和成员变量的注意事项

    1、final修饰局部变量的注意事项:

            final修饰哪个变量,哪个变量不能改变

            final修饰基本数据类型,变量中的值不能改变

            final修饰引用数据类型,变量中的地址值不能改变

    2、final修饰成员变量的注意事项:

            final修饰成员变量,需要注意初始化时机,原因:

            成员变量有很多的初始化步骤,所以有可能在我们没有手动给变量赋值之前,变量就已经赋值很多次了

            时机:

    在构造方法结束之前,必须给final修饰的成员变量赋值

    final修饰的成员变量,没有默认初始化

            结论:final修饰的成员变量,只能有显式初始化、构造方法初始化

    代码示例1

    class Demo06_final修饰局部变量 {

             public static void main(String[] args) {

                      Person p = new Person();

                      p.name = "zhangsan";

                      p.name = "lisi";

     

                      final Person p1 = new Person();

                      p1.name = "zhangsan";

                      System.out.println(p1.name);

                      p1.name = "lisi";

                      System.out.println(p1.name);

     

                      //p1 = new Person();//编译报错,因为p1是最终变量,不能修改内容

             }

    }

     

    class Person {

             String name;

    }

    代码示例2

    class Demo07_final修饰成员变量 {

             public static void main(String[] args) {

                      System.out.println("Hello World!");

             }

    }

     

    class Person {

             //final String name;//编译报错,没有在有限的两次机会中初始化该变量

             final int age = 6;

     

             final String sex;

     

             public Person() {

                      sex = "m";

             }

     

             /*public Person(int age) {

            

             }*///编译报错,如果调用该构造方法,没有初始化sex属性

     

             /*public void setSex(String sex) {

                      this.sex = sex;

             }*///编译报错,因为已经确保最终变量在创建对象时,已经分配值

    }

    多态

    多态的概述

    1、多态:事物的多种状态,polymorphic

            对象的多态性:同一个对象,可以有不同的名称,有不同的类型的引用指向它

                    本质:同一个对象有不同的名称和描述

            类型的多态性:同一个类型的引用,将来可以指向不同的子类对象

                    本质:同一个名称可以描述多种具体的事物

    2、多态的前提:

            1、要有子父类(接口和实现类)的继承关系(实现关系)

            2、要有方法的重写

            3、父类的引用指向子类的对象

    代码示例

    class Demo08_多态概述 {

             public static void main(String[] args) {

                      Man m = new Man();

                      m.speak();

     

                      Person p = new Man();

                      p.speak();

     

             }

    }

     

    class Person {

             public void speak() {

                      System.out.println("我是人");

             }

    }

     

    class Man extends Person {

             @Override

             public void speak() {

                      System.out.println("我是大男人");

             }

    }

    在多态中成员变量的访问特点

    1、编译看左边,运行看左边

    2、在编译阶段,使用父类的引用访问某个成员变量,检查在引用所属的类型中(赋值符号左边的类型)是否有该变量的定义,如果有,编译成功,如果没有就编译失败。

    3、在运行阶段,使用父类的引用访问某个成员变量,访问的还是引用所属的类中(赋值符号左边的类型)对该变量的赋值

    代码示例

    class Demo09_多态中成员变量的访问特点 {

             public static void main(String[] args) {

                      Person p = new Man();

                      System.out.println(p.name);

             }

    }

     

    class Person {

             //String name = "张三";

    }

     

    class Man extends Person {

             String name = "张三丰";

    }

    在多态中成员方法的访问特点

    1、编译看左边,运行看右边

    2、使用父类的引用访问了某个成员方法,在编译阶段,检查引用所属的类型中(赋值符号左边的类型),是否有该方法的定义,如果有,编译成功,如果没有,就编译失败

    3、使用父类的引用访问某个成员方法,在运行阶段,运行的内容是对象所属的类型(赋值符号右边的类型)重写过的内容。

    代码示例

    class Demo10_多态中成员方法的访问特点 {

             public static void main(String[] args) {

                      Person p = new Man();

                      p.speak();

     

                      Person p1 = new Woman();

                      p1.speak();

             }

    }

     

    class Person {

             public void speak() {

                      System.out.println("我叫张三");

             }

    }

     

    class Man extends Person {

             public void speak() {

                      System.out.println("我叫张三丰");

             }

    }

     

    class Woman extends Person {

             public void speak() {

                      System.out.println("我是张小凤");

             }

    }

    多态中静态方法的访问特点

    1、编译看左边,运行看左边

    2、编译时,要看【=】左边的引用所属的类型(父类)是否有该方法的定义,如果有就编译成功,如果没有,就编译失败

    3、运行时,要看【=】右边的引用所属的类型(父类)究竟是如何实现该方法的,运行的是父类中方法的实现

    4、静态理解总结:

            静态变量:存储在类的字节码中,被所有该类对象共享,这个变量的值不会随着对象的不同,而又不同的值,都是相同的值,称为“静态”

            静态方法:只会引用所属的父类,决定运行内容,不会随着对象的不同而运行不同的方法实现,称为“静态方法”

    代码示例

    class Demo11_多态中静态方法的访问特点 {

             public static void main(String[] args) {

                      Person p = new Man();

                      //父类中定义了speak这个方法,如果是子类重写了这个方法,那么在父类调用这个方法的时候,就应该走子类的实现

                      //而运行结果是父类的内容,因此说明子类没有重写这个方法,而是新定义了一个方法

                      p.speak();

     

                      Person p1 = new Woman();

                      p1.speak();

             }

    }

     

    class Person {

             public static void speak() {

                      System.out.println("我是张三");

             }

    }

     

    class Man extends Person {

             //@Override    //静态方法没有重写的概念

             public static void speak() {

                      System.out.println("我是张三丰");

             }

    }

     

    class Woman extends Person {

             public static void speak() {

                      System.out.println("我是张小凤");

             }

    }

    超人案例

    代码示例

    class Demo12_超人案例 {

             public static void main(String[] args) {

                      Man m = new SuperMan();

                      System.out.println(m.name);

                      m.谈生意();

                      //向下转型:恢复原本的访问范围

                      SuperMan sm = (SuperMan)m;

                      sm.fly();

             }

    }

     

    class Man {

             String name = "Mike";

     

             public void 谈生意() {

                      System.out.println("谈一谈不同的小生意");

             }

    }

     

    class SuperMan extends Man {

             String name = "Spider";

     

             @Override

             public void 谈生意() {

                      System.out.println("谈的是几个亿的大单子");

             }

     

             public void fly() {

                      System.out.println("到处飞着救人");

             }

    }

    多态的内存理解

     

    引用类型的向上向下转型

    1、向上转型:多态的体现

            父类的引用指向了子类的对象

            以前:子类的引用 = 子类的对象

            现在:父类的引用 = 子类的对象

           

            本质:从概念上说,把概念扩大了,但是从功能和数据说,把访问范围缩小了

    2、向下转型:

            本质:把曾经扩大的概念进行恢复;把曾经缩小的访问范围恢复

            前提:曾经向上转型过

            格式:

                    子类类型 子类引用名称 = (子类类型)父类引用名称;

    多态的好处

    1、提高了代码的可扩展性

            同一个类型的引用,可以有不同的子类对象作为实现

    2、在方法的形式参数中,使用父类类型的引用,将来在调用方法的时候,传入的实际参数可以是这个父类的所有子类的对象。

    3、不在方法的形式参数中,使用父类类型的引用,指向的对象,来源非常广泛的(不仅仅是new出来的),可以是通过反射的方式获取的,可以是通过文件读取获取的,可以是网络中传过来的,数据库中读取的。以上方式,都是程序员在写代码的时候,不知道对象具体的子类类型,仍然可以使用父类的引用指向他们,将来根据具体子类的不同,仍然可以运行不同的代码。

    代码示例

    import java.io.BufferedReader;

    import java.io.FileReader;

    class Demo13_榨汁机案例 {

             public static void main(String[] args) throws Exception {

                      JuiceMachine jm = new JuiceMachine();

                      /*Apple a = new Apple();

                      jm.makeJuice(a);

     

                      Orange o = new Orange();

                      jm.makeJuice(o);*/

     

                      BufferedReader br = new BufferedReader(new FileReader("config.txt"));

                      String className = br.readLine();

                      Class c = Class.forName(className);

                      //Object也是最顶层的父类,指向了我们不知道的具体类型的子类对象

                      Object obj = c.newInstance();

                      //父类的Fruit类型的对象,指向了我们不知道具体类型的子类对象

                      Fruit f = (Fruit)obj;

                      jm.makeJuice(f);

             }

    }

     

    class JuiceMachine {

             public void makeJuice(Fruit f) {//Fruit f = new Orange();

                      f.flow();

             }

    }

     

    class Fruit {

             public void flow() {

            

             }

    }

     

    class Apple extends Fruit {

             public void flow() {

                      System.out.println("流出苹果汁");

             }

    }

     

    class Orange extends Fruit {

             public void flow() {

                      System.out.println("流出橘子汁");

             }

    }

     

    class WaterMelon extends Fruit {

             public void flow() {

                      System.out.println("流出西瓜汁");

             }

    }

    抽象类

    抽象方法

    1、抽象:抽取像的,相同的相似的内容出来

    2、抽象方法:

            在子类中,对同一个方法,不同的子类有不同的实现,不同子类中的这些方法,就只有方法声明是相同的,所以把方法名称抽取到父类中,就是抽象方法。

            抽象方法:就是只有方法声明,没有方法实现的方法

    3、定义格式:

            1、没有方法体,只有方法实现,连方法体的大括号都没有,通过分号结束方法

            2、在方法声明上,需要加一个abstract关键字来说明这个方法是抽象方法

    代码示例

    class Demo14_抽象方法 {

             public static void main(String[] args) {

                      System.out.println("Hello World!");

             }

    }

     

    class Employee {

             public abstract void work();

    }

     

    class Coder extends Employee {

             public void work() {

                      System.out.println("敲代码");

             }

    }

     

    class Tester extends Employee {

             public void work() {

                      System.out.println("软件测试");

             }

    }

    抽象类

    1、可以定义抽象方法的类,就是抽象类

    2、定义格式:

            abstract class 类名 {

                    抽象方法;

    }

    代码示例

    class Demo15_抽象类 {

             public static void main(String[] args) {

                      System.out.println("Hello World!");

             }

    }

     

    abstract class Employee {

             public abstract void work();

    }

     

    class Coder extends Employee {

             public void work() {

                      System.out.println("敲代码");

             }

    }

     

    class Tester extends Employee {

             public void work() {

                      System.out.println("软件测试");

             }

    }

    抽象类的特点

    1、抽象类和抽象方法都需要使用abstract关键字声明

            abstract class 类名 {}

            public abstract 返回值类型 方法名称() {}

    2、抽象类和抽象方法的关系:

            1、抽象类中,未必有抽象方法

            2、抽象方法所在的类,一定是抽象类

    3、抽象类不能实例化(创建对象)

            抽象类中有抽象方法,如果能创建对象,就会调用没有意义的方法

            只能定义子类,重写(实现)抽象方法之后,使用子类来创建对象

    4、抽象类的子类:

            1、如果子类没有把父类中的所有抽奖方法都重写,那么这个子类就还是一个抽象类

            2、如果子类重写了父类中所有的抽象方法,那么子类就变成了一个具体类。

    代码示例

    class Demo16_抽象类的特点 {

             public static void main(String[] args) {

                      Coder c = new Coder();

             }

    }

     

    abstract class Employee {

             public void test() {}

     

             public abstract void test2();

    }

     

    class Coder extends Employee {

     

    }

    抽象类中成员的特点

    1、成员变量的特点:

            既可以是变量、也可以是常量

            但是不能被抽象

    2、构造方法的特点:

            抽象类中,有构造方法

            用于子类创建对象的时候,要访问父类的构造方法

            一个类中是否需要定义构造方法,不是取决于这个类是否可以创建对象,而是取决于该类是否可以定义成员变量

    3、成员方法的特点:

            可以是抽象方法:强制让子类重写这个抽象方法

            也可以是非抽象方法:用于给子类继承

    代码示例

    class Demo17_抽象类中成员的特点 {

             public static void main(String[] args) {

                      System.out.println("Hello World!");

             }

    }

     

    abstract class Employee {

             String name;

             final int age = 65;

    }

    员工类案例完善

    代码示例

    class Demo18_员工类案例 {

             /*

             定义程序员类和项目经理类

             程序员类:属性(姓名、工号、工资)、方法(工作:敲代码)

             项目经理类:属性(姓名、工号、工资、奖金)、方法(工作:项目进度控制

             */

             public static void main(String[] args) {

                      //Coder c = new Coder("李白", "lb666", 20000.0);

                      //抽象父类的引用,指向具体子类的对象:抽象类的多态

                      Employee e1 = new Coder("李白", "lb666", 20000.0);

                      System.out.println(e1.getName() + "..." + e1.getId() + "..." + e1.getSalary());

                      e1.work();

     

                      //Manager m = new Manager("秦始皇", "qsh888", 0, 999999999);

                      Employee e2 = new Manager("秦始皇", "qsh888", 0, 999999999);

                      //编译报错,因为在父类Employee中没有getBonus这个方法

                      //System.out.println(e2.getName() + "..." + e2.getId() + "..." + e2.getSalary() + "..." + e2.getBonus());

                      System.out.println(e2.getName() + "..." + e2.getId() + "..." + e2.getSalary());

                      e2.work();

             }

    }

     

    abstract class Employee {

             private String name;

             private String id;

             private double salary;

             public Employee() {}

     

             public Employee(String name, String id, double salary) {

                      this.name = name;

                      this.id = id;

                      this.salary = salary;

             }

     

             public void setName(String name) {

                      this.name = name;

             }

     

             public String getName() {

                      return name;

             }

     

             public void setId(String id) {

                      this.id = id;

             }

     

             public String getId() {

                      return id;

             }

     

             public void setSalary(double salary) {

                      this.salary = salary;

             }

     

             public double getSalary() {

                      return salary;

             }

     

             public abstract void work();

    }

     

    class Coder extends Employee {

             public Coder() {}

            

             public Coder(String name, String id, double salary) {

                      super(name, id, salary);

             }

     

             public void work() {

                      System.out.println("敲代码");

             }

    }

     

    class Manager extends Employee {

             private int bonus;

     

             public Manager() {}

     

             public Manager(String name, String id, double salary, int bonus) {

                      super(name, id, salary);

                      this.bonus = bonus;

             }

     

             public void setBonus(int bonus) {

                      this.bonus = bonus;

             }

     

             public int getBonus() {

                      return bonus;

             }

     

             public void work() {

                      System.out.println("项目进度控制");

             }

    }

  • 相关阅读:
    【Java EE 学习 36】【struts2】【struts2系统验证】【struts2 ognl值栈】【struts2 ongl标签】【struts2 UI标签】【struts2模型驱动和令牌机制】
    【Java EE 学习 35 下】【struts2】【struts2文件上传】【struts2自定义拦截器】【struts2手动验证】
    【Java EE 学习 35 上】【strus2】【类型转换器】【struts2和Servlet API解耦】【国际化问题】【资源文件乱码问题已经解决】
    【Java EE 学习 34】【struts2学习第一天】
    【JavaScript中的正则表达式】
    【Java EE 学习 33 下】【validate表单验证插件】
    【Java EE 学习 33 上】【JQuery样式操作】【JQuery中的Ajax操作】【JQuery中的XML操作】
    【Java EE 学习 32 下】【JQuery】【JQuey中的DOM操作】
    【Java EE 学习 32 上】【JQuery】【选择器】
    【Java EE 学习 31】【JavaScript基础增强】【Ajax基础】【Json基础】
  • 原文地址:https://www.cnblogs.com/man-tou/p/10635905.html
Copyright © 2011-2022 走看看