0 0

关于Java继承和多态的问题!!!5

最近看到两个Java基础题,自己搞了半天糊里糊涂的,看来自己Java基础还有很多理解不到位,希望高手给俺讲讲!
class A {}
class B extends A {
  void print() {
    System.out.println(super.getClass().getName());
  }
  public static void main(String[] args) {
    B b = new B();
    b.print();
  }
}

输出结果是什么?为什么?如果你懂了再讲讲下面这个问题:
class A {
  int i = 1;
  void print() {
    System.out.println(i);
  }
}
class B extends A {
  int i = 2;
  public static void main(String[] args) {
    B b = new B();
    b.print();
  }
}

俺不是想问输出结果,想问为什么会输出这样的结果?


问题补充:嗯,你回答的似乎没错,但好像不是用Java语言本身定义的一些规则来解释,感觉像是在看着答案自圆其说,看了之后还是模模糊糊,无法让俺理解透彻和信服。不过还是谢谢你!!!

问题补充:
shjavaer 写道
前面几个说的很对,可能你没看懂

第一个其实是动态绑定

你可能认为super是A,它的getClass返回是A.class,所以getName应该是A,这里的问题是super确实是A,但A,B都是object的子类,getClass又是object中的final方法,其返回的是Runtime class,这是规范定义好了的,而你的runtime class的实例是B,所以返回的class对象是B.class


第二个其实就是作用域问题
子类B中i覆盖了父类A中i,要想操作A中的i,就要用super.i进行显示操作,否则默认操作B中的i,就跟买烟一样,你说买红双喜,可能人家老板给你拿一盒10元红双喜,可你就喜欢5块钱的红双喜,所以你下次就会说买5元红双喜




第二个问题的输出结果是2,你好像打错了吧!!!

问题补充:
shjavaer 写道
前面几个说的很对,可能你没看懂

第一个其实是动态绑定

你可能认为super是A,它的getClass返回是A.class,所以getName应该是A,这里的问题是super确实是A,但A,B都是object的子类,getClass又是object中的final方法,其返回的是Runtime class,这是规范定义好了的,而你的runtime class的实例是B,所以返回的class对象是B.class


第二个其实就是作用域问题
子类B中i覆盖了父类A中i,要想操作A中的i,就要用super.i进行显示操作,否则默认操作B中的i,就跟买烟一样,你说买红双喜,可能人家老板给你拿一盒10元红双喜,可你就喜欢5块钱的红双喜,所以你下次就会说买5元红双喜


我也晕了,第二个问题的输出结果是1!!! 看来你也理解不到位啊

问题补充:
shjavaer 写道

引用
我也晕了,第二个问题的输出结果是1!!! 看来你也理解不到位啊



我没有就题论题,扯远了,其实主要想说的是 第二个其实就是作用域问题

呵呵,别误会,"就题论题..."那个是之前说一楼的。
不过你第二个问题确实回答错了,输出结果是A中的i为1。而你的意思是会输出B中的i为2......

问题补充:
longxiaoyan 写道
估计你没有看我的回答,第二个问题其实就是:子类定义与父类同名的成员变量,并没有覆盖父类的成员变量,而是两个成员变量共存。

嗯,是的,继承中不存在属性或者说实例变量的覆盖,只有方法的覆盖。

我的理解第二题,实例一个B对象,并调用print()方法。但B中并没有覆盖A中的print()方法,故实例化B之后,print()方法还是在A中的,并不会成为B的一部分,B的对象只能调用父类中的print()方法,或者说只有访问的权利,而print()方法并不是自身一部分。

简单点不知道可不可以这样理解:由于B没有覆盖A的print()方法,实际上B对象调用print()方法就是跳到A中执行print()方法,所以所访问的属性也就理所当然的是A中的i属性。

假如B中覆盖了A中的print()方法,一切都变得很简单了......
不知道这样理解是否正确,赐教~

问题补充:
longxiaoyan 写道
当B中没有覆盖print方法的时候,调用的是A中的print方法,加个this或许能更加容易理解:
class A { 
  int i = 1; 
  void print() { 
    System.out.println(this.i); 
  } 
}

当B覆盖print方法的时候,可以这样写:
void print() {
  System.out.println(this.i);
  System.out.println(super.i);
}

还有就是多态3要素:有继承,有重写,有父类引用指向子类对象。如果B覆盖了方法print,这样写就是多态了:
A a = new B();
a.print();//这里调用的就是子类的方法,多态的体现

