多态深入学习


本文前面是铺垫多态的,如果想学习多态,请直接转到多态。

面向对象深入了解

字节码文件

在这里插入图片描述

class文件其中包括常量池,代码指令。

电脑就把这些输入到jvm里面,高速执行。

常量池分为两种

  • class常量池
    • 存放一些静态信息,比如类名,方法名,属性名,各种字面量(基础类型的值,final值,字符串)等等
  • 运行时常量池
    • 这个比较特殊,只有在内存中加载时才能知道他是什么样子。

进行转换后的常量池

Constant pool:
   #1 = Methodref          #7.#27         // java/lang/Object."<init>":()V
   #2 = Class              #28            // com/ydlclass/Computer
   #3 = Methodref          #2.#27         // com/ydlclass/Computer."<init>":()V
   #4 = Fieldref           #29.#30        // java/lang/System.out:Ljava/io/PrintStream;
   #5 = Methodref          #2.#31         // com/ydlclass/Computer.plus:(II)I
   #6 = Methodref          #32.#33        // java/io/PrintStream.println:(I)V
   #7 = Class              #34            // java/lang/Object
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               LocalVariableTable
  #13 = Utf8               this
  #14 = Utf8               Lcom/ydlclass/Computer;
  #15 = Utf8               plus
  #16 = Utf8               (II)I
  #17 = Utf8               i
  #18 = Utf8               I
  #19 = Utf8               j
  #20 = Utf8               main
  #21 = Utf8               ([Ljava/lang/String;)V
  #22 = Utf8               args
  #23 = Utf8               [Ljava/lang/String;
  #24 = Utf8               computer
  #25 = Utf8               SourceFile
  #26 = Utf8               Computer.java
  #27 = NameAndType        #8:#9          // "<init>":()V
  #28 = Utf8               com/ydlclass/Computer
  #29 = Class              #35            // java/lang/System
  #30 = NameAndType        #36:#37        // out:Ljava/io/PrintStream;
  #31 = NameAndType        #15:#16        // plus:(II)I
  #32 = Class              #38            // java/io/PrintStream
  #33 = NameAndType        #39:#40        // println:(I)V
  #34 = Utf8               java/lang/Object
  #35 = Utf8               java/lang/System
  #36 = Utf8               out
  #37 = Utf8               Ljava/io/PrintStream;
  #38 = Utf8               java/io/PrintStream
  #39 = Utf8               println
  #40 = Utf8               (I)V

对象创建流程

我们使用那么就的java,是否清楚java对象创建的流程呢

其流程大概分为

  • 1,内存分配(属性为默认值)
  • 2,初始化属性值
  • 3,执行构造器(加载所有父类)

在堆中开启对象内存,将对象名具体为地址,然后在虚拟机栈中存放该地址,执行堆对象。

在这里插入图片描述

多态

接下主要以多态为核心进行讲解,因为在java中实在太重要了。

Human man = new Man();

上面这行代码是我们熟悉的多态吧,用的多一看就知道。我们先介绍一下专有名词。

  • 在左边的Human是叫 静态类型,他属于静态的(这个后面具体会讲到)
  • 在右边的Man是叫 动态类型,也叫运行时类型。

和刚开始的一样,也是静态和运行时的区别,运行时是先要加载到内存中才能确定是什么样子。

举个最简单的例子

Animal animal = Math.random() > 0.5 ? new Dog():new Cat();

下面我们来介绍一下其中的体现

重载方法

public class Human {
    public static void main(String[] args) {
        Human human = new Human();
        Human man = new Man();
        Human woman = new Woman();
        human.test(human);
        human.test(man);
        human.test(woman);
    }

    public void test(Human human){
        System.out.println("我是人类");
    }

    public void test(Man man){
        System.out.println("我是男的");
    }

    public void test(Woman woman){
        System.out.println("我是女的");
    }
}
class Man extends Human{

}
class Woman extends Human{

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XSCyHbeq-1671072276839)(C:\Users\86135\AppData\Roaming\Typora\typora-user-images\image-20221215101440268.png)]

从运行结果来看,我们知道都是调用的是第一个方法,也就是Human的方法。这就是静态类型的体现了。

说明在重载方法中类型是取决于静态解析的,在编译java文件为字节码的时候以及确定了类型,根本不是在内存中决定的运行时类型。

再看一个很经典例子

public class Overload {

    public void sayHello(Object arg){
        System.out.println("hello object");
    }

    public void sayHello(int arg){
        System.out.println("hello int");
    }

    public void sayHello(long arg){
        System.out.println("hello long");
    }

    public void sayHello(Character arg){
        System.out.println("hello Character");
    }

    public void sayHello(char arg){
        System.out.println("hello char");
    }

    public void sayHello(char... arg){
        System.out.println("hello char...");
    }


    public static void main(String[] args) {
        new Overload().sayHello('a');
    }

}

    
    hello int
    hello long
    hello Character
    hello object
    hello char...

如果我们一个个把出现的注释掉,最终可以得到的结果是下面的

优先级

char > int > long > Character > Object > char…

其实这个是jvm的工作,在静态解析中,它会为我们进行重载方法的匹配,选择它自己认为最优的版本。

重写方法

这个比重载方法要简单,它也是属于静态解析,是从下到上进行寻找方法匹配。

比如先看看自己有没有这个方法进行匹配,若无再一层层往上找。

类型转换

创建对象,再用对象调用方法,这个是根据静态类型来决定你可以调用什么方法

但是对象的类型仍然是运行时决定。

public class Human {
    public static void main(String[] args) {
        //------测试1
        Human human = new Man();
        human.test();

        //------测试2
        Man man = (Man)human;
        man.man();

        //------测试3
        Woman woman = (Woman)human;
        woman.woman();
    }

    public void test(){
        System.out.println("我是人类");
    }

}
class Man extends Human{
    public void man(){
        System.out.println("我是男的");
    }
}
class Woman extends Human{
    public void woman(){
        System.out.println("我是女的");
    }
}

运行结果

在这里插入图片描述

说说结论:

  • 方法的可调用数是看静态类型,就是看左边有什么方法可以调用
    • 所以,在向上转换类型后,会丢失一些方法的使用。
      (){
      System.out.println(“我是男的”);
      }
      }
      class Woman extends Human{
      public void woman(){
      System.out.println(“我是女的”);
      }
      }

运行结果

![在这里插入图片描述](https://img-blog.csdnimg.cn/e457aaef4e7047afaa977d45787feae7.png#pic_center)




说说结论:

- 方法的可调用数是看静态类型,就是看左边有什么方法可以调用
  - 所以,在向上转换类型后,会丢失一些方法的使用。
- 但是方法的实际调用对象是看运行时类型,就像上面的你运行时类型是man,向上转换后是human,再向下转换为woman,一个男的转为女的显然不可行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值