`
mfcai
  • 浏览: 410197 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java继承容易犯的错误

阅读更多
在网上看见一个关于java继承的问题,觉得这是很多初学java应该注意的问题。
public abstract class A {
  int i=1;
  public void printI() {
    System.out.println("i="+i);
  }
}

public class B  extneds A{
  int i=2;
  public static void main(String[] args) {
    B b=new B();
    b.printI();
  }
}

那么,控制台打出来的i的值是多少?
呵呵,如果一下功夫就能说出正确结果1,那么,下面部分就不需要往下看了。

1、类的继承知识点
(1)java不支持多重继承,也就是说子类至多只能有一个父类
(2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法
(3)子类中定义的成员变量和父类中定义的成员变量相同时,则父类中的成员变量不能被继承
(4)子类中定义的成员方法,并且这个成员方法的名字,返回类型,及参数个数和类型与父类的某个成员方法完全相同,则父类的成员方法不能被继承。

2、答案是2者如是说
  子类B中的变量i和父类A中的变量i重名, 那么子类B中的变量i将会覆盖掉父类中的同名变量i. 则访问父类中的变量时jvm会把子类cast到父类.所以,打印出的结果应该是“i=2”;

3、歧义的产生
  歧义的产生最关键的地方是子类B中的变量i将会覆盖掉父类中的同名变量i的覆盖两个字。这里,我觉得这两个字容易误导。应该改为屏蔽或隐藏。因为在这里父类的成员变量是没有被改变。

4、jvm的执行过程
(1)子类B 的构造方法被调用,实例化一个B对象,B对象的成员被初始化
(2)jvm隐含的调用父类的构造方法,实例化一个A对象,A对象的成员被初始化。
(3)由于A对象的printI()未被屏蔽,所以调用的A对象的printI()函数。
那么,在这里A的成员函数当然是访问自己的成员变量了。

5、super关键字
super关键字在java中的作用是使被屏蔽的成员变量或者成员方法或变为可见,或者说用来引用被屏蔽的成员变量和成员成员方法。super是用在子类中,目的是访问直接父类中被屏蔽的成员。上面的代码也可以这样写:
public abstract class A {
  int i=1;
  public void printI() {
    System.out.println("i="+i);
  }
}
public class B extends A{
	public int i=2;
	public void printI(){
		super.printI();
	}
	public static void main(String[] args){
		B b= new B();
		b.printI();
		
	}
}
分享到:
评论
29 楼 gembler 2008-12-31  
如果主帖中有代码片段,麻烦在发前先自己运行一下
28 楼 xintian3 2008-12-31  
抽象类不能实例化,然而可以创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例。
抽象类初始化同类的初始化。
27 楼 mars李 2008-04-15  
学习。。。
26 楼 bomb_football 2008-04-15  
foy 写道
mfcai 写道
foy 写道
引用
我觉得你这句话“抽象类,和类的差别就是,不可以有实体。“有待商榷。
你这句话要表达的意思应该是这样理解:abstract类不能创建对象,必须由其子类来创建对象。
我觉得这里应该是指用户不能创建abstract类的对象。但没有表明jvm不能初始化abstract类啊?
退一步,如果抽象类在jvm中没有被实例化,那么用户在子类中使用super调用抽象类的方法,怎么理解?


类的初始化和实例化是两码事。任何类在使用前都会经过装载-->连接-->初始化三个过程。
类的构造方法不能当成普通的方法,应当看成类似于static的方法

foy,类的初始化和实例化是两码事,就不讨论了。
我的观点是反对“父类根本就没有在堆内存空间中”。


我觉得“父类根本就没有在堆内存空间中”这话是没有错的。



1、按照jvm规范,堆是运行时数据区域,类实例化的内存都由类分配,抽象类也是类,为什么抽象类就不在堆空间里呢?那你能告诉我,“父类根本就没有在堆内存空间中”,那父类在哪里实例化的呢?
2、对于你的那句“类的构造方法不能当成普通的方法,应当看成类似于static的方法”,我也不敢苟同.恕我愚钝,实在是不能明白为什么要和构造方法看成是static的方法???  static方法是类在装载的过程中,JVM会调用内置的<clinit>方法对其进行初始化调用。而构造方法是在对象创建时,JVM会调用内置的<init>方法来调用它。
25 楼 njustwalker 2008-04-14  
我忽然想到另外一个问题
如果我要使用父类中的方法而要使用子类中的变量 可以吗?
我要用就是想让楼主题目中用父类函数打印出子类中的i可以吗?
24 楼 ericxu131 2008-04-13  
我觉得

抽象的父类给我感觉就是其子类的参照

JVM在初始化子类前会先初始化父类中的成员,调用构造函数但而并非实例化父类

父类根本就没有在堆内存空间中,而他里面的成员是被先初始化到堆内存空间中
23 楼 lishali12345 2008-04-13  
其实这个问题是不是可以从Java初始化的顺序上来给出一个解释呢!?
其顺序如下:

1.  父类静态成员和静态初始化块  ,按在代码中出现的顺序依次执行

2.  子类静态成员和静态初始化块 ,按在代码中出现的顺序依次执行

3.  父类实例成员和实例初始化块 ,按在代码中出现的顺序依次执行

4.  父类构造方法

5.  子类实例成员和实例初始化块 ,按在代码中出现的顺序依次执行

6.  子类构造方法

如此不就很明了了吗?
父类的实例成员在子类的实例成员初始化前已经初始化好了,打印出来的当然就是父类中定义的1了吧!
不知理解是否正确?!
还请各位酌定!
22 楼 foy 2008-04-12  
mfcai 写道
foy 写道
引用
我觉得你这句话“抽象类,和类的差别就是,不可以有实体。“有待商榷。
你这句话要表达的意思应该是这样理解:abstract类不能创建对象,必须由其子类来创建对象。
我觉得这里应该是指用户不能创建abstract类的对象。但没有表明jvm不能初始化abstract类啊?
退一步,如果抽象类在jvm中没有被实例化,那么用户在子类中使用super调用抽象类的方法,怎么理解?


类的初始化和实例化是两码事。任何类在使用前都会经过装载-->连接-->初始化三个过程。
类的构造方法不能当成普通的方法,应当看成类似于static的方法

foy,类的初始化和实例化是两码事,就不讨论了。
我的观点是反对“父类根本就没有在堆内存空间中”。


我觉得“父类根本就没有在堆内存空间中”这话是没有错的。
21 楼 mfcai 2008-04-12  
foy 写道
引用
我觉得你这句话“抽象类,和类的差别就是,不可以有实体。“有待商榷。
你这句话要表达的意思应该是这样理解:abstract类不能创建对象,必须由其子类来创建对象。
我觉得这里应该是指用户不能创建abstract类的对象。但没有表明jvm不能初始化abstract类啊?
退一步,如果抽象类在jvm中没有被实例化,那么用户在子类中使用super调用抽象类的方法,怎么理解?


类的初始化和实例化是两码事。任何类在使用前都会经过装载-->连接-->初始化三个过程。
类的构造方法不能当成普通的方法,应当看成类似于static的方法

foy,类的初始化和实例化是两码事,就不讨论了。
我的观点是反对“父类根本就没有在堆内存空间中”。
20 楼 foy 2008-04-12  
引用
我觉得你这句话“抽象类,和类的差别就是,不可以有实体。“有待商榷。
你这句话要表达的意思应该是这样理解:abstract类不能创建对象,必须由其子类来创建对象。
我觉得这里应该是指用户不能创建abstract类的对象。但没有表明jvm不能初始化abstract类啊?
退一步,如果抽象类在jvm中没有被实例化,那么用户在子类中使用super调用抽象类的方法,怎么理解?


类的初始化和实例化是两码事。任何类在使用前都会经过装载-->连接-->初始化三个过程。
类的构造方法不能当成普通的方法,应当看成类似于static的方法
19 楼 mfcai 2008-04-12  
dearmite 写道
抽象类,和类的差别就是,
不可以有实体。

B b = new B();  
        A a = new B();
这里的变量类型看似不同,

但是,内存中实际上都是B类。
这个和接口一样,
接口中不同样也可以定义变量么。(只是都变成了final)

指向类的时候,它就指到了类的首地址上!


  A a = new B();为什么不可能写成  A a = new A();

  A a = new B();  
实际上是,
A a ;
a= new B();
a 是抽象的,根本就无实体。
     

我觉得你这句话“抽象类,和类的差别就是,不可以有实体。“有待商榷。
你这句话要表达的意思应该是这样理解:abstract类不能创建对象,必须由其子类来创建对象。
我觉得这里应该是指用户不能创建abstract类的对象。但没有表明jvm不能初始化abstract类啊?
退一步,如果抽象类在jvm中没有被实例化,那么用户在子类中使用super调用抽象类的方法,怎么理解?
18 楼 dearmite 2008-04-12  
B b;
sysout (b);

b= new B();  
sysout (b);
  A a;
sysout (a);
a = b;

sysout (a);

把这里的null,和类的首地址打出来,一看便知!!!

null 是栈中变量无任何指向。
这个和C++一样,

A a = new B();

和C++ 中  A *p = new B() p 这里放了B的首地址。
是一样的,JAVA的隐指针!


17 楼 dearmite 2008-04-12  
抽象类,和类的差别就是,
不可以有实体。

B b = new B();  
        A a = new B();
这里的变量类型看似不同,

但是,内存中实际上都是B类。
这个和接口一样,
接口中不同样也可以定义变量么。(只是都变成了final)

指向类的时候,它就指到了类的首地址上!


  A a = new B();为什么不可能写成  A a = new A();

  A a = new B();  
实际上是,
A a ;
a= new B();
a 是抽象的,根本就无实体。
     
16 楼 mfcai 2008-04-12  
dearmite 写道
lsk 写道
mfcai 写道

(4)子类中定义的成员方法,并且这个成员方法的名字,返回类型,及参数个数和类型与父类的某个成员方法完全相同,则父类的成员方法不能被继承

改成这样试试看
public abstract class A {

	int i = 1;

	public void printI() {
		System.out.println("i=" + i);
	}
}

class B extends A {

	@Override
	public void printI() {
		System.out.println("i="+(++i));
	}

	public static void main(String[] args) {
		B b = new B();
		A a = new B();
		a.printI();
		b.printI();
	}
}




父类,无实体,
穿过父类的无发(子类的手)

父类根本就没有在堆内存空间中。。。

也许这里,我们理解有偏差了.
我们知道,在Java中,只要通过关键字new为每个对象申请内存空间 (基本类型除外),所有的对象都能在堆 (Heap)中分配到空间。父类也能被new,那么请问为什么不存在堆内存空间中?
15 楼 dearmite 2008-04-12  
lsk 写道
mfcai 写道

(4)子类中定义的成员方法,并且这个成员方法的名字,返回类型,及参数个数和类型与父类的某个成员方法完全相同,则父类的成员方法不能被继承

改成这样试试看
public abstract class A {

	int i = 1;

	public void printI() {
		System.out.println("i=" + i);
	}
}

class B extends A {

	@Override
	public void printI() {
		System.out.println("i="+(++i));
	}

	public static void main(String[] args) {
		B b = new B();
		A a = new B();
		a.printI();
		b.printI();
	}
}




父类,无实体,
穿过父类的无发(子类的手)

父类根本就没有在堆内存空间中。。。
14 楼 mfcai 2008-04-11  
backbase 写道
4、jvm的执行过程
(1)子类B 的构造方法被调用,实例化一个B对象,B对象的成员被初始化
(2)jvm隐含的调用父类的构造方法,实例化一个A对象,A对象的成员被初始化。
(3)由于A对象的printI()未被屏蔽,所以调用的A对象的printI()函数。

疑问:
     针对楼主这个例子:jvm的执行过程应该是先加载父类,然后加载子类的吧。

我的意思就是:jvm先初始化父类的成员变量和构造函数,在初始化子类的成员变量和构造函数。不知道我的理解是否正确,请大虾们不吝指教,谢谢!

谢谢你的提醒,根据类的加载机制:应该先是父类的成员变量和构造方法,然后才是子类的成员变量和构造方法
在这个地方我表达的不对,抱歉。
13 楼 trydofor 2008-04-11  
如果哪个开发人员写这样的程序,直接开除就行了
12 楼 helyho 2008-04-11  
看懂.学习
11 楼 backbase 2008-04-11  
4、jvm的执行过程
(1)子类B 的构造方法被调用,实例化一个B对象,B对象的成员被初始化
(2)jvm隐含的调用父类的构造方法,实例化一个A对象,A对象的成员被初始化。
(3)由于A对象的printI()未被屏蔽,所以调用的A对象的printI()函数。

疑问:
     针对楼主这个例子:jvm的执行过程应该是先加载父类,然后加载子类的吧。

我的意思就是:jvm先初始化父类的成员变量和构造函数,在初始化子类的成员变量和构造函数。不知道我的理解是否正确,请大虾们不吝指教,谢谢!
10 楼 yulenice 2008-04-10  
It is interesting.

相关推荐

    写Java程序最容易犯的错误例析

    ### 写Java程序最容易犯的错误例析 在软件开发过程中,编写高质量的代码是非常重要的。良好的代码不仅能提高系统的可维护性和可扩展性,还能减少未来的维护成本。本文将详细介绍编写Java程序时最常见的21个错误,并...

    Java程序最容易犯的21种错误

    【Java程序最容易犯的21种错误】是一个关于Java编程中常见问题的总结,这些问题可能导致代码质量下降,可维护性和可扩展性降低。以下是对这些错误的详细解释: 1. **重复代码(Duplicated Code)**:代码重复是降低...

    写Java程序最容易犯的21种错误

    Java编程中,程序员可能会遇到各种常见错误,这些错误不仅影响代码质量,还可能导致软件的可维护性和可扩展性降低。以下是对标题和描述中提到的21种常见错误的详细解释: 1. **重复代码(Duplicated Code)**:当相同...

    Java程序最容易犯的错误

    ### Java程序中最易犯的21种错误解析 在Java编程实践中,开发人员经常会遇到一些常见的陷阱和误区,这些问题不仅会影响代码的质量,还可能导致程序运行时出现不可预知的错误。下面将详细介绍这些常见的错误,并提供...

    编写Java程序最容易犯的21种错误

    以下是对这些最容易犯的21种错误的详细解释: 1. **重复代码 (Duplicated Code)** - 在多个地方存在相同或几乎相同的代码段,这违反了DRY(Don't Repeat Yourself)原则,应通过提取公共方法或模块化设计来避免。 ...

    Java习题(一些不注意就犯的错误)

    本篇将详细探讨"Java习题(一些不注意就犯的错误)"中涉及的知识点,包括字符谜题、循环谜题、异常谜题、类谜题以及库谜题,旨在帮助你更好地理解和避免这些常见问题。 1. 字符谜题: Java中的字符处理有时会让人...

    有经验的Java开发者和架构师容易犯的10个错误(下)Ja

    在Java开发领域,即使是经验丰富的开发者和架构师也可能会陷入一些常见的误区,这些错误可能导致代码质量下降、系统性能瓶颈或维护困难。以下是对标题和描述中提到的十个常见错误的详细解析,以及如何避免它们: 1....

    用Java语言编写程序最容易犯的21种错误

    ### 用Java语言编写程序最容易犯的21种错误 #### 1. 代码重复 (Duplicated Code) 在软件开发过程中,代码重复是最常见的问题之一。这种现象通常来源于程序员使用复制粘贴的方式来快速构建功能,这导致代码库中存在...

    JAVA基础易错总结(50%你不知道)

    然而,即使是经验丰富的开发者,也可能会在一些基本的Java知识点上犯错误。"JAVA基础易错总结(50%你不知道)"这份资料,由大鹏历时5个月精心原创,旨在揭示那些易被忽视或误解的Java基础知识,帮助开发者提高代码...

    Java工作学习牛客网刷题错误总结.rar

    1. **基础语法错误**:这是初学者最容易犯的错误,包括但不限于括号不匹配、缺少分号、类型转换错误、变量未声明或初始化等。例如,Java中的`==`用于比较基本类型,而`equals()`用于对象的比较,这两者的混淆是常见...

    java面试题目精选

    - **易犯错误的关键字**:列出了一些容易被误用的Java关键字。 - **注释的使用**:介绍了不同类型的注释及其在代码中的作用。 - **3.2 原始类型** - **int与Integer的区别**:解释了int作为基本类型与Integer...

    Big_Java(英文版)

    - **常见错误**:列举并解释在Java编程过程中容易犯的错误,帮助读者避免这些陷阱。 - **怎样做**:提供具体的编程技巧和方法,指导读者如何实现特定功能。 - **质量提示**:强调高质量代码的重要性,并给出编写高效...

    java初学者福音

    4. 编写Java程序最容易犯的21种错误: 初学者常犯的错误包括: - 忘记分号或括号不匹配 - 不理解作用域规则,导致变量未声明或不可见 - 对null值处理不当,引发NullPointerException - 不合理使用equals()和==,混淆...

    疯狂JAVA讲义

    1.6.3 初学者容易犯的错误 18 1.7 垃圾回收机制 20 1.8 何时开始使用IDE工具 21 学生提问:老师,我想学习Java编程,到底是学习Eclipse好呢,还是学习JBuilder好呢? 21 1.9 本章小结 22 本章练习 22 第2章 ...

    JAVA-web基础知识点

    9. jsp 初学者容易犯的错误 在 JSP 开发中,初学者容易犯的错误包括将 HTML、JSP 文件放在 WEB-INF 目录下,直接打开 JSP 文件等。 10. jsp/servlet 连接数据库时要注意的事项 在 JSP/Servlet 中连接数据库时,...

    Java工程师必知必会.docx

    12. 初学者容易犯的错误 Java编程基础结构化程序设计简介: 1. 程序的三种基本结构 2. 面向对象程序设计简介 3. 面向对象的基本特征 4. Java的面向对象特征 5. 类和对象 6. 注释、标识符和关键字 7. 数据类型分类 ...

    Java基础知识精华总结

    3. **常见误区**:指出初学者容易犯的错误,提供正确的解决办法。 4. **代码规范**:讲解Java编程规范,如命名规则、注释规范等,提高代码可读性。 通过这些文档的学习,你不仅可以系统地了解Java的基础知识,还能...

    OCAOCP Java SE 7 Programmer I & II Study Guide (Exams 1Z0-803 & 1Z0-804)

    4. **常见错误解析**:列举考生在备考过程中容易犯的错误,并提供改正方案。 综上所述,《OCA/OCP Java SE 7 Programmer I & II Study Guide (Exams 1Z0-803 & 1Z0-804)》这本书覆盖了从 Java 基础到高级主题的广泛...

    SCJP1.4陷阱总结

    《SCJP1.4陷阱总结》是一份针对...这份笔记通过分析错误案例和陷阱,帮助考生避免在实际考试中犯同样的错误,从而提高得分。对于准备SCJP1.4认证的考生来说,它是宝贵的参考资料,能够补充教材中可能未提及的实战经验。

    Cracking the Coding Interview

    - **十大常见错误**:列举了求职者在面试过程中容易犯的错误,并给出了相应的避免策略。 - **常见问题解答**:解答了一些求职者普遍关心的问题。 - **面试题目汇总**:收录了大量的面试题目,涵盖了数据结构、算法等...

Global site tag (gtag.js) - Google Analytics