向上与向下转型

 向下转型

  在向下转型过程中,分为两种情况:

  1. 如果父类引用的对象如果引用的是指向的子类对象,那么在向下转型的过程中是安全的。也就是编译是不会出错误的。
  2. 如果父类引用的对象是父类本身,那么在向下转型的过程中是不安全的,编译不会出错,但是运行时会出现java.lang.ClassCastException错误。它可以instanceof来避免出错此类错误。
 1 Father fh=new Father();
 2 if(fh instanceof Son)
 3 {
 4     Son son =(Son)fh;
 5 }

 向上转型

  1. 向上转型时,父类指向子类引用对象会遗失子类独有的新函数,在编译时,系统会提供找不到方法的错误。
  2. 向上转型是安全的。
 1 Father fh=new Son();

  

  当需要调用父类的函数时,编译器如何知道这个父类的引用指向的是哪一个子类的对象呢?这就涉及到动态绑定了

  

  以下引用《JAVA动态绑定的内部实现机制》,作者 飞天金刚 。

  附上链接 http://blog.csdn.net/sureyonder/article/details/5569617

  JAVA虚拟机调用一个类方法时,它会基于对象引用的类型(通常在编译时可知)来选择所调用的方法。相反,当虚拟机调用一个实例方法时,它会基于对象实际的类型(只能在运行时得知)来选择所调用的方法,这就是动态绑定,是多态的一种。动态绑定为解决实际的业务问题提供了很大的灵活性,是一种非常优美的机制。

  • Java对象模型

   JAVA虚拟机规范并没有规定JAVA对象在堆里是如何表示的。对象的内部表示也影响着整个堆以及垃圾收集器的设计,它由虚拟机的实现者决定。

   JAVA对象中包含的基本数据由它所属的类及其所有超类声明的实例变量组成。只要有一个对象引用,虚拟机就必须能够快速地定位对象实例的数据。另外,它也必须能通过该对象引用访问相应的类数据(存储于方法区的类型信息),因此在对象中通常会有一个指向方法区的指针。当程序在运行时需要转换某个对象引用为另外一种类型时,虚拟机必须要检查这种转换是否被允许,被转换的对象是否的确是被引用的对象或者它的超类型。当程序在执行instanceof操作时,虚拟机也进行了同样的检查。所以虚拟机都需要查看被引用的对象的类数据。

   不管虚拟机的实现使用什么样的对象表示法,很可能每个对象都有一个方法表因为方法表加快了调用实例方法时的效率。但是JAVA虚拟机规范并未要求必须使用方法表,所以并不是所有实现中都会使用它。

   下面是一种JAVA对象的内存表示:

   

   方法数据存放在类的方法区中,包含一个方法的具体实现的字节码二进制。方法指针直接指向这个方法在内存中的起始位置,通过方法指针就可以找到这个方法。

  • 动态绑定内部机制

   方法表是一个指向方法区中的方法指针的数组。方法表中不包含static、private等静态绑定的方法,仅仅包含那些需要动态绑定的实例方法。

   在方法表中,来自超类的方法出现在来自子类的方法之前,并且排列方法指针的顺序和方法在class文件中出现的顺序相同,这种排列顺序的例外情况是,被子类的方法覆盖的方法出现在超类中该方法第一次出现的地方。

   例如有超类Base和子类Derive:

  

  

 1 public class Base
 2 {
 3   public Base(){}
 4
 5   public void test()
 6   {
 7     System.out.println( "int Base" );
 8   }
 9
10   public void print(){}
11 }
12
13 public class Derive extends Base
14 {
15   public Derive(){}
16
17   public void test()
18   {
19     System.out.println( "int Derive" );
20   }
21
22   public void sayHello(){}
23
24   public static void main( String[] args )
25   {
26       Base base = new Derive();
27       base.test();
28   }
29 }

  

   上例中的Base和Derive的方法表如下:

  

   在这个例子里,test()方法在Base和Derive的方法表中都是同一个位置:索引为1。

   当JAVA虚拟机执行base.test()时,通过base引用可以找到base所指向的实际对象的内存位置,现在虚拟机不知道base引用的实际对象是Base还是Derive。但是根据上面的对象内存模型,虚拟机从对象内存中的第一个指针“特殊结构指针”开始,可以找到实际对象的类型数据和Class实例,这样虚拟机就可以知道base引用的实际对象是Derive对。为了执行test(),虚拟机需要找到test()的字节码,方法的字节码存放在方法区中。虚拟机从对象内存中的第一个指针“特殊结构指针”开始,搜寻方法表的索引1,索引1指向的test()方法是Derive类的test()方法,这就是JAVA虚拟机将要执行的test()的字节码。现在,虚拟机知道了调用的实际对象是Derive对象,调用的实际test()方法是Derive类的test()方法,所以JAVA虚拟机能够正确执行-调用base引用的实际对象的方法而不是base引用本身的方法。

   这是动态绑定的一种实现方式,根据不同的JAVA虚拟机平台和不同的实际约束,动态绑定可以有不同的内部实现机制。