理解这个才是重要的。

嗯,第二题理解的差不多了,说说第一题,getClass()方法的原型是:
public final native Class<?> getClass();
这是一个final方法,不能被继承,并且是一个native方法,所以不能用第二题的逻辑去解释,否则用那个逻辑解释下去就会输出“Object”。
这里就理解为它就是一个死的规定,死的约定,Java虚拟机执行这个方法时,就只返回调用处所在的类的Class对象。就是无论谁调用,就是返回调用者所在的类的Class对象,再用getName()方法返回这个Class对象名字,自然结果就是“B”,这样理解行否?

问题补充:
longxiaoyan 写道
对,就这样理解,就把它当成一个方法,返回就看它API所说的,其中的实现方法不用深究了。因为这里没有重写,调用的就是Object中的本地方法。

嗯,我又多次验证了一下,确实这个getClass()方法只依赖于调用者对象,就是说如果:
A中:
void print() {
  System.out.println(super.getClass().getName());
}

然后在B的main方法中:
如果
B b = new B();b.print();
打印结果为“B"。

如果
A a = new B();a.print();
打印结果为“B”

如果
A a = new A();
a.print();
打印结果为“A”。

通过几次测试,发现这个getClass()依赖于调用者实例,就是运行时对象(Runtime Class)。就是说getClass()方法,不论他在哪儿被使用,不论什么super、this指着,他只认最终调用者的身份。。。
呵呵,转了半天其实还是这句话:“运行时对象”,不过没有这一大圈的折腾,不会理解透彻这句话。。。
2011年12月30日 10:55

10个答案 按时间排序 按投票排序

0 0

采纳的答案

第一个问题:
getClass在Object中的定义为 public final native Class<?> getClass();既然定义为final说明这个方法可以继承但不能重写,既然没有重写,那么调用this.getClass()和调用

super.getClass()都是一样调用Object中的本地方法getClass()。所以我们只需知道getClass()是怎么实现的就可以了,但这是一个本地方法,我们没法看见源代码,那就看API:
Returns the runtime class of this {@code Object}.
这是API里的一句话,the runtime class当然是B了。

第二个问题:
这个问题无非就是考查能否继承实例变量?这里我先把Class A的代码变成这样:
class A { 
  int jjj = 1; 
  void print() { 
    System.out.println(jjj); 
  } 
}
我就是把变量名给变了一下而已,这里你肯定能理解了。剩下的问题就是子类定义与父类同名的成员变量时是个什么情况?子类定义与父类同名的成员变量,并没有覆盖父类的成

员变量,而是两个成员变量共存。再把Class B代码修改一下:
class B extends A {
int i = 2;

void print() {
System.out.println(i);
System.out.println(super.i);
}

public static void main(String[] args) {
B b = new B();
b.print();
}
}
明白了吧。

2011年12月30日 14:52
0 0

对,就这样理解,就把它当成一个方法,返回就看它API所说的,其中的实现方法不用深究了。因为这里没有重写,调用的就是Object中的本地方法。

2011年12月31日 17:44
0 0

当B中没有覆盖print方法的时候,调用的是A中的print方法,加个this或许能更加容易理解:
class A { 
  int i = 1; 
  void print() { 
    System.out.println(this.i); 
  } 
}

当B覆盖print方法的时候,可以这样写:
void print() {
  System.out.println(this.i);
  System.out.println(super.i);
}

还有就是多态3要素:有继承,有重写,有父类引用指向子类对象。如果B覆盖了方法print,这样写就是多态了:
A a = new B();
a.print();//这里调用的就是子类的方法,多态的体现

理解这个才是重要的。

2011年12月31日 17:15
0 0

你理解的没问题,但不会举一反三

2011年12月31日 16:39
0 0

估计你没有看我的回答,第二个问题其实就是:子类定义与父类同名的成员变量,并没有覆盖父类的成员变量,而是两个成员变量共存。

2011年12月31日 16:38
0 0


引用
我也晕了,第二个问题的输出结果是1!!! 看来你也理解不到位啊



我没有就题论题,扯远了,其实主要想说的是 第二个其实就是作用域问题

2011年12月31日 16:15
0 0

前面几个说的很对,可能你没看懂

第一个其实是动态绑定

