多态、内部类和lambda表达式

1多态

1.1多态概述

多态:不同时刻表现出不同的形态,比如平常生活中,猫可以表现动物的形态,也可以表现猫的特定形态。

多态的前提:
1、有继承或者实现关系
2、方法的重写
3、父类的引用指向子类的对象

1.2多态例子解析

class Animal {
    public void eat(){
        System.out.println("动物吃饭");
    }
}
//满足多态继承前提
class Cat extends Animal {
//满足多态前提方法重写
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

public class Test1Polymorphic {
   
    public static void main(String[] args) {
        // 当前事物, 是一只猫
        Cat c = new Cat();
        // 当前事物, 是一只动物,不同形态体现多态
        //满足多态前提父类的引用指向子类对象
        Animal a = new Cat();
        a.eat();

    }
}

1.3多态中成员的访问特点

  1. 成员变量:编译看父类,运行看父类
  2. 成员方法:编译看父类,运行看子类

1.4多态的好处和弊病

  1. 好处
    提高程序的扩展性。定义方法的时候,使用父类型作为参数,在使用具体的子类参与操作(成员方法的访问特点)
  2. 弊病
    不能使用子类的特有成员

1.5多态中的转型

1、向上转型的格式:多态的格式,父类引用指向子类对象
2、向下转型的格式:子类型 对象名 = (子类型)父类引用
为了解决多态不能获取子类的特有成员,我们可以考虑:

  1. 直接使用子类来创建对象
  2. 使用向下转型
  3. 通过分析可以得出结论,多态用于共享的成员方法中,在私有的成员方法使用直接创建对象或向下转型

1.6多态中转型存在的风险

如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException异常。为了防止此风险,子类对象需要添加instanceof关键字来判断条件是否成立,再来向下转型和执行里面的特有方法。

1、instanceof关键字格式:变量名 instanceof 类型
2、理解:判断关键字左边的变量是否是右边的类型,是返回true,否则返回false

1.7多态向下转型例子解析

abstract class Animal {
    public abstract void eat();
}

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

    public void watchHome(){
        System.out.println("看家");
    }
}

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

public class Test4Polymorpic {
    public static void main(String[] args) {
        useAnimal(new Dog());
        useAnimal(new Cat());
    }

    public static void useAnimal(Animal a){  // Animal a = new Dog();
                                             // Animal a = new Cat();
        a.eat();
        //a.watchHome();

//        Dog dog = (Dog) a;
//        dog.watchHome();  // ClassCastException  类型转换异常
      
        // 判断a变量记录的类型, 是否是Dog
        if(a instanceof Dog){
            Dog dog = (Dog) a;
            dog.watchHome();
        }
    }

}

2内部类

在一个类中定义一个类。举例:在一个类A的内部定义一个类B,类B就被称为内部类

2.1内部类的访问特点

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

2.2内部类的分类

2.21成员内部类

2.211普通成员内部类

成员内部类所在位置为成员的位置,由此称为成员内部类

  • 外界创建成员内部类的格式:外部类名.内部类名 对象名 = 外部类对象.内部对象
  • 举栗子,Outer.Inner oi = new Outer().new Inner();
2.212私有成员内部类

私有成员内部类将一个类设计为内部类的目的,大多数是不想让外界去访问,所以内部类的定义应该私有化,私有化后,在提供一个可以让外界调用的方法,方法内部创建内部类对象并调用。

class Outer {
    private int num = 20;
    private class Inner {
        public void show() {
            System.out.println(num);
        }
    }
    public void method() {
        Inner i = new Inner();
        i.show();
    }
}
public class InnerDemo {
    public static void main(String[] args) {
        Outer o = new Outer();
        o.method();
    }
}
2.212静态成员内部类
  • 静态成员内部类访问格式:外部类名.内部类名 对象名 = new 外部对象名.内部类名();
  • 静态成员内部类中的静态方法访问格式:外部类名.内部类.方法名();
class Outer {
    static class Inner {
        public void show(){
            System.out.println("inner..show");
        }

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

public class Test3Innerclass {
    /*
        静态成员内部类演示
     */
    public static void main(String[] args) {
        // 外部类名.内部类名 对象名 = new 外部类名.内部类名();
        Outer.Inner oi = new Outer.Inner();
        oi.show();

        Outer.Inner.method();
    }
}

2.23局部内部类

局部内部类定义位置处在方法内部中定义的类,我们之前称方法内部的变量为局部变量,故此同理,方法里面的类称为局部内部类。

