Java和C++访问权限以及多态机制的一些区别

来源:互联网 发布:淘宝卖什么好呢 编辑:程序博客网 时间:2024/05/18 19:44

Java默认访问权限:

Java默认访问权限是default(包访问权限,也就是同个包下的文件能访问,包外的文件无权限访问),这种访问权限关键字在C++中是不存在的。C++中class默认访问权限是private,struct结构体的默认访问权限是public, default比private的访问权限大,但是比prodected小,prodected除了能访问同个包的文件,也能让子类访问不同包的父类文件。

--java比C++多了一个访问权限范围:包访问权限。除了private,其他访问标识符都具有包访问权限。

多态机制的区别:

C++的多态机制是同个虚拟指针和虚拟表来实现的,只有声明为virtual的函数才会放置在虚拟表中,所以动态调用时是通过虚拟指针找到虚拟表中的偏移量找到函数的入口(如果虚拟函数被子类覆盖则调用子类的函数,否则调用的还是父类的入口),java的多态机制也是通过方法表来实现的,一个类所有方法都放在方法表中,所以某种意义可以认为java的所有方法都是虚方法,可以被子类直接覆盖的。看起来C++和java的多态实现机制差不多。总的来说C++的多态实现机制比较巧妙和隐蔽,而java的多态实现机制比较简单明了,这种区别的原因在于两者的编译类型是不一样的,C++属于静态编译类型语言,每个类的方法入口地址都必须在编译前确认,而java属于动态编译语言,在运行时才确定绑定的实例类型,并调用该类型的方法。也就是C++要实现多态,设计上需要巧妙很多,引用虚拟表是因为C++在编译时就需要确定调用的方法的全局偏移量,所以用着虚拟表这种方法来实现多态。而java是动态编译的,在java对象创建时(构造方法前)就已经创建了该对象的方法表,java对象的引用指向两个指针,一个指针指向方法表和类对象地址,另一个指针指向对象的成员变量数据(堆区)。

有个需要注意的知识点:

C++中父类的私有函数是可以被子类重写覆盖的,但是java中父类的私有方法只能被子类继承而不能覆盖,如果在子类中定义一个和父类私有方法同名同参的方法,那么只能说子类该方法屏蔽了父类的私有方法,但是并非覆盖。所以单子类通过父类的其他方法调用该私有方法时,调用的是父类的方法而非子类的方法。

public class VirtualFather{

         privatevoid virtualTest(){

                   System.out.println("VirtualFather.virtualTest");

         }

         voidtest()

         {

                   System.out.println(this.getClass());

                   this.virtualTest();

         }

}

 

class VirtualChild extends VirtualFather{

         voidvirtualTest(){

                   System.out.println("VirtualChild.virtualTest");

         }

         publicstatic void main(String[] args){

                   VirtualChildvirtual = new VirtualChild();

                   virtual.test();

         }

}

 

--输出是:classcom.tisson.zrftest.VirtualChild

VirtualFather.virtualTest

 

---为什么会这样呢,明明this的类型是VirtualChild,但是调用的是VirtualFather.virtualTest,这貌似不合理,这个可能是跟java的编译机制有关,VirtualFather类编译时,已经确定了this.virtualTest();调用的是VirtualFather类方法表的偏移量1,如果子类重写了父类,那么该偏移量对应的指针指向的是子类重写后代码的入口,但是java禁止子类重写父类的私有方法,所以1偏移量对应的还是父类的virtualTest代码的入口而不是子类同名方法的入口。

在C++中不同,父类的私有虚拟函数是可以被子类重写覆盖的。从实现的角度来说其实java也能实现这个功能,只是可能java的面向对象思想认为父类的私有方法只应该是属于父类的,子类不应该覆盖它。这是语言的设计思想的不同,而非不能实现。

 

隐藏和覆盖:

一直对隐藏和覆盖没做太多总结,在网上看到一段总结比较好:

隐藏:若B隐藏了A的变量或方法,那么B不能访问A被隐藏的变量或方法,但将B转换成A后可以访问A被隐藏的变量或者方法。

覆盖:若B覆盖了A的变量或者方法,那么不仅B不能访问A被覆盖的变量或者方法,将B转换成A后同样不能访问A被覆盖的变量或者方法。

 

--覆盖其实只会出现在方法的多态性上,变量不存在覆盖问题,方法存在覆盖和隐藏,父类的私有方法会被子类的同名同参方法隐藏但不是覆盖。

0 0
原创粉丝点击