Given the following class:
import java.util.ArrayList;
import java.util.Collection;
public class Main {
private static class A {
}
private static class B<T> {
private void thenReturn(T value) {
}
}
private static <T> B<T> when(T methodCall) {
return new B<T>();
}
private static Collection<? extends A> method() {
return new ArrayList<>();
}
public static void main(String[] args) {
Collection<? extends A> result = new ArrayList<>();
// Does not compile.
when(method()).thenReturn(result);
}
}
I get the compilation error The method thenReturn(Collection<capture#1-of ? extends Main.A>) in the type Main.B<Collection<capture#1-of ? extends Main.A>> is not applicable for the arguments (Collection<capture#3-of ? extends Main.A>)
What have I to change in the main method in order that it will compile? Is there a better solution than
public static void main(String[] args) {
Collection result = new ArrayList<>();
when(method()).thenReturn(result);
}
This works to get around it - it looks like the capture rules get a bit stretched for long expressions.
Collection<? extends A> result = new ArrayList<>();
B<Collection<? extends A>> when = when(method());
when.thenReturn(result);
Related
I get error: Cannot resolve method 'sort(java.util.List<T>, boolean)' in case:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Arrays;
public class MyClass {
public static void main(String args[]) {
MyArray arr = new MyArray();
arr.set("b");
arr.set("a");
arr.sort();
}
}
class MyArray<T> {
List<T> myList;
MyArray(){
myList = new ArrayList<T>();
}
public void set(T val) {
myList.add(val);
}
public void sort() {
ListFunctions.sort(myList, true);
System.out.println(myList);
}
}
class ListFunctions {
public static <T extends Comparable<T>> void sort(List<T> array, boolean ascending){
if (ascending){
array.sort(null);
}
else {
array.sort(Collections.reverseOrder());
}
}
}
Problem is in line ListFunctions.sort(myList, true). I can't convert this way (List)myList, because meaning of constraint T extends Comparable<T> is lost.
I see examples of code where T need to implement Comparable interface, but in my case I can't specify class. I implicitly use List<String>
Your class
class MyArray<T>
Should simply be
class MyArray<T extends Comparable<T>>
If you don't do that, you may potentially pass an out of bound type to your utility function which the compiler will reject accordingly.
MyArray arr = new MyArray();
will hence become
MyArray<String> arr = new MyArray<>();
Consider the following scenario:
public abstract class A {}
public class B extends A {}
public interface Provider<T extends A> {
List<String> list(T param);
}
public class ProviderB implements Provider<B> {
#Override
public List<String> list(B param) {
return Collections.singletonList("ProviderB");
}
}
public class Factory {
public static Provider get(int x) {
if (x == 1)
return new ProviderB();
throw new RuntimeException("Not supported");
}
}
public class Main {
public static void main(String[] args) {
Provider provider = Factory.get(1);
A a = new B();
List<String> result = provider.list(a);
}
}
In Main at List<String> result = provider.list(a); , I'm getting:
Unchecked call to list(T) ..
Unchecked assignment java.util.List .. Reason 'provider' has raw type.
I do know some basic stuff about type erasure in generics. How would you solve the warnings ?
EDIT:
Actually main will look like this:
public static void main(Map<Integer, ? extends A> types) {
for (Map.Entry<Integer, ? extends A> entryType : types.entrySet()) {
Provider provider = Factory.get(entryType.getKey());
List<String> result = provider.list(entryType.getValue());
}
}
I want to implement a class that instantiates generic types.
public class DisjointSet<T extends Set<E>, E> {
private final Class<T> setType;
public DisjointSet(Class<T> setClass) {
this.setType = setClass;
}
public void doSomething(E Element) {
T set = setClass.newInstance();
set.add(element);
}
}
I tried instantiating the class like this:
DisjointSet<HashSet<Integer>, Integer> disjointSet = new DisjointSet<>(HashSet<Integer>.class);
However using .class on a generic type does not seem to be allowed. How would I correctly pass the required Class of a generic type to the constructor?
Not sure it is good to expose the inner set type (Hash versus other) in the parameterized type.
Actually due to type erasure you can't instantiate parameterised types directly, but you can pass in a factory,
package langGenerics;
import java.util.HashSet;
import java.util.Set;
public class UseGenerics {
public static void main(String[] args) {
SetFactory<Integer> setFactory = HashSet::new;
DisjointSet<Integer> disjointSet = new DisjointSet<>(setFactory);
disjointSet.doSomething( 123 );
}
}
interface SetFactory<T> { Set<T> get(); }
class DisjointSet<T> {
private SetFactory<T> setFactory;
public DisjointSet(SetFactory<T> setFactory) {
this.setFactory = setFactory;
}
public void doSomething(T item) {
Set<T> set = setFactory.get();
set.add(item);
}
}
If you really want to init your own set storage, then I suggest you to pass Supplier to your constructor:
public static class DisjointSet<T extends Set<E>, E> {
T set;
public DisjointSet(Supplier<T> supplier) {
set = supplier.get();
}
public void doSomething(E element) {
set.add(element);
}
}
Then use it:
DisjointSet<HashSet<Integer>, Integer> set = new DisjointSet<>(HashSet::new);
if this is what you wanted,
public class DisjointSet<T extends Set<E>, E> {
private final Class<T> setType;
public DisjointSet(Class<T> setClass) {
this.setType = setClass;
}
public static void main(String[] args) {
DisjointSet<HashSet<Integer>, Integer> disjointSet = new DisjointSet(new HashSet<Integer>().getClass());
}
}
Is is possible to have a generic return type such that collection can built with interface as well as implementation.
public static void main(String[] args) {
List<Test1> list = ImmutableList.of(new Test1());
List<ITest> test_return_1 = buildIntRange(list);
List<Test1> test_return_2 = buildIntRange(list); //error
}
private static <K extends ITest> List<ITest> buildIntRange(List<K> test) {
return ImmutableList.copyOf(test);
}
Sure. Use the same signature as ImmutableList.copyOf, or just use ImmutableList.copyOf directly:
static <T> List<T> copyOf(Iterable<? extends T> collection)
I have this class
public class Tree<T> {
//List of branches for this tree
private List<Tree<? super T>> branch = new ArrayList<Tree<? super T>>();
public Tree(T t){ this.t = t; }
public void addBranch(Tree< ? super T> src){ branch.add(src); }
public Tree<? extends T> getBranch(int branchNum){
return (Tree<? extends T>) branch.get(branchNum);
}
private T t;
}
And I am trying to create a variable out of this class using this
public static void main(String[] args){
Tree<? super Number> num2 = new Tree<? super Number>(2);
}
and it is giving me this error
Cannot instantiate the type Tree<? super Number>
While instantiating generics should be replaced with corresponding objects.
Ex:
Tree<Integer> num2 = new Tree<Integer>(2);
Wildcards ? cannot be used when creating new instances. You should change your code to something like that
import java.util.ArrayList;
import java.util.List;
public class Test1 {
public static void main(String[] args){
Tree<? super Number> num2 = new Tree<Number>(2);
num2.addBranch(new Tree<Number>(1));
Tree<? super Number> num3 = (Tree<? super Number>) num2.getBranch(0);
System.out.println(num3);
}
}
class Tree<T> {
//List of branches for this tree
private List<Tree<? super T>> branch = new ArrayList<Tree<? super T>>();
public Tree(T t){ this.t = t; }
public void addBranch(Tree<Number> src){ branch.add((Tree<? super T>) src); }
public Tree<? extends T> getBranch(int branchNum){
return (Tree<? extends T>) branch.get(branchNum);
}
public String toString(){
return String.valueOf(t);
}
private T t;
}