  • 局部类部类访问方式
    • 局部内部类,外界是无法直接使用的,成员方法的生命周期会随方法的调用完毕也结束,在外界创建局部内部类就会显得没有意义,因此需要在方法内部创建对象并使用
    • 该类可以直接访问外部类成员,也可以访问该方法内的局部变量
class Outer {
    private int num = 10;
    public void method() {
        int num2 = 20;
        class Inner {
            public void show() {
                System.out.println(num);
                System.out.println(num2);
            }
        }
        Inner i = new Inner();
        i.show();
    }
}
public class OuterDemo {
    public static void main(String[] args) {
        Outer o = new Outer();
        o.method();
    }
}

2.24匿名内部类

2.241匿名内部类概述

匿名内部类是特殊的局部内部类,实际上是接口的实现类或继承该类的子类对象,由于这个对象没有名称,故此称为匿名内部类。

  • 匿名内部类的前提
  • 存在一个类或者接口,这里的类可以是具体类也可以是抽象类
  • 匿名内部类的格式
  • 格式1:new 类名(){重写方法}
  • 格式2:new 接口名(){重写方法}
new Inter(){
    @Override
    public void method(){}
} 

匿名内部类是将创建对象、继承\实现、方法重写三个步骤放在了一起,可以便捷的创建子类对象

2.243匿名内部类调用方式
  • 匿名内部类可以通过多态的形式接收再调用
Inter i = new Inter(){
  @Override
    public void method(){
        
    }
}
  • 匿名内部类可以直接调用
    直接调用只能调用一个重写方法方法
    当我们想调用两个以上重写的方法时,就可以使用多态的形式接收,再分别调用即可。
interface Inter{
    void method();
}

class Test{
    public static void main(String[] args){
        new Inter(){
            @Override
            public void method(){
                System.out.println("我是匿名内部类");
            }
        }.method();	// 直接调用方法
    }
}
2.244匿名内部类的应用
  • 匿名内部类在开发中的使用
    • 当发现某个方法需要,接口或抽象类的子类对象,我们就可以将匿名内部类作为参数传递过去,来简化传统的代码
/*
    游泳接口
 */
interface Swimming {
    void swim();
}

public class TestSwimming {
    public static void main(String[] args) {
        goSwimming(new Swimming() {
            @Override
            public void swim() {
                System.out.println("铁汁, 我们去游泳吧");
            }
        });
    }

    /**
     * 使用接口的方法
     */
    public static void goSwimming(Swimming swimming){
        /*
            Swimming swim = new Swimming() {
                @Override
                public void swim() {
                    System.out.println("铁汁, 我们去游泳吧");
                }
            }
         */
        swimming.swim();
    }
}

3lambda

3.1lambda表达式概述

lambda表达式可以理解为对匿名内部类的优化,当然这里面的优化是有前提的,即lambda表达式的使用前提

1、有一个接口
2、接口中有且仅有一个抽象方法

lambda思想:
lambda表达式是采用函数式编程思想,而匿名内部类采用面向对象编程思想。在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿数据做操作”
面向对象思想强调“必须通过对象的形式来做事情”
函数式思想则尽量忽略面向对象的复杂语法:“强调做什么,而不是以什么形式去做”,而我们要学习的Lambda表达式就是函数式思想的体现

3.2lambda表达式格式

(形式参数)->{代码块}

  • 形式参数如果只有一个,小括号可以省略
  • 形式参数的数据类型可以省略,如果两个以上的形式参数如果要省略数据类型,必须一起省略,否则只省略一个会编译错误。
  • 代码块只有一行语句,大括号、封号,甚至有return都可以一起省略

组成Lambda表达式的三要素:

  • 形式参数,箭头,代码块

3.3Lambda表达式和匿名内部类的区别

  • 所需类型不同
    • 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
    • Lambda表达式:只能是接口
  • 使用限制不同
    • 如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
    • 如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
  • 实现原理不同
    • 匿名内部类:编译之后,产生一个单独的.class字节码文件在硬盘中
    • Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成,在内存中存储,不会存硬盘中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值