您的位置:首页 > 编程语言 > Java开发

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

2015-01-23 18:24 393 查看
1 概念: 把引用变量转化为子类类型,则成为向下转型。如果把引用变量转化为父类类型,则成为向上转型。

Java代码


public class Base {

/**

* 父类实例变量

*/

String var = "baseVar";

/**

* 父类的静态变量

*/

static String staticVar = "staticBaseVar";



/**

* 父类实例方法

*/

void method() {

System.out.println("Base method");

}



/**

* 父类静态方法

*/

static void staticMethod() {

System.out.println("Base static Method");

}

}



public class Sub extends Base {

/**

* 子类的实例变量

*/

String var = "subVar";

/**

* 子类的静态变量

*/

static String staticVar = "staticSubVar";



// 覆盖父类的method()方法

void method() {

System.out.println("Sub static Method");

}



String subVar = "var only belonging to Sub";



void subMethod() {

System.out.println("Method only belonging to Sub");

}



public static void main(String args[]) {

// who 被声明为Base类型,引用Sub实例

Base who = new Sub();

System.out.println("who.var=" + who.var);// print:who.var=baseVar

System.out.println("who.staticVar=" + who.staticVar);// print:who.staticVar=staticBaseVar

who.method();// print:Sub static Metho

// 这里为什么不打印Base method呢 这是java动态机制的表现,

// 虽然who的类型是Base 但是 实际引用的是Sub类 new Sub()会在堆区分配内存空间

// 当who.method()方法时,jvm会根据who持有的引用定位到堆区的Sub实例

// 再根据Sub持有的引用 定位到方法区Sub类的类型信息 获得method的字节

// 在当前环境下(上面代码所示)获得method的字节码,此时Sub类复写了Base的method的方法,

// 获得method的字节码,直接执行method包含的指令,

// 如果没有复写method方法 则去获得Base类的字节码 执行包含的指令(这个机制实现有待去研究有关资料)

who.staticMethod();// print:Base static Method



// who.subVar="123";//编译错误

// who.subMethod();//编译错误

// 对于一个引用变量,java编译器按照它什么的类型来处理,这里who 的类型是Base类型的引用变量.不存在subVar

// 和subMethod方法

// 如果要访问Sub类成员,可以进行强制类型转换(向下转型)

Sub sub = (Sub) who;

sub.subVar = "23";

sub.subMethod();



Base base2 = new Base();

Sub sub2 = (Sub) base2;

sub2.subMethod();

// 编译通过 但是抛出ClassCastException

// sub2实际引用的是Base实例

// 对应一个引用类型的变量,运行时jvm按照它实际引用的对象来处理,假设上面能够通过,但是

// 当我们sub2引用变量调用subMethod()方法时,我们看到在Base类中并没有subMethod方法。

// 由此可见 ,子类对象可以向上转型为父类对象,但是父类对象不能转换为子类对象,父类拥有的成员子类

// 子类肯定也有,而子类拥有的成员父类不一定有。上面就是一个例子。



// 在运行时环境中,通过引用类型变量来访问所引用的方法和属性时,java虚拟机采用如下绑定机制。

// 1 实例方法与引用变量 实际引用的对象 的方法绑定 属于动态绑定.由运行时jvm动态决定的。

// 2 静态方法与引用变了所声明的对象 的方法绑定 属于静态绑定 在编译阶段就已经做了绑定

// 3 成员变量 (静态和实例)与引用变量所声明的类型的成员变量绑定属于静态绑定。

}

}





Java代码


abstract class A {

abstract void method();



void test() {

method();// 这里调用哪个类的method方法呢

}

}



public class B extends A {

@Override

void method() {

System.out.println("B method");

}



public static void main(String[] args) {

new B().test(); // print:B method

// 方法test()在父类A中定义,它调用了方法method

// 但是method在A中是抽象的 但是仍然可以调用

// 因为在运行时环境中jvm会执行B的实例的method方法

// 一个实例所属的类肯定是实现了父类中所有的抽象方法

}

}





Java代码


class A {

void method() {

System.out.println("A method");

};



void test() {

method();// 这里调用哪个类的method方法呢

}

}



public class B extends A {



@Override

void method() {

System.out.println("B method");

}



public static void main(String[] args) {

//new B().test(); // print:B method

// 方法test()在父类A中定义,它调用了方法method

// 但是method在A中是抽象的 但是仍然可以调用

// 因为在运行时环境中jvm会执行B的实例的method方法

// 一个实例所属的类肯定是实现了父类中所有的抽象方法



new A().test();

new B().test();

//test()方法在A类中定义,它调用了method()方法,和上面的例子的区别是父类A的method方法



//不是抽象的,但是通过new B().test()执行的仍然是子类B的method方法,由此可见

//在运行时环境中,当通过B类的实例去调用一系列的实例方法(包括一个方法调用另外一个方法)

//将优先和B类本身包含的实例方法动态绑定,如果没有这个实例方法,才会从父类A中继承来的

//实例方法动态绑定。

}

}

———————————————————————————————————————————————————————————————————————————————————————
实验测试:
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的多态性
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: