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("项目进度控制");

             }

    }

  • 相关阅读:
    GFS文件系统和在RedHat Linux下的配置
    FastDFS connect timed out
    大型高并发高负载网站的系统架构
    FastDFS 上传文件
    FastDFS常见命令
    FastDFS安装、配置、部署
    分布式文件系统FastDFS原理介绍
    Jenkins+Maven+Svn搭建持续集成环境持续集成和自动部署
    Java中的向上转型和向下转型
    Java中的final修饰符
  • 原文地址:https://www.cnblogs.com/man-tou/p/10635905.html
Copyright © 2011-2022 走看看