java继承向上转型和向下转型和动态绑定

本文详细解析了Java中向上转型和向下转型的概念,并通过具体示例展示了如何使用这两种转型方式,同时深入探讨了Java多态性的实现机制。

1 概念: 把引用变量转化为子类类型,则成为向下转型。如果把引用变量转化为父类类型,则成为向上转型。 

Java代码  收藏代码
  1. public class Base {  
  2.     /** 
  3.      * 父类实例变量 
  4.      */  
  5.     String var = "baseVar";  
  6.     /** 
  7.      * 父类的静态变量 
  8.      */  
  9.     static String staticVar = "staticBaseVar";  
  10.   
  11.     /** 
  12.      * 父类实例方法 
  13.      */  
  14.     void method() {  
  15.         System.out.println("Base method");  
  16.     }  
  17.   
  18.     /** 
  19.      * 父类静态方法 
  20.      */  
  21.     static void staticMethod() {  
  22.         System.out.println("Base static Method");  
  23.     }  
  24. }  
  25.   
  26. public class Sub extends Base {  
  27.     /** 
  28.      * 子类的实例变量 
  29.      */  
  30.     String var = "subVar";  
  31.     /** 
  32.      * 子类的静态变量 
  33.      */  
  34.     static String staticVar = "staticSubVar";  
  35.   
  36.     // 覆盖父类的method()方法  
  37.     void method() {  
  38.         System.out.println("Sub static Method");  
  39.     }  
  40.   
  41.     String subVar = "var only belonging to Sub";  
  42.   
  43.     void subMethod() {  
  44.         System.out.println("Method only belonging to Sub");  
  45.     }  
  46.   
  47.     public static void main(String args[]) {  
  48.         // who 被声明为Base类型,引用Sub实例  
  49.         Base who = new Sub();  
  50.         System.out.println("who.var=" + who.var);// print:who.var=baseVar  
  51.         System.out.println("who.staticVar=" + who.staticVar);// print:who.staticVar=staticBaseVar  
  52.         who.method();// print:Sub static Metho  
  53.         // 这里为什么不打印Base method呢 这是java动态机制的表现,  
  54.         // 虽然who的类型是Base 但是 实际引用的是Sub类 new Sub()会在堆区分配内存空间  
  55.         // 当who.method()方法时,jvm会根据who持有的引用定位到堆区的Sub实例  
  56.         // 再根据Sub持有的引用 定位到方法区Sub类的类型信息 获得method的字节  
  57.         // 在当前环境下(上面代码所示)获得method的字节码,此时Sub类复写了Base的method的方法,  
  58.         // 获得method的字节码,直接执行method包含的指令,  
  59.         // 如果没有复写method方法 则去获得Base类的字节码 执行包含的指令(这个机制实现有待去研究有关资料)  
  60.         who.staticMethod();// print:Base static Method  
  61.   
  62.         // who.subVar="123";//编译错误  
  63.         // who.subMethod();//编译错误  
  64.         // 对于一个引用变量,java编译器按照它什么的类型来处理,这里who 的类型是Base类型的引用变量.不存在subVar  
  65.         // 和subMethod方法  
  66.         // 如果要访问Sub类成员,可以进行强制类型转换(向下转型)  
  67.         Sub sub = (Sub) who;  
  68.         sub.subVar = "23";  
  69.         sub.subMethod();  
  70.   
  71.         Base base2 = new Base();  
  72.         Sub sub2 = (Sub) base2;  
  73.         sub2.subMethod();  
  74.         // 编译通过 但是抛出ClassCastException  
  75.         // sub2实际引用的是Base实例  
  76.         // 对应一个引用类型的变量,运行时jvm按照它实际引用的对象来处理,假设上面能够通过,但是  
  77.         // 当我们sub2引用变量调用subMethod()方法时,我们看到在Base类中并没有subMethod方法。  
  78.         // 由此可见 ,子类对象可以向上转型为父类对象,但是父类对象不能转换为子类对象,父类拥有的成员子类  
  79.         // 子类肯定也有,而子类拥有的成员父类不一定有。上面就是一个例子。  
  80.   
  81.         // 在运行时环境中,通过引用类型变量来访问所引用的方法和属性时,java虚拟机采用如下绑定机制。  
  82.         // 1 实例方法与引用变量 实际引用的对象 的方法绑定 属于动态绑定.由运行时jvm动态决定的。  
  83.         // 2 静态方法与引用变了所声明的对象 的方法绑定 属于静态绑定 在编译阶段就已经做了绑定  
  84.         // 3 成员变量 (静态和实例)与引用变量所声明的类型的成员变量绑定属于静态绑定。  
  85.     }  
  86. }  

 

 

