> Well thats because of the Java compiler and in some parts the language of Java. It has nothing to do with the JVM otherwise Clojure wouldn't work.
Clojure is constrained by the JVM and its implementation. Though Java is even more constrained.
You get a mini Common Lisp Object System demo in the LispWorks REPL:
We define a class person with a slot 'name':
CL-USER 1 > (defclass person () ((name :initarg :name :accessor name)))
#
Let's create a list of persons:
CL-USER 2 > (setf persons (mapcar (lambda (name)
(make-instance 'person :name name))
'("Jan" "Ralph" "Joan")))
(# # #)
Let's define a custom print method:
CL-USER 3 > (defmethod print-object ((p person) stream)
(print-unreadable-object (p stream :type t :identity t)
(write-string (name p) stream)))
#
How does a person print now?
CL-USER 4 > persons
(# # #)
Let's add a slot to the class, a slot 'age':
CL-USER 5 > (defclass person ()
((name :initarg :name :accessor name)
(age :initarg :age :accessor age :initform 0)))
#
Let's update the print method:
CL-USER 6 > (defmethod print-object ((p person) stream)
(print-unreadable-object (p stream :type t :identity t)
(format stream "~a ~a" (name p) (age p))))
#
Woops: all persons now have already got the new slot:
CL-USER 7 > persons
(# # #)
Let's set the new slot:
CL-USER 8 > (mapc (lambda (p age)
(setf (age p) age))
persons
'(23 43 21))
(# # #)
Let's define a new class: social-security-mixin:
CL-USER 9 > (defclass social-security-mixin ()
((social-security-number :initarg :ssn :accessor ssn)))
#
Let's add this new class to the superclasses of PERSON.
CL-USER 10 > (defclass person (social-security-mixin)
((name :initarg :name :accessor name)
(age :initarg :age :accessor age :initform 0)))
#
Now we do something really wild: we write an around method for printing:
CL-USER 11 > (defmethod print-object :around ((p person) stream)
(print-unreadable-object (p stream :type t :identity t)
(call-next-method)))
#
We redefine the original method just to print the name and age of the person.
CL-USER 12 > (defmethod print-object ((p person) stream)
(format stream "~a ~a" (name p) (age p)))
#
Then we define an AFTER method for the social-security-mixin class:
CL-USER 13 > (defmethod print-object :after ((o social-security-mixin) stream)
(format stream " ~a" (ssn o)))
#
Now we set the social security number of the persons. Wait?
Lisp has updated my objects, since I added a new superclass to their class? All objects now have a changed superclass for their class? They inherit the new slot?
And the print-method gets reassembled for the new inheritance tree and the changed set of methods?
CL-USER 14 > (mapc (lambda (p ssn)
(setf (ssn p) ssn))
persons
'("123-345" "321-455" "443-222"))
(# # #)
As you see the objects have a SSN and the print methods are dynamically combined. For the person it runs the around method, then the primary method of person and then the after method of the mixin. If I'd now change the inheritance tree, then the methods would be recombined according to the inheritance at runtime... I could also dispatch on the second argument...
CLOS supports multi-dispatch over multiple-inheritance with dynamic combinations of applicable methods.
CLOS can do quite a bit more than that...
Java can't do anything like that.
It can't update objects on class changes/inheritance changes/...
It can't combine methods based on the multiple-inheritance class tree.
It can't change the class of objects. It can't reprogram the object system itself. See the CLOS MOP...