class A
{
String name="张三";
int age=30;
void qq()
{
System.out.println("第一次");
}
public static void main(String args[])
{
A x=new B();
System.out.println(x.name);
x.qq();
}
}
class B extends A
{
int age=20;
void qq()
{
System.out.println("第二次");
}}请问一下,上面申请了一个A类的引用X指向B类的实例,为什么x.name是访问A类的成员变量,而x.qq()是访问B类的成员方法.我是这么认为的,引用X要么都访问A类的成员变量,和成员方法,要么都访问B类的成员变量和成员方法,怎么交叉访问了,请问一下,有什么规律吗?
请大家给我说一下它的运行机制好吗?谢谢.
{
String name="张三";
int age=30;
void qq()
{
System.out.println("第一次");
}
public static void main(String args[])
{
A x=new B();
System.out.println(x.name);
x.qq();
}
}
class B extends A
{
int age=20;
void qq()
{
System.out.println("第二次");
}}请问一下,上面申请了一个A类的引用X指向B类的实例,为什么x.name是访问A类的成员变量,而x.qq()是访问B类的成员方法.我是这么认为的,引用X要么都访问A类的成员变量,和成员方法,要么都访问B类的成员变量和成员方法,怎么交叉访问了,请问一下,有什么规律吗?
请大家给我说一下它的运行机制好吗?谢谢.
解决方案 »
- 这个程序异常,应该是T1/T2分别不同的线程,但是目前都是相同了,为什么?
- bat执行java的问题
- java基础提问
- 如何让JDK1.6支持jax-ws2.2
- 为什么用java读取的证书DN信息乱码?C++,C#都没有问题
- 帮忙看下...
- 求于java的环境变量及包的问题
- 我想請問一下:從來沒有學過java, 我想從java的數據結構開始學習java, 直接學習java的算法, 不直到好不好? :)
- 菜问题AG,3Q了
- JPanel重写的paint覆盖JPanel上控件的问题!求助!!!
- java怎样启动局域网内其它机器上的程序?能实现吗?
- 关于在eclipse中间导入jbuild自带包的问题。
你这叫'方法的覆盖',也就是说b类重写了a类的方法,所以实例化b的时候,a类的qq()已经被覆盖了....
"
但是,不知道,你仔细看了没有,B类中的age同样也覆盖了A类中的age为什么输出的时候,还是访问了A类中的age呢,按照你说的这种原则,应当访问B类中的age才对啊?
不要叫我回去看书了,谢谢你,有些东西书上没有啊.
不好意思,也许我的认为是错误的,不过我一直这么认为的,如果错了,今天请你给你出,小弟不胜感激.]
class A
{
String name="九天玄狐";
public static void main(String args[])
{
B b=new B();
System.out.println(b.name);
}
}
class B extends A
{
String name=" JAVA 民工";//重写父类中的name属性.
}
{
void qq()
{
System.out.println("第一次");
}
public static void main(String args[])
{
A a=new A();
a.qq();//再按照"九天玄狐"的思路来,这个地方应当输出"第二次",实际上输出了"第一次",证明了"九天玄狐"的看法有问题.
}
}
class B extends A
{
void qq()
{
System.out.println("第二次");
}
}
从另一个角度来考虑,虚拟机,父类会开辟一块空间来存放他的实例成员,子类是在父类的基础上,对父类的空间进行了新的扩展,这种扩展并不会消除父类已经实例的成员.
最后一顶了....
您说:"也正是因为多态,B类的qq()方法覆盖了其父类A的qq()方法.所以会打印"b.qq()"内的东东
"
那么:B类的age也同样覆盖了其父类的age属性.为什么不会打印b.age()内的东东.
如果方便还是想请你介绍一点有关内存结构方面的东东,我很想知道.期待你的回答.
以前是我理解错了应当是:父类的属性相对于子类来说只是隐藏了.(您的回答是正确的)
方法是覆盖对吗?如果这样的话,为什么子类覆盖了父类中的方法,此时还能再一次的调用父类中的方法呢?如下:不好意思,你千万不要生气,也许是我太笨的原因吧<
class A
{
void qq()
{
System.out.println("a");
}
public static void main(String[]args)
{
B b=new B();
b.qq();
}
}
class B extends A
{
void qq()
{
super.qq();
}
}
子类的对象在调用方法和成员变量时,先要从子类本身找起,如果自己类中有这个方法则使用子类自己的方法,如果没有才会找到父类的方法.这就是方法的重写.继承中很重要的特征.
A类为B类的父类:
A a=new b();
a.属性:(访问谁的属性,为什么)
a.方法:(访问谁的方法.为什么)
{
String name="张三";
int age=30;
void qq()
{
System.out.println("第一次");
}
public static void main(String args[])
{
A x=new B(); //这里改成B x=new B();是一样的,创建对象是A,但是开内存的时候只开了B所需要的
System.out.println(x.name); //这里显然是张三
x.qq(); //因为内存中只有B的空间,所以访问的是B的方法
}
}
class B extends A
{
int age=20;
void qq()
{
System.out.println("第二次");
}把主方法放到B里面看着就顺些,理论上是一样的,结果也一样,如下:
class A
{
String name="张三";
int age=30;
void qq()
{
System.out.println("第一次");
}
}
class B extends A
{
int age=20;
void qq()
{
System.out.println("第二次");
}
public static void main(String args[])
{
A x=new B();
System.out.println(x.name);
x.qq();
}
}
A x = new B();这个时候方法就看B的,成员变量就看A的
看一下这个,应该就容易理解了。
public String f(D obj){return ("A and D");}
public String f(A obj){return ("A and A");}
}
class B extends A{
public String f(B obj){return ("B and B");}
public String f(A obj){return ("B and A");}
}
class C extends B{}
class D extends B{}class TestComplexPoly{
public static void main(String[] args){
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
//System.out.println(a1.f(b)); // A and A
//System.out.println(a1.f(c)); //A and A
//System.out.println(a1.f(d)); //A and D
--------------------------------------------------------------
System.out.println(a2.f(b)); //B and A
System.out.println(a2.f(c)); //B and A
问题就是这两个为什么会是B and A 呢
-------------------------------------------------------------- //System.out.println(a2.f(d)); //A and D
//System.out.println(b.f(b)); //B and B
//System.out.println(b.f(c)); //B and B
//System.out.println(b.f(d)); //A and D
}
}你研究一下这段代码.
不明白的请看:
http://bbs.chinaunix.net/viewthread.php?tid=965826&extra=page%3D1
正好看见这了,顶下
每个对象都在内存中有自己的区域。
当一个子类对象实例化之后,那么也就意味着其父类的所有属性也被实例化了。
方法在内存的一片区域,属性值存在于另一片区域,当执行方法调用时,CPU根据方法入口地址找到方法的位置,并执行方法。父类的方法在一片区域,子类的方法在另一片区域,如果调用一个子类对象的方法,CPU会去寻找这个方法的入口,它首先在子类对象的区域内找,如果找到了就执行,没有找到就去父类的方法区域找,然后是祖父,曾祖父直到找到为止,如果你深入了解了这个机制,那么所谓的方法重写的低层实现也就是这么简单而已。这么看来所谓的重写的方法其实在内存中的表现仍旧不是同一方法。(即,即使子类与父类有相同的方法签名,但它们是两个不同的方法)那么如果父类与子类的有同名的属性怎么办?其实看上去属性好像是相同的,但实际上这也是两个不同的属性,分别存在于不同的内存区域(当然,肯定都在一个对象的内存区域内)。请看这段代码:
public class A { String name = "zhangShan";
protected int age = 20; public static void main(String[]args)
{
B b=new B();
System.out.println(b.getAge());
System.out.println((new B()).getParentAge());
b.printlnParentAge();
A a = new B();
System.out.println(a.age);
} public int getAge() {
return this.age;
}
}class B extends A {
int age = 10; public void printlnParentAge() {
System.out.println(super.age);
} public int getParentAge() {
return super.age;
}
}你猜猜它会出什么样的结果呢?
20
20
20
20
都是父类的age属性值。super.age指示是父类的那个属性age, 那个从父类继承来的方法,getAge()得到的仍旧是父类的age属性。属性的操作和方法的操作不太一样,它不会像方法操作那样根据类的层次的结构寻找最适当的方法入口。你可这样认为,它使用一种“直接”的策略寻找一个属性地址。因为JVM没有在B中找到getAge方法,就到父类A中寻找,它直接地操作了A的age属性.
我们把程序改一下。就是在类B中加重写A的getAge方法。
class B extends A {
int age = 10; public void printlnParentAge() {
System.out.println(super.age);
} public int getParentAge() {
return super.age;
}
public int getAge() {
return age;
}
这时你使用
B b = new B()
print b.getAge
得到的结果就是10了
在程序执行的时候,JVM首先找到了B中的getAge方法,运行之,返回B的age值。再看一个:
A a = new B();
print a.age
输出的是20,它不管具体a对象到底是个什么玩意儿,反正JVM发现了a.age的属性。
如果要输出“真正的”age属性怎么办?强制转换:
A a = new B();
print ((B)a).age
这下就是10了,你使用强制转换告诉JVM你要的是子类的age属性。我大学学的一些东西有点忘了,以上是根据我还记得的一些知识推测的,属于个人观点。PS:同志们,不要以为学软件工程会个编程就也不起了,许多东西要理解起来,你没有微型计算机原理就是不行,你操作系统学得不好,学多线程就困难,你写测试类,不会测试原理你写的测试类就是垃圾... ...
还有我们微型计算机的老师说的一句话很有道理:自学能力强的人就是那种能把事情说圆的人。
有什么问题不懂,查些资料,资料看得差不多的时候,推敲一下,发现你把那不懂的东西说圆了,你就“懂”了。再写点BLOG去“找骂”,一定能真懂。
看我上面发的那个链接就行了,我把帖子发到别的论坛了。这里不能发图。
我把图片放在:http://images13.51.com/26/a/9e/a9/renqiang_888/724_1024_356569950b779c52.jpg请点击放大镜查看.
同时更希望有经验和了解对象模型的朋友能指点迷津.谢谢
unbelieveable.
String name="张三"; 已经给对象赋值了
就是说如果你new A(),而在A的构造函数里没有对name另外赋值,那name就会用默认的张三
2.B是继承自A,如果B没有重新定义name,就会使用A中的name