新手必看!向上转型向下转型 和 匿名内部类

话不多说直接丢结论:

首先两种转型是发生在继承体系中的

向上转型:获取子类的共有方法,多态的一种形式,。

向下转型:父类获取子类特有的方法,或者说用于找回子类的丢失的方法。

匿名内部类:如果该类只用一次,那就舍去类的创建,简化代码的开发。

我们举几个列子来理解这句话:

向上转型:

多态:从一开始的重写,重载,到面向对象后的父类引用指向子类,以及接口指向实现接口类的对象,还有多态的传递,接口可以指向继承实现接口类的对象,那么向上转型就是一种多态的思想。

这里通过接口来介绍一下多态,新建一个购物接口,实现类为学生,并重写了购物的方法。

public interface shopping {
    void buy();
}

public class student implements shopping{
    @Override
    public void buy() {
        System.out.println("学生在购物");
    }
}

在测试类调用学生购物方法并用接口类型引用接收,我们可以打印出它的运行类型

public class Text {
    public static void main(String[] args) {
        shopping shopping = new student();
        shopping.buy();
        System.out.println(shopping);
    }
}

可以看到此时运行类型为com包下的student类,而编译类型是接口shopping类型,这里就是多态的动态绑定至运行类型。 

向上转型的用处:在开发中我们往往不止一个类的几个方法,而是很多类的很多方法在一起,这时我们用接口来管理这些类,每个接口对应很多实现类,并完成对应的功能,这就是面向接口编程

比如如下定义方式,定义了Service包用来实现业务功能,然后有一个接口和实现类去实现这个接口,接口也可以理解成统一规范和方法,有了如下定义方式,我可以通过接口来实现不同的实现类的方法,实现代码解耦。

 

向下转型:

在向上转型的基础上,将子类的引用指向父类对象

在学生类中新加一个学习方法。

public class student implements shopping{
    @Override
    public void buy() {
        System.out.println("学生在购物");
    }
    //子类特有方法
    public void study(){
        System.out.println("我在学习");
    }
}

在测试类中,先将父类引用指向子类,即向上转型,然后在将父类引用强制为子类引用,即向下转型。

  shopping shopping = new student();
  student student = (student) shopping;
  student.study();

这里将引用转为子类,这样就可以调用子类的特有方法了

这里转其实就是欺骗编译器,给父类引用一个子类的外壳,并没有将父类转为子类 ,那么我们为什么要多此一举呢?不会直接用子类引用去调用自己的方法吗,为什么还有先让父类指向子类,在强转父类的引用呢,这里有两点,一是java设计者对多态的补充完善,我们在使用多态时,用父类引用指向子类对象,这时子类对象的特有方法我们获取不到,即发生了丢失,必须要进行强转,二是,java泛型中,我们给集合一个泛型,那么该类及其子类我们都可以存入这个集合里,并调用自己的方法,在泛型编程中底层也也通过向下转型来获取子类特有的方法。

关于向下转型的文章可以看看这位大佬讲的很详细:

https://blog.csdn.net/xyh269/article/details/52231944

然后就是匿名内部类,初学者一开始很不能接受这种格式,不太理解,但其实很多框架底层都用来匿名内部类,其根本就是简化开发提高效率。

定义

//格式:
new 接口/类名(参数1, 参数2...){//直接new我们需要调用的方法的类或者是接口
    @Override
    重写方法1(){
        
    }
    @Override
    重写方法2(){
        
    }
    ......
};

下面还是用接口来演示匿名内部类,新建一个接口,然后正常是通过实现类来调用接口的方法

public interface Inter {
    void show();
}


public class A implements Inter{
    @Override
    public void show() {
        System.out.println("实现了inter接口的show方法");
    }
}


   Inter inter = new A();
   System.out.println(inter); //打印该对象
   inter.show();        

测试打印如下: 此时运行类型为实现类A(记住这句话后面会用)

 假设我们这个类只使用一次,那么我们去新建一个实现类,是不是很繁琐,这里我们使用匿名内部类来代替这个实现类,简化一些代码的书写:

   //匿名内部类,不用创建实现类,而实现接口的方法,简化开发
        Inter inter = new Inter(){
            @Override
            public void show() {
                System.out.println("实现了inter接口的show方法");
            }
        };
        inter.show();

我们重写了接口中的show方法,并成功打印 了同样的语句,这里没有创建类为什么又能完成接口的方法呢,介于上面原生的接口实现类的演示,我们可以联想是不是底层给我们自动实现了一个类来实现这个接口并重写接口的方法,为了验证我们打印inter对象的运行类型,通过动态绑定机制,运行类型应该是实现类而不是接口,最终打印Test$1@14ae5a5为底层分配的一个实现类的地址,其命名规律为外部类名加$1,$2,$3...来表示实现类,可以发现底层确实有一个实现类,这种属于实现接口的匿名内部类,比如在集合中的定值排序就是匿名内部类,关于匿名内部类还有一种是继承类的匿名内部类,底层生成一个类来继承你的类,这里是看你的匿名类型是接口还是类然后底层在选择不同的生成类型。

匿名内部类也可以使用lambda表达式来更近一步代替,但是前提是该匿名内部类只有一个方法

因为lambda是函数式接口,规定只包含一个抽象方法的接口,其形式如下:

  //lambda表达式即函数式接口(前提该接口只有一个方法),java8新特性
        Inter inter = () -> {
            System.out.println("nihao");
        };
        inter.show();

有什么错误请指正,谢谢各位 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值