`
huangfeiNetJava
  • 浏览: 39563 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

用极端例子再探java”继承"

 
阅读更多

    好久好久的,没有发表blog,之前都一直是开快车,脑子里的知识一个劲的刷新,虽然装了很多,但依然感到大脑轻飘飘的。难得有个机会停下了,深刻的理解java基础,尝试着探究最简单的问题的深层机制,发现收获还颇多。不多说,来技术总结了。

     再探继承:

//父类构造器的隐式调用

class grandFather {
	
	public grandFather(){
		
		System.out.println("这是祖父类");
		
	}
	
}

class father extends grandFather {
	
	public father(){
		
		System.out.println("这是父类!");
		
	}
	
}

class child extends father {
	
	public child(){
		
		System.out.println("这是子类");
		
	}
	
	public static void main(String [] args){
		
		new child();
		
	}

}

 

运行结果:

这是祖父类
这是父类!
这是子类

 

说明:

    只要在程序创建java对象,系统总是先调用最顶层父类的初始化操作,包括初始化块和构造器,然后依次向下调用所有父类的初始化操作,最终执行本类的初始化操作返回本类的实例。(至于为什么要保留隐式调用功能,至今我也没弄明白,也许是没用到这个功能,但是“存在的东西总有它的理由”,求高手解答了)

 

再看一例:

package cn.Sep.day24.InheritanceTest;

//内存中子类的实例

class Base{
	
	int count = 2;
	
}

class Mid extends Base{
	
	int count = 20;
	
}

public class subClass extends Mid {

	int count = 200;
	
	public static void main(String[] args) {

		subClass s = new subClass();
		
		Mid s2m = s;
		
		Base s2b = s;
		
		System.out.println(s.count);
		
		System.out.println(s2m.count);
		
		System.out.println(s2b.count);
		
	}
	
}


//这里有个问题,s,s2m,s2b三个变量不是指向同一个变量吗?为什么输出的数值不同呢
//总结:当发生继承时,子类即使定义了与父类里同型同名的变量,但是父类里的该变量不是被覆盖,而是被隐藏了
//当发生转型时,会根据声明的类型调用父类的变量(这个与方法的重写不同)

 

来一极端例:

package cn.Sep.day24.InheritanceTest;

//父类的内存控制

class BaseClass {

	int count = 2;

	public void display() {

		System.out.println(this.count);

	}

}

class DerivedClass extends BaseClass {

	int count = 20;

	@Override
	public void display() {

		System.out.println(this.count);

	}

}

public class FildAndMethodTest {

	public static void main(String[] args) {

		BaseClass b = new BaseClass();

		System.out.println(b.count);

		b.display();

		DerivedClass d = new DerivedClass();

		System.out.println(d.count);

		d.display();

		BaseClass bd = new DerivedClass();

		System.out.println(bd.count);

		bd.display();

		BaseClass d2b = d;

		System.out.println(d2b.count);

	}

}
//输出顺序分别为:2,2,20,20,2,20,2(不信自己可以运行看看)

// 总结:如果在子类重写了父类的方法,就意味着子类里定义的方法彻底覆盖了父类的同名方法,系统将不可能把父类里的
// 方法转移到子类中。对于实例变量则不存在这样的现象,即使子类中定义了与父类完全同名的实例变量,这个实例变量依
// 然不可能覆盖父类中定义的事例变量

 

 

 

 

又来一极端例:

package cn.Sep.day24.InheritanceTest;

class Fruit {

	String color = "蓝色";

	public Fruit getThis() {

		return this;

	}

	public void info() {

		System.out.println("Fruit方法");

	}

}

public class Apple extends Fruit {

	@Override
	public void info() {

		System.out.println("Apple方法");

	}

	public void AccessSuperInfo() {

		super.info();

	}

	public Fruit getSuper() {

		return super.getThis();

	}

	String color = "红色";

	public static void main(String[] args) {

		Apple a = new Apple();

		Fruit f = a.getSuper();

		System.out.println("a和f所引用的对象是否相同" + (a == f));

		System.out.println("访问a所引用的对象的color实例变量" + a.color);

		System.out.println("访问f所引用的对象的color实例变量" + f.color);

		a.info();

		f.info();

		a.AccessSuperInfo();

	}

}
//运行结果:
//a和f所引用的对象是否相同true
//访问a所引用的对象的color实例变量红色
//访问f所引用的对象的color实例变量蓝色
//Apple方法
//Apple方法
//Fruit方法


//解析:从运行结果可以看出,Apple对象的getSuper()方法所返回的实际是该Apple对象本身(此时super.getThis()方法
//中的this指Apple对象),只是他的声明类型是Fruit
//因此通过f变量访问color实例变量时,该实例变量的值由Fruit类决定;但通过f变量调用info()方法时,该方法的行为
//由f变量实际所引用的java对象决定,因此程序输出"Apple方法"。


//总结:至此,对父、子对象在内存中存储有了准确的结论:当程序创建一个子类对象时,系统不仅会为该类中定义的实例变量分配内存
//也会为其父类中定义的所有实例变量分配内存,即使子类定义了与父类中同名实例变量。也就是说,当系统创建一个java对象的
//时候,如果该java类有两个父类(一个直接父类A,一个间接父类B),假设A类中定义了2个实例变量,B类中定义了3个实例变量,
//当前类中定义了2个实例变量,那这个java对象将会保存2+3+2个实例变量

//如果在子类里定义了与父类中已有的同名变量,那么子类中定义的变量会隐藏父类定义的变量。注意不是完全覆盖,因此系统为
//创建子类对象事,依然会为父类中定义的、被隐藏的变量分配内存空间。

 

 

到此,初探“继承”已经结束了,在这之中,收获的不只是技术,更重要的是懂得一种方法,有时候,学一样东西,切不可浮于表面,学习到的知识不可模模糊糊的,只知道怎么用是不够的,当自己知道了其中的实现的机制后,不仅知识更扎实,对于创新是很有用的,而且该知识点也会用得更灵活,不至于到后来出了错依然不知所以然,悲哉!不知所云……

0
0
分享到:
评论
1 楼 feargod 2011-09-27  
嗯,同意。光是会用,是远远不够的,要了解深层的原理。

相关推荐

Global site tag (gtag.js) - Google Analytics