面向对象之多态

面向对象之多态

  • 对象的多种形态和状态
  • 针对方法
  • 有了封装、继承才有了多态
  • 必要条件
    • 继承、重写
  • 当编译时类型和运行时类型不一致,就会出现多态(Polymorphism)
    • 编译看左边(左边=),运行看右边(=右边)

多态实现基础

  • 父类声明的变量可以引用所有子类的对象,这是多态实现的基础
  • 只有在运行时,才会知道引用变量所指向的具体实例对象

多态的作用

​ 把不同的子类对象都当做父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。

  • 就是父类或接口的引用限量指向子类的对象

多态入门–继承

//父类
public class Fruit {
    //水果类
}
//子类
public class Apple extends Fruit {
    //苹果类也是水果的一种,所以继承水果类
}
//子类
public class Banana extends Fruit {
    //香蕉类
}
//子类
public class Grape extends Fruit {
    //葡萄类
}
//测试
public class Test {
    public static void main(String[] args) {
        Fruit fruit1 = new Fruit();
        Apple apple = new Apple();
        Banana banana = new Banana();
        Grape grape = new Grape();

		//等号左侧是一个父类的引用,右侧是一个子类的对象
		//父类引用指向了子类的对象
        Fruit fruit2 = apple;
        Fruit fruit3 = new Apple();
        System.out.println(fruit2);
        System.out.println(fruit3);
        System.out.println("--------------");

        Fruit fruit4 = banana;
        Fruit fruit5 = new Banana();
        System.out.println(fruit4);
        System.out.println(fruit5);
        System.out.println("--------------");

        Fruit fruit6 = grape;
        Fruit fruit7 = new Grape();
        System.out.println(fruit6);
        System.out.println(fruit7);
        System.out.println("--------------");

    }
}

多态进阶–继承

//父类
public class Animal {
    public void shout(){
        System.out.println("动物会叫");
    }
}
//子类
public class Cat extends Animal {
    @Override
    public void shout(){
        System.out.println("喵喵喵");
    }
    public  void eatFish(){
        System.out.println("小猫吃鱼");
    }
}
//子类
public class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("汪汪汪");
    }
    public void eatBone(){
        System.out.println("小狗啃骨头");
    }
}
//测试
public class Test {
    public static void main(String[] args) {
        //a1 又叫引用,它指向了堆里面的真正的对象。也就是常说的栈指向堆
        //a1 叫做引用 创建出来的对象叫做实例(instans)---多态
        Animal a1 = new Animal();
        a1.shout();
        Dog d1 = new Dog();
        d1.shout();
        d1.eatBone();
        Cat c1 = new Cat();
        c1.shout();
        c1.eatFish();
        System.out.println("------------");
        Animal a2 = new Dog();
        a2.shout();
        //a2.eatBone();//Animal类的引用 只能看到Animal的方法 它引用的是子类重写父类的方法
        Animal a3 = new Cat();
        a3.shout();
        //a3.eatFish();
        System.out.println("--------------");
        // 类型转换---多态
        Animal a4 = new Dog();
        Dog d2 = (Dog) a4;
        d2.shout();
        d2.eatBone();
        Animal a5 = new Cat();
        Cat c2 = (Cat) a5;
        c2.shout();
        c2.eatFish();
        System.out.println("--------------");

    }
}

结果:

动物会叫
汪汪汪
小狗啃骨头
喵喵喵
小猫吃鱼
------------
汪汪汪
喵喵喵
--------------
汪汪汪
小狗啃骨头
喵喵喵
小猫吃鱼
--------------

向上转型 upcasting

  • 系统自动转型
  • 执行父类的方法
  • 一个引用变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能访问子类中特有的属性和方法
Animal a2 = new Dog();
a2.shout();
//a2.eatBone();//Animal类的引用 只能看到Animal的方法 它引用的是子类重写父类的方法
Animal a3 = new Cat();
a3.shout();
//a3.eatFish();

向下转型 downcasting

  • 强制转型(强制类型转换符—())
  • 父类转换子类
  • 执行子类的方法
