自己动手验证java和C++在动态性上的区别 求大侠斧正
以下是对java动态性学习时网上看到的一段话:
//==============引用====start===================================
自http://book.51cto.com/art/200709/55217.htm
Java 语言具有动态特性。Java 动态特性是其面向对象设计方法的扩展,允许程序动态地装入运行过程中所需的类,这是 C++ 进行面向对象程序设计所无法实现的。C++ 程序设计过程中,每当在类中增加一个实例变量或一种成员函数后,引用该类的所有子类都必须重新编译,否则将导致程序崩溃。Java采取如下措施来解决此类问题。
(1)Java编译器不是将对实例变量和成员函数的引用编译为数值引用,而是将符号引用信息在字节码中保存后传递给解释器,再由解释器在完成动态连接类后,将符号引用信息转换为数据偏移量。存储器生成的对象不在编译过程中决定,而是延迟到运行时由解释器确定。这样,对类中变量和方法进行更新时就不至于影响现存的代码。解释执行字节码时,这种符号信息的查找和转换过程仅在一个新的名字出现时才进行一次,随后代码便可以全速执行。(2)在运行时确定引用的好处是可以使用已被更新的类,而不必担心会影响原有的代码。如果程序连接了网络中另一系统的某一类,该类的所有者也可以自由地对该类进行更新,而不会使任何引用该类的程序崩溃。(3)Java还简化了使用一个升级的或全新的协议的方法。如果系统运行 Java 程序时遇到了不知怎样处理的程序,没关系, Java 能自动下载你所需要的功能程序。Java是一种比C/C++更具动态特性的语言。在设计上强调为运行中的运算环境提供支持。Java是在运行时为模块与模块之间建立连接,并能够更直接地运用面向对象设计体系。程序库可以自由地增加新方法和实例变量,而不会对它们的客户产生任何影响。//===============引用===end===================================
接下来是我做的实验 分两部分 主要是以代码 辅助说明的形式阐述
一.首先验证java
/*A.java*/
public class A{
public int i=0;
public int j=1;
public int k=1;
}
/*UA.java*/
public class UA{
public A a;
public void aa(){
a= new A();
System.out.println(a.i);
} }
/*doM.java*/
public class doM{
public static void main(String args[]){
UA ua=new UA();
ua.aa();
}
}
1 命令提示符中 javac A.java
Javac B.java
Javac doM.java 产生三个相应的 .class文件
Java doM 控制台 输出0
2 将B.java 删除 保证B不能被编译成新的B.class
改动A.java 变量最后添加 int jj=99;
删除原A.clss
Javac A.java 产生新A.class 且被保证是新产生的
Java doM 控制台输出0
说明A的源代码改动了 且编译出新的.class但是原有的B.class还是可以运行
//-----------------------------------------------------------------------------------------------------------------
二.对C++进行实验
/*A.cpp*/
class A{
public:
int geti()
{return i;}
void seti(int newi)
{
i=newi;
}
public:
int i;
int j;
};
/*B.cpp*/
#include"A.cpp"
#include<iostream>
using namespace std;
class B
{
A aa;
public:
void pr()
{
// aa=new A();
aa.i=99;
cout<<aa.i;
}
};
/*doM.cpp*/
#include"B.cpp"
#include<iostream>
using namespace std;
void main(){
b bb;
bb.pr();
}
1. 编译 A.cpp B.cpp doM.cpp 产生 A.obj B.obj doM.obj build 产生d.exe 执行输出99
2. 删除 d.exe
将 B.cpp 删除保证B不能被重新编译 删除A.obj 代码不做改动
编译A.cpp 产生新的A.obj build 产生d.exe 执行可输出99
3. 还原到原始状态 把B.cpp放回来
编译 A.cpp B.cpp doM.cpp 产生 A.obj B.obj doM.obj build 产生d.exe 执行输出99
4. 删除 d.exe
将 B.cpp 删除保证B不能被重新编译 删除A.obj 在A.cpp 变量中加入 int jjjj;
编译A.cpp 产生新的A.obj build 产生报错 找不到B.cpp
5. 还原到原始状态 把B.cpp放回来 A.cpp改回最初状态
编译 A.cpp B.cpp doM.cpp 产生 A.obj B.obj doM.obj build 产生d.exe 执行输出99
6. 删除 d.exe
删除A.obj 在A.cpp 变量中加入 int jjjj;
编译A.cpp 产生新的A.obj 编译B.obj build 产生d.exe 执行可输出99
说明A.cpp不改动时 重新编译得到A.obj 和原始B.obj可以连接产生.exe
而 A.cpp改动时 重新编译得到A.obj和原始B.obj 不能连接了,需要重新编译B
//----------------------------------------------------------------------------------------------------------
根据实验结果加上上面一段引用文字 猜测如下:
Java在编译时 在B.class中只保存了需要用到的A.i这个引用 到了运行时才会哪这个引用到A.class中去找到A.i的实际偏移量。所以哪怕A.class随时改变 只要有A.i 运行时都能获得正确最新的A.i;
而C++在编译时 B.obj中不只保存了需要用到的A.i这个引用 并且保存了A.i在A.class中的实际偏移量。所以A.obj改变了B.obj也就不能用了,因为保存了过时的A.i的偏移量。
步骤虽然很罗嗦,但是目的是想验证的更加严谨。在这分享给大家看看,也当自己的一个小总结。不知道我上面的猜测是否符合实际情况,请各位大侠斧正。
田旭园 奚亮亮
2011.7.1 于419宿舍