Java代码  收藏代码
  1. abstract class A {  
  2.     abstract void method();  
  3.   
  4.     void test() {  
  5.         method();// 这里调用哪个类的method方法呢  
  6.     }  
  7. }  
  8.   
  9. public class B extends A {  
  10.     @Override  
  11.     void method() {  
  12.         System.out.println("B method");  
  13.     }  
  14.   
  15.     public static void main(String[] args) {  
  16.         new B().test(); // print:B method  
  17.         // 方法test()在父类A中定义,它调用了方法method  
  18.         // 但是method在A中是抽象的 但是仍然可以调用  
  19.         // 因为在运行时环境中jvm会执行B的实例的method方法  
  20.         // 一个实例所属的类肯定是实现了父类中所有的抽象方法  
  21.     }  
  22. }  

 

 

Java代码  收藏代码
  1. class A {  
  2.     void method() {  
  3.         System.out.println("A method");  
  4.     };  
  5.   
  6.     void test() {  
  7.         method();// 这里调用哪个类的method方法呢  
  8.     }  
  9. }  
  10.   
  11. public class B extends A {  
  12.   
  13.     @Override  
  14.     void method() {  
  15.         System.out.println("B method");  
  16.     }  
  17.   
  18.     public static void main(String[] args) {  
  19.         //new B().test(); // print:B method  
  20.         // 方法test()在父类A中定义,它调用了方法method  
  21.         // 但是method在A中是抽象的 但是仍然可以调用  
  22.         // 因为在运行时环境中jvm会执行B的实例的method方法  
  23.         // 一个实例所属的类肯定是实现了父类中所有的抽象方法  
  24.       
  25.         new A().test();  
  26.         new B().test();  
  27.         //test()方法在A类中定义,它调用了method()方法,和上面的例子的区别是父类A的method方法  
  28.           
  29.         //不是抽象的,但是通过new B().test()执行的仍然是子类B的method方法,由此可见  
  30.         //在运行时环境中,当通过B类的实例去调用一系列的实例方法(包括一个方法调用另外一个方法)  
  31.         //将优先和B类本身包含的实例方法动态绑定,如果没有这个实例方法,才会从父类A中继承来的  
  32.         //实例方法动态绑定。   
  33.     }  
  34. }  


———————————————————————————————————————————————————————————————————————————————————————
实验测试:
import java.util.ArrayList;
import java.util.List;




public class BreakTest {
	
	public static void main(String arg[]){


		List<String> list = new ArrayList<String>();
		 list.add("a");
		 //编译时类型是List,运行时类型是ArrayList,而List接口的实现类不只有ArrayList一个,用一个List类型的引用这是“面向接口编程”,好处有很多
		 //,提但是尽量面向接口编程,这里只说一个这样写的好处:
		 //强转 类型后, list才能调用 ArrayList()实现类的方法
		 ((ArrayList<String>) list).ensureCapacity(16);
		 System.out.println("list size :" + list.size());
		 
		 //Child类向上转型,编译时是Father类,可运行时是Child类,调用的方法自然是对子类进行调用。好处,实现面向对象的多态性
		 Father people = new Child();
		 people.eat();
		 
		 Son son =new Son();
		 
	}
	
	//内部内声明成static
	//因为Father是一个动态的内部类,创建这样的对象必须有实例与之对应,程序是在静态方法中直接调用动态内部类会报这样错误
	//。  如果类是单独放在另一文件里,不会报错 
	//这样的错误好比类中的静态方法不能直接调用动态方法。可以把该内部类声明为static。或者不要在静态方法中调用。
	 static class Father{
		public  void eat(){
			System.out.println("father eat!");
		}
	}
	
	static class Child extends Father{
		public  void eat(){
			System.out.println("chlid eat!");
		}
	}
}

