第十天多态继承补充和final

继承补充:

方法重写的注意事项:

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

2、子类重写父类的方法时候,访问权限不能更低

要么子类重写的方法访问权限比父类的访问权限要高或者一样

建议:以后子类重写父类的方法的时候,权限修饰符写一样就不会发生这样的问题。

3、父类中静态的方法不能被重写,也就是说不能被Override修饰,因为静态的是属于类本身的东西。

class OldPhone {
    private String name;

    public void call(String name) {
        System.out.println("打电话给" + name);
    }

    public static void play() {//当这个方法是静态时后面子方法便无法重写
        System.out.println("玩俄罗斯方块");
    }
}

class NewPhone extends OldPhone {
    @Override
    public void call(String name) {
        System.out.println("看抖音");
    }
    public static void play(){
        System.out.println("打王者");
    }

}

public class ExtendsDemo1 {
    public static void main(String[] args) {
        NewPhone newPhone=new NewPhone();
        newPhone.call("小王");
        newPhone.play();
    }
}

第二个

class A {
   static int a = 10;
    //将父类中的静态成员看作一个全局共享的,被所有的子类共享
    public static void fun() {
        System.out.println("hello");
    }
}

class B extends A {
    public void fun2() {
        a = 200;
        System.out.println(a);
    }

    public static void fun() {
        System.out.println("world");

    }
}

public class ExtendsDemo2 {
    public static void main(String[] args) {
        B b=new B();
        System.out.println(b.a);
        b.fun();
        b.fun2();//当调用完这个后改变了a的值为200导致后面的调用a变成了200
        System.out.println(b.a);
        System.out.println(A.a);
    }
}

final的特点:

final:最终的的意思。它可以修饰类,成员变量,成员方法

特点:

1、修饰类,类不能被继承

2、修饰成员变量,变量变常量,并且只能赋值一次,在构造方法完毕之前赋值即可。

常量:

字面值常量

自定义常量:被final修饰变量变成自定义常量

3、final修饰成员方法:方法不能被重写

class Fu2 {
    int num = 10;
    final int num2 = 20;
}

class Zi2 extends Fu2 {
    public void show() {
        num = 100;
        System.out.println(num);
//        num2=300;//报错无法为num2赋值
        System.out.println(num2);
    }
}

public class FinalDemo {
    public static void main(String[] args) {
        Zi2 zi2 = new Zi2();
        zi2.show();
    }
}

final修饰局部变量

1、在方法内部,修饰基本数据类型的变量,变量值只能赋值一次,不能发生改变

2、final修饰引用数据类型的变量呢?

引用的地址值不可以发生改变,但是该对象的堆内存中的值是可以发生改变的。

class Student {
     int  age = 10;
}

public class FinalDemo2 {
    public static void main(String[] args) {
        int x = 100;
        x = 300;
        System.out.println(x);
        final int y = 200;
        //        y = 400; //无法为最终变量y分配值
        System.out.println(y);
        Student student=new Student();
        System.out.println(student.age);
        final Student s2=new Student();
        System.out.println(s2.age);
        s2.age=202;
        System.out.println(s2.age);
        System.out.println("===========");
        //        s2 = new Student(); //无法为最终变量s2分配值
    }
}

有些时候,我们不想让子类覆盖重写父类中的方法或者功能,只能让子类去使用。

那怎么办呢?

针对这个情况,java提供了一个关键字:final

final:最终的意思。可以修饰类,成员变量,成员方法。

class Fu{
    public final void show(){
        System.out.println("这是父类中的show方法");
    }
}

class Zi extends Fu{
//    @Override
//    public void show(){
//        System.out.println("这是子类中的show方法");
//    }

}

public class ZiDemo {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.show();
    }
}

多态:

多态:某一事物,在不同时刻表现出来的不同状态

举例:

水:

固态、液态、气态

固态的水是水、液态的水也是水、气态的水也是水

水果:

波罗蜜、香蕉、榴莲

波罗蜜是水果、香蕉是水果、榴莲是水果

水果是波罗蜜。// 反过来说是有问题的

动物:

狗、虎、猫、大象

狗是动物,这么说是没问题的

动物是狗,这么说是不可以。

通过观察例子发现,要想有多态,就必须要继承,继承是多态的前提。

多态的前提:

要有继承关系

要有方法的重写

其实没有重写也是可以的,但是不重写就没有意义

动物都有吃这个方法,但是每个具体的动物吃的实现不一样,变现出不同动物的特有属性

要有父类的引用指向子类的对象

父类名 f = new 子类名(...);

多态访问成员的特点:

1、成员变量

编译看左,运行看左

2、构造方法

创建子类对象的时候,先访问父类中的构造方法,对父类的数据先进行初始化

3、成员方法

编译看左,运行看右。

