Tor said:
But not in the sense of the method table or name relevant for
reflection, unless you want to change how those work.
I'm not trying to change how it works, as the way it works saves
confusion between methods in the same class at the expense of confusion
as to what namespace the method new Foo().bar() is drawn from and the
occasional need to recompile despite the lack of source code changes in
a client; there are in effect two namespaces for methods in the JVM, and
there is a constraint that names in these spaces must not collide.
In addition to this constraint, there is a constraint that two methods
cannot have both identical argument types and identical names; strictly
the signature (as expressed in the name and type info constant
referenced by the method table) encodes the return type as well as the
argument types, so the dispatch mechanism could differentiate on this as
well, but it doesn't, and returns an error if there is a collision.
In Java there is no method table in the C++ sense; there is only a class
file format and a specification of the behaviour of the JVM.
One part of the description of a method in the class file and JVM spec
is its name, another its argument types and return type, another is a
bit flag for public/private/protected/package access and for
static/instance scope. Of these the argument types, the return type, and
the name and the static/instance bit must agree with the invoked method,
and the access flags must allow suitable access rights, for the runtime
to dispatch the method invocation.
There is no constraint that a JVM finds a method with the same name then
reports and error if the method differs in the status/instance regard,
or searches for all methods with the same static/instance bit and
returns an error than none can be found. In fact, the JVM spec (5.4.3.4)
says that "If C declares a method with the name and descriptor specified
by the method reference, method lookup succeeds" for _both_ static and
virtual methods; so strictly the example I posted _should_ work as the
spec does not differentiate between lookup from virtual and static
methods (despite having different instructions for them, and obviously
different stack states), but only differentiates between interface and
non-interface method invocations (which are completely the same as far
as the Java language is concerned). But the example I gave doesn't work
on any JVM or compiler I've used, and I wouldn't expect it to etiher.
All compilers/JVMs use the static keyword/bit to differentiate between
static and virtual methods. This is an inherent part of
that-which-is-used-to-identify-the-method. Normally,
that-which-is-used-to-identify-the-method is called its signature.
Because of the constraints on collisions within the static and instance
method namespaces, the parameters used to identify a method to the
reflection API (name + arguments type) suffice. They do not suffice for
non-reflective method invocation; this requires the static bit agrees
and the return type agrees; therefore the name given to the reflection
API is obviously a weaker specifier than that required by the rest of
the language's dispatch mechanism. The reflection API is a tool whose
form is defined by additional constraints placed on the language's
dispatch mechanism; if this mechanism was different, and had fewer
collision constraints, the inputs to the reflection API would have to
reflect this.
These were design decisions, and it is perfectly possible to devise
dispatch mechanisms where these constraints do not apply: for example
C++ loosens the return type constraint slightly in that you may return a
more specific type (though this difference is enough to cause linking
errors in Java, it wouldn't be enough to effect the reflection API
lookup arguments, again showing that the reflection API uses a weaker
specifier).
So apart from the reflection API, which was designed after the decision
to dispatch on name+argment types only was made, everywhere Java has to
identify a method it uses a richer encoding which includes whether the
method is static or instance, either by keyword in source code for the
compiler or a bit flag in compiled classes, along with the return type
as part of its signature.
Pete