你可能认为super是A,它的getClass返回是A.class,所以getName应该是A,这里的问题是super确实是A,但A,B都是object的子类,getClass又是object中的final方法,其返回的是Runtime class,这是规范定义好了的,而你的runtime class的实例是B,所以返回的class对象是B.class


第二个其实就是作用域问题
子类B中i覆盖了父类A中i,要想操作A中的i,就要用super.i进行显示操作,否则默认操作B中的i,就跟买烟一样,你说买红双喜,可能人家老板给你拿一盒10元红双喜,可你就喜欢5块钱的红双喜,所以你下次就会说买5元红双喜

2011年12月31日 00:12
0 0

第一个问题上面两位已经解释清楚了,实际上就是一个"动态绑定"问题,java默认返回返回的是当前类。

第二个问题。表面上是一个名字迷惑问题。这个问题在实际编程中几乎不存在,但提出这个问题有助于理解java对象初始化。在java中new一个对象时从父类开始,所有父类
的变量都将被初始化,名字只是变量在程序中的一个标识,在类存中变量他们都具有自己的地址,是拿地址来区分变量的,不是那名字来区分。这个b对象实际拥有两个名字为i的变量一个是父类的i=1,自身的i=2,在java中每个类中方法调用自己本身的变量,java为了不混淆,在子类对象调用父类的变量时需要super.i,并且是直接父类的i。
看看下面的代码你就明白了:

public class C extends B {

	  int i = 3;   
	  public static void main(String[] args) {   
	    B b = new C();   
	    b.print();   
	  }  
	  void print() {
		super.print();
	    System.out.println(super.i);
	  }
}

结果:
1
2
	    B b = new C();   


这里不管是A,B,C谁来引用实例C,都是动态绑定到C中的print
System.out.println(super.i);

没有输出顶层父类中的变量 而是C的直接父类B中的2.

2011年12月30日 19:42
0 0

第一个问题:
getClass在Object中的定义为 public final native Class<?> getClass();既然定义为final说明这个方法可以继承但不能重写,既然没有重写,那么调用this.getClass()和调用super.getClass()都是一样调用Object中的本地方法getClass()。所以我们只需知道getClass()是怎么实现的就可以了,但这是一个本地方法,我们没法看见源代码,那就看API:
Returns the runtime class of this {@code Object}.
这是API里的一句话,the runtime class当然是B了。

第二个问题:
这个问题无非就是考查能否继承实例变量?这里我先把Class A的代码变成这样:
class A { 
  int jjj = 1; 
  void print() { 
    System.out.println(jjj); 
  } 
}
我就是把变量名给变了一下而已,这里你肯定能理解了。剩下的问题就是子类定义与父类同名的成员变量时是个什么情况?子类定义与父类同名的成员变量,并没有覆盖父类的成员变量,而是两个成员变量共存。再把Class B代码修改一下:
class B extends A {
int i = 2;

void print() {
System.out.println(i);
System.out.println(super.i);
}

public static void main(String[] args) {
B b = new B();
b.print();
}
}
明白了吧。

2011年12月30日 14:54
0 0

先回答第一个问题:
(1)输出结果是B
因为,你new了一个b对象,调用print方法,打印super.getClass().getName(),在这里super指的是B的父类A,但是A类没有明确复写方法getClass(),所以这个地方真正调用的是Object类的getClass()方法,这个方法就是返回当前类B,因此getClass().getName()就是"B"。

(2)输出结果是1
new了一个b对象,调用print方法,由于当前B类没有明确定义print方法,因此会调用父类A的print方法,A中print方法打印的是A中的变量i,而不是B中的i。再说的具体一点就是,创建对象b后,调用一个父类的方法,因为方法没有声明为static类型,所有就得创建父类A的一个对象a,然后调用 a.print(),自然会打印a对象中的变量i。

不知道我是否把问题解释明白了,呵呵。
解释错误的地方,还请批评指教,大家一起学习!

2011年12月30日 11:49

