图片 2

Java学习之路09

图解多态2

图片 1

final 关键字的特点

  • final可以修饰类,该类不能被继承
  • final可以修饰方法,该方法不能被重写
  • final可以修饰变量,该变量不能被重新赋值,因为这个变量其实是常量
  • 常量
  1. 字面值常量:”hello”,10,true
  2. 自定义常量:final int x = 10
  • 代码示例:

//final class Fu//无法从最终Fu进行继承
class Fu {
    /*public final void show() {
        System.out.println("lhk");
    }
    */
    public int num = 10;
    public final int num2 = 20;
    public void show() {

    }
}

class Zi extends Fu {
    //Zi中的show()无法覆盖Fu中的show()
    public void show() {
        num = 100;
        //num2 = 200;
        System.out.println(num);
        System.out.println(num2);
    }
}
public class finalDemo {
    public static void main(String[] args) {
        Zi z = new Zi();
        z.show();
    }
}

图解多态2代码

(参考https://www.cnblogs.com/luchuangao/p/6739557.html)

#多态:同一种事物的多种形态,动物分为人类,猪类(在定义角度)
class Animal:
    def run(self):
        raise AttributeError('子类必须实现这个方法')


class People(Animal):
    def run(self):
        print('人正在走')

class Pig(Animal):
    def run(self):
        print('pig is walking')


class Dog(Animal):
    def run(self):
        print('dog is running')

peo1=People()
pig1=Pig()
d1=Dog()

peo1.run()
pig1.run()
d1.run()

参考:本文参考学习《Python3 Object Oriented
Programming》,根据自己理解改编,Dusty Phillips 著

final 修饰变量的初始化时机

  • 被final 修饰的变量只能赋值一次
  • 在构造方法完毕前(非静态的常量)

多态的作用

调用不同的子类将会产生不同的行为。
多态是在继承上实现的。

抽象类的成员特点

  • 成员变量:既可以是变量,也可以是常量
  • 构造方法:有,用于子类访问父类数据的初始化
  • 成员方法:既可以是抽象的,也可以是非抽象的
  • 抽象类的成员方法特征
  1. 抽象方法:强制要求子类做的事情
  2. 非抽象方法,子类继承的事情,提高代码的复用性
  • 代码示例:

abstract class Animal5 {
    public int num = 10;

    public Animal5() {}

    public Animal5(String name,int age) {}

    public abstract void show();

    public void method() {
        System.out.println("show method");
    }
}

class Dog5 extends Animal5 {
    public void show() {
        System.out.println("show Dog5");
    }
}
public class AbstractDemo {
    public static void main(String[] args) {
        Animal5 animal5 = new Dog5();
        System.out.println(animal5.num);
        System.out.println("------");
        animal5.show();
        animal5.method();
    }
}

图解多态1代码

class AudioFile:
    def __init__(self, filename):
        if not filename.endswith(self.ext):
            raise Exception("Invalid file format")
        self.filename = filename

class MP3File(AudioFile):
    ext = "mp3"
    def play(self):
        print("playing {} as mp3".format(self.filename))

class WavFile(AudioFile):
    ext = "wav"
    def play(self):
        print("playing {} as wav".format(self.filename))

class OggFile(AudioFile):
    ext = "ogg"
    def play(self):
        print("playing {} as ogg".format(self.filename))

ogg = OggFile("myfile.ogg")
ogg.play()

mp3 = MP3File("myfile.mp3")
mp3.play()

not_an_mp3 = MP3File("myfile.ogg")
not_an_mp3.play()

抽象类的概述

  • 在Java
    中,我们把一个不是具体的功能称为抽象的功能,而一个类中如果有抽象的功能,该类必须是抽象类

图解多态1

图片 2

接口的成员特点

  • 成员变量:只能是常量,并且是静态的
    默认修饰符:public static final
    建议手动给出
  • 构造方法:接口没有构造方法
  • 成员方法:只能是抽象方法
    默认修饰符:public abstract
    建议手动给出
  • 所有的类都默认继承自一个类:Object
    类Object 是类层次结构的根类,每个类都使用Object 作为超类
  • 代码示例:

interface Inter {
    public int num = 10;
    public final int num2 = 20;
    //完整版中的接口变量
    public static final int num3 = 30;
    //public Inter() {}

    //接口方法不能带有主体
    //public void show() {}

    //abstract void show();默认是public
    public void show();//默认是abstract
}
//接口名+Impl这种格式是接口的实现类格式
//class InterImpl extends Object implements Inter {}
class InterImpl implements Inter {
    public InterImpl() {
        super();
    }

    public void show() {

    }
}
public class InterfaceDemo {
    public static void main(String[] args) {
        Inter inter = new InterImpl();
        System.out.println(inter.num);
        System.out.println(inter.num2);
        //inter.num = 199;
        //无法为num或者num2分配值,因为接口中默认num已为常量
        //和final效果一样
        System.out.println("------");
        System.out.println(Inter.num);
        System.out.println(Inter.num2);

    }
}

抽象类的特点

  • 格式:
  1. 抽象类和抽象方法必须用abstract 关键字修饰
  2. 抽象类中不一定有抽象方法,但是有抽象方法的类
  3. 抽象类不能实例化(抽象类有构造方法,但是不能实例化,构造方法用于子类访问父类数据的初始化)
  4. 抽象的子类
    a. 如果不想重写抽象方法,该子类是一个抽象类
    b. 重写所有的抽象方法,这时候子类是一个具体的类
  • 抽象类的实例化其实是靠具体的子类实现的,是多态的方式
  • 代码示例:

abstract class Animal4 {
    //抽象方法
    //public abstract void eat() {}//空方法体,报错
    public abstract void eat();//没有方法体
}

//子类是抽象类
abstract class Dog4 extends Animal4 {}

//子类是具体类,重写抽象方法
class Cat4 extends Animal4 {
    public void eat() {
        System.out.println("eat fish");
    }
}

public class ChouxiangDemo {

    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        //通过多态的方法
        Animal4 animal4 = new Cat4();
        animal4.eat();
    }
}

