I need to make an instance of generic class. Do not know what to use as parameter.
import java.util.List;
import java.util.ArrayList;
public class Main{
public static void main(String[] args){
Class type = someMethod(); //It could return String.class, Integer.class, MyClass.class etc
//Now I need to make a instance of something using generic parameter. I use List as example here.
List<type)> list = new ArrayList<>(); //Does not work, obvioulsy since it looks weird.
//But what does work?
}
}
You can make compiler ensure compile-type (not runtime) safety for you by passing desired class of List elements:
public static <T> List<T> makeList(#SuppressWarnings("UnusedParameters") Class<T> elClass) {
return new ArrayList<>();
}
public static void main(String[] args) {
List<String> strings = makeList(String.class);
List<Integer> ints = makeList(Integer.class);
}
Related
Can someone explain to me why this is okay:
public static void main(String args[]) {
List<Integer> integers = new ArrayList<>();
test(integers);
}
public static void test(List list) {
}
But this creates the error in the comment:
public static void main(String args[]) {
List<List<Integer>> integers = new ArrayList<>();
test(integers);
//'test(java.util.List<java.util.List>)' cannot be applied to '(java.util.List<java.util.List<java.lang.Integer>>)'
}
public static void test(List<List> lists) {
}
In my understanding, in both cases, the program casts a parameterized type to a generic type, but it only works in the first case. Why is this and how do I go about making a method with a parameter like the second example that could take any list of lists as input?
What you're looking for is
public static <T> void test(List<List<T>> lists) {
}
or
public static void test(List<? extends List<?>> lists) {
}
Don't ever have List without a < after it, except when importing it. It has strange properties and removes type safety. Having List<List> puts the compiler into a weird state where it's trying to have some level of type safety and some not.
What is the difference between the last two statements ? why does one statement work and the other doesn't ?
package Main;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void printIt(List<Object> l)
{
System.out.println(l);
}
public static void main(String[] args) {
List<String> l =new ArrayList<>();
l.add("A");
//what is the differance between the following statments ?
printIt(Arrays.asList("A")); // it compiles successfully
printIt(l); // it does not compile
}
}
The problem is printIt() method expects List<Object> as parameter but we are passing List<String> to it, that's why there is compilation problem.
Replace the parameter List in method printIt() as below:
public static void printIt(List<? extends Object> l)
{
System.out.println(l);
}
Now both will compile,
This is because your method expects a List<Object> and you give it a List<String>.
As weird as it can appear the first time you read this, a List<String> is not a List<Object>.
In your example, you don't modify the content of the lists but let's imagine a method where you want to add a new element.
public static void addIt(List<Object> l, Object o)
{
l.add(o);
}
public static void main(String[] args) {
List<String> l =new ArrayList<>();
l.add("A");
addIt(l, new Integer(1)); // What?! you want to add an Integer to a List<String>!!!!
}
You will have to use wildcards (?) or to solve your problem so your your List .
public static void printIt(List<?> l) //or printIt(List<? extends Object> l)
{
System.out.println(l);
}
The case of printIt(Arrays.asList("A")) is a bit different. It is due to the fact that the generic is determined dynamically, by type inference on a generic method.
List<Object> l = Arrays.asList("A"); //this is valid, the generic type is determined from the type we expect in this declaration.
To help you grok this, here is another compiling code example that demonstrated type inference from return type:
import java.util.*;
// our main class becomes a file but the main method is still found
public class HelloWorld
{
public static void main(String[] args)
{
foo(createList()); // T must be Object
}
private static void foo(List<Object> objs) { }
private static <T> List<T> createList() { return new ArrayList<>(); }
}
so as #csharpfolk mentioned it is all about "Type Inference"!
the following document could be helpful to understand the idea behind that!
https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html
I am writing in Java and trying to create a method that will take any Enum class that I pass to it, as described here (mostly):
Java: Generic method for Enums
I am getting a problem when I try to pass an enum into this type of method. It wants me to change the method to take a specific Enum class. Does anyone know what I am doing wrong?
Here is my version of the method:
public Class Presenter{
public static <E extends Enum<E>> List<String> getEnumString(Class<E> eClass){
List<String> returnList = new ArrayList<String>();
for (E en: EnumSet.allOf(eClass)){
returnList.add(en.name());
}
return returnList;
}
}
and here is what I am attempting to pass in. The error is saying that the argument is not applicable, and it suggests changing the method above to only take MyEnumClass:
MyEnumClass eclass;
List<STtring> string = presenter.getEnumString(eclass);
I thank anyone who can help in advance.
Thanks!
-Eli
MyEnumClass eclass;
eClass is a reference to a MyEnumClass object. What you need to pass into your function is the class type itself. The syntax is:
MyEnumClass.class
The following code will do what you want. Notice I pass in MyEnumClass.class, not a variable.
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
public enum MyEnumClass
{
ENUM_1, ENUM_2, ENUM_3, ENUM_4, ENUM_5;
public static void main(String[] args)
{
for (String string : getEnumString(MyEnumClass.class))
System.out.println(string);
}
public static <E extends Enum<E>> List<String>
getEnumString(Class<E> eClass)
{
List<String> returnList = new ArrayList<String>();
for (E en : EnumSet.allOf(eClass))
{
returnList.add(en.name());
}
return returnList;
}
}
Output:
ENUM_1
ENUM_2
ENUM_3
ENUM_4
ENUM_5
Is it anyway possible to create a list by using the parametrized TYPE
of the generic class? In the below code T is the parametrized type.
Any possible solutions?
package collectionsDemo;
import java.util.*;
public class ListDemo<T> {
public void listCreator(){
List<T> listDemo=new ArrayList<>();
/*i intended to add something like below Since
T is type of Integer Object,which i can't perform right now.
and below is the compile time error*/
listDemo.add(34);
listDemo.add(55);
/*The method add(int, T) in the type List<T> is not
applicable for the arguments (int)*/
}
public static void main(String[] args) {
ListDemo<Integer> listdemo=new ListDemo<>();
}
}
No. This is not the way you can do it.
You can not store an int in a list that wants a element of type T.
ListDemo<T> and List<T>, in both these cases, the type parameter T is different.
You need to do this:
List<Integer> listDemo = new ArrayList<>();
Then, and only Then, you cad add integers in your list.
I have been able to answer my own question and i am not sure whether it is best practice or not?Correct me if i am wrong!
*package collectionsDemo;
import java.util.*;
import java.util.Scanner;
public class GenericListCreator<T> {
public void listCreator( T[] e){
List<T> listDemo=new ArrayList<>();
for(T t:e){
listDemo.add(t);
}
for(T t:e){
System.out.println(t);
}
}
public static void main(String[] args) {
GenericListCreator<Integer> age=new GenericListCreator<>();
age.listCreator(new Integer[]{21,22,24});
GenericListCreator<String> name=new GenericListCreator<>();
name.listCreator(new String[]{"John","michell","bing"});
GenericListCreator<Double> price=new GenericListCreator<>();
price.listCreator(new Double[]{23.5,556.5,55.6});
}
}*
Let's say I have something like:
public void do(DataType type) {
ArrayList<DataType> list = new ArrayList<DataType>();
doStuff();
}
In some cases I want to create an arrayList of another type by passing the type as a parameter, how can I do this in Java?
try this..
public <T> void stuff(T type){
ArrayList<T> arrayList = new ArrayList<T>();
doStuff();
}
generics may be helpfull you if you want to create sigle object that represent it, but when you want a simple private attribute the easy way is this.
I assume you want something like this:
public static <T>List<T> makeList(T t) {
List<T> list = new ArrayList<T>();
// doStuff();
return list;
}
And usage of makeList function:
makeList("String list").add("new String"); // ok
makeList("String list").add(5); // compile error
More universal approach is the following:
public <T extends IDataType> void doSomething(T type) {
ArrayList<T> list = new ArrayList<T>();
doStuff();
}
where: DataType implements IDataType
In this case you can use any type which implements IDataType
Java doesn't allow to pass class types as method parameters. As far as I know, the closest you can get is this :
import java.util.*;
class MyClass<T> {
public void stuff() {
ArrayList<T> list = new ArrayList<T>();
//doStuff();
}
}
class Test {
public static void main(String args[]) {
(new MyClass<String>()).stuff();
(new MyClass<Integer>()).stuff();
}
}
So you would need to instanciate the class each time you need it.
Are you looking for something like this?
public static <T> List<T> doSomething(Class<T> clazz){
ArrayList<T> testList = new ArrayList<T>();
return testList;
// more code
}
and you can invoke this like :
List<Integer> intList = doSomething(Integer.class);
intList.add(1);
List<String> stringList = doSomething(String.class);
stringList.add("test");
and if you want to restrict the type of Class you need, you could use T extends youDataType. If what #subhash has explained is not the one you are looking for, and if what #zoyd explains is true, then i believe this could be of some use.