I have generic class ConsumerTest<T, U> and I plan that T is mutable type and U is ekvivalent immutable type like <StringBuilder, String>, <MutableInt, Integer>, <MutableDouble, Double>, ... How can I write generic constructor which creates the mutable type from immutable? Here is my attempt:
import org.apache.commons.lang3.mutable.MutableDouble;
import org.apache.commons.lang3.mutable.MutableInt;
class ConsumerTest<T, U> {
private T value;
public <T, U> ConsumerTest(U u) {
this.value = new T(u); // compile error
}
public static void main(String[] args) {
ConsumerTest ctS = new ConsumerTest<StringBuilder, String>("Hello");
ConsumerTest ctI = new ConsumerTest<MutableInt, Integer>(666);
ConsumerTest ctD = new ConsumerTest<MutableDouble, Double>(11.11);
}
}
new T(u) is invalid because T isn't a type. In order to create an instance of a class, you need to know the type, and you don't in that context.
As another answer states, new T(u) is invalid syntax. One cannot use a type parameter as a new class to instantiate, because there is no guarantee that that particular class's constructor takes exactly one argument of that exact type.
In addition, you've created a generic constructor that defines its own T and U, which shadow the class's declarations of T and U. That's why you get a compiler error message such as "Cannot convert T to T". Remove the declarations of T and U from the constructor, but not from the class.
You still need to be able to construct an object of type T from one of type U, so provide a converter function. Note here that Java's built in Functions reverse the sense of U and T that you have.
class ConsumerTest<T, U> {
private T value;
public ConsumerTest(U u, Function<U, T> converter) {
this.value = converter.apply(u);
}
public static void main(String[] args) {
ConsumerTest ctS = new ConsumerTest<StringBuilder, String>("Hello", StringBuilder::new);
ConsumerTest ctI = new ConsumerTest<MutableInt, Integer>(666, MutableInt::new);
ConsumerTest ctD = new ConsumerTest<MutableDouble, Double>(11.11, MutableDouble::new);
}
}
There may be additional reasons you need to encapsulate this functionality in a class that you haven't shown, but you may not need a class such as ConsumerTest. Just create the functions.
Function<String, StringBuilder> ctS = StringBuilder::new;
Or you may not need to bother with the functions at all. Create the mutable objects directly.
StringBuilder sb = new StringBuilder("Hello");
Related
I need to create a container that provides a way for me to store elements of generic type, kind of like this effective java pattern but storing generic things
Is it possible to create a typesafe heterogeneous container where generic typed things are involved?
<T> void put(T ele, SomeTypedThing<T> genEle);
<T> SomeTypedThing<T> get(T ele);
I am fine to add the Class<T> as method param. example:
public static class Container {
Map<Class<?>, Set<?>> store = new HashMap<>();
public <T> void put(Set<T> ele, Class<T> type) {
store.put(type, ele);
}
public <T> Set<T> get(Class<T> type) {
return store.get(type);
}
}
would it be possible to achieve this?
Set<?> raw = store.get(type);
Set<T> typed = // some magic;
how, or why not? is it something that java doesn't do or is it something fundamental (so no language can do, or just doesn't make sense to do)
The problem is with the wildcard parameter on the Set. Instead of using a Set<?>, make it a Set<Object>, and everything works:
public static class Container {
Map<Class<?>, Set<Object>> store = new HashMap<>();
public <T> void put(T ele, Class<T> type) {
store.putIfAbsent(type, new HashSet<>());
store.get(type).add(ele);
}
}
The difference between Set<?> and Set<Object> is this:
A Set<?> could be a Set of any type - it could be a Set<String> or a Set<Integer>. And the java compiler wants to make sure that you are not trying to add a String object to a Set<Integer>.
On the other hand, a Set<Object> is just a Set that can contain instances of the Object class. And since String and Integer are both subclasses of Object, you can easily store strings and Integers into such a set.
Adding the method
public <T> Set<T> get(Class<T> type) {
return (Set<T>) store.get(type);
}
to the class gives a compiler warning about an unchecked cast. This warning can be safely ignored here, because you know that you added only elements of type T to that Set.
I stumbled upon this problem a few weeks ago as I needed a typesafe heterogenous container (THC) for literally any object (including generic interface implementations) AND any number of them (like two keys that provide a String for example).
Although this question is rather old, I'd like to provide another approach.
THCs are all about parameterizing the keys. So you can use a key object that wraps the class type instead of using the class type as key.
For example:
Key-Class:
static class Type<T> {
private final Class<T> object_type;
public Type(String name, Class<T> object_type){
this.object_type = object_type;
}
public Class<T> getObjectType() {
return object_type;
}
}
Container-Class:
static class Container{
private final Map<Type<?>, Object> properties = new HashMap<>();
public <T> T get(Type<T> type){
return type.getObjectType().cast(properties.get(type)); //no compiler complaints
}
public <T> void put(Type<T> type, T value){
properties.put(type, type.getObjectType().cast(value)); //no compielr complaints
}
}
Since we can't provide Set<Foo>.class as object type we have like two possibilites to deal with the generic type. Either we use inheritence or we use composition.
Inheritence:
static class IntHashSet extends HashSet<Integer>{}
Composition:
static class IntSetComposition{
private final Set<Integer> set;
public IntSetComposition(Set<Integer> set){
this.set=set;
}
public Set<Integer> getSet(){
return this.set;
}
}
How to use all this:
public static void main(String[] args) {
Type<String> string_type = new Type<>("string_type_1", String.class);
Type<Integer> int_type = new Type<>("int_type_1", Integer.class);
Type<IntHashSet> int_set = new Type<>("int_hashset", IntHashSet.class);
Type<IntSetComposition> int_set_comp = new Type<>("int_set_comp", IntSetComposition.class);
Container container = new Container();
String s = container.get(string_type); //no compiler complaints
int i = container.get(int_type); //no compiler complaints
IntHashSet set = container.get(int_set); //no compiler complaints
Set<Integer> set2 = container.get(int_set_comp).getSet(); //no compiler complaints
String s2 = container.get(int_type); //the compiler does not like this!
}
Note: NotNull checks should be implemented as well as hashcode() and equals() overrides
Thomas Klägers solution is an answer that also came to my head. Creating an fully functioning heterogeneous container which works like this:
Set<?> raw = store.get(type);
Set<T> typed = // some magic;
But as far as I know, It is not possible to use container You mentioned with that 'smooth' code I quoted above. However it is usable and You can get sets of Your stored by class sets. Here goes the code:
public class Container {
Map<Class<?>, Set<Object>> container = new HashMap<>();
public <T> void put(T e, Class<?> type) {
container.putIfAbsent(type, new HashSet<>());
container.get(type).add(e);
}
public <T> Set<T> get(Class<T> type) {
#SuppressWarnings("unchecked") //It is fine to ignore warnings here
Set<T> res = (Set<T>) container.get(type);
return res;
}
}
And working example of storing ang retreiving Containers elements:
public class Run {
public static void main(String[] args) {
Foo foo = new Foo();
Bar bar = new Bar();
Container con = new Container();
con.put(foo, foo.getClass());
con.put(bar, bar.getClass());
Set<? extends Foo> foos = con.get(foo.getClass());
Set<? extends Bar> bars = con.get(bar.getClass());
//here You can use Your sets as ususal
}
If approach <? extends Foo> and usage is fine for You, it's working solution. Above that if You work in Java 10+, there's possibility for that 'dirty' declaration omission. Just declare it as var and poof, its hidden.
I'm trying to create a Variable class that can represent either an Integer or Double value using generics.
Below is the code that I have tried. Because of erasure I use an enum to store the intended type of the Variable and then try and use this to initialise the value to the correct type.
public class Variable<T> {
private enum Type {INTEGER, DOUBLE};
private Type type;
private T value;
public static Variable<Integer> createAsInteger() {
return new Variable<Integer>(Type.INTEGER);
}
public static Variable<Double> createAsDouble() {
return new Variable<Double>(Type.DOUBLE);
}
private Variable(Type type) {
this.type = type;
if(type == Type.INTEGER) {
value = new Integer(0);
} else {
value = new Double(0.0);
}
}
public static void main(String[] args) {
Variable.createAsInteger();
Variable.createAsDouble();
}
}
However when I compile it I get the following message...
error: incompatible types: Integer cannot be converted to T
value = new Integer(0);
and likewise for the Double.
Can anyone explain why this is happening and if there is a way round this without having to write two separate classes, one for Integer and one for Double?
Edit
Thanks for all your answers...based on them I now realise there are better ways of doing this. However I'm trying to get my head round why this approach isn't working so that I don't make the same mistake in the future.
When I define my class as public class Variable<T extends Number> as suggested, I still get the same error.
Your architecture seems to defile the concept of generics.
The simplest way would be to have an upper bound in your type parameter:
class Variable<T extends Number> {...}
Then you can have a generic factory method creating a Variable<X> based on your required class:
static <X extends Number>Variable<X> create() {
return new Variable<X>();
}
You can then invoke it as:
Variable.<Integer>create(); // returns an instance of `Variable<Integer>`
This will not limit to Integer and Double, but rather any Number.
If you have to, you can limit those choices by performing the following:
Add a parameter to your create method: create(Class<X> clazz)
Check the value of your clazz argument within the method's body:
if (!clazz.equals(Integer.class) && !clazz.equals(Double.class)) {
// TODO complain
}
Otherwise, you can ensure you use a private constructor and provide static createAs... non-generic methods such as createAsInteger etc., that would return a new Variable<Integer> etc.
The problem here is that T can be anything. What if T was for instance String, your code would amount to:
String value = new Integer(0);
You could lay out your factory methods like this:
public static Variable<Integer> createAsInteger() {
return new Variable<>(new Integer(0), Type.INTEGER);
}
Where you have a constructor like:
private Variable(T value, Type type) {
this.value = value;
this.type = type;
}
You get the error because you are typizing a method inside a generic class. You can't define some inside the T generic class.
By the way you are mistaking the design pattern.
You have to design a generic class for Variable, also the constructor must have T as argument type.
In an other class you implement the factory with the createInteger and the createDouble methods.
You can make your class inherit from Numbers and use type checking to invoke appropriate method for Integer or Double.
public class Variable<T extends Number> {
public static Variable<T extends Number> Variable<T> create(Variable<T> var){
if (var instanceOf Integer){
// Take appropriate action
}
else if (var instanceOf Double){
// Take appropriate action
}
}
}
By this, there is no peculiar need of maintaining a separate enum for Types.
I come from a C# world and I've just learned about erasure in Java, which put me a bit off. Is there really no way to distinguish SomeGenericInstance<String> from SomeGenericInstance<Integer> runtime in Java?
I'm asking because I've implemented a super simple pub-sub framework and I wanted to have a generic class GenericMessage<T>. It's essential not to send GenericMessage<String> to listeners of GenericMessage<Integer>. I tried implementing it by having a List of key-value pairs where the key is the Class object representing the type of the message. But this code line yields true which is a problem...:
new GenericMessage<Integer>().getClass.equals(new GenericMessage<String>().getClass())
As far as I am aware, sorry, it is simply impossible.
You can do it using Java Reflection. Don't know if it's always a good idea, but it's surely possible. Here's an example:
public class Test{
private List<String> list;
public static void main(String[] args) throws Exception{
Field field = Test.class.getDeclaredField("list");
Field f = field.getGenericType().getClass().getDeclaredField("actualTypeArguments");
f.setAccessible(true);
Type[] genericTypes = (Type[]) f.get(field.getGenericType());
System.out.println(genericTypes[0]);
}
}
Or you can cast directly to ParameterizedType, if it seems any better to you:
public class Test{
private List<String> list;
public static void main(String[] args) throws Exception{
Field field = Test.class.getDeclaredField("list");
ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
Type[] actualTypes = parameterizedType.getActualTypeArguments();
System.out.println(actualTypes[0]);
}
}
Both examples print: class java.lang.String
Now just to leave a more complete answer, the same can be done for a Map. As you can see the getActualTypeArguments() method returns a Type[] and for a Map, the key type would be index 0, and the value type would be index 1. Example:
public class Test{
private Map<String, Integer> map;
public static void main(String[] args) throws Exception{
Field mapField = Test.class.getDeclaredField("map");
ParameterizedType mapParameterizedType = (ParameterizedType) mapField.getGenericType();
Type[] actualMapTypes = mapParameterizedType.getActualTypeArguments();
System.out.println(actualMapTypes[0]);
System.out.println(actualMapTypes[1]);
}
}
Prints:
class java.lang.String
class java.lang.Integer
You can access it using next trick:
public class Example<T> {
Class<T> genericType;
public Example(Class<T> genericType) {
this.genericType= genericType;
}
public static void main(String args[]) {
Example<Integer> ex1 = new Example<>(Integer.class);
Example<String> ex2 = new Example<>(String.class);
System.out.println(ex1.genericType);
System.out.println(ex2.genericType);
}
}
Output:
class java.lang.Integer
class java.lang.String
Here's a way of getting what you're looking for without using reflection (assuming that you are able to make modifications to your pub-sub framework to pass a Class token). A big hat-tip to assylias and zvzdhk for pointing me in the direction of class literals.
interface GenericMessage<T> {
}
interface StringMessage<T extends String> extends GenericMessage<T> {
String getString();
}
interface IntMessage<T extends Integer> extends GenericMessage<T> {
int getInt();
}
interface MessageListener<T> {
<T> void handleMessage(Class<T> type, GenericMessage<T> instance);
}
// "marker interfaces"
interface StringMessageListener<T extends String> extends MessageListener<T> {
}
interface IntMessageListener<T extends Integer> extends MessageListener<T> {
}
class IntMessageImpl<T extends Integer> implements IntMessage<T> {
public int getInt() {
return 0;
}
}
class StringListenerImpl<T extends String> implements StringMessageListener<T> {
public <T> void handleMessage(Class<T> type, GenericMessage<T> genericMessage) {
StringMessage stringMessage = (StringMessage) genericMessage; // Typesafe cast since T extends String on both StringMessage and StringMessageListener
String message = stringMessage.getString();
// Do something with message
}
}
class IntListenerImpl<T extends Integer> implements IntMessageListener<T> {
// an implementation for the Integer case ...
}
void showTypeChecking() {
GenericMessage<String> badStringMessage = new IntMessageImpl<>(); // Compile-time check fails due to bad type of new message implementation
MessageListener<Integer> badIntListener = new StringListenerImpl<>(); // Compile-time check fails due to bad type on new listener implementation
MessageListener<String> stringListener1 = new StringListenerImpl<>();
MessageListener<String> stringListener2 = new StringListenerImpl<>();
MessageListener<Integer> intListener = new IntListenerImpl<>();
GenericMessage<String> stringMessage = new GenericMessage<String>() {};
stringListener1.handleMessage(String.class, stringMessage);
stringListener1.handleMessage(Integer.class, stringMessage); // Compile-time check fails due to bad type on class literal
GenericMessage<Integer> intMessage = new GenericMessage<Integer>() {};
intListener.handleMessage(Integer.class, intMessage);
GenericMessage<String> badIntMessage = new GenericMessage<String>() {};
intListener.handleMessage(Integer.class, badIntMessage); // Compile-time check fails due to bad type on intMessage
GenericMessage uncheckedMessage = new IntMessageImpl();
intListener.handleMessage(Integer.class, uncheckedMessage); // Compiler issues warning about unchecked assignment of uncheckedMessage argument
MessageListener uncheckedListener = new StringListenerImpl();
uncheckedListener.handleMessage(String.class, stringMessage); // Compiler issues warning about an unchecked call to handleMessage() method
}
It's not directly applicable in this case, but you may find this discussion of the typesafe heterogeneous container pattern helpful in learning a bit more about Java generics. It's definitely one of the harder parts of the language to master.
It is not possible to distinguish "a SomeGenericInstance<String> object" and "a SomeGenericInstance<String> object", because there is no difference. There is just "a SomeGenericInstance object".
The problem: I've a Function Object interface defined in a class:
public static interface FunctionObject<T> {
void process(T object);
}
I need it generic because I'd like to use T methods in the process implementations.
Then, in other generic class, I've a Map where I have classes as keys and function objects as values:
Map<Class<T>, FunctionObject<T>> map;
But I also want the map to accept subtype classes and function objects of supertypes OF THE KEY TYPE, so I did this:
Map<Class<? extends T>, FunctionObject<? super T>> map; //not what I need
The basic idea is to be able to use the map as follows:
//if T were Number, this should be legal
map.put(Class<Integer>, new FunctionObject<Integer>(){...});
map.put(Class<Float>, new FunctionObject<Number>(){...});
map.put(Class<Double>, new FunctionObject<Object>(){...});
As I want to enforce the FunctionObject has the type of the class key or a supertype, what I really would like to define is this:
Map<Class<E extends T>, FunctionObject<? super E>>> map;
How can I achieve the desired effect? Is a typesafe heterogenous container the only option? What would the Map generic types look like to allow populating it from a reference?
Parametrized container, seems to work just fine:
public class MyMap<T>
{
interface FunctionObject<X> {}
private Map<Class<? extends T>, FunctionObject<Object>> map = new HashMap<>();
#SuppressWarnings("unchecked")
public <E extends T> void put(Class<E> c, FunctionObject<? super E> f)
{
map.put(c, (FunctionObject<Object>) f);
}
public <E extends T> FunctionObject<Object> get(Class<E> c)
{
return map.get(c);
}
public static void Main(String[] args)
{
MyMap<Number> map = new MyMap<>();
map.put(Integer.class, new FunctionObject<Integer>() {});
map.put(Float.class, new FunctionObject<Number>() {});
map.put(Double.class, new FunctionObject<Object>() {});
}
}
Edited to comply to the question. Sadly there is no way to avoid the downcasting to object.
Edit added get().
You can do this with encapsulation, assuming you only use the map through the method which check this on a per entry basis.
The following add method avoids the need to double up on the type as well.
public class Main {
interface FunctionObject<T> { }
private final Map<Class, FunctionObject> map = new LinkedHashMap<Class, FunctionObject>();
public <T> void add(FunctionObject<T> functionObject) {
Class<T> tClass = null;
for (Type iType : functionObject.getClass().getGenericInterfaces()) {
ParameterizedType pt = (ParameterizedType) iType;
if (!pt.getRawType().equals(FunctionObject.class)) continue;
Type t = pt.getActualTypeArguments()[0];
tClass = (Class<T>) t;
break;
}
map.put(tClass, functionObject);
}
public <T> void put(Class<T> tClass, FunctionObject<T> functionObject) {
map.put(tClass, functionObject);
}
public <T> FunctionObject<T> get(Class<T> tClass) {
return map.get(tClass);
}
public static void main(String... args) throws IOException {
Main m = new Main();
m.add(new FunctionObject<Integer>() {
});
FunctionObject<Integer> foi = m.get(Integer.class);
System.out.println(foi.getClass().getGenericInterfaces()[0]);
}
}
prints
Main.Main$FunctionObject<java.lang.Integer>
You can use #SuppressWarnings("unchecked") if you want to disable the warning.
The point is; there is no way to describe the constraint you have in the field declaration, you can achieve the same result if you use accessor methods which do the check on a per entry basis. You can add runtime checks as well if you need to ensure raw types are correct.
The following is a snippet on how to make a java generic class to append a single item to an array. How can I make appendToArray a static method. Adding static to the method signature results in compile errors.
public class ArrayUtils<E> {
public E[] appendToArray(E[] array, E item) {
E[] result = (E[])new Object[array.length+1];
result[array.length] = item;
return result;
}
}
the only thing you can do is to change your signature to
public static <E> E[] appendToArray(E[] array, E item)
Important details:
Generic expressions preceding the return value always introduce (declare) a new generic type variable.
Additionally, type variables between types (ArrayUtils) and static methods (appendToArray) never interfere with each other.
So, what does this mean:
In my answer <E> would hide the E from ArrayUtils<E> if the method wouldn't be static. AND <E> has nothing to do with the E from ArrayUtils<E>.
To reflect this fact better, a more correct answer would be:
public static <I> I[] appendToArray(I[] array, I item)
public static <E> E[] appendToArray(E[] array, E item) { ...
Note the <E>.
Static generic methods need their own generic declaration (public static <E>) separate from the class's generic declaration (public class ArrayUtils<E>).
If the compiler complains about a type ambiguity in invoking a static generic method (again not likely in your case, but, generally speaking, just in case), here's how to explicitly invoke a static generic method using a specific type (_class_.<_generictypeparams_>_methodname_):
String[] newStrings = ArrayUtils.<String>appendToArray(strings, "another string");
This would only happen if the compiler can't determine the generic type because, e.g. the generic type isn't related to the method arguments.
I'll explain it in a simple way.
Generics defined at Class level are completely separate from the generics defined at the (static) method level.
class Greet<T> {
public static <T> void sayHello(T obj) {
System.out.println("Hello " + obj);
}
}
When you see the above code anywhere, please note that the T defined at the class level has nothing to do with the T defined in the static method. The following code is also completely valid and equivalent to the above code.
class Greet<T> {
public static <E> void sayHello(E obj) {
System.out.println("Hello " + obj);
}
}
Why the static method needs to have its own generics separate from those of the Class?
This is because, the static method can be called without even
instantiating the Class. So if the Class is not yet instantiated, we
do not yet know what is T. This is the reason why the static methods
needs to have its own generics.
So, whenever you are calling the static method,
Greet.sayHello("Bob");
Greet.sayHello(123);
JVM interprets it as the following.
Greet.<String>sayHello("Bob");
Greet.<Integer>sayHello(123);
Both giving the same outputs.
Hello Bob
Hello 123
You need to move type parameter to the method level to indicate that you have a generic method rather than generic class:
public class ArrayUtils {
public static <T> E[] appendToArray(E[] array, E item) {
E[] result = (E[])new Object[array.length+1];
result[array.length] = item;
return result;
}
}
How can I make appendToArray a static method?
To make it static, you need to:
add the static modifier
add the generic type E to the method signature
Specifically for your example, that means changing the method signature from this:
public E[] appendToArray(E[] array, E item) {
to this:
// same as above, but with "static <E>" before return type E[]
public static <E> E[] appendToArray(E[] array, E item) {
The key piece that's easy to miss: the generic type should be added to the signature, appearing just before the return type. Excerpt below from
the Java Tutorial on Generic Methods:
Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter's scope is limited to the method where it is declared. Static and non-static generic methods are allowed, as well as generic class constructors.
The syntax for a generic method includes a list of type parameters, inside angle brackets, which appears before the method's return type. For static generic methods, the type parameter section must appear before the method's return type.
From javadoc
Generic Methods
Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter's scope is limited to the method where it is declared. Static and non-static generic methods are allowed, as well as generic class constructors.
The syntax for a generic method includes a list of type parameters, inside angle brackets, which appears before the method's return type. For static generic methods, the type parameter section must appear before the method's return type.
The Util class includes a generic method, compare, which compares two Pair objects:
public class Util {
public static <K, V> boolean compare(Pair<K, V> p1, Pair<K, V> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
public class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public void setKey(K key) { this.key = key; }
public void setValue(V value) { this.value = value; }
public K getKey() { return key; }
public V getValue() { return value; }
}
The complete syntax for invoking this method would be:
Pair<Integer, String> p1 = new Pair<>(1, "apple");
Pair<Integer, String> p2 = new Pair<>(2, "pear");
boolean same = Util.<Integer, String>compare(p1, p2);
The type has been explicitly provided, as shown in bold. Generally, this can be left out and the compiler will infer the type that is needed:
Pair<Integer, String> p1 = new Pair<>(1, "apple");
Pair<Integer, String> p2 = new Pair<>(2, "pear");
boolean same = Util.compare(p1, p2);
This feature, known as type inference, allows you to invoke a generic method as an ordinary method, without specifying a type between angle brackets.
After understanding this doc , for your question answer is that :
public static <I> I[] appendToArray(I[] array, I item)