// 类型转换---多态
Animal a4 = new Dog();
Dog d2 = (Dog) a4;
d2.shout();
d2.eatBone();
Animal a5 = new Cat();
Cat c2 = (Cat) a5;
c2.shout();
c2.eatFish();

多态的总结

  • 静态方法不能被重写,故静态方法没有多态性
  • 成员变量不具备多态性。成员变量的取值取决于所属的类
  • 成员方法
    • 编译时:检查引用变量所属类中是否有所调用的方法
    • 运行时:调用实际对象所属类中的重写方法

类型转换的重点

  • 弄清楚继承关系,谁是父类谁是子类
  • 关键点在于创建时调用的是谁的构造器

instanceof

  • 关键字
  • 是否 是实例
  • 返回布尔值
  • 语法
    • boolean result = 检查的对象 instanceof 对象是不是这类的实例(类名);
    • System.out.println(a5 instanceof Animal);

public static void main(String[] args){
    Animal a5 = new Cat();
	Cat c2 = (Cat) a5;
	c2.shout();
	c2.eatFish();
    System.out.println(a5 instanceof Animal);
	System.out.println(c2 instanceof Animal);
	System.out.println(c2 instanceof Cat);
}

结果:

true
true
true

多态的应用场景

继承的多态

  • 多个子类对同一个父类方法的重写,可以在运行时表现出不同行为

接口的多态

  • ​ 一个接口可以有多个实现类。所以,多个实现对接口中同一个方法的重写,可以在运行时表现出不同的行为
  • 实例
    • 接口名 变量名 = new 实现类名();
public interface MyInterface {
    void test();
}


public class MyInterfaceImpl1 implements MyInterface{
    @Override
    public void test() {
        System.out.println("Impl111");
    }
}

public class MyInterfaceImpl2 implements MyInterface{
    @Override
    public void test() {
        System.out.println("test222");
    }
}

public class Test {
    public static void main(String[] args) {
        MyInterfaceImpl1 myInterfaceImpl1  = new MyInterfaceImpl1();
        myInterfaceImpl1.test();
        MyInterfaceImpl2 myInterfaceImpl2 = new MyInterfaceImpl2();
        myInterfaceImpl2.test();
        System.out.println("-----------");
        MyInterface myInterface1 = new MyInterfaceImpl1();
        myInterface1.test();
        MyInterface myInterface2 = new MyInterfaceImpl2();
        myInterface2.test();
        System.out.println("------------");
        //=右边 是没有名字的类的对象的方法--给予接口实现匿名内部类
        MyInterface myInterface3 =new MyInterface() {
            @Override
            public void test() {
                System.out.println("怎么回事!");
            }
        };
        myInterface3.test();
    }
}

形参的多态

  • 多态可以作为参数,接受范围更广的对象,接收参数更加灵活
public class Test2 {
    public static void main(String[] args) {
        Test2 t1 = new Test2();
        Cat cat = new Cat();
        t1.getCat(cat);
    }
    public void getCat(Animal animal){
        System.out.println("cat");
    }
}

返回值的多态

  • 多态可以作为返回值,接受范围更广的对象
public class Test3 {
    public static void main(String[] args) {
        Animal animal = Test3.printClass();
    }
    public static Animal printClass(){
        Cat cat =  new Cat();
        return cat;
    }
}

内部类

概述

​ 在一个类的内部定义的类称为 内部类,其实就是类定义的位置发生了变化。再类中定义的内部类叫 成员内部类,在函数中定义的内部类 叫局部内部类; 使用static修饰的成员内部类叫 静态内部类。讲台内部类使用很少,用的最多的是成员内部类。

  • 内部类生产的class文件为“外部类$内部类”,它表明该内部类是属于那个外部类

成员内部类

  1. 定义成员内部类
    • 成员内部类也是一个类,可以由自己的成员属性,成员方法
    • 成员内部类可以访问外部类的成员方法和成员属性
    • 内部类中this.name 中的this 表示内部类
public class Test {
    private int treeType = 100;
    private String name = "le";

    public int getTreeType(){
        return treeType;
    }

    public String getName() {
        return name;
    }

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

