So how comes that they missing out all the cool features like "performSelector", "respondsToSelector"? Sure the whole OOP part may comes from Objective-C (SmallTalk to be precise) but the dynamic parts were poorly executed.
Well, they're a lot longer to type, but you can use [1] to get a method (and handle the error to see if it exists) and [2] to call the method on a given object.
Java takes its most basic ideas about how OOP is done from the Simula and C++ side, rather from Smalltalk and Objective-C. In that world view you don't ask if something responds to a selector but rather whether it's an instance of a suitable interface. There are still occasions when responsa to/perform is a nice pattern but its often better done with lambdas. Perform also tends to need annoying special casing to optimise.
The exception I'd make to that is meta-programming—especially for ORM libraries—where responds to, perform, and lambdas together produce some lovely patterns to marry a schematic to a dynamically generated object hierarchy.
The only difference I know of is that you can override inherited class methods, but not in Java. Is that really an important feature that you use? I suppose you could use it to do "factory" stuff, without an actual factory class.
Imagine my surprise when I disovered Delphi has class methods too, but they were not copied to C#. I guess most of the time they're not particularly useful, but when you do need to create some factory code, having pure virtual class methods (template methods), is really useful.
Downside w/ Delphi is the metaclasses do not implicitly exist - you have to manually define it, eg TMyObjectClass = class of TMyObject; They should just be implicity, when you define a class, the metaclass is defined too. I guess when they first designed it memory constraints were still a consideration
They are closer to global functions that are attached to classes and don't support inheritance the same way as instance methods. e.g. if a subclass implements a static function with the same signature as its parent, and you call it with the parent class, it invokes the parent class version instead of the subclass version.
Class-side methods in Smalltalk are inherited, working with classes (as an object) is analogous to how instance-side methods work with instances (also objects). So e.g implementing and using factory methods are simpler in Smalltalk and similar languages.