多态的好处

  • 提高了代码的维护性(继承保证)
  • 提高了代码的扩展性(由多态保证)
  • 代码示例:

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

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

class Dog extends Animal {
    public void eat() {
        System.out.println("eat bone");
    }

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

class Cat extends Animal {
    public void eat() {
        System.out.println("eat fish");
    }

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

class Pig extends Animal {
    public void eat() {
        System.out.println("eat fruit");
    }

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

//针对动物类操作的工具书
class AnimalTool {
    //让使用者无法创建对象
    /*
    private AnimalTool() {      
    }
    //调用猫的功能
    public static void useCat(Cat cat) {
        cat.eat();
        cat.sleep();
    }
    //调用狗的功能
    public static void useDog(Dog dog) {
        dog.eat();
        dog.sleep();
    }
    //调用猪的功能
    public static void usePig(Pig pig) {
        pig.eat();
        pig.sleep();
    }
    */  
    public static void useAnimal(Animal a) {
        a.eat();
        a.sleep();
    }
}

public class DuotaiDemo2 {
    public static void main(String[] args) {
        //喜欢猫
        Cat cat = new Cat();
        cat.eat();
        cat.sleep();

        //超喜欢猫
        Cat cat2 = new Cat();
        cat2.eat();
        cat2.sleep();
        System.out.println("------");
        //改进版本
        //useCat(cat);
        //useCat(cat2);
        //AnimalTool.useCat(cat);
        //AnimalTool.useCat(cat2);
        AnimalTool.useAnimal(cat);
        AnimalTool.useAnimal(cat2);
        System.out.println("------");
        //我喜欢狗
        Dog dog = new Dog();
        Dog dog2 = new Dog();
        //AnimalTool.useDog(dog);
        //AnimalTool.useDog(dog2);
        AnimalTool.useAnimal(dog);
        AnimalTool.useAnimal(dog2);
        System.out.println("------");
        //我喜欢猪
        Pig pig = new Pig();
        Pig pig2 = new Pig();
        //AnimalTool.usePig(pig);
        //AnimalTool.usePig(pig2);
        AnimalTool.useAnimal(pig);
        AnimalTool.useAnimal(pig2);
        System.out.println("------");
        //我喜欢的动物还有很多
        //但我们必须写一个方法去代替重复构造动物功能的过程      
    }
}

跳高猫代码示例

package exp2.demo;
//定义跳高接口
interface Jumpping {
    public abstract void jump();
}

//定义抽象类
abstract class Animal {
    private String name;
    private int age;

    public Animal() {};

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    //吃饭
    public abstract void eat();
    //睡觉
    public void sleep() {
        System.out.println("sleep");
    }
} 

class Dog extends Animal {
    public Dog() {}

    public Dog(String name,int age) {
        super(name,age);
    }

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

class Cat extends Animal {
    public Cat() {}

    public Cat(String name,int age) {
        super(name,age);
    }

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

//跳高猫
class JumpCat extends Cat implements Jumpping {
    public JumpCat() {}

    public JumpCat(String name,int age) {
        super(name,age);
    }
    public void jump() {
        System.out.println("jump cat");
    }
}

public class TestDemo {
    public static void main(String[] args) {
        //定义跳高猫
        JumpCat jumpCat = new JumpCat();
        jumpCat.setName("nihao");
        jumpCat.setAge(20);
        System.out.println(jumpCat.getName() + jumpCat.getAge());
        jumpCat.eat();
        jumpCat.sleep();
        jumpCat.jump();
        System.out.println("------");
    }
}

Java学习笔记09

多态的概述和成员访问特点

