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

         }

}

原文地址:https://www.cnblogs.com/man-tou/p/10635905.html