Your example is in some way a special case. In a non trivial program you can typically not determine the class of the object a certain reference points to better than "it is of the type the reference was declared for or a subtype of it".
The whole concept of polymorphism is based on the fact that the concrete class is only known at runtime but not at compile time. This of course means that the compiler must ensure that the methods that are called on a reference will be available on the referenced object at runtime. The only methods for which this holds true are the methods of the class for which the variable was declared (including all inherited methods from the super classes).
EDIT
As @David said in his comment the reason behind this is that typing is done statically by the programmer in java. If java had type inference the typing would be done by the compiler (but still statically) and your example would be absolutely valid. But it could be invalidated by another line doing this ob = new A()
.
If java were a dynamic typed language the compiler wouldn't care at all (at compile time) what methods you call on an object.
Have any class that requires a random number source accept a Function<Integer, Integer>
(or any equivalent functional interface you like) in its constructor.
Create a static method int rollDie(int sides)
that generates a random number from 0
to sides
, inclusive. This avoids the redundancy of rollD20
, rollD8
, etc. Interally this'll probably just be a call to Random.nextInt(sides + 1)
.
You can pass the static method to any class that needs it using a method reference:
new Character(Dice::rollDie)
For unit testing, you can easily replace rollDie
with a predictable function:
new Character(sides -> 5);
This is equivalent to valenterry's approach but with less boilerplate and possibly more efficient, if the compiler/virtual machine can make use of the fact that the lambda refers to a static method. It's also a bit easier to reuse, since rollDie
works with any interface containing one method that takes an Integer
and returns an Integer
, so you can use it in other contexts as well.
Best Answer
A
finalize()
method is a method like any other. It does whatever you program it to do. The only thing special is that it may be called unpredictably by the JVM before an object is garbage collected. If you call it manually, it does the same thing it would do during a GC-triggered call.However, with all modern garbage collectors, in practice you cannot rely on an object being collected at any particular time, or in fact at all. Therefore you cannot use
finalize()
to ensure that some action will be performed, which severely limits is usefulness. (About the only thing it is good for is debugging when objects get collected, and the JVM has better options for that.) This is why the general advice is "Just ignorefinalize()
altogether".