因为成员方法存在重写,所以访问看右边

4、静态成员方法

编译看左,运行也看左。

由于被static修饰的成员都是与类相关的,这里不是重写,所以运行的时候,访问的还是左边的。

class Fu3{
    int num=100;
    public void show(){
        System.out.println("这是父类中的show()f方法");
    }
    public static void fun(){
        System.out.println("这是父类中的静态fun()方法");
    }
}
class Zi3 extends Fu3{
    int num=1000;

    @Override
    public void show() {
        System.out.println("这是子类中的show()方法");
    }
    public void show2() {
        System.out.println("这是子类中的特有方法");
    }
    public static void fun() {
        System.out.println("这是子类中的静态fun()方法");
    }

}
public class PolymorphicDemo {
    public static void main(String[] args) {
        Fu3 fu3=new Zi3();
        System.out.println(fu3.num);
        fu3.show();// 这是子类中的show()方法
        fu3.fun();//这是父类里的静态方法

    }
}

class Father{
    public void show(){
        System.out.println("这是父类的show方法");
    }
}
class Son extends Father{
    @Override
    public void show() {
        System.out.println("这是子类里的show方法");
    }
    public void show2() {
        System.out.println("这是子类里特有的show方法");
    }

}
public class PolymorphicDemo2 {
    public static void main(String[] args) {
        Father father=new Son();
        father.show();
        //需求:我现在就想调用父类中的show方法,怎么办?

    }
}

多态的弊端:

多态无法访问父类中的方法名一样的方法

1、我就想使用父类中的方法,能不能用,能。不使用多态

2、如果我想使用子类中的特有方法,还必须使用多态,咋办?

1)就不使用多态,创建子类对象然后调用方法

但是在我上一个例子上,再次创建对象,还会在堆内存中开辟空间,很有可能会造成资源浪费

2、将子类看成一个小的类型,将父类看成一个大的类型,现在想要用小的类型中的方法

我们应该要将大的类型转成小的类型。在我们之前的做法是用强制类型转换。

如果在继承关系,也有类似的这样的做法就好了。

java替我们考虑到这样的问题,提供了一个技术给我们使用:向下转型

将父类的引用强制转换成子类的引用

子类类名 变量名 = (子类类名)父类的引用;

对象之间转型的问题:

1、向上转型:

Fu f = new Son();

2、向下转型

Son s = (Son)f;

int a = 10;

byte b = (byte)a;

向下转型需要注意的一个问题:

要求转型的类与父类引用存在继承关系,并且一开始创建多态的时候,使用的是该类。

关键字abstract,它可以修饰类,方法

1、抽象类中可以没有抽象方法,但是有抽象方法的类一定是抽象类

2、抽象类不能被实例化

3、要想实例化抽象类,必须用一个具体的子类继承它

注意:具体的子类继承抽象类,必须重写该抽象类中的所有的抽象方法

4、最终以抽象多态的形式进行实例化。

class Father2{
    public void show(){
        System.out.println("这是父类中的show方法");
    }
}
class Son2 extends Father2{
    @Override
    public void show() {
        System.out.println("这是子类中的show方法");
    }
    public void show2() {
        System.out.println("这是子类中的特殊show方法");
    }

}
public class PolymorphicDemo3 {
    public static void main(String[] args) {
        Father2 father=new Son2();
        //father.show2();//这里不能直接调用show2()因为父类里没有show2()无法编译
        Son2 s=(Son2) father;
        s.show2();
        s.show();

    }


}

实例:

动物之猫和狗

class Animal2{
    public void eat(){
        System.out.println("吃");
    }
}
class Dog extends Animal2{
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
    public void lookDoor(){
        System.out.println("看门");
    }
}
class Cat extends Animal2{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
    public void catchMouse(){
        System.out.println("猫捉老鼠");
    }
}

public class PolymorphicDemo4 {
    public static void main(String[] args) {
        Animal2 animal2=new Dog();
        animal2.eat();
        Dog d=(Dog) animal2;
        d.eat();
        d.lookDoor();
        Animal2 animal21=new Cat();
        animal21.eat();
        Cat c=(Cat) animal21;
        animal21.eat();
        ((Cat) animal21).catchMouse();
    }
}

不同地方饮食文化不同的案例

Person

eat()

SouthPerson

eat()

NorthPerson

eat()

class Person {
    public void eat() {
        System.out.println("吃");
    }
}

class SouthPerson extends Person {
    @Override
    public void eat() {
        System.out.println("南方人吃米饭");
    }

    public void playMaJiang() {
        System.out.println("南方人打麻将");
    }
}

class NorthPerson extends Person {
    @Override
    public void eat() {
        System.out.println("北方人吃面食");
    }

    public void bath() {
        System.out.println("北方人搓澡");
    }
}