输出结果:





总结:
1 概念: 把引用变量转化为子类类型,则成为向下转型。如果把引用变量转化为父类类型,则成为向上转型。 
2.java继承向上转型和向下转型和动态绑定 显示的是一个目的:就是java的多态性























<think>嗯,用户问的是Java中的多态,特别是向上转型向下转型的概念用法,需要示例解释。首先,我需要回忆一下多态的基本概念,然后重点放在转型上。根据提供的引用资料,多态是Java的三大特性之一,继承接口实现是前提。向上转型是父类引用指向子类对象,而向下转型则是反过来,但需要强制转换instanceof检查。 用户可能需要知道为什么需要这两种转型,以及它们的具体应用场景。比如向上转型如何实现多态,让代码更灵活,而向下转型则在需要调用子类特有方法时使用。要注意的是,向上转型后不能访问子类特有的属性方法,但重写的方法会动态绑定。 接下来,需要结合引用中的例子,比如PetDog的关系,或者AnimalDog的例子。要确保示例清晰,展示向上转型的语法,以及向下转型时的强制转换instanceof的使用。同时,需要解释动态绑定的概念,即方法调用在运行时确定,这是多态的关键。 可能还需要提到向下转型的风险,比如如果不做instanceof检查直接转换可能会导致ClassCastException,所以安全性很重要。此外,应用场景方面,向上转型常用于方法参数返回类型,提高通用性;向下转型则用于需要子类特定功能的情况。 要确保回答结构清晰,先介绍概念,再分点讲解向上向下转型,给出代码示例,最后总结注意事项应用场景。同时,根据用户的要求,生成相关问题,可能涉及动态绑定、instanceof的作用、转型异常处理等。</think>### 多态中向上转型向下转型详解 #### 一、核心概念 多态是面向对象编程中通过**父类引用操作子类对象**的特性,分为向上转型(Upcasting)向下转型(Downcasting)两种形式: - **向上转型**:父类类型变量引用子类对象(自动完成) $$ \text{父类类型 变量名 = new 子类类型();} $$ - **向下转型**:将父类引用强制转换回子类类型(需显式声明) $$ \text{子类类型 变量名 = (子类类型)父类引用;} $$ --- #### 二、向上转型示例与特性 **代码示例**: ```java class Animal { void eat() { System.out.println("动物进食"); } } class Cat extends Animal { @Override void eat() { System.out.println("猫吃鱼"); } void jump() { System.out.println("猫跳跃"); } } public class Test { public static void main(String[] args) { Animal animal = new Cat(); // 向上转型 animal.eat(); // 输出"猫吃鱼"(动态绑定) // animal.jump(); // 编译报错,无法访问子类特有方法[^3] } } ``` **特性说明**: 1. **自动完成**:无需强制类型转换 2. **动态绑定**:调用重写方法时根据实际对象类型执行(如`eat()`方法)[^5] 3. **限制访问**:无法直接调用子类特有方法(如`jump()`)[^4] --- #### 三、向下转型示例与规则 **代码示例**: ```java Animal animal = new Cat(); if (animal instanceof Cat) { // 安全检查 Cat cat = (Cat) animal; // 向下转型 cat.jump(); // 成功调用特有方法 } ``` **强制规则**: 1. **必须显式转换**:使用`(子类类型)`语法 2. **类型检查必要**:需通过`instanceof`验证对象实际类型[^3] 3. **转换异常风险**:若未检查直接转换可能抛出`ClassCastException` --- #### 四、应用场景对比 | 转型类型 | 典型场景 | 优点 | 风险 | |---------|----------|------|------| | 向上转型 | 1. 方法参数统一化<br>2. 集合存储异构对象 | 提高代码扩展性[^2] | 丢失子类特性 | | 向下转型 | 调用子类特有方法/属性 | 恢复对象完整能力 | 类型转换异常[^4] | --- #### 五、注意事项 1. **向下转型前置条件**:对象必须原本就是目标子类实例(如`new Cat()`转`Cat`有效,但`new Animal()`转`Cat`无效)[^3] 2. **设计建议**:优先通过方法重写实现功能,减少向下转型使用 3. **性能影响**:`instanceof`检查会带来轻微性能开销
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值