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<>();
Related
Please explain to me why I have one example that compiles and the other one doesn't compile
This is example that compiles
import java.util.ArrayList;
public class MyClass1 <T> {
public ArrayList<MyClass1<?>> lst;
public MyClass1()
{
lst = new ArrayList<MyClass1<?>>();
}
public static void main(String[] args) {
M(new MyClass1<Double>());
}
public static <T1> void M(MyClass1<T1> t1)
{
var d0 = new MyClass1<Double>();
d0.lst.add(t1);
}
}
But that doesn't compiles
import java.util.ArrayList;
public class MyClass1 <T> {
public ArrayList<?> lst;
public MyClass1()
{
}
public static void main(String[] args) {
M(Double.valueOf(1.1));
}
public static <T1> void M(T1 t1)
{
var d0 = new MyClass1<Double>();
d0.lst.add(t1); // error — java: incompatible types: T1 cannot be converted to capture#1 of ?
}
}
Why in the first case I have wildcard, and everything is OK, but in the second case I have wildcard and it doesn't compile
The second snippet can not be compiled because the generics in Java are about type safety(type guarantee). Thus, if we are declearing List<Integer> the compiler is convinced, that the list will contain only integers. But when we have List<?> (read this like list of some type), compiler cant predict what will the list contain. Today we are adding Integers, tomorrow somebody else will add a ServerSocket. In runtime if we will try to get a value from such a list, we will get a ClassCastException. That is why this code cant even be compiled - to prevent such situations. Read about type erasure and bridge methods.
In your concrete case, i guess, you would like to have something like this:
public class MyClass<T> {
public ArrayList<T> lst;
public static void main(String[] args) {
var obj = new MyClass<Double>();
obj.foo(1.1);
}
public void foo(T s) {
lst.add(s);
}
}
The question mark also can be useful:
static void m(List<? extends Shape> list) {
for (Shape el : list) {
// we are not quite interested what type is this list of.
}
}
And the usage example:
m(new ArrayList<Circle>());
m(new ArrayList<Shape>());
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());
}
}
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);
I had an interface initially as below.
public interface testMe {
public Set<String> doSomething();
}
public class A implements testMe {
public Set<String> doSomething() {
return // Set<String>
}
}
I had similar classes implementing testMe. Now I have to add one more class which returns Set<Some Object>
public class X implements testMe() {
public Set<Some OBject> doSomething() {
}
}
How could i add this method in the interface without breaking existing classes?
You can use
public interface testMe {
public Set<?> doSomething();
}
Or
public interface testMe {
public Set<? extends CommonSuperclass> doSomething();
}
You can't for two reasons.
A class or interface can't have two or more methods that have the same number and type of parameters with the same name but differing return types; and
Because of type erasure, all Set<...> instances are, at runtime, simply Set, so they would have the exact same return type anyway.
You will need to name the second something different.
The more complicated answer is that you can make the parameter type extensible:
public interface TestMe<T extends Serializable> {
Set<T> doSomething();
}
public class A implements TestMe<String> {
#Override
public Set<String> doSomething() { ... }
}
public class X implements TestMe<ASerializableObject> {
#Override
public Set<ASerializableObject> doSomething() { ... }
}
I don't believe you can, because type erasure will ruin the effect you have in mind.
You can parameterize the interface:
import java.util.Set;
public interface ISomething<T>
{
Set<T> doSomething(T [] data);
}
And the implementation:
import java.util.HashSet;
import java.util.Set;
public class Something<T> implements ISomething<T>
{
public static void main(String[] args)
{
Something<String> something = new Something<String>();
Set<String> set = something.doSomething(args);
System.out.println(set);
}
public Set<T> doSomething(T [] data)
{
Set<T> foo = new HashSet<T>();
for (T x : data)
{
foo.add(x);
}
return foo;
}
}
I'm not sure this accomplishes what you have in mind, though.
Please have a look at following code :
import java.util.ArrayList;
import java.util.List;
class Main{
public static <T> List<T> modifiedList(final List<T> list){
return new ArrayList<T>(){
#Override
public boolean add(T element){
super.add(element);
return list.add(element);
}
};
}
public static void main(String[] args) {
List<String> originalList=new ArrayList<String>();
List<String> duplicateList=modifiedList(originalList);
originalList.add("1");
originalList.add("2");
originalList.add("3");
System.out.println(originalList+" "+duplicateList);
duplicateList.add("4");
duplicateList.add("5");
duplicateList.add("6");
System.out.println(originalList+" "+duplicateList);
}
In the above code, the instance of an anonymous inner class declared in the method modifiedList() is able to access the parameter passed to that method. AFAIK Java creates a separate bytecode file for inner classes.
Can anyone explain how these local variable bindings are handled by Java at the bytecode level? I mean, how exactly does Java keep track of the reference to the object passed as a parameter to that method?
Any help would be greatly appreciated!
[Sorry for my poor English! If you understand my question, please edit this post and remove the grammatical errors. Thanks!]
Essentially the code is rewritten by the complier as (note I didn't try to compile it..., might have errors):
class Main$1<T>
extends ArrayList<T>
{
private final List<T> list;
Main$1(final List<T> a)
{
list = a;
}
#Override
public boolean add(T element)
{
super.add(element);
return list.add(element);
}
}
and
class Main{
public static <T> List<T> modifiedList(final List<T> list)
{
return new Main$1<T>(list);
}
public static void main(String[] args)
{
List<String> originalList=new ArrayList<String>();
List<String> duplicateList=modifiedList(originalList);
originalList.add("1");
originalList.add("2");
originalList.add("3");
System.out.println(originalList+" "+duplicateList);
duplicateList.add("4");
duplicateList.add("5");
duplicateList.add("6");
System.out.println(originalList+" "+duplicateList);
}
import java.util.ArrayList;
import java.util.List;
class Main{
public static <T> List<T> modifiedList(final List<T> list){
return new ArrayList<T>(){
private List<T> originalList=list;
#Override
public boolean add(T element){
super.add(element);
return originalList.add(element);
}
};
}
public static void main(String[] args) {
List<String> originalList=new ArrayList<String>();
List<String> duplicateList=modifiedList(originalList);
originalList.add("1");
originalList.add("2");
originalList.add("3");
System.out.println(originalList+" "+duplicateList);
duplicateList.add("4");
duplicateList.add("5");
duplicateList.add("6");
System.out.println(originalList+" "+duplicateList);
}
}
Java allows such a strange thing just in order to make things easier for programmers.
Both the codes are semantically same and boil down to the identical bytecode.