时间: 2024-10-16 22:43:53

向上与向下转型的相关文章

“全栈2019”Java第九十章:内部类可以向上或向下转型吗?

难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第九十章:内部类可以向上或向下转型吗? 下一章 "全栈2019"Java第九十一章:内部类具有多态特性吗? 学习小组 加入同步学习小组,共同交流与进步. 方式一:关注头条号Gorhaf,私信"Java学习小组". 方式二:关注公众号Gorhaf,回复"Java学

对象向上、向下转型

向上转型(Son-->Father),程序会自动完成 父类 父类对象 = 子类实例 向下转型(Father-->Son),强制类型转换 子类 子类对象 = (子类)父类实例 class Father { public void tell() { System.out.println("Father tell"); } } class Son extends Father { public void tell() { System.out.println("Son

11 向上与向下转型

什么是向上转型:将子类的对象赋值给父类的引用 Student s=new Student(); Person p=s; 什么是向下转型:将父类的对象赋值给子类的引用 Student s1=new Student(); Person p=s1; Student s2=(Student)p;

java 向上,向下转型

在对Java学习的过程中,对于转型这种操作比较迷茫,特总结出了此文.例子参考了<Java编程思想>. 目录 几个同义词 向上转型与向下转型 例一:向上转型,调用指定的父类方法 例二:向上转型,动态绑定 例三:向上转型,静态绑定 例四:向下转型 转型的误区 1.运行信息(RTTI) 2.数组类型 3.Java容器 几个同义词 首先是几组同义词.它们出现在不同的书籍上,这是造成理解混淆的原因之一. 父类/超类/基类 子类/导出类/继承类/派生类 静态绑定/前期绑定 动态绑定/后期绑定/运行时绑定

多态 向上,向下转型

注意:自始自终都是子类对象在做着类型的变化向上转型:作用:限制对子类特有方法的访问父类引用   指向 子类对象   //向上转型 ,但是不能访问子类特有的方法       Animal    父类                 cat()子类继承与Animal  Animal  a  =  new  cat();----------------------------------------------向下转型:作用:为了访问子类中的特有方法子类引用   指向 父类(引用)  对象cat s 

equals跟向上,向下转型

package day14; public class instanceof1 { public static void main(String[] args) { teacher1 t1=new teacher1(); teacher1 t2=new teacher1(); t1.setAge("李四"); t2.setAge("李四"); System.out.println(t1.equals(t2)); } } class teacher1{ private

Java向上转型和向下转型(附具体样例)

                                            Java向上转型和向下转型(附具体样例) 熬夜整理的关于Java向上和向下转型的样例,很的通俗易懂哦~~~~ 一.向上转型 package com.sheepmu; class Animal { public void eat() { System.out.println("父类的 eating..."); } } class Bird extends Animal { @Override publ

Java向上转型和向下转型(附详细例子)

                                            Java向上转型和向下转型(附详细例子) 熬夜整理的关于Java向上和向下转型的例子,非常的通俗易懂哦~~~~ 一.向上转型 package com.sheepmu; class Animal { public void eat() { System.out.println("父类的 eating..."); } } class Bird extends Animal { @Override pub

向上转型和向下转型

对象的多态性: 向上转型:子类对象变为父类对象 向下转型:父类对象变为子类对象 class A{ public void print(){ System.out.println("A"); } } class B extends A{ public void print(){ System.out.println("B"); } } class C extends A{ public void print(){ System.out.println("C&