Can, and if yes how, I access the generic parameter of another generic parameter, without also specifying it?
The example below is simplified from my current situation. All members and methods are omitted as they aren't relevant to the situation. LibraryRepository is a JPA/Spring-Type expecting an ENTITY and an ID.
abstract class AbstractEntity<ID> {}
class ConcreteEntity extends AbstractEntity<Long> {}
interface AbstractRepository<ENTITY extends AbstractEntity<?????>> extends LibraryRepository<ENTITY, ?????> {}
//Desired declaration:
interface ConcreteRepository extends AbstractRepository<ConcreteEntity> {}
Without specifying Long on AbstractRepository, what to write instead of the two ?????, if that is at all possible?
For the sake of question-scope, please answer the question regarding generics, not how to implement spring-repositories in a better way. I'm glad for hints about that in the comments though.
interface AbstractRepository<ENTITY extends AbstractEntity<?????>> extends LibraryRepository<ENTITY, ?????> {}
One (particularly useful) way of thinking about generics is that they link types together. If you declare a new typevar and use it in only one place, because of erasure, that is effectively useless. Use it in two places and now you've told the compiler that the two places you used your T are linked: They can be anything, as long as they are the same thing.
This way of thinking also provides some insight here: Clearly you want your first ????? to be linked to your second ?????: For them to be equal.
The way to do that, then, is to declare a new typevar and use it:
interface AbstractRepository<ENTITY extends AbstractEntity<Q>, Q>
extends LibraryRepository<ENTITY, Q> {}
Unfortunately, that means AbstractRepository now gained a type variable, and I gather you didn't want that to happen.
Unfortunately, java has no way to link types without a type variable.
As a general rule of thumb, if you mix class hierarchies (things extending things implementing things), and lots of generics, you end up with looooots of generic parameters, and some of those will feel like DRY violations. The solution is to either accept it, or to not do one of those two things (Use composition over inheritance, or reduce the type variables you're using, or move them to methods instead), or to use a bunch of hacky reflection and 'warning-casts' (where you cast things to a typevar, which doesn't actually typecheck anything and tends to result in ClassCastExceptions in bizarre places: Places that don't even have a cast anywhere in the line, and not the place with the faulty code. Resulting in long and arduous bughunting exercises.
Maybe this is what you're trying to avoid, but I think you'd specify the generic parameter of your AbstractEntity as a parameter in AbstractRepository, something like this:
interface LibraryRepository<ENTITY, ID> {}
abstract class AbstractEntity<ID> {}
class ConcreteEntity extends AbstractEntity<Long> {}
interface AbstractRepository<ENTITY extends AbstractEntity<ID>, ID>
extends LibraryRepository<ENTITY, ID> {}
interface ConcreteRepository extends AbstractRepository<ConcreteEntity, Long> {}
I don't know how otherwise the compiler would be able to type-check the generic parameters for LibraryRepository.
Related
In JDK 11 I'm creating a generic class called "Collection" such that whatever type is provided for the type parameter must implement the Comparable interface. The class declaration is currently as follows:
public class Collection <T extends Comparable<T>>
Originally I thought the class declaration should be this:
public class Collection <T implements Comparable<T>>
but JDK didn't like that.
So my question is why the class declaration is the former rather than the latter. Don't we extend classes and implement interfaces?
With respect to the syntax of bounds declaration, the language architects who added generics in Java 5 faced the following choice:
Mirror the declaration structure (with separate extends and implements bounds), or
Choose one form for upper-bounded types (e.g., T extends Foo, T <: Foo, etc.)
The latter was (sensibly, IMO) viewed as the more pragmatic choice, as at the point of declaring a type variable, whether the supertype happens to be a class or an interface is not material, and having a fussy syntax that required clients to use exactly the right keyword (and would have made compound bounds like <T extends ArrayList implements Serializable> even uglier) would likely be viewed as just making things harder to use with no actual benefit to either writers or readers of code.
Such decision often come about as a language is evolved, where strict consistency with precedent would only make things more difficult for no good benefit, and so language designers sometimes (after carefully considering the pros and cons of both alternatives) choose to break with precedent for the sake of a better result.
Collection is already in java.util. Creating another class with that name is going to confuse everybody; I suggest you pick something else.
Generics is about types in general. The word extends is used, and this kinda mirrors the same use of that keyword in, for example, class Foo extends Bar, but it's not quite the same meaning. The point is, the spec says it is extends and not implements regardless of what comes after, and there's not much point in going any further than 'spec says so' on this one.
Would you therefore want implements E or extends E, given that E may be a class or an interface? Unless you want a third keyword (possibly context-sensitive) then it doesn't make sense to distinguish.
I'm creating something like this and got struck about the usage of generics in java.
Idea: Producer produces something of type T and consumers contains command objects, command objects holds different mediators. Mediators holds objects of type Subject and updates values of type T
Note: I'm doing this to understand how generics works in terms of inheritance of the generic types and composition of the type parameter definitions in generic type intefaces and concrete classes, so please don't bother about rationale of the design.
Interfaces definitions:
Composition:
IObserver
ISubject which holds object of type T and IObserver.
IMediator holds objects of type ISubject and type T
ICommand holds objects of type IMediator and type T
IProducerConsumer holds objects of type T and ICommand.
There are some concrete Objects for the corresponding interfaces.
I defined interfaces like this:
public interface IObserver<T>
public interface ISubject<T,O extends IObserver<T>>
Cool until now. But Now the problems started.
public interface IMediator<T,S extends ISubject<T,O>, O extends IObserver<T>>
compiler is forcing me to do this. I mean O extends IObserver<T> as above. So, I infered that I can't define like below
public interface IMediator<T,S extends ISubject<T,O extends IObserver<T>> >
I concluded: that inner type parameter definition must not be expanded as above.
So, finally happy with
public interface IMediator<T,S extends ISubject<T,O>, O extends IObserver<T>>
Now mess started in ICommand
public interface ICommand <T,M extends IMediator<T, ?, ?>>,
I'm struck now compiler is not accepting many of my possibilities even what inference i made as above. I mean
public interface ICommand <T,M extends IMediator<T, S, o>, S extends ISubject<T, IObserver<T>>,O extends IObserver<T>>
is not working.
I don't want to user wild card I want to tell to the compiler something more concrete.
My questions are:
Is my inference correct as in ICommand definition.
How to interpret the above case studies.
What are the best defintions assuming that I want to insert T and must able to get and put.
What is the rules and relations of the type parameter definitions in interface and implemented classes.
Please explain ?
Generics with Bound Parameters (no wildcards)
Is my inference correct as in ICommand definition?
No. Two reasons
You have written a small 'o' while passing it to Mediator. (I guess it's just a typing mistake.)
You passed IObserver<T> in stead of O to ISubject which would definitely cause a parameter bound mismatch.
Correct Version:
interface ICommand<T, M extends IMediator<T, S, O>, S extends ISubject<T, O>, O extends IObserver<T>>
How to interpret the above case studies?
The first thing you'd need to understand that you have one unknown type T and five interfaces.
Therefore you would have total six concrete types which have to be included progressively in the interface declarations. (You explicitly asked not to bother about rationale of the design.)
If you write them in a correct order, it becomes much more manageable.
Interface declarations:
interface IObserver<T>
interface ISubject<T, O extends IObserver<T>>
interface IMediator<T, O extends IObserver<T>, S extends ISubject<T,O>>
interface ICommand<T, O extends IObserver<T>, S extends ISubject<T, O>,
M extends IMediator<T, O, S>>
interface IProducerConsumer<T, O extends IObserver<T>, S extends ISubject<T, O>,
M extends IMediator<T, O, S>, C extends ICommand<T, O, S, M>>
What are the best defintions assuming that I want to insert T and must able to get and put?
If you want to get and put object of type T, what you probably need is bunch of interfaces which take only one parameter T. Generics will enforce that all would be compatible as T will be replaced by same type everywhere.
Your current system is too rigid. In real scenario, you would never have so many implementations of these interfaces (unless you are re-implementing facebook in java) so that you'd have many possible combinations of the implementations and you want to ensure compatibility.
Generics enforces type-safety by applying restrictions which are good. But you should not put restrictions just because you can put them. You are losing flexibility, readability and maintainability of your code.
You should add bounds only when you need them. They should not affect the design in any way before contracts between interfaces have been decided.
Possibly sufficient way:
interface IObserver<T>
interface ISubject<T>
interface IMediator<T>
interface ICommand<T>
interface IProducerConsumer<T>
What is the rules and relations of the type parameter definitions in interface and implemented classes?
The only relation between type parameters in interfaces and implementing class that I can think of is that implementing class has to provide a type to replace the generic type parameter.
In some cases, that type can again be a generic type in which case the responsibility of providing concrete type is forwarded to the code using the class reference or another class which extends that class. It may even be recursive!
The rules are not written in the language, in stead, you are applying all the rules on this mechanism when you make any type parameter bound. So as long as you are supplying a type which qualifies against all of your rules, you are good to go.
More rules means more robust but less flexible/readable. So do the trade of wisely.
Two simple cases:
// General way
private class ProductObserver implements IObserver<Product> { }
private ProductObserver productObserver;
// Aspect oriented way
private class LoggerObserver<T> implements IObserver<T> { }
private LoggerObserver<Product> loggerObserver;
Lastly, I'd suggest you to read (comprehensive) Java Generics FAQ by Angelika Langer if you have any further doubt.
If you keep experimenting like this, you might as well end up inventing a design pattern. Don't forget to share it with us when you do :D
Hope this helps.
Good luck.
Can someone tell me what the differences between the first and second codes are?
MaxPQ stands for priority queue, which is a collection of "Key" objects that can be compared with each other.
Code 1:
public class MaxPQ<Key extends Comparable<Key>>{
...
}
Code 2:
public class MaxPQ<Key implements Comparable<Key>>{
...
}
The second code doesn't compile, but it is not intuitive to me why we need to extend instead of implement interfaces when using a generic.
The difference is pretty straightforward: second code snippet does not compile and never will. With generics you always use extends, for both classes and interfaces. Also super keyword can be used there, but it has different semantics.
There is no implements in generics. The second code is invalid. You probably confusing with :
public class MaxPQ implements Comparable<Key> {
...
}
I assume it was decided to use extends for both interfaces and classes, because in the case of generic class declaration it does not make any difference is type argument bound to interface or to class.
Of course meaning of extends is quite different from its typical usage in class definition. Angelika Langer do have nice text about different meanings of extends in Java: Does "extends" always mean "inheritance"?
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 was trying to find a way to create an interface/abstract method with the declaring/extending class as return type. (e.g. classA extends interfaceA, and the method should return a ClassA object).
Now I found some post that the compiler wont complain about something like that, but the JVM isn't able to handle such thing, meaning this mechanic just doesn't exist in java.
So I came up with the following idea, from wich I have no idea if it is technically save enough to do. (e.g. will it cause an loop)
public interface ISomeInterface<T extends ISomeInterface<T>> {
public T get();
}
meaning you can use it in this way. Although this doesnt force an external user to use the extending class, it at least gives the opportunity to do so if prefered:
public class ExtendingClass implements ISomeInterface<ExtendingClass>{
#Override
public ExtendingClass get(){}
}
Now this gives no compiler or runtime error, but I'm concerned if this would create any problems if used extensively.
I would appreciate if someone could confirm that this would or wouldn't cause problems. (any other feedback is welcome as well).
There's nothing wrong with this. It's actually a fairly common practice.
It's a very common practice. Examples include:
Enum<E extends Enum<E>>
BaseStream<T, S extends BaseStream<T, S>>
However, make sure you are aware of the limitations. The main one is that it doesn't work well with inheritance.
For example, if you have an interface
interface Animal<A extends Animal<A>>
you may decide to write a concrete implementation like this
class Duck implements Animal<Duck>
This works fine, but if you later decide you want to extend Duck, you won't be able to write this:
class MallardDuck extends Duck implements Animal<MallardDuck>
The reason you can't do this is that you can't implement the same generic interface with two different type parameters - since Duck already implements Animal<Duck>, it is not possible for MallardDuck to implement Animal<MallardDuck>.
So, make sure that if you use this pattern you think very carefully to begin with how you intend to implement the interface. It works with Enum because the language does not allow you to extend them, but if used too much this pattern can create a total mess.