Here is what I think about the virtual methods in java.
In java, by design and specification, all the non-static, non-private, non-final, non-constructive methods are virtual. This means, the selection of the method to be invoked at a call site will depend on the actual (runtime) type of the invoker object (reciever), rather than its declared (static, compile time) type.
In the case of C++, this is true only when the invoker object is declared as a pointer type, and the method is declared explicitly as 'virtual'. If either of this is false, then the method is resolved (identify and select the definition) always to the definition in the defining class of the declared type of the invoker.
In contrast in java, since there is no pointer, there is no flexibility for methods to exhibit virtual and non-virtual behavior based on the type declaration mode - there is only one way to cite objects, that is through references. And moreover, in JRE implementations, java object looses its connection with the declaring type and gets associated with the defining class. At this point it is imperative that the virtual keyword be removed and designate all the normal methods as virtual.
But how often a program really requires the virtual property? Very rarely. What is the percentage of virtual methods who exercise this feature in a meaningful manner? less than 5%. Even in those cases where multiple subclasses are designed and methods redefined, an efficient programmer will go for an interface (or abstract class) for the base class, which means the base method is pure virtual(abstract), not virtual.
This precisely means that a normal, concrete java method (designed to be virtual) actually utilizing its virtual-ness is a rarest possibility.
Implementing virtual methods is easy in JREs, but their presence make the execution engine incapable of pre-linkage of the method call site, potentially slowing down the performance. In practice, the method resolution has to wait until the execution reaches the call site. Dynamic compilers devirtualize methods up to an extend, by tracing the source of the invoker object in the neighborhood of the call site, but this does not really alleviate the problem, and adds it's own additional computation overhead. One of the potential challenges of JIT today is the inability to perform inter-procedural analysis and compress the code any further owing the extremely delayed method resolutions. A powerful technique called ahead-of-time compilation is rendered ineffective because of the inability to resolve methods in advance.
The decision to qualify all the methods as virtual was not a well thought-out design, instead an un-anticipated side effect. An accidental by-product or an unexpected misfire came out of the pointer-less design.
Hyper-virtual methods in java.