    class Test1{
        private String name = "fa";

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
        //访问外部类属性
        public int getTreeNumber(){
            int numTpye = Test.this.treeType;
            return numTpye;
        }
        //访问外部类方法
        public String getTestName(){
            return Test.this.getName();
        }
    }
}

小结1

  • 内部类访问外部类的字段
    • 外部类名.this.字段
  • 内部类访问外部类的方法
    • 外部类名.this.方法
  • 内部类访问内部类字段
    • this.字段
  • 内部类访问内部类方法
    • this.方法

2.成员内部类的使用

  • 成员内部类必须依赖于外部类的对象
    • 所以,首先创建外部类,然后使用外部类的实例创建普通内部类
//第一种
public class Test1 {
    public static void main(String[] args) {
        //创建外部类对象
        Test test = new Test();
        System.out.println(test.getName());
        System.out.println(test.getTreeType());
        //创建内部类对象
        Test.Test1 test1 = test.new Test1();
        System.out.println("----------------");
        //内部类对象调用方法
        int number = test1.getTreeNumber();
        System.out.println(number);
        System.out.println(test1.getTestName());
        System.out.println(test1.getName());
    }
}
//第二种
public class Test1 {
    public static void main(String[] args) {
        //创建外部类对象
        Test test = new Test();
        System.out.println(test.getName());
        System.out.println(test.getTreeType());
        //创建内部类对象
        Test.Test1 test1 = new Test().new Test1();
        System.out.println("----------------");
        //内部类对象调用方法
        int number = test1.getTreeNumber();
        System.out.println(number);
        System.out.println(test1.getTestName());
        System.out.println(test1.getName());
    }
}

小结2

  • 内部类可以直接访问玩不累的成员,包括外部类的私有对象
  • 外部类要访问内部类,必须创建对象

3.静态内部类

  1. 静态内部类的定义
    • 静态内部类就是一个Java类,它可以访问外部类的静态成员和静态方法,不能访问外部类的实例成员和实例方法
  2. 静态类内部类的使用
    • 创建静态内部类时,不需要先创建外部类的实例,直接使用 new Test.Test1(); 语法就可以创建一个实例
Test.Test1 test2 = new Test().Test1();
System.out.print(a.getName());
System.out.print(Test.Test1.getTreeType());

4.局部内部类

​ 包含在外部类的函数中的内部类称之为局部内部类。

  • 局部内部类只能访问所在函数的final属性
public class Demo {
    String name = "外部类的name";
    public void test(){
        final int a=100;//只有声明为final 才能被局部内部类访问
        int c = 10;
        //局部内部类
        class DemoSon{
            int b = 10;
            public void print(){
                System.out.println("这是局部内部类的方法"+a);
                System.out.println("内部类:b="+b);
                System.out.println("内部类访问test:c="+c);
                System.out.println("内部类访问test:name="+name);
            }
        }
        DemoSon demoSon = new DemoSon();
        demoSon.print();
        System.out.println("test b="+demoSon.b);
    }
}
//测试
public class Test3 {
    public static void main(String[] args) {
        Demo demo = new Demo();
        demo.test();
        System.out.println(demo.name);

    }
}

结果:

这是局部内部类的方法100
内部类:b=10
内部类访问test:c=10
内部类访问test:name=外部类的name
test b=10
外部类的name

Process finished with exit code 0

匿名内部类

基于接口实现匿名内部类

public static void main(String[] args){
	//=右边 是没有名字的类的对象的方法--给予接口实现匿名内部类
        MyInterface myInterface3 =new MyInterface() {
            @Override
            public void test() {
                System.out.println("怎么回事!");
            }
        };
        myInterface3.test();
    }
}

基于类实现匿名内部类

//抽象类
public abstract class Animal {
   public abstract void run();
   public abstract void sleep();
}
//测试
public class Demo {
    public static void main(String[] args) {
        Demo demo = new Demo();
        Animal animal = new Animal() {
            @Override
            public void run() {
                System.out.println("你在狗叫什么");
            }

            @Override
            public void sleep() {
                System.out.println("狗在睡觉");
            }
        };
        animal.run();
        animal.sleep();
    }
}

结果

你在狗叫什么
狗在睡觉

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咸鱼不咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值