How to use Comparable<T>? - java

I have the following interface
public interface Identifiable {
public Comparable<?> getIdentifier();
}
And an implementing class
public class Agreement implements Identifiable {
private Long id;
public Comparable<Long> getIdentifier() {
return id;
}
}
EDIT: Note that there may be other implementations with different types of identifiers.
Now I would like to, yes, compare the comparables:
// Agreement a;
// Agreement b;
...
if (a.getIdentifier().compareTo(b.getIdentifier()) {
...
But the compareTo gives me the following compiler error:
The method compareTo(Long) in the type Comparable<Long> is not applicable for the arguments (Comparable<Long>)
How is this interface supposed to be used with Generics?

Comparable<T> is meant to be used as an upper bound for a generic parameter:
public interface Identifiable<T extends Comparable<T>> {
public T getIdentifier();
}
public class Agreement implements Identifiable<Long> {
private final Long id;
public Long getIdentifier() {
return id;
}
}
This forces the return type to be a T, not just something that can be compared to a T.
Your code is inherently unsafe.
To understand why, consider the following code:
class Funny implements Comparable<Long> { ... }
class Funnier implements Identifiable {
public Comparable<Long> getIdentifier() {
return new Funny();
}
}
Identifiable<Funny> funnier;
funnier.getIdentifier().compareTo(funnier.getIdentifier());
// You just tried to pass a Funny to compareTo(Long)

Related

Generics Entity and EntityDTO similar methods

Is there any way to unite getEntityId and getEntityDTOId?
public class Entity {
private Integer id;
public Integer getId() {return id;}
}
public class EntityDTO {
private Integer id;
public Integer getId() {return id;}
}
public class EntityProcessing {
public Integer getEntityId(Entity entity) {
return entity.getId();
}
public Integer getEntityDTOId(EntityDTO entityDTO) {
return entityDTO.getId();
}
}
I've read about Generics, but can't understand how to implement them in such a case.
You can for example create some interface:
public interface WithId {
Integer getId();
}
and implement it (you need to implement this interface in all the classes you want to use in the EntityProcessing.getId method):
public class Entity implements WithId { // add implements ...
private Integer id;
#Override // add to mark that it's method from the interface
public Integer getId() {return id;}
}
And now you can create one method to get id from all the classes implementing WithId interface:
public Integer getId(WithId withId) {
return withId.getId();
}
The other option is to use abstract class containing the id field. But it's against Liskov Substitution Principle (L from SOLID object oriented programming principles).
And there is a limitation, that you can extend only one class in java, but you can implement multiple interfaces. So in my opinion better use interface like above, but for completeness I added this solution as well.
public abstract class WithId {
private Integer id;
public Integer getId() {
return id;
}
}
and extend the abstract class:
public class Entity extend WithId { // in this case add extend ...
// you don't need to add anything here,
// because field and the method are already present in the base class
}
And usage is the same as in the first solution above.
This solution at the first glance seems to be better because you can write the method only once in the abstract class, but you have to remember the limitations (you can extend only one class in java), because if you want in the future add another common field like e.g. createdDate - you can implement second interface e.g. WithCreatedDate, but you cannot extend second class
The example you provided, doesn't actually need to use generics, but it looks like you're learning about generics:
public class Test {
public static void main(String[] args) {
Entity entity = new Entity();
EntityDTO entityDTO = new EntityDTO();
EntityProcessing<Base> a = new EntityProcessing<>();
System.out.println(a.getEntityId(entity));
System.out.println(a.getEntityId(entityDTO));
System.out.println(EntityProcessing.getId(entity));
System.out.println(EntityProcessing.getId(entityDTO));
}
}
interface Base {
public Integer getId();
}
class Entity implements Base {
private Integer id = 1;
public Integer getId() {return id;}
}
class EntityDTO implements Base {
private Integer id = 2;
public Integer getId() {return id;}
}
// T must be a subtype of Base, otherwise, after generic erasure, the T type does not have a getId method
class EntityProcessing<T extends Base> {
public Integer getEntityId(T entity) {
return entity.getId();
}
// Generics Method
// T must be a subtype of Base, otherwise, after generic erasure, the T type does not have a getId method
// Note that there is no relationship between the <T> in the generic method and the <T> in the life of the generic class.You can completely replace the T here with an R, or any other char
// public static <F extends Base> Integer getId(F entity)
// public static <ABC extends Base> Integer getId(ABC entity)
// .....
public static <T extends Base> Integer getId(T entity) {
return entity.getId();
}
}

Java generics both methods have same erasure error

In my project, I have multiple services performing three basic operations - create, edit and search. For this, I am trying to create a generic service. Below is what I have come up with so far.
Search method will take a list of objects at runtime.
public interface GenericService<T> {
void update(T t);
void create(T t);
T search(List<?> t);
}
Also, I have created an abstract class where the common code for all services will be placed.
public abstract class AbstractService<T> implements GenericService<T> {
}
Here is my implementation
public class AccountService extends AbstractService<Account> implements GenericService<Account> {
#Override
public void update(Account account) { }
#Override
public void create(Account account) { }
#Override
public Account search(List<SearchCriteria> t) { return null; }
}
Here are my Account and SearchCriteria classes
public class Account {
private String accountNumber;
private Date openingDate;
// more fields
// getter setter removed for brevity
}
Search criteria class
public class SearchCriteria {
private String key;
private String value;
// getter setter removed for brevity
}
Problem: on line public Account search(List t) { return null; }, getting compilation error saying
'search(List)' in
'com.test.AccountService' clashes with
'search(List)' in 'com.test.GenericService';
both methods have same erasure, yet neither overrides the other
In order for
public Account search(List<SearchCriteria> t) { ...}
to override
T search(List<?> t);
The arguments must be the same after type parameter substitution, but ? is not SearchCriteria.
Therefore, if you want to keep these methods (the inheritance looks a bit wild to me), you'll need to parameterise the types further.
public interface GenericService<T, C> {
// ...
T search(List<C> t); // probably change that parameter name
}
public abstract class AbstractService<T, C>
implements GenericService<T, C>
{
}
public class AccountService
extends AbstractService<Account, SearchCriteria>
implements GenericService<Account, SearchCriteria> // unnecessary
{
// ...
#Override
public Account search(List<SearchCriteria> t) { /* ... */ }
}
Changing List<?> to List<SearchCriteria> in GenericService will solve the error. There is no benefit in using a wildcard if the search method will always take a list of SearchCriteria objects in every service implementation.
If, however, you want to make this generic as well, you can introduce a second type parameter.

Does a Java enum itself extend an interface I can make use of?

I have several enums which implement an interface I've defined. Now I'd like to provide some boilerplate operations on these enums based on their common interface as well as their common enum ancestry. Is this possible?
In other words, I have:
public enum Car implements Vehicle {
FORD, HONDA;
}
public interface Vehicle {
String getLicensePlate();
}
And I'd now like to write something like this, perhaps in a default interface method or some other common place:
public static showLicensePlates(Vehicle.class vEnum) {
for(Vehicle v : vEnum.values()) {
System.out.println(v.getLicensePlate());
}
}
Notice how I'm relying on enum's "values()" method, so the interface must be an enum for this to work. How can I specify that this interface must be an enum? Or if that's not possible, how an I write boilerplate methods to operate on enums in general?
What you want is for the showLicensePlates() method to only take an argument that is both a vehicle and enum. This is done with generics:
public <T extends Enum & Vehicle> showLicensePlates(T vEnum) {
//do stuff
}
Can call
Vehicle.class.getEnumConstants()
If it does not return null,then its an enum.
Java doc says:
Returns the elements of this enum class or null if this Class object does not represent an enum type.
Since you have the interface and the Enumerator implemets such... then you can adapt the enum to return some Ids and...
interface Vehicle {
String getLicensePlate();
}
enum Car implements Vehicle {
FORD("F-007"), HONDA("H-860");
private final String id;
private Car(String id) {
this.id = id;
}
#Override
public String getLicensePlate() {
return this.id;
}
}
...and play with the Constraints in the method ShowLicenseMEthod.
public class Abc {
public static void main(String[] args) {
Abc c = new Abc();
c.showLicensePlates(Car.class);
}
public <E extends Enum<E> & Vehicle> void showLicensePlates(Class<E> vEnum) {
for (E v : vEnum.getEnumConstants()) {
System.out.println(v.getLicensePlate());
}
}
}
Then you can pass ALL the enum classes you have and the method will print the LicensePlates of all the Enum Constants...

Generics: generic class based on generic class

I'm trying to create a generic service that is based on a class with a generics based collection
public class GenericClass<T> {
List<T> results;
public List<T> getResults() {
return results;
}
}
Im just not sure how to create a service that is based on this GenericClass and has a concrete implementation of T. I would expect something like
public class ServiceManagerImpl<GenericClass<T>> implements ServiceManager<GenericClass<T>> {
public GenericClass<T> getMyClass() {
...
}
}
But the compiler doesn't like this. Any ideas how to do this?
Marc
You are close... just pass the T through:
public class ServiceManagerImpl<T> implements ServiceManager<GenericClass<T>> {
public GenericClass<T> getMyClass() {
...
}
}
I can suggest the following implementation that doesn't break the rules of JLS:
// ServiceManager.java
public interface ServiceManager<E, T extends GenericClass<E>> {
}
// ServiceManagerImpl.java
public class ServiceManagerImpl<E, T extends GenericClass<E>> implements ServiceManager<E, T> {
public T getMyClass() {
return null;
}
}
The content between <> is called Type Parameters, and GenericClass<T> is not a valid Type Parameter in declaration.
Quote from java generic guide
A generic class is defined with the following format:
class name<T1, T2, ..., Tn> { /* ... */ }
The type parameter section, delimited by angle brackets (<>), follows the class name. It specifies the type parameters (also called type variables) T1, T2, ..., and Tn.
so, you need to use GenericClass<T> in implementation, not in declaration.
// declaration
public class ServiceManagerImpl<YourGenericType> implements ServiceManager<YourGenericType> {
public YourGenericType getMyClass() {
...
}
}
// implementation
ServiceManager<GenericClass<Object>> sm = new ServiceManagerImpl<GenericClass<Object>>();
public class ServiceManagerImpl<T extends GenericClass<T>> implements ServiceManager<T extends GenericClass<T>> {
public GenericClass<T> getMyClass() {
...
}
}
I am not sure my answer is legal , but it seems meet your requirement:
public class ServiceManagerImpl<T extends GenericClass> implements ServiceManager<T>
{
#Override
public T getMyclass() {
//do your work here;
}
}
Although it may have a unchecked warning when I declare this class , but this really does!
ServiceManager<GenericClass<Integer>> manager = new ServiceManagerImpl<GenericClass<Integer>>();//passed
You should try likes this;
public class ServiceManagerImpl<GenericClass<Object>> implements ServiceManager<GenericClass<Object>> {
public GenericClass<Object> getMyClass() {
...
}
}
You can replace Object with Integer or String or any data types as you likes.

Comparator for Generic Interface Without Warnings

Given:
public interface PrimaryKey<Key extends Comparable> {
Key getKey();
}
and
public class PrimaryKeyComparator implements Comparator<PrimaryKey> {
public int compare(PrimaryKey first, PrimaryKey second) {
return first.getKey().compareTo(second.getKey());
}
}
This combination works, but gives warnings about raw types. I've tried various ways of adding the type arguments, but every combination I've tried breaks the code.
Try this:
public interface PrimaryKey<TKey extends Comparable<TKey>> {
TKey getId();
}
public class PrimaryKeyComparator<TKey extends Comparable<TKey>>
implements Comparator<PrimaryKey<TKey>> {
public int compare(PrimaryKey<TKey> first, PrimaryKey<TKey> second) {
return first.getId().compareTo(second.getId());
}
}

Categories

Resources