  • 某一个对象,在不同时刻表现出来的不同状态
  • 多态的前提
  1. 要有继承关系或者实现关系
  2. 要有方法重写
  3. 要有父类或者父类接口引用指向子类对象
    父 f = new 子();
  • 多态的分类
  1. 具体类多态
    class Fu() {}
    class Zi extends Fu {}
    Fu f = new Zi();
  2. 抽象类多态
    abstract class Fu() {}
    class Zi extends Fu {}
    Fu f = new Zi();
  3. 接口多态
    interface Fu() {}
    class Zi implements Fu {}
    Fu f = new Zi();
  • 多态中的成员访问特点
  1. 成员变量
    编译看左边,运行看左边
  2. 构造方法
    创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化
  3. 成员方法(方法存在覆盖)
    编译看左边,运行看右边
  4. 静态方法
    编译看左边,运行看左边
    (静态和类相关,算不上重写,所以,访问还是左边的)
  5. 代码示例:

class Fu2 {
    public int num = 100;

    public void show() {
        System.out.println("show Fu2");
    }
    public static void function() {
        System.out.println("function Fu2");
    }

}

class Zi2 extends Fu2 {
    public int num = 1000;
    public int num2 = 100;

    public void show() {
        System.out.println("show Zi");
    }
    public void method() {
        System.out.println("Method zi");
    }
    public static void function() {
        System.out.println("function zi");
    }
}

public class DuotaiDemo {
    public static void main(String[] args) {
        Fu2 fu = new Zi2();
        System.out.println(fu.num);
        //System.out.println(fu.num2);
        fu.show();
        //fu.method();
        fu.function();
    }
}

抽象类中的小问题

  • 一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
  1. 可以
  2. 不让外界创建对象
  • abstract 不能和哪些关键字共存
  1. private 冲突

建立抽象方法的目的是让子类去重写这个方法,而一旦加了private,子类就不能进行重写了,无意义

  1. final 冲突

同理,子类不能进行方法重写

  1. static 无意义
  2. 代码示例:

abstract class Fu6 {
    //public abstract void show();
    //非法的修饰符组合:abstract和private
    //private abstract void show();
    //非法的修饰符组合
    //final abstract void show();
    //show方法没有方法体,访问一个没有方法体的方法,无意义
    //static abstract void show();

    public static void method() {
        System.out.println("method");
    }
}

class Z6 extends Fu6 {
    public void show() {        
    }
}
public class XiaoWenTiDemo {
    public static void main(String[] args) {
        Fu6.method();
    }
}

类与类,类与接口,接口与接口的关系

  • 类与类
  1. 继承关系:只能单继承,但是可以多层继承
  • 类与接口
  1. 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
  • 接口与接口
  1. 继承关系,可以单继承,也可以多继承
  • 代码示例;

package exp2.demo;
/*
 * 类与类:继承关系:只能单继承,但是可以多层继承
 * 类与接口:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
 * 接口与接口:继承关系,可以单继承,也可以多继承
 */

interface Father {
    public void show();
}

interface Mother {
    public abstract void show2();

}

interface Sister extends Father,Mother {

}
//class Son implement Father,Mother //多实现
//还可以在继承一个类的同时实现多个接口
class Son extends Object implements Father,Mother{
    public void show() {
        System.out.println("show son");
    }

    public void show2() {
        System.out.println("show2 son");
    }
}
public class AbstractDemo {
    public static void main(String[] args) {
        Father father = new Son();
        father.show();
        //father.show2();
        Mother mother = new Son();
        mother.show2();
        //mother.show();
    }
}

多态的弊端和解决方法

  • 父不能使用子类的特有功能
  • 我们要解决这个问题:多态中向上转型和向下转型
  1. 向上转型:Fu f = new Zi();
  2. 向下转型:Zi z = (Zi)f;//要求该f必须是能够转换为Zi的
  3. 代码示例:

class Fu3 {
    public void show() {
        System.out.println("show Fu3");
    }
}

class Zi3 extends Fu3 {
    public void show() {
        System.out.println("show Zi3");
    }

    public void method() {
        System.out.println("method Zi3");
    }
}
public class DuotaiDemo3 {
    public static void main(String[] args) {    
        Fu3 fu3 = new Zi3();
        fu3.show();
        //fu.method();
        //我们能够把子的对象赋值给父亲,那能否把父的引用赋值给子的引用呢?
        Zi3 zi3 = (Zi3)fu3;//向下转型
        zi3.show();
        zi3.method();
    }
}

final 关键字修饰局部变量

