I'm not that familiar with java Generics (using IntelliJ).
What I want is adding generic values to collections.
Two question for the code below.
I read https://docs.oracle.com/javase/tutorial/java/generics/methods.html
and https://docs.oracle.com/javase/tutorial/extra/generics/methods.html
but don't know why the code below has an error.
Q1) I have error message in map.put(T, T); in add method such that red ripple under Ts: Expression Expected, introduce local variable
Q2) Wondering in this case, should I declare class as public class Test<T> or can I declare public class Test?
public class Test<T> {
Map<T, T> map;
public Test() {
map = new HashMap<T, T>();
}
public <T> void add(T value) throws Exception {
map.put(value, value); // Q1) red ripple under value: Expression Expected, introduce local variable
}
}
There are two problems in here.
The generic method parameter T hides the class one T. They are different types and you have no ways to refer to that T (unless you rename one of them).
The method map.put expects values of T type, not this type itself (it is not an instance of Class anyway).
The solution:
public void add(T value) throws Exception {
map.put(value, value);
}
Wondering in this case, should I declare class as public class Test<T> or can I declare public class Test?
You don't necessarily need to declare class generic types if you want few generic methods - make your methods with their own generic types. Note that there won't be any resemblance between them.
But, in your case, a generic type T is mandatory since you declared a generic field Map<T, T> map.
Related
Without any introduction to generics, I will post my question straight away. Why is this correct:
static<T extends Object> void m1(List<T> list){
//some code
}
And this is not (doesn't compile):
static void m2 (List<T extends Object> list){
//some code
}
Remember that we could use wildcards in the same approach, which would compile just fine:
static void m2 (List<? extends Object> list){
//some code
}
To sum up, why can we use wildcards declaration in parameters, while using type parameter we must declare it before return type?
There are two main points.
First off, as #akuzminykh said in the comments to the question, the ? wildcard is basically just a way to tell the compiler "I don't know what this is gonna be, just assume it could be anything that derives from this class/interface, kthxbye". It doesn't declare any parameter that you could make use of within the method, no identifier you can call upon, nothing. However, type parameters do exactly that, and if you declare a new one, it's a different story than just "calling" the wildcard which you don't have to declare.
Secondly, think of how you would declare a type parameter for a generic class. Do you think this would be enough?
public class Foo {
public T extends CharSequence getBar() {...}
}
public class Foo {
public <T extends CharSequence> getBar() {...}
}
No, none of these two options would work. In order to use a generic type parameter within a class, you have to declare it along with the type itself, not along with the methods/fields that use them. Like this:
public class Foo<T extends CharSequence> {
public T getBar() {...}
}
And in order to use a generic type parameter within a method, you have to declare it along with the method itself or the type that contains the method, not along with the method parameters that use them.
Can anyone please explain me below code
public <T extends Emp> void foo(ArrayList<T> list) {
list.add(list.remove(0)); // (cycle front element to the back)
}
I am trying to understand how Generics will apply on void return type.
Note: i have changed the code now it is not giving any error.
I am trying to understand how generics will apply on void return type.
This is only a syntax. Generics do not apply to void return type, they apply to the method as a whole.
The name and restrictions on the generic parameter need to go somewhere in the text of your program. In a class declaration they follow the class name in angular brackets. In a generic method declaration they follow the accessibility designator public, and precedes the return type void.
One could easily imagine an alternative placement of generic types, such as
public void foo<T extends Emp>(ArrayList<T> list) // Imaginary syntax
or even
public void foo(ArrayList<T> list) <T extends Emp> // Imaginary syntax
but Java designers decided on the placement before the return type designator.
Generics won't be applied to void.
If you say that the type is <T extends Emp>, you are saying, that any subtype of Emp can be applied in place of T.
In your code, You can use <T> instead of <T extends Emp> as you aren't doing anything with Emp
public <T> void foo(ArrayList<T> list) {
list.add(list.remove(0)); // (cycle front element to the back)
}
Regarding how it'll work, the type will be provided by you when you use this method and at compile time, java will place required casts automatically. So, if you are using this:
ArrayList<String> list = new ArrayList<>();
// Add some items into list
foo(list);
in that case, your foo() method will find out that type <T> is String and so, will behave something like:
public void foo(ArrayList<String> list) {
list.add((String)(list.remove(0)));
}
Whilst playing around with solutions for this question, I came up with the following code, which has some compiler warnings. One warning is:
Type safety: The expression of type Test.EntityCollection needs unchecked conversion to conform to Test.EntityCollection<Test.Entity>
I don't entirely understand why this warning appears. By passing in a Class<M> type and declaring the method returns EntityCollection<M>, why am I not doing enough to convince the (Java 7) compiler that the correct type is being returned?
static class Entity {
}
static class EntityCollection<E extends Entity> {
private EntityCollection(HashMap<?, E> map) {
}
public static <T extends HashMap<?, M>, M extends Entity> EntityCollection<M> getInstance(
Class<T> mapType, Class<M> entityType)
throws ReflectiveOperationException {
T map = mapType.getConstructor().newInstance();
return new EntityCollection<M>(map);
}
}
public static void main(String[] args) throws Exception {
// both compiler warnings are on the line below:
EntityCollection<Entity> collection = EntityCollection.getInstance(
LinkedHashMap.class, Entity.class);
}
Bonus points if anyone can improve the code to avoid warnings entirely. I've been staring at it for a while and haven't dreamt up any ways to lessen the warnings.
The problem is that getInstance is a generic method but you don't pass generic type parameters to it. You can get around it by passing them like this:
public static void main(String[] args) throws Exception {
EntityCollection<Entity> collection = EntityCollection.<LinkedHashMap, Entity>getInstance(
LinkedHashMap.class, Entity.class);
}
You will still have to deal a rawtypes warning because LinkedHashMap is a generic type. This is problematic in your case since there is a wildcard in the key type.
You face several problems here:
You can't pass parameterized class objects like this: LinkedHashMap<Object, Entity>.class so you pretty much stuck with the rawtypes warning.
The problem there is T. You are adding a constraint to your method saying that T should extends HashMap<?, M>. However, the way you are later referencing to T is like a generic parameter of the type Class (Class<T>). LinkedHashMap.class is of type Class<LinkedHashMap> not Class<LinkedHashmap<?, Entity>> (which is what you needed)
A Class object always references a non-parameterized type, and that makes sense. Because the generic binding exists in compile-time, and you are going to use that Class to dynamically reflect the state and behaviour of an instance in runtime. Long story short, you can use a Class<HashMap> to build a new instance, not bounded to any type.
So, I guess what you need to do to your code to modify that constraint in the way it looks like:
public static <T extends HashMap, M extends Entity> EntityCollection<M> getInstance(
Class<T> mapType, Class<M> entityType)
throws ReflectiveOperationException {
T map = mapType.getConstructor().newInstance();
return new EntityCollection<M>(map);
}
I had an interview test and saw the following code:
EDIT:
public class TestValue {
private Value<SomeValue> defaultValue;
#Test
public void Empty_Value_Has_No_Value() {
Assert.assertFalse(Value.<SomeValue> createEmptyValue()
.hasValue());
}
#Test
public void Default_Value_IsEmpty() {
Assert.assertEquals(Value.<SomeValue> createEmptyValue(),
defaultValue);
}
#Test
public void Non_Empty_Value_Has_Value() {
Assert.assertTrue(new Value<SomeValue>(true, new SomeValue())
.hasValue());
}
}
I had never seen Java generic like
Value.<SomeValue>
The test is to implement Value class with the given unit test code above.
I tried to figure out the Value method signature below (need implementation):
public interface Value<T> {
public boolean hasValue();
public Value<T> createEmptyValue();
}
Any one know, please help?
Thank you
EDIT: Should be like this according to answers below #marlon
public class Value<T> {
public boolean hasValue(){}
public static <M> Value<M> createEmptyValue(){}; //need <M>
}
The key syntax to know:
Value.<SomeValue> //ClassName.<Type>method
is way to invoke static method of a class with parameterized argument.
EDIT: according to #snipes83, syntax to invoke non-static method of a class with parameterized argument.
SomeObject.<Type>method
Value.<SomeValue> it's the way generics are represented for methods.
Using Google Guava's Optional as an example:
Optional<String> email = Optional.<String>of(strEmail);
See Generic Types - Invoking generic methods
Since interfaces cannot declare static methods (shame on you java), just declare your method as static and forget about the interface, like this:
class Value<T> {
public static <T> Value<T> createEmptyValue(){
return null;
}
}
Look at the class Test with the method getEmptyList below:
public class Test {
public <T> List<T> getEmptyList() {
return new ArrayList<T>();
}
}
It returns an empty List containing objects of type T.
If you use Test like this
Test t = new Test();
List<Integer> list = t.getEmptyList();
Then the type inference mechanism is able to infer the type parameter based on the variable type.
However if you need to use the return value of getEmptyList within a method invocation expression like in the following example where the method printList expects a single argument of type List<Integer>, then the type can not be infered from any variable type.
public void printList(List<Integer> list) {
for (int i : list) {
System.out.print(i);
}
}
printList(t.getEmptyList()); // This will FAIL.
In this case you need to specify the type using the following:
printList(t.<Integer>getEmptyList());
1) This is how generic methods are invoked. Refer >> http://docs.oracle.com/javase/tutorial/java/generics/methods.html
2) <SomeValue> in Value.<SomeValue> is optional. Compiler can infer the type. This is called TypeInference. Refer >> http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html
Answer Updated:
3) Value.<SomeValue> createEmptyValue() is right and Value.<SomeValue>createEmptyValue() is right too. Both ways are legal. Just tested it. Didn't notice before.
Although Value is itself obviously typed ( based on the instance variable type of Value<SomeValue>), the static createEmptyValue() method is also typed.
A reasonable assumption, if naming conventions have been adhered to, is that SomeValue extends (or implements) Value.
Although there us no one correct answer, a likely possibility for the signature of Value is:
public class Value<T extend Value> {
public static <V extends Value> V createEmptyValue() {
// some impl
}
}
I am new to generics.
Having a Map like
private static Map<String, Object> map;
and a method like
public <T> T getObject(final Class<T> myClass) {
return (T)map.get(myClass);
}
How to change the map declaration in order to not have to do the cast when returning from the method ?
You would need to make a generic class, not a generic method:
public class MyClass<T> {
private Map<String, T> map;
public T getObject(final String key) {
return map.get(key);
}
}
Also, I changed the parameter from a Class to a String. It doesn't make sense to pass a Class if map.get() expects a String.
Edit: I didn't notice that map was static. If you can change it to non-static without it breaking other parts of your program, this could work. If you can't, then you cannot avoid a cast.
You can't avoid the cast operation as the get() method returns Object
see here for more info
If you're willing to drop the static modifier of your map, than you can do like so:
public class MyClass<T> {
private Map<String, T> map;
public T getObject(final Class<T> myClass) {
return map.get(myClass);
}
}
Otherwise:
It is a compile-time error to refer to a type parameter of a generic
class C anywhere in:
the declaration of a static member of C
(excerpt from the JLS), which prevents you from using parameterized class to achieve the above.
What you were trying to do, however, is to refer a parameterized method's type-parameter from another member (which happen to also be static), which also unreachable.