对于长期使用C++的人来说,这样的语义确实叫人一下子难以接受。/*
* Main.java
*
* Created on 2006年8月17日, 下午8:28
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/package javaapplication2;/**
*
* @author Zenny Chen
*/class Parent
{
protected int t;
public Parent()
{
System.out.println("Creating Parent...");
create();
}
public void create()
{
System.out.println("Parent created!");
t = 1;
}
}class Child extends Parent
{
private int c;
public void create()
{
c = 1;
System.out.println("Child created!");
}
public Child()
{
System.out.println("Creating Child...");
create();
}
public int getValue()
{
return c + t;
}
}public class Main {
/** Creates a new instance of Main */
public Main() {
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Child ch = new Child();
System.out.println("The result is: "+ch.getValue());
}
}从语义学和工程学角度,在Child对象被创建时首先要创建其父类域,然后可以根据父类属性
来获得创建自身资源的需要。然而Java在处理方法重写这个语义时,执行的是“一刀切”,
父类域尚未被创建完就开始调用其子类所重写的方法来。这样很可能造成子类的资源也无法
被初始化(若子类构造方法不去构建)。
从这点上,C++做得就比较好。创建一个对象就像造房子,一层一层建造。C++中虚函数的多态性
不会表现在构造函数和析构函数中,而且构造函数和析构函数也不会受到const对象的限制。
尽管在语义的实现上确实要比Java复杂一点,但符合语义学和工程学。
* Main.java
*
* Created on 2006年8月17日, 下午8:28
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/package javaapplication2;/**
*
* @author Zenny Chen
*/class Parent
{
protected int t;
public Parent()
{
System.out.println("Creating Parent...");
create();
}
public void create()
{
System.out.println("Parent created!");
t = 1;
}
}class Child extends Parent
{
private int c;
public void create()
{
c = 1;
System.out.println("Child created!");
}
public Child()
{
System.out.println("Creating Child...");
create();
}
public int getValue()
{
return c + t;
}
}public class Main {
/** Creates a new instance of Main */
public Main() {
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Child ch = new Child();
System.out.println("The result is: "+ch.getValue());
}
}从语义学和工程学角度,在Child对象被创建时首先要创建其父类域,然后可以根据父类属性
来获得创建自身资源的需要。然而Java在处理方法重写这个语义时,执行的是“一刀切”,
父类域尚未被创建完就开始调用其子类所重写的方法来。这样很可能造成子类的资源也无法
被初始化(若子类构造方法不去构建)。
从这点上,C++做得就比较好。创建一个对象就像造房子,一层一层建造。C++中虚函数的多态性
不会表现在构造函数和析构函数中,而且构造函数和析构函数也不会受到const对象的限制。
尽管在语义的实现上确实要比Java复杂一点,但符合语义学和工程学。
我最喜欢C++ Templates里面那个例子了。
不看不知道,那样一封装,模板展开了循环,速度超过了机器码;而且重载了运算符,计算几个矩阵的值,看起来就像数学公式那样漂亮,而且类型安全。
JAVA就是一种实用的语言,是有很多地方为了简化而舍弃了严谨性。
换来的好处是非常明显的:JAVA普及不过就楼主给的例子,我认为这没什么,道理很简单啊:
你既然知道子类没有构建完,那你为什么还要调用重载方法呢?请给我一个理由!语言是死的,人是活的!
我就有一个编程原则:在类的加载代码、对象的初始化代码、构造方法中,不做与初始化成员的动作。如果你也能遵守,就不会指责JAVA的不是了。
我定义Parent的时候没有想到Child会重载create();但是作为Child的作者,你应该知道在这种情况下,你很明显不能用继承!
组合应该是更好的选择!==========
问一下自己为什么要使用JAVA
> 我就有一个编程原则:在类的加载代码、对象的初始化代码、构造方法中,不做与初始化成员无关的动作。楼主的这段程序,create() 从内容上看,也算是“初始化成员”的动作呀?那可不可以这样理解:这种“初始化成员”的操作,比如 create(),不应该用 public ?
反正我把 Parent 里的 create() 改成 private,倒是能达到预期的效果。
在子类的create()方法中在开头添加:super.create();不过这样看上去有点别扭。【
语言是死的,人是活的!
我就有一个编程原则:在类的加载代码、对象的初始化代码、构造方法中,不做与初始化成员的动作。如果你也能遵守,就不会指责JAVA的不是了。
】
我不反对你这么说,不过如果对于编程语言本身能够提供更科学的语义,对于
开发人员来说也是种福气。当然,Java在很多方面确实比C++更“动态”,也有自己的优势,
语言的使用者当然要遵守它的规则,不是自己说的算的。这里列出这个问题也想提醒从C++到Java或从Java到C++的使用者,引起注意。
===========你真会问问题,专往JAVA的死穴上点。
你在下次JAVA规范制定的时候,提出一个“if_you_invoked_my_children's_method__i_will_kill_you”关键字,这样就应该OK了。
我觉得也可以理解,既是,想要使用那种类型的方法,取决于在内存创建时创建那种类型的对象.而不是用哪种引用来使用对象.
不管怎样.LZ这种做法本身是不高明的.上层类在实现的时候没有把自己的方法保护起来,使得子类有机会重载,并且,子类在没有调查父类便重写父类的方法.子类的重载初期使用SUPER.CREATE();或者父类把仅仅初始化自己字段的方法PRIVATE掉.就不会出现LZ的问题.
对于一个用来被继承的类,不要在其构造函数中调用可以被之类覆写的方法