  • 修饰基本类型:基本类型的值不能发生改变
  • 修饰引用类型:引用类型的地址值不能发生改变,但是,该对象的堆内存的值(即类中的变量值)是可以改变的
  • 代码示例:

class Student {
    int age = 10;
}

public class FinalTest {
    public static void main(String[] args) {
        int x = 10;
        x = 100;
        System.out.println(x);

        final int y = 10;
        //无法为最终变量y分配值
        //y = 100;
        System.out.println(y);
        System.out.println("------");
        //局部变量是引用数据类型
        Student s = new Student();
        System.out.println(s.age);
        s.age = 100;
        System.out.println(s.age);
        System.out.println("------");

        final Student ss = new Student();
        System.out.println(ss.age);
        ss.age = 100;
        System.out.println(ss.age);
        //final 修饰ss的地址值

        //重新分配内存空间给ss,这是不允许的
        //ss = new Student();
    }
}

多态中的内存图解

  • 多态继承中的内存图解
  • [图片上传失败…(image-39fa80-1510752835050)]
  • 多态中的对象变化内存图解
  • [图片上传失败…(image-340db8-1510752835050)]

示例代码

//定义员工类
abstract class Employee {
    private String name;
    private String id;
    private int salary;

    public Employee() {

    }

    public Employee(String name,String id,int salary) {
        this.name = name;
        this.id = id;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

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

    public String getid() {
        return id;
    }

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

    public int getSalary() {
        return salary;
    }

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

    //工作
    public abstract void work();

}

//员工
class programmer extends Employee {
    public programmer() {

    }

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

    public void work() {
        System.out.println("code");
    }
}

//经理
class manager extends Employee {
    private int money;

    public manager() {

    }

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

    public void work() {
        System.out.println("communicate");
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }
}
public class AbstractTestDemo3 {
    public static void main(String[] args) {
        //测试普通员工
        Employee employee = new programmer();
        employee.setName("lhk");
        employee.setid("hk");
        employee.setSalary(1000000000);
        System.out.println(employee.getName() + "---" + employee.getid() + "---" + employee.getSalary());
        System.out.println("-------");
        employee = new programmer("lhk","nihao",10000);
        System.out.println(employee.getName() + "---" + employee.getid() + "---" + employee.getSalary());
        System.out.println("-------");
        /*
        employee = new manager();
        employee.setName("lhk");
        employee.setid("hk");
        employee.setSalary(2000000000);
        employee.setmoney(3151345);
        */
        //由于子类特有的内容,所以我们用子类来测试
        manager manager = new manager();
        manager.setName("lhk");
        manager.setid("hk");
        manager.setSalary(2000000000);
        manager.setMoney(3151345);
        System.out.println(manager.getName() + "---" + manager.getid() + "---" + manager.getSalary() + "---" + manager.getMoney());
        manager.work();
        System.out.println("-------");
        //通过构造方法赋值
        manager = new manager("lhk","hk",66666,352354);
        System.out.println(manager.getName() + "---" + manager.getid() + "---" + manager.getSalary() + "---" + manager.getMoney());
        manager.work();
    }
}

final 关键字引入

  • 我们不想让子类去覆盖掉父类的功能(方法重写会覆盖掉父类的方法),只能让父类使用,这个时候,Java就提供了一个关键字:final
  • final:常见可以修饰类,方法,变量

多态基本案例

  • 代码示例:

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

class Dog2 extends Animal2 {
    public void eat() {
        System.out.println("bone");
    }

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

class Cat2 extends Animal2 {
    public void eat() {
        System.out.println("fish");
    }

    public void playGame() {
        System.out.println("sweater");
    }
}
public class DuotaiTest {

    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        Animal2 animal = new Dog2();
        animal.eat();
        System.out.println("-------");
        //还原成狗
        Dog2 d = (Dog2)animal;
        d.eat();
        d.lookDoor();
        System.out.println("-------");
        //变成猫
        animal = new Cat2();
        animal.eat();
        System.out.println("-------");
        //还原成猫
        Cat2 cat = (Cat2)animal;
        cat.eat();
        cat.playGame();
        System.out.println("-------");
    }
}

抽象类和接口的区别

  • 成员区别
  1. 抽象类:
    成员方法:可以变量,也可以常量
    构造方法:有
    成员方法:可以抽象,也可以非抽象
  2. 接口:
    成员变量:只可以常量
    成员方法:只可以抽象
  • 关系区别
  1. 类与类:继承,单继承
  2. 类与接口:实现,单继承,多实现
  3. 接口与接口:继承,单继承,多继承
  • 设计理念区别
  1. 抽象类:被继承体现的是:“is
    a”的关系,抽象类中定义的是该继承体现的共性功能
  2. 接口:被实现体现的是:“like
    a”的关系,接口中定义的是该继承体系的扩展功能