相关推荐

    java继承和多态ppt

    java 继承和多态PPT教程

    Educoder题目:Java面向对象 - 封装、继承和多态的综合练习答案解析.md

    Educoder题目:Java面向对象 - 封装、继承和多态的综合练习答案解析

    java继承和多态PPT教案学习.pptx

    Java继承和多态PPT教案学习 本PPT教案主要讲解了Java中的继承和多态机制,包括继承、里式代换原则、多态和动态绑定、方法重载、重载构造函数和方法覆盖等概念。 继承是面向对象编程的基本机制之一,允许一个类继承...

    Educoder题目:Java面向对象 - 封装、继承和多态答案解析.md

    Educoder题目:Java面向对象 - 封装、继承和多态答案解析

    java继承与多态教学及练习

    1继承的概念 2继承的实现 3变量隐藏与方法覆盖 4super关键字 5 子类的构造顺序 6Object类 7 final关键字

    java基础继承封装多态

    本资源摘要信息将对 Java 基础知识点进行总结,涵盖继承、封装、多态等概念,并对面向对象的设计、数据库设计模式等进行讲解。 继承 继承是 Java 中的一种机制,允许一个类继承另一个类的属性和方法。继承的语法是...

    详解java接口、继承和多态

    ### 详解Java接口、继承和多态 #### 一、Java接口 在Java中,接口是一种定义行为的方式,它提供了一种实现抽象方法的手段。通过接口,开发人员可以为类定义一组方法签名,但不提供这些方法的具体实现。这有助于...

    java中继承与多态的题目

    本资源摘要信息是关于 Java 中继承和多态的题目,涵盖了面向对象编程的基本概念和继承机制的应用。 继承的概念 继承是面向对象编程的一种机制,允许一个类(子类)继承另一个类(父类)的属性和方法。继承的目的是...

    Java继承和多态

    Java继承和多态

    java继承与多态

    ### Java继承与多态知识点详解 #### 一、引言 在面向对象编程语言中,继承和多态是非常重要的概念。它们提供了强大的机制来管理代码的复杂性,并且能够有效地复用现有代码。本文将详细介绍Java中的继承和多态概念...

    java继承、多态的简单程序.zip

    这个压缩包"java继承、多态的简单程序.zip"显然包含了一些示例代码,旨在帮助初学者理解这两个概念。接下来,我们将深入探讨Java中的继承和多态性。 ### 继承(Inheritance) 在Java中,继承允许一个类(子类)...

    java 实验 继承与多态rectAngle 定义矩形类源代码

    java 实验 继承与多态rectAngle 定义矩形类,用户输入矩形的长与宽,程序计算其面积和周长;派生子类正方形类,定义一个接口Printable源代码

    Java实验报告——类的继承、多态的应用

    在本实验报告中,我们将深入探讨Java编程中的两个核心概念:类的继承和多态的应用。实验主要目标是加深对抽象类和抽象方法的理解,并掌握如何在实际编码中实现类的继承以及多态性。 首先,让我们理解抽象类和抽象...

    java面向对象三要素封装继承和多态源码

    java面向对象三要素封装继承和多态源码java面向对象三要素封装继承和多态源码java面向对象三要素封装继承和多态源码java面向对象三要素封装继承和多态源码java面向对象三要素封装继承和多态源码java面向对象三要素...

    JAVA 继承和多态实验报告.pdf

    本实验报告的目的是为了掌握Java语言中的继承和多态机制,通过模拟编写程序,理解类的继承、多态、继承和多态规则,并独立编程,实现类的继承和多态。 继承机制 在Java中,继承是一种机制,允许一个类继承另一个类...

    Java第8章 继承和多态含源代码

    Java第8章 继承和多态含源代码 Java第8章 继承和多态含源代码Java第8章 继承和多态含源代码 Java第8章 继承和多态含源代码 Java第8章 继承和多态含源代码 Java第8章 继承和多态含源代码

    《java面向对象程序设计-继承和多态》教案.doc

    面向对象编程是Java的核心特性,本教程主要涵盖了三个关键概念:封装、继承和多态,以及相关的访问修饰符和方法修饰符。 封装是面向对象编程的基础,它涉及到将数据(属性)和操作这些数据的方法(行为)组合在一个...

    java封装 继承与多态

    java封装 继承与多态 程序设计 类与对象

    java学习资料-Java继承和多态

    Java 继承和多态是面向对象编程中的核心概念,它们是Java中实现代码复用和灵活设计的关键机制。在Java中,继承允许一个类(子类)从另一个类(父类)继承特性,而多态则使得不同类型的对象能够共享相同的操作。 ###...

    Java语言程序设计ppt第十一章(继承和多态)

    Java语言程序设计ppt第十一章(继承和多态) 本章节主要讲解Java语言中的继承和多态机制,包括继承的定义、继承的应用、多态性和动态绑定等知识点。 一、继承的定义 继承是一种机制,允许一个类继承另一个类的...

Global site tag (gtag.js) - Google Analytics