It took 2 months, but this is the "final" answer we got from Support on this topic. Note that the investigation by Tier 3 resulted in this Known Issue being filed which was ultimately the cause for our documented behavior (i.e. by setting a log filter override on a class with a hashCode()/equals() implementation, it effectively disabled hashCode() from being called)
And here's the explanation on why FINEST vs. DEBUG makes a difference
Here is a recap of the current issue:
with log level = debug
DEBUG|Final HashableClass.hashCodeCount=10
DEBUG|Final HashableClass.equalsCount=0
with log level = finest
DEBUG|Final HashableClass.hashCodeCount=0
DEBUG|Final HashableClass.equalsCount=45
In this testcase, adding 10 HashableClass objects to a Set causes 10
hasCode() method calls because there are not any hash conflicts.
However, if the log level is set to FINEST, a Set Interpreter Instance
is converted to a Set Wrapper Instance in order to log an event of a
static field's assignment at line#6 (hashables = new
Set(); ) in the HashableClassDemo class.
When an object is added to a Set Wrapper Instance, we traverse the
entire list in it and compare objects for equality. That's why the
number of the equals() calls becomes 45 (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8
+ 9).
========================
The difference comes from underlying Map representations.
Internally, we have 2 representations for Map.
1) One keeps the objects in a Map in the interpreter (apex) native
representation.And in this case, if the put() method is called to it,
uniqueness of keys are determined by using both of hashCode() and
equals(). (A value returned by the hashCode() method is used to
determine a bucket, and the equals() method is used to identify
objects in the same bucket.)
2) Once a Map is marshaled, the other representation is used.In this
representation, in the put() method call, we traverse all objects in a
Map and linearly check uniqueness of keys using the equals() method if
a user defined key is used.That's why you don't see the hashCode()
method calls but see the equals() method calls in your testcase. (In
your org, the Map object is marshaled when trying to generate a debug
message for local variable assignments.)
However, the latter representation does not violate the Map contract.
Any method call defined in the Map class works as per doc.
Best Answer
Take a look at the Parameterized Typing and Interfaces section in the Apex Developer's Guide. This is what you are looking for, I'm pretty sure.
The other way that Generics are commonly used in Apex are what you stated which is in the Collections and Batch Apex classes.
For example, without generics you'd have something like:
With generics you have the compile time type safety:
So, in theory there's some generic code somewhere in the Apex system that handles all of the List work such as: