From a Java perspective which does it mean for a class to be public but not abstract, not interface and not final?
You may want to read deeply of some Java documentation, or something like Head First Java. It will answer all these questions: the clojure APIs are clojure-y sugar on top of them, as is mentioned above. The answers to these questions I think are invaluable for someone interested in being productive with Clojure, since Clojure gains so much by the Java ecosystem, but I think when you understand all these concepts you will see that only a subset are strictly necessary to solve your problem.
However, having said that, and given that I like to explain these kinds of things…
These are all properties that a class can have, and govern what can be done with the class. They come in a few different categories, but I think they revolve around three key concepts: accessibility, extensibility, and instantiability.
These concepts correspond to basic syntax in the Java language that one encounters in even the simplest examples. Here are two examples for discussion:
package com.jingibus.example;
public class MyClass extends Object implements MyInterface {
public String getName() {
return "MyClass";
}
}
package com.jingibus.example;
public interface MyInterface {
String getName();
}
First, notice that the interface has no implementation. This is the key difference between classes and interfaces: an interface is nothing more than a set of methods that an instance must implement to satisfy the interface. A class, on the other hand, always describes a concrete object in memory. Even non-instantiable classes contain their own data and implementation details, and so conceptually are set apart from interfaces, which never do.
Now to address the aforementioned three concepts. First: accessibility.
Acessibility
This class’s accessibility is public
. Accessibility defines where one can refer to this class; public
is “everyone, everywhere”, private
is “only within this class file,” and so on. These accessibilities are all mutually exclusive. Accessibility guarantees can be bypassed if necessary. This is discouraged, but it is possible by using Java’s mutable reflection APIs.
Next up:
Extensibility
Extensibility is which types can extend which other types. There are two sides to this question: who can extend us, and who can we extend?
Who can extend my type?
You won’t see anything in the example above that pertains to this, because this behavior is implicit. By default, classes are open for extension, as are abstract classes and interfaces. (“Abstract” is an instantiability notion addressed later.) A class may only be extended by another class, but an interface may be extended by either an interface or a class.
final
modifies this behavior. If I wrote public final class MyClass { ... }
, no other class could extend my class. Non-instantiable types like interfaces and abstract classes cannot be used without extending them, so final
has no meaning for them and is not valid.
So much for the question of which types can extend my class or interface. Now for the other side of the coin:
What types can I extend?
To frame the answer to this question, it may help to consider the class not as a description of a set of objects, but as a description of a concrete implementation. In that light, the design of Java chose to avoid any confusion that might be introduced by defining complicated rules on how to inherit that implementation from two or more superclasses.
However, they wanted to retain the programming advantages that come from multiple type inheritance. So they introduced the concept of the interface. An interface has no implementation, so it can safely extend multiple superinterfaces without defining any rules for merging implementations. And therefore it is also safe for a class to implement as many interfaces as it likes.
So, having said that, here are the rules:
For a class, every class must extend exactly one other class, and may extend as many interfaces as it like. In the example above, no base class is provided, and so the base class defaults to Object. Object is the one exception to this rule: it is the root class, and does not extend any other class.
For an interface, every interface may extend as many interfaces as it likes.
Since the rules are so different between classes and interfaces, Java uses the word “implement” for the case where a class extends an interface, and “inherit” or “extend” for every other case. As a result, in Java code class and interface inheritance are easily distinguished (see the API for java.lang.Class). In Clojure’s reflect
it is not immediately apparent which entries in :bases
are classes and which are interfaces, though.
Whew. Now for the last bit:
Instantiability
Instantiability is whether one can create an instance of a type or not. Java uses the term “abstract” to refer to types that may not be instantiated.
As discussed above, interfaces never have an implementation, so interfaces are always abstract. A class may also be marked as abstract, though. This done for classes that are designed for use by subclassing.
I think that covers everything I wanted to write about. I hope it was useful.