Compile time error: The generic class may not subclass java.lang.Throwable
public class TestGenericClass<E> extends Exception {
/*Above line will give compile error, the generic class TestGenericClass<E> may
not subclass java.lang.Throwable*/
public TestGenericClass(String msg) {
super(msg);
}
}
Above compile time error is for the reason given in § jls-8.1.2 as below, and explained in this question:
It is a compile-time error if a generic class is a direct or indirect subclass of Throwable(§11.1.1).
This restriction is needed since the catch mechanism of the Java Virtual Machine works only with non-generic classes.
Question:
How it is restricted that subclass of java.lang.Throwable will not be generic class?
Or more generic question will be, how to restrict that subclasses of any class cannot be generic?
How it is restricted that subclass of java.lang.Throwable will not be
generic class?
Here's how OpenJDK compiler performs the check:
import com.sun.tools.javac.code.Symbol.*;
private void attribClassBody(Env<AttrContext> env, ClassSymbol c) {
....
// Check that a generic class doesn't extend Throwable
if (!c.type.allparams().isEmpty() && types.isSubtype(c.type, syms.throwableType))
log.error(tree.extending.pos(), "generic.throwable");
As you can see forbidden type is kind of harcoded, so you can't use the same technique for your custom class without compiler code customization.
Full source code
How it is restricted that subclass of java.lang.Throwable will not be generic class?
This was a decision to write a special case into the compiler itself. The reason why is detailed in this question. Basically, this is to do with a type being reifiable. You can read about this term here. In short, a type is reifiable if it's type is fully available at compile time. Generic types, for example, are not reifiable, because their types are removed by type erasure. Objects appearing in a catch block need to be reifiable.
Or more generic question, how to restrict that subclasses of a class cannot be generic?
Well there's a few options..
At present, there is no option within the normal bounds of Java to do this. It doesn't have some sort of final implementation that prevents genericity being applied to subclasses. The closest thing you can get to this, as explained in the comments, is to extend the compiler and add a rule specifically for your class. This solution sends shivers down my spine. Dodge it. It means that your code will only behave with your version of Java, and that anyone else who wants to use your code will have to install the same version.
Obviously, the other option is to extend Throwable, but this really isn't a good idea. It adds a whole bunch of functionality to your class, and adds a lot of new methods to the interface of your class, that you will never use. From an OOP point of view, you're sacrificing the integrity of your class for the benefit of having this feature.
If you're willing to delay the error until run time, you can use use reflection in the superclass constructor(s) to see if the subclass declares any type parameters.
public class Example {
public static class ProhibitsGenericSubclasses {
public ProhibitsGenericSubclasses() {
if (getClass().getTypeParameters().length > 0)
throw new AssertionError("ProhibitsGenericSubclasses prohibits generic subclasses (see docs)");
}
}
public static class NonGenericSubclass extends ProhibitsGenericSubclasses {}
public static class GenericSubclass<T> extends ProhibitsGenericSubclasses {}
public static void main(String[] args) {
System.out.println(new NonGenericSubclass());
System.out.println(new GenericSubclass<Object>());
}
}
This code prints
Example$NonGenericSubclass#15db9742
Exception in thread "main" java.lang.AssertionError: ProhibitsGenericSubclasses prohibits generic subclasses (see docs)
at Example$ProhibitsGenericSubclasses.<init>(Example.java:12)
at Example$GenericSubclass.<init>(Example.java:17)
at Example.main(Example.java:21)
If you want to prohibit type parameters of all classes in the hierarchy, not just the most-derived class, you'll need to walk up the hierarchy using Class#getSuperclass().
Related
This is a tricky one - I have a java interface that I want to implement in scala:
public interface Foo {
public void bar(scala.Array arr);
}
Is it even possible to implement in scala? when I try:
class FooImpl extends Foo {
override def bar(arr: Array[_]): Unit = ???
}
I get:
Error:(13, 7) class FooImpl needs to be abstract, since method bar
in trait Foo of type (x$1: Array)Unit is not defined
(Note that Array does not match Array[_]. To implement a raw type, use
Array[_])
class FooImpl extends Foo {
The error message is giving you the answer for any generic type other than Array (after replacing the name, of course):
To implement a raw type, use Array[_]
"Raw type" is what Java calls a generic type used without a type parameter and e.g. https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html explains why you should not use them except to interface with now horribly obsolete pre-Java-5 code. So if it is at all an option, you should fix the Java interface in the first place.
Now, why does this not work for Array? It's a special type, which is really built into compiler. Its instances are real JVM arrays, which don't have a common type in Java. So when it's used in Scala code, the compiled bytecode doesn't use scala.Array at all. I guess that it only exists as a JVM type (unlike e.g. scala.Any or scala.Null) to put the static methods there, but all instance methods are defined as throw new Error(). It seems the error message didn't take this unique case into account.
So, the answer is: no, it can't be implemented in Scala, as far as I am aware. But it can't be non-trivially implemented in Java either. And even for trivial implementations, you'd run into the same issues when trying to write code using it.
To make the code work you either have to
Make the FooImpl declaration as abstract class
Implement the bar method
because "Java interfaces don’t implement behaviour".
For your reference see this page.
First I want to clarify that I don't have any real business requirements for that, It's a purely theoretical question.
Assuming that we have these two Interfaces :
public interface SuperInterface {
void doSuperStaff();
void doComStaff();
}
public interface SubInterface extends SuperInterface {
// Something here to invalidate doSuperStaff()
}
Is there any way to invalidate / disable the doSuperStaff() for all classes that implement the SubInterface? So only the classes that directly implement SuperInterface can use that method and override it.
NB: I know that we can resolve that in a conceptual manner, but I want to know if there is a way to make that possible technically: using annotations for example ( like the #Deprectaed, which only instructs the compiler that the method is deprecated.)....
Limited, but the following helps a bit.
public interface SubInterface extends SuperInterface {
#Deprecated
void doSuperStaff();
}
Or even
public interface SubInterface extends SuperInterface {
#Deprecated
default void doSuperStaff() {
throw new UnsupportedOperationException("...");
}
}
UPDATE If it's purely theoritical and you are not stuck with a legacy design you can't change, then it's bad idea to try and remove Super interface methods on a sub-interface (or class). It's indicative the design is wrong (Dog -> Animal (useLegs, hasBody), Owl -> Animal (useLegs-??, hasBody). useLegs in this case doesn't belong in Animal.
But if you have legacy code you want to remove it from, and enforce it with Compile-time errors, this approach will work.
You can remove the method with Aspects. Create a pointcut that triggers when the method is called, add Around Advice which is triggered on that pointcut and throws an unsupported operation exception rather than proceed.
With AspectJ Spring syntax it looks something like this (Syntax details here -http://www.eclipse.org/aspectj/doc/next/adk15notebook/ataspectj-pcadvice.html)
#Around("call(* SubInterface.doSuperStuff())")
public Object removeMethod(ProceedingJoinPoint thisJoinPoint) {
throw new UnsupportedOperationException("...");
}
You can also use the native AspectJ language and it's Eclipse plugin to have Eclipse (or your build) show a compile error on the call site if any code attempts to use it. I think that would look something like this (https://eclipse.org/aspectj/doc/released/adk15notebook/annotations-decp.html)
declare error : call(* SubInterface.doSuperStuff())
: "Method doSuperStuff removed from SubInterface";
As you said the answer is NO.
This is simple illustration, why this feature cannot be added.
Firstly the meaning of Interface in Java is Behavior
Suppose if I create a new interface AdavancedComparable<T> which extends java.lang.Comparable<T> and if I deprecate the public int compareTo(T o); in my AdvancedComparable interface and add my own method like advancedCompare(T o);
public interface AdavancedComparable<T> extends Comparable<T> {
// invalidate/deprecate for compareTo method using requested feature somehow
public int advancedCompare(T o);
}
Any method which is accepting Comparable<T> type parameter will also accept AdvancedComparable<T> type parameter, but when the method tries to call compareTo, it will break if the feature you asked is implemented.
Suppose if compiler updated to recognize this issues and made to throw compile time error, that's fine, but it also has to support the legacy code. Remember the Generics case, many classes which altered to support generic type, supports Raw type too (Like List, Class etc). Just to support legacy code. But in our case it is difficult to do so, I feel.
Can not you use super Abstract Class which would implement doSuperStuff() and other concrete class could extend it to override other method.
You can always cast a subtype to a supertype, and invoke methods in the supertype.
However, there is a way to prevent overriding --
public interface SuperInterface
Object doSuperStaff(); // return value doesn't matter, can be null
public interface SubInterface extends SuperInterface
default Foo doSuperStaff() { ... }
Here, Foo is a package-private type. Subclasses of SubInterface (in different packages) have no way to override this method, because they can't access Foo.
It's also possible to use a private class Foo there.
I'd like to use define a generic class in java, that can only be instantiated using my custom data types that all share the same base class. Is it possible to do so without checking the datatype at runtime? Furthermore I'd like to prohibit instantiating a generic class without providing a datatype.
Edit:
I writing a java wrapper for my c++ library and therefore the java class should only allow wrapper classes for my c++ datatypes as parameters. I just tried using bounded type parameters, as suggested, but then I can still instantiate an object like this:
MyClass c = new MyClass();
This is basically the code:
public class MyClass<T extends MyType>
{
public MyClass()
{
}
public doSomething(MyOtherClass<T> other)
{
}
}
What you are looking for is called Bounded Type Parameters:
There may be times when you'll want to restrict the kinds of types that are allowed to be passed to a type parameter. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.
public <U extends Number> void inspect(U u){
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}
Due to type erasure -- and the now very old requirement for backwards-compatibility -- there is no way to require that a class is instantiated with generic type parameters. Two solutions:
Heed the warnings. Let the developers who don't feel the wrath of run-time exceptions :-)
Only allow access through classes that extend the generic class (and provide type parameters). For instance, class MyClassFoo extends MyClass<Foo> and then hide the MyClass constructor from external code.
Neither is ideal, but it is what it is. Both C++ and .NET work differently, but then again they are C++/.NET and not Java :-)
Happy coding.
If you're worried about others creating their own subclass of your base class and using this in your generic type, the only way you can prohibit this is to control extension to your base class.
One way is to protect the base class's constructor using default visibility and put the concrete implementations in the same class. Make those concrete implementations final, or make their constructors private.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
java Enum definition
Better formulated question, that is not considered a duplicate:
What would be different in Java if Enum declaration didn't have the recursive part
if language designers were to use simply Enum<E extends Enum> how would that affect the language?
The only difference now would be that someone coud write
A extends Enum<B>
but since it is not allowed in java to extend enums that would be still illegal.
I was also thinking about someone supplying jvm a bytecode that defines smth as extending an enum - but generics can't affect that as they all are erased.
So what is the whole point of such declaration?
Thank you!
Edit
for simplicity let's look at an example:
interface MyComparable<T> {
int myCompare(T o);
}
class MyEnum<E extends MyEnum> implements MyComparable<E> {
public int myCompare(E o) { return -1; }
}
class FirstEnum extends MyEnum<FirstEnum> {}
class SecondEnum extends MyEnum<SecondEnum> {}
what's wrong with this class structure? What can be done that "MyEnum<E extends MyEnum<E>>" would restrict?
This is a common question, and understandably so. Have a look at this part of the generics FAQ for the answer (and actually, read as much of the whole document as you feel comfortable with, it's rather well done and informative).
The short answer is that it forces the class to be parameterized on itself; this is required for superclasses to define methods, using the generic parameter, that work transparently ("natively", if you will) with their subclasses.
Edit: As a (non-)example for instance, consider the clone() method on Object. Currently, it's defined to return a value of type Object. Thanks to covariant return types, specific subclasses can (and often do) define that they return a more specific class, but this cannot be enforced and hence cannot be inferred for an arbitrary class.
Now, if Object were defined like Enum, i.e. Object<T extends Object<T>> then you'd have to define all classes as something like public class MyFoo<MyFoo>. Consequently, clone() could be declared to return a type of T and you can ensure at compile time that the returned value is always exactly the same class as the object itself (not even subclasses would match the parameters).
Now in this case, Object isn't parameterized like this because it would be extremely annoying to have this baggage on all classes when 99% of them aren't going to utilise it at all. But for some class hierarchies it can be very useful - I've used a similar technique myself before with types of abstract, recursive expression parsers with several implementations. This construct made it possible to write code that was "obvious" without having to cast everywhere, or copy-and-paste just to change concrete class definitions.
Edit 2 (To actually answer your question!):
If Enum was defined as Enum<E extends Enum>, then as you rightly say, someone could define a class as A extends Enum<B>. This defeats the point of the generic construct, which is to ensure that the generic parameter is always the exact type of the class in question. Giving a concrete example, Enum declares its compareTo method as
public final int compareTo(E o)
In this case, since you defined A to extend Enum<B>, instances of A could only be compared against instances of B (whatever B is), which is almost certainly not very useful. With the additional construct, you know that any class that extends Enum is comparable only against itself. And hence you can provide method implementations in the superclass that remain useful, and specific, in all subclasses.
(Without this recursive generics trick, the only other option would be to define compareTo as public final int compareTo(Enum o). This is not really the same thing, as then one could compare a java.math.RoundingMode against a java.lang.Thread.State without the compiler complaining, which again isn't very useful.)
OK, let's get away from Enum itself as we appear to be getting hung up on it. Instead, here is an abstract class:
public abstract class Manipulator<T extends Manipulator<T>>
{
/**
* This method actually does the work, whatever that is
*/
public abstract void manipulate(DomainObject o);
/**
* This creates a child that can be used for divide and conquer-y stuff
*/
public T createChild()
{
// Some really useful implementation here based on
// state contained in this class
}
}
We are going to have several concrete implementations of this - SaveToDatabaseManipulator, SpellCheckingManipulator, whatever. Additionally we also want to let people define their own, as this is a super-useful class. ;-)
Now - you will notice that we're using the recursive generic definition, and then returning T from the createChild method. This means that:
1) We know and the compiler knows that if I call:
SpellCheckingManipulator obj = ...; // We have a reference somehow
return obj.createChild();
then the returned value is definitely a SpellCheckingManipulator, even though it's using the definition from the superclass. The recursive generics here allow the compiler to know what is obvious to us, so you don't have to keep casting the return values (like you often have to do with clone(), for example).
2) Notice that I didn't declare the method final, since perhaps some specific subclasses will want to override it with a more suitable version for themselves. The generics definition means that regardless of who create a new class or how it is defined, we can still assert that the return from e.g. BrandNewSloppilyCodedManipulator.createChild() will still be an instance of BrandNewSloppilyCodedManipulator. If a careless developer tries to define it to return just Manipulator, the compiler won't let them. And if they try to define the class as BrandNewSloppilyCodedManipulator<SpellCheckingManipulator>, it won't let them either.
Basically, the conclusion is that this trick is useful when you want to provide some functionality in a superclass that somehow gets more specific in subclasses. By declaring the superclass like this, you are locking down the generic parameter for any subclasses to be the subclass itself. This is why you can write a generic compareTo or createChild method in the superclass and prevent it from becoming overly vague when you're dealing with specific subclasses.
I am extending a class defined in a library which I cannot change:
public class Parent
{
public void init(Map properties) { ... }
}
If I am defining a class 'Child' that extends Parent and I am using Java 6 with generics, what is the best way to override the init method without getting unchecked warnings?
public class Child extends Parent
{
// warning: Map is a raw type. References to generic type Map<K,V> should be parameterized
public void init(Map properties) { }
}
If I add generic parameters, I get:
// error: The method init(Map<Object,Object>) of type Child has the same erasure as init(Map) of type Parent but does not override it
public void init(Map<Object,Object>) { ... }
// same error
public void init(Map<? extends Object,? extends Object>) { ... }
// same error
public void init(Map<?,?>) { ... }
This error occurs regardless of whether I use a specific type, a bounded wildcard, or an unbounded wildcard. Is there a correct or idiomatic way to override a non-generic method without warnings, and without using #SuppressWarnings("unchecked")?
Yes, you have to declare the overriding method with the same signature as in the parent class, without adding any generics info.
I think your best bet is to add the #SuppressWarnings("unchecked") annotation to the raw-type parameter, not the method, so you won't squelch other generics warnings you might have in your own code.
Short answer: no way to do that.
Unsatisfying answer: disable the (specific) warnings in your IDE/build.xml.
If you cannot change the library, alas, you have to stick with non-generic methods.
The problem is that, despite after type erasure both init() have the same signature, they may in fact be different methods -- or the same(*). Compiler cannot tell should it do override or overload, so it's prohibited.
(*)
Suppose the library developer meant init(Map<String,Integer>). Now you are implementing init(Map<String,String>). This is overloading, and two methods should exist in the vtable of Child class.
But what if the library developer meant init(Map<String,String>)? Then it's overriding, and your method should replace original init in Child class, and there would be only one method in the vtable of Child.
P.S. I hate how Generics implemented in Java :-(
I think above answer meant to say #SuppressWarnings("rawtypes") instead.
You have to declare the method with the same signature as the parent, and therefore you will get warnings when you compile. You can suppress them with #SuppressWarnings("unchecked")
The reason why there is no way to get rid of this is that the warnings are there to let you know that it's possible to create Collections with invalid types in them. The warnings should only go away when all code that might allow that has been removed. Since you are inheriting from a non-generic class it will always be possible to create a Collection with invalid contents.