public class PolymorphicDemo5 {
    public static void main(String[] args) {
        Person person = new SouthPerson();
        person.eat();
        SouthPerson s = (SouthPerson) person;
        s.eat();
        s.playMaJiang();
        Person person1 = new NorthPerson();
        person1.eat();
        NorthPerson n = (NorthPerson) person1;
        n.bath();
        n.eat();
    }
}

多态的好处有哪些?

1、多态可以使代码的扩展性很好(这是由继承所保证的)

2、多态可以使代码的维护性很好(这是由多态保证的)

class Animal {
    String name;
    int age;

    Animal() {

    }

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

    public void eat() {
        System.out.println("吃");
    }
}

class Dog1 extends Animal {
    public Dog1() {

    }

    public Dog1(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

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

class Cat1 extends Animal {
    public Cat1() {

    }

    public Cat1(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

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


}


class AnimalTool {//工具类

    private AnimalTool() {

    }

    public static void useDog(Dog1 dog1) {
        dog1.sleep();
        dog1.eat();

    }

    public static void useCat(Cat1 cat1) {
        cat1.sleep();
        cat1.eat();

    }

    public static void useAnimal(Animal animal) {
        animal.eat();
        animal.sleep();
    }
}


public class CatDogDemo {
    public static void main(String[] args) {
        System.out.println("=====第二种通过下面创建方法调用=====");//第一种方法调用子类
        Dog1 dog1 = new Dog1("小白哦", 2);
        dog1.eat();
        dog1.sleep();
        Cat1 cat1 = new Cat1("小号", 3);
        cat1.eat();
        cat1.sleep();
        System.out.println("=====第二种通过下面创建方法调用=====");//第二种通过下面创建方法调用
        Dog1 d1 = new Dog1("小白", 2);
        useDog(d1);
        Cat1 c1 = new Cat1("小红", 2);
        useCat(c1);
        System.out.println("====第三种通过工具类调用=====");//第三种通过工具类调用
        Dog1 d2 = new Dog1("小白", 2);
        AnimalTool.useDog(d2);
        Cat1 c2 = new Cat1("小红", 2);
        AnimalTool.useCat(c2);//这里注意工具类是私有的不可直接调用use方法
        //工具类里的内容是私有的不好改动
        System.out.println("=====用多态改进=====");
        Animal a1 = new Dog1("小白",2);
        AnimalTool.useAnimal(a1);
        Animal a2 = new Cat1("小红",2);
        AnimalTool.useAnimal(a2);

    }

    public static void useDog(Dog1 dog1) {//创建方法调用
        dog1.sleep();
        dog1.eat();

    }

    public static void useCat(Cat1 cat1) {
        cat1.sleep();
        cat1.eat();

    }
}

抽象的表述:

之前所说的猫,狗,猪,熊猫,老虎等等都是动物具体的例子,而动物本身是一个抽象的概念 但是回想一下我们之前都是将动物写成了一个具体的,而类又可以创建对象,但是实际上抽象的东西本身应该不能被实例化.

并且动物中吃的方法应该也不是一个具体的实现,以及所有动物共同拥有的方法在动物中应该都是抽象的表现

今天之后,把一个不具体的功能,叫做抽象方法,而如果一个类中有抽象方法,我们就把这个类称之为抽象类。

抽象类的特点:

1、抽象类和抽象方法都要用一个关键字修饰:abstract

修饰一个类 放在class的前面

举例: abstract class Animal3{}

修饰一个方法 一般是放在权限修饰符后面

定义一个抽象的show方法

举例:public abstract void show();

2、有抽象方法的类一定要是抽象类,抽象类不一定要有抽象方法,具体的类中不能有抽象方法,抽象类中既可以存在抽象方法

也可以存在有方法体的方法。

3、抽象类不能被实例化

既然不能被实例化,那写在抽象类中的方法如何被调用呢?

抽象类如何创建呢?

通过多态的形式,使用具体的子类去实例化调用方法,专业术语称之为:抽象多态

4、如果继承抽象类的是一个具体的子类,需要重写该抽象类中所有的抽象方法

如果继承抽象的也是一个抽象类,可以不去重写父类中的抽象方法,也可以选择性的去重写。

abstract class Animal3 {
    //注意:
    //抽象方法没有方法体{},连大括号都没有,直接以分号结尾
    //java: 抽象方法不能有主体
    public abstract void eat();

    public abstract void drink();
}

class Dog3 extends Animal3 {
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }

    @Override
    public void drink() {
        System.out.println("狗喝水");
    }
}

abstract class Demo2 {
    public abstract void fun();

    public abstract void fun2();
}

abstract class Demo3 extends Demo2 {
    @Override
    public void fun() {
        System.out.println("抽象类Demo3中重写了fun方法");
    }

    @Override
    public void fun2() {
        System.out.println("抽象类Demo3中重写了fun2方法");
    }
}

public class AbstractDemo1 {
    public static void main(String[] args) {
//        Demo2 demo2=new Demo2();   //java: com.shujia.wyh.day11.Demo2是抽象的; 无法实例化
        //利用具体子类多态形式创建对象
        //抽象多态的形式
        Animal3 animal3 = new Dog3();
        animal3.drink();
        animal3.eat();
        //Demo2 demo2= new Demo2() //都是抽象无法调用


    }
}



抽象类的成员的特点:

成员变量:

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

构造方法:

可以存在构造方法,上一个程序中总结出抽象类不能被实例化,这里构造方法意义是什么?

之前在继承中要想初始化子类,必须先初始化父类,所以这里构造方法是提供初始化父类的作用

成员方法:

可以是抽象方法,但是具体的子类必须要重写该方法

也可以不是抽象方法,提高代码的复用性。

abstract class Animal4 {
    int a = 100;
    final int b = 20;

    Animal4() {
        System.out.println("这是Animal4中无参构造方法");//即使不去定义也会存在
    }

    public abstract void eat();

    public void show() {
        System.out.println("父类中不是抽象方法的show");
    }
}
class Cat4 extends Animal4{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
public class AbstractDemo2 {
    public static void main(String[] args) {
        Animal4 a = new Cat4();
        System.out.println(a.a);
        System.out.println(a.b);
        a.eat();
        a.show();
    }
}

不写抽象方法,也是可以的。

1、抽象类中可以没有抽象方法

2、抽象类不能被实例

抽象类中可以存在哪些关键字?

abstract关键字不能和哪些关键字共存?

private

static

final

abstract class YeTi{
//    YeTi(){
//        super();
//    }//不会报错因为所有的类都有一个共同的父类:object
//abstract可以和public关键字共存
public abstract void show();
    //private和abstract关键字冲突
//private abstract void show2(); java: 非法的修饰符组合: abstract和private
    //static和abstract关键字冲突
//    static abstract void show3();  // java: 非法的修饰符组合: abstract和static

    //final和abstract关键字冲突
//    final abstract void show4();  // java: 非法的修饰符组合: abstract和final

}
public class AbstractDemo3 {
    public static void main(String[] args) {

    }
}

抽象类改进猫狗案例

abstract class Animal5{
    public abstract void eat();
    public abstract void sleep();

}
class Dog5 extends Animal5 {
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }

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

    }
    public void play(){
        System.out.println("狗和狗玩");
    }
}
class Cat5 extends Animal5{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    @Override
    public void sleep() {
        System.out.println("猫趴着睡");
    }
    public void play(){
        System.out.println("猫和猫玩");
    }
}
public class AbstractTest1 {
    public static void main(String[] args) {
        Animal5 animal5=new Dog5();
        animal5.eat();
        animal5.sleep();
        Dog5 dog5=(Dog5) animal5;
        dog5.play();
        Animal5 animal51=new Cat5();
        animal51.sleep();
        animal51.eat();
        Cat5 cat5=(Cat5) animal51;
        cat5.play();
    }
}

假如我们在开发一个系统时需要对员工类进行设计,员工包含3个属性:姓名、工号以及工资。

经理也是员工,除了含有员工的属性外,另为还有一个奖金属性。

请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问。

分析:

普通员工:

成员变量:姓名,工号,工资

成员方法:工作(敲代码)

经理

成员变量:姓名,工号,工资,奖金

成员方法:工作(做PPT)

abstract class Stuff{
    private String name;
    private String id;
    private int salary;
    public  Stuff(){
    }
    public Stuff(String name,String id,int salary){
        this.id=id;
        this.name=name;
        this.salary=salary;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setId(String id) {
        this.id = id;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public String getId() {
        return id;
    }

    public int getSalary() {
        return salary;
    }
   public abstract void work();
}
class CommonStaff extends Stuff{
    public CommonStaff(){

    }
    public CommonStaff(String name, String id, int salary) {
        super(name, id, salary);
    }


    @Override
    public void work() {
        System.out.println("敲代码");
    }
}
class Manager extends Stuff{
    //特有的属性 奖金
    private int bonus;

    public Manager(int bonus) {
        this.bonus = bonus;
    }

    public Manager(String name, String id, int salary, int bonus) {
        super(name, id, salary);
        this.bonus = bonus;
    }

    @Override
    public void work() {
        System.out.println("做PPT");
    }
}

public class AbstractTest4 {
    public static void main(String[] args) {
        //创建第一个对象
        Stuff s1 = new CommonStaff("小虎","KZ0080",100000);
        s1.work();

        //创建第二个对象
        Stuff s2 = new Manager("小明","SJ00030",200000,1000000);
        s2.work();

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值