public class TestAnimals {
public static void main (String [] args) {
Horse b = new Horse();
System.out.println(b.getI());
}
}class Animal {
private int i=1;
public int getI(){
return i;
}
public void setI(int i){
this.i=i;
}
}class Horse extends Animal {
int i=2;
}
--------------------------------------
执行TestAnimals 时,问什么结果是1 而不是2呢,
public static void main (String [] args) {
Horse b = new Horse();
System.out.println(b.getI());
}
}class Animal {
private int i=1;
public int getI(){
return i;
}
public void setI(int i){
this.i=i;
}
}class Horse extends Animal {
int i=2;
}
--------------------------------------
执行TestAnimals 时,问什么结果是1 而不是2呢,
解决方案 »
- NetBeansIDE自己下载subversion问题
- 请问这个程序怎么修改才能运行
- 编译找不到javas.faces.tree.Tree
- 在哪一层处理异常最好呢?
- java 关闭当前窗体后刷新父窗体
- 大家知不知道这个ip(65.214.45.41)是谁的阿?
- O'REILLY关于JAVA四个包的书名字是什么
- 讨论一下关于用JAVA作动画的问题?
- System.exit(0);中的0表示什么意思?还有别的什么值可以放在0的那个位置?
- 我是菜鸟,想要个oracle数据库操作 的例子
- 100分求!如何同时删除JTable和数据库中的一行数据?
- 请问String aa;与String aa=null;两个语句有什么差别?
----------------------
请大家解释!
你先别做JAVA开发了,先来和我一起学基础如何,呵呵:)
我个人理解为:horse继承了animal,但 int i= 2是不同于父类中的i,也就是说,虽然和父类中成员变量i的名称一样,但子类中不是真正对父类中的i赋值。
那么:b.getI()更因该返回2,谁能把内存中的分配情况说一下另外:把Animal 类的成员变量i 改为public,就可以输出2, 这句话是对的,
这是给继承的经典问题 也是最容易出错的地方
----------------------
在子类中追加方法
public int getI(){
return i;
}
才可以返回2
两个i各自在栈中分配,和public没什么关系
return i; //返回的i始终是Animal类中的属性i的值
}楼主可以单步调试一下。
1.子类可以继承父类的任何变量和方法,这肯定是。private、protected只是访问权限而已。
2.java中的对象化过程应该是这样的:首先,jvm中应首先载入class对象【这儿不是实例化对象】,它作为生成实例对象的模板;这个模板中有变量、方法;其中方法、静态变量只有一份,也就是说,从此模板生成的对象中,不会再含有方法、与静态变量;生成的任何对象共享class对象的静态变量和方法。 根据你的例子来说,父类class对象中有i变量、set get两个方法。子类class中应有i【继承于父class对象】、i【子class对象】两个变量、set get两个方法【继承于父class对象】。 对于实例变量来说,每生成一个对象,都会在内存中产生新的存储空间,用于存放实例变量的值;对于上例来说,就是每次生成对象时,都会为两个i分配空间。上面我们说方法只有class对象中的一份,那么在对特定对象调用方法时,方法就会使用本对象的相关实例变量。那么方法如何和相关变量相关?它只能在类的定义中建立联系。对上例来说,set get方法只能和父类中的i相关,这在类定义时,就规定好了。在上例中,如果在父类中定义一个public 或protected的i,不定义其set get方法,而在子类中定义其set get方法,那么方法和i变量的联系也可以建立,也就是子类的set get方法和父类的i在类的定义和继承中建立了联系,这个大家应该很容易想的到了。
3.因此得出结论,上例中get应该得到1;而不管子类的i为private还是public。因为set和get方法是与父类的i建立了联系的。
public class TestAnimal {
public static void main (String [] args) {
Horse b = new Horse();
System.out.println(b.getI());
b.setI(4);
System.out.println(b.getI());
}
}class Animal {
private int i=1;
public int getI(){
return get_i();
}
public void setI(int i){
set_i(i);
}
protected int get_i(){
return i;
}
protected void set_i(int i)
{
this.i = i;
}
}class Horse extends Animal {
int i=3;
protected int get_i(){
return i;
}
protected void set_i(int v)
{
i = v;
}
}
子类在构造的过程中要隐式的调用父类的构造函数
所以内存中有一份父类变量的拷贝,既是super.i=1;
然后又有一份子类内存变量的拷贝,是i=2;
一种类在内存中只有一份方法的拷贝,则既是setI(),getI()
我们调用b.getI的时候,关键是看这一份拷贝与那份内存变量拷贝
发生联系,在这里是用父类的内存变量发生关系,所以返回的是
super.i
2class Animal {
public int i=1;
public int getI(){
return this.i;
}
public void setI(int i){
this.i=i;
}
}
b.getI()实际调用的是从父类继承过来的方法,但字类没有覆盖getI(),关键在于this,他实际上是一个Animal类型的引用,但实际指向的是b Horse类的实例,成员变量没有多态行为,只有隐藏,也就是说依据引用类型来确定调用哪个类的成员变量,而多态是依据引用所指向的类型确定调用方法
在子类覆盖getI(),就会显示2
新手,学习!
应该说两i虽然看起来是一样的,但实际的指向位置是不同的(不知道说的对不对)
-----------------------------------------------------
C#中没有这个问题,是不是BUG阿?
要求透过父类“指针”去访问子类信息。所以,这个问题的要点就是理解“多态”是只适用于“方法”的概念。至于private还是protected,我甚至发现JAVA的编译器都会把关的。
public static void main (String [] args) {
Horse b = new Horse();
System.out.println(b.getI());
}
}class Animal {
public int i=1;
public int getI(){
return i;
}
public void setI(int i){
this.i=i;
}
}class Horse extends Animal {
public Horse()
{
i=2;
}
}
这样就可以输出2了。
int i=2 ;是不能修改对子类变量,而是申请了一个新的变量
1、父类已经被实例化;
2、子类没有覆盖父类的getI方法;
把子类i改为public也是不会返回2的,
除非给子类添加getI()方法,才会返回2
2、将int i = 2 改为 i = 2
用hibernate,spring ,struts的时候也记得看下JAVA基础
我想补充的是,从来没有父类的函数可以操作子类中新定义的成员的.而子类中的函数可以访问本身和父类的成员.非对称.
public static void main (String [] args) {
Horse b = new Horse();
System.out.println(b.getI());//输出1
System.out.println(b.i);//输出2 表明父类和子类中的两个i是不一样的.
}
}class Animal {
public int i=1;
public int getI(){
return i;
}
public void setI(int i){
this.i=i;
}
}class Horse extends Animal {
int i=2;
}
忽忽。
我运行了两次都是1。应该在子类中重写geti()方法去覆盖父类的这个
方法,就可以得到子类i的值。关键还是要自己上机去运行,才能找到问题
的所在。
public class TestAnimals {
public static void main (String [] args) {
Animal a = new Horse();
Horse b = new Horse();
a.setI(10);
b.setI(5);
System.out.println(b.getI());
System.out.println("Animal.i = " + a.getI());
System.out.println("Horse.i = " + b.i);
}
}class Animal {
private int i=1;
public int getI(){
return i;
}
public void setI(int i){
this.i=i;
}
}class Horse extends Animal {
int i=2;
}
输出结果:
5
Animal.i = 10
Horse.i = 2
========================
楼主你就能知道, Animal 中的 private 和 Horse 中的i 是两个毫无关联的变量
关键是对继承后的内存情况要了解
子类在构造的过程中要隐式的调用父类的构造函数
所以内存中有一份父类变量的拷贝,既是super.i=1;
然后又有一份子类内存变量的拷贝,是i=2;
一种类在内存中只有一份方法的拷贝,则既是setI(),getI()
我们调用b.getI的时候,关键是看这一份拷贝与那份内存变量拷贝
发生联系,在这里是用父类的内存变量发生关系,所以返回的是
super.i
这是哪个版本的JDK编译出来的?谈谈我的想法:
new Horse();之后,如果在Horse中找不到getI() 方法,
就回去他的父类寻找,在Animal中找到getI()方法后,
在父类取这个I,所以输出的值不受I定义为public还是private的影响,
所以二者输出的都是 1
所以在 Horse b = new Horse();时,
首先Animal的成员变量i被初始化为1,当Animal的构造器运行完后,Horse 开始初始化Horse里的变量i被初始化为2 ,但因为在继承时,成员变量并不能被覆盖
所以Horse里面的i和Animal里面的i ,一点关系都没有,只是变量名一样而已。
所以无论怎么该public 还是priate,结果都为1。
public class TestAnimals {
public static void main (String [] args) {
Horse b = new Horse();
System.out.println(b.getI());
}
}注意这个类
class Animal {
private int i=1;
public int getI(){
return i;
//注意:这里返回的是 this.i
//所以即使是子类继承类父类的成员 i 父类应用的还是自己的 i。所以
//输出的一定是 父类i 的值
}
public void setI(int i){
this.i=i;
}
}class Horse extends Animal {
int i=2;
}
正好检验一下大家的基础是否牢固!真是百家争鸣啊!
这里觉得zhaoqiubo(赵小刀)和ecaol的说法是对的。
本人初学者没有什么发言权,仅是看看,学习知识!
事实上是这样的,即使i是public的
输出结果也肯定是1
因为成员变量并没有覆盖一说,也就是子类的i和父类的public 的i是共存在子类体内的。为什么输出的不是子类的i,因为你如果不覆盖public int getI()这个方法的话
那么子类调用的其实是父类的getI()方法,java中的原则是调用的是哪个类的方,那么这个方法
访问的就是这个类中的成员。也就是输出的肯定是父类中的i(无论父类i是public或private,也无论子类中是否也有i)
这也说明了为什么在覆盖getI()之后就会输出的是子类中的i了,因为调用的是子类中的方法。
跟着说几句:
1.按照规范,成员变量应该是private,提供(方法)调用,而Horse的成员变量i是默认的访问权限,暴露了成员变量。
2.将Animal的i改为public解决不了问题,也破坏了封装,显然不能用;好的解决方法应是将Horse的i也改为private,然后添加getI()方法提供访问。