I would like to know if there is a way to do something like this in Java:
Integer a = new Integer(2);
a.getClass() newVariable = new Integer(4);
My question is can I declare the type of a new variable by using a variable?
It is not possible to specify the type by retrieving it from an other variable.
Note that the reflection tutorial of Oracle provide some methods that would simulate it. It will allow you to instantiate an object by specifying it type as a class. But that won't allow you to first specify the object type by retrieving it from the variable.
You might want to have a look at generics which would probably help you fix the hidden problem that made you ask this question.
A simple example would be
public class Foo<T> {
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
Note that T stands for Type as per the documentation.
#param the type of the value being boxed
So you can give any type.
You can also specify the extends of the type, which kind of give you some security.
class Foo<T extends Integer>
No, you cannot base the type of a variable on the type of another variable like that.
Depending on your real goal, you might be able to use Java's generics to get around your reason for feeling you want to do that, but it depends a lot on what your real end goal is. For instance, if this is all in class Foo, you could parameterize it, and then use the parameter in both places:
class Foo<T> {
public method doSomething() {
T a = /*...*/;
T newVariable = /*...*/;
}
}
Then:
Foo<Integer> f = new Foo<Integer>();
...results in an f with a doSomething that works with and returns Integers.
Note the /*...*/ after the = in the above: I can't do new T() there, which is a famous limitation of Java's generics. The values for a and newVariable would have to come from somewhere (arguments to the method, for instance, or data members, etc.).
More about generics here, again depending on whether they really help with what you're ultimately trying to do.
Related
class A<T> extends B<T> {}
class B<T> implements ParameterizedType {
#Override
public Type[] getActualTypeArguments() {
Type superclass = this.getClass().getGenericSuperclass();
System.out.println("A superClass:" + superclass);
return superclass.getClass().getTypeParameters();
}
#Override
public Type getRawType() {
return null;
}
#Override
public Type getOwnerType() {
return null;
}
}
public static void main(String[] args) {
Action<String> action = new Action<>();
action.getActualTypeArguments();
B<String> b = new B<>();
b.getActualTypeArguments();
}
the result is:
superClass:class java.lang.Object
superClass:Main$Action<T>
I want to get right result(java.lang.String), what can I do.
I Try to change this.getClass().getSuperClass().getGenericSuperclass(); in class B, but the result also is java.lang.Object...
B<String> b = new B<>();
It is impossible to get String out, that's what erasure means. No amount of futzing with .getActualTypeArguments() or getGenericType() let you do an end-run around this. If it was possible, don't you think there'd be considerably simpler APIs for this?
Bit for bit, in memory, there is no difference, whatsoever, between new B<String>() and new B<Integer>. Those generics are pretty much all things the compiler uses to link things together. It's the compiler that complains when you mess things up, java.exe has no idea what generics are.
Generics in signatures remain - they have to, as the compiler needs them to do its work, and the compiler often has only compiled code to work with (for example, to compile a hello world program, you need the java.lang.String class, but you don't need its source). As far as java.exe is concerned, these are comments - they exist solely for javac to look at it.
You can however, get at these with reflection, and that is what getGenericSuperclass() and all that jazz is about. So, while you cannot get the String out of B<String> b = new B<>(), you can get it out of the subtly different B<String> b = new B<>() {}. That's an anonymous inner class literal. If you don't know what they are, that's syntax sugar for:
// You can declare a class inside a method just fine
class $RandomName extends B<String> {
}
new $RandomName();
And, crucially, extends B<String>, that's signature stuff, and signatures can be read out with generics.
This principle is called a super type token. It means to pass along generics, you have to use this new Foo<TheActualGenericsYouWantToPass>() {} construct, ending in the braces, to ensure a new local anonymous class is made, as that then carries the generic type. The exact thing you put in it is then transfered, i.e. if you have:
public class Foo<T> {
public void example() {
new SuperTypeToken<T>() {};
}
}
You're creating one that is literally just T, and not whatever T actually is, in other words, if you then do: new Foo<String>.example(), that type token is still literally T, it cannot be used to derive String (again, erasure, it's literally impossible, that information just does not exist at runtime and therefore cannot possibly be derived).
You can search the web for tutorials on how to make these, and various libraries, such as JSON parsing libraries, have TypeTokens (and documentation on how to use them), which are all implementations of this idea.
I have the following code:
public class I<T> {
private T t;
public I(T t) {
this.t=t;
}
}
public class G<T> {
private I<T> tab[];
public G() {
tab=(I<T>[]) new Object[10];
}
}
Calling G() throws a ClassCastException.
How could I code the G constructor in order to initialize tab?
tab=(I<T>[]) new I<?>[10];
is the answer, but it is still mysterious for me!
To hopefully demystify your own answer a bit: be aware, that java implements generics via erasure, i.e. the compiler basically does some compile time checks, and then discards the generics.
So, from the runtime point of view, your first approach boils down to:
I[] tab = (I[]) new Object[10];
As array types are really distinguished classes, you get a class cast exception here, as I[].class is not the same as Object[].class.
Your second approach is (generics discarded):
I[] tab = (I[]) new I[10];
... no problems here.
Tab is an array of I. I is an Object, but a simple Object created by new Object() is not a I. That explains why the first way produced an error. You must create a array of I to initialize tab.
But that's not all: java generics use type erasure. That means that at run time the compiler does not know what T is. tab = new I<T>[10]; is executed at run time when T has no meaning any more, hence the error.
The solution is to create an array of I of any (new I<?>) or an array of I<Object> or even use the old (pre-generic) syntax new I[10].
That's not asked here, but when you really need to know the type of the parameter in a generic, the common idiom is to pass explicitely the class in constructor or with a setter so that the generic object can use it. Code could be:
class G<T> {
private I<T> tab[];
private Class<T> clazz;
...
public G(Class<T> clazz) {
this.clazz = clazz;
tab = new I[10];
// here we can use the type of T from clazz by reflexion...
}
}
I am working on a class that will have functionality similar to JTable's setDefaultRenderer method. I want to have Class-specific formatters which convert objects to strings suitable for displaying.
public interface Formatter<T> {
String format(T value);
}
private Map<Class<?>, Formatter<?>> formatters;
public <T> void addFormatter(Formatter<T> formatter) {
formatters.put(T.class, formatter);
}
That's the code I have right now, but Java doesn't accept T.class.
error: cannot select from a type variable
formatters.put(T.class, formatter);
^
1 error
Is there a way to write this without passing a separate Class<T> parameter? I'm trying to avoid that. It seems redundant.
No, it's impossible because of generic type erasure in Java. All information about a generic class is lost at runtime, the only solution is to explicitly pass around the class as a parameter.
Not a solution but a hack.
You can do it. But through dirty tricks and reflection. Look at below code for example. Courtesy here:
class ParameterizedTest<T> {
/**
* #return the type parameter to our generic base class
*/
#SuppressWarnings("unchecked")
protected final Class<T> determineTypeParameter() {
Class<?> specificClass = this.getClass();
Type genericSuperclass = specificClass.getGenericSuperclass();
while (!(genericSuperclass instanceof ParameterizedType) && specificClass != ParameterizedTest.class) {
specificClass = specificClass.getSuperclass();
genericSuperclass = specificClass.getGenericSuperclass();
}
final ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
final Type firstTypeParameter = parameterizedType.getActualTypeArguments()[0];
return (Class<T>) firstTypeParameter;
}
}
//change the type of PrameterizedTest<Integer> to Parameterized<String> or something to display different output
public class Test extends ParameterizedTest<Integer>{
public static void main(String... args){
Test test = new Test();
System.out.println(test.determineTypeParameter());
}
}
Here on the runtime, you get the Type Parameter. So instead in your class, you will have to define a Class object which gets the class as explained above. Then using Class.newInstance you get a new Object. But you will have to manually handle type cast and so on.
The question is: Is all this worth it??
No according to me as most of it can be avoided by using bounds in generic types and interfacing to the bound type. So you should be looking for alternative solution
In general it's not possible. In your case, though, it might be reasonable to have Formatter implement a Class<T> getFormatterTargetClass() method, which you could then use instead of T.class in your code.
Due to type-erasure T.class is not available at runtime, so you would have to pass in a separate parameter. In general, generic type-information is not available at runtime (unless you are using unbounded wildcards).
That's not possible in Java language. All the generic types are determited at compilation time, so you can't access class value in execution. So you need to pass the Class<T> parameter as well in order to be able to access it.
public Class MyGenericClassContainer<T>{
public T instance;
public Class<T> clazz;
public MyGenericClassContainer(Class<T> clazz){
intance = clazz.newInstance();
}
}
An instructive exercise is to ask yourself, "How would I do this without generics?" The answer to that is also the answer to your question.
A program with generics can be written into an equivalent program without generics, by removing generics and inserting casts in the right places, without changing anything else in the code. This transformation is called "type erasure". This means that if something cannot be written without generics, then it cannot be written with generics either.
Without generics, your code looks like this:
public interface Formatter {
String format(Object value);
}
private Map formatters;
public void addFormatter(Formatter formatter) {
formatters.put(?, formatter);
}
So, I ask you, how would you do it?
I have this class, just for the purpose of learning:
public class MyClass{ //Looking for a solution without making my class also generic <Type>
//Private Arraylist var to hold the value called myvar
public MyClass(ArrayList<MyDesiredType> incoming) {
//CODE myVar=incoming
}
public MyDesiredType getType() {
return myVar.get(0);
}
}
Is there any way to infer in the incoming object from the constructor to the return type of the method without warnings and castings and loosing typesafeness, but most of all WITHOUT making the whole class GENERIC (seems redundant to me)? If not, why should I think this is not feasible for the compiler?
This is a reformulated question I already did, but it was my first one and I learned how to expose it clear because nobody understood. I tried to edit later the original question but everything was buried. I changed and simplified the example and try to put it easy. Original question: Java Generics Silly Thing (Why cant I infer the type?).
If there is any problem just tell it to me and I will remove it.
No, there is not. How would the compiler know what type to return? The generic type of ArrayList in the constructor will not be known during compile time. You either have to make the whole class generic or take another approach.
Consider this:
public class Test {
public static void main(String[] args) {
List<String> arrList = new ArrayList<String>();
arrList.add("FOO");
Test test = new Test(arrList);
String testStr = test.returnWhat();
System.out.println("testStr");
}
private final List myList; //warning
public <T> Test(List<T> ttype) {
myList = ttype;
}
public <T> T returnWhat() {
return (T) myList.get(0); //warning
}
}
This works but gives you warnings on the marked lines. So, really there is no way to achieve what you are describing without making the whole class generic.
Because, what if:
public class Test {
public static void main(String[] args) {
List<String> arrList = new ArrayList<String>();
arrList.add("FOO");
Test test = new Test(); // now what?
String testStr = test.returnWhat(0); // no warning...
JPanel p = test.returnWhat(0); // goes through without warning, real nice...
test.returnWhat(0); // returns Object
Test test2 = new Test(arrList);
test2.addElement(new Object()); // boom, inserted object into list of string.
String nono = test2.returnWhat(1); // the universe goes down. assign an object to string without warning. even
// though one COULD think the class is generic.
}
// private List<T> myList = new ArrayList<T>(); compiler error, T is unknown
private List myList = new ArrayList();
public Test() {
myList.add(new Object());
}
public <T> Test(List<T> ttype) {
myList = ttype;
}
public <T> T returnWhat(int index) {
return (T) myList.get(index);
}
public <T> void addElement(T el) {
myList.add(el);
}
}
The second one doesn't compile when myList is made generic. How could the compiler determine the type of <T> in the case where the default constructor is used?
Further, this could lead to serious problems with Objects in collections that rely on the fact that only certain types are inserted.
This will generate the following exception:
Exception in thread "main" java.lang.ClassCastException:
java.lang.Object cannot be cast to java.lang.String at
Test.main(Test.java:27)
Did I manage to convince you?
Real nice question, btw. I had to think about this one quite a bit.
When you say that you want the compiler to "infer in the incoming object from the constructor to the return type of the method without warnings and castings and loosing typesafeness", it seems that you are saying that it should infer the result of getType() from the input of the constructor. If both happen in the same function, it could. The problem is that the object may not exist in only one function, and so the extra type information (the generic type) is needed to pass this kind of object between functions.
For example, if I want to write a function that takes a MyClass object, I need to know what getType() will return so I can use the returned value. By adding a generic type of MyClass we are giving a description to what it holds.
Another way to look at it is that MyClass is a container. By adding generics, we are saying it is a container of a specific type of thing, and so we can more easily predict what we will get out of it.
There is no way for the compiler to know at runtime what type your arraylist is. I really dont see the problem using something along the lines of this:
public class MyClass<TYPE> {
private ArrayList<TYPE> incoming;
public MyClass(ArrayList<TYPE> incoming) {
this.incoming = incoming;
}
public TYPE getType() {
return incoming.get(0);
}
}
This way you can do:
ArrayList<Integer> numbers = createListOfNumbers();
MyClass<Integer> myClass = new MyClass<>(numbers);
Integer number = myClass.getType();
Or am i misinterpreting the question and you want to know the class at runtime?
No, if you want a class that can hold a list of a parameterized type.
Yes, if you want a class that can hold a list of exactly one type. You can declare that type explicitly in the field, constructor and accessor.
What you're forgetting is that not all code that you may run against is visible to the compiler! Jars can be added, removed, substituted at run time, that the compiler never saw. You may compile against an interface that is just:
public interface MyClassFactory {
MyClass getInstance();
}
Then at runtime you supply into the JVM an implementation. So the compiler never saw the actual code creating the MyClass that you will be using, so there is no way to perform such a compile time inference. You must either make the class generic or accept that there will not be type safety.
This question already has answers here:
Get generic type of class at runtime
(30 answers)
Closed 4 years ago.
I have a small problem in java while using genericity. I have a class A :
public class A<T>
In a method of A, I need to get the type name of T.
Is there a way to find the string s using T ?
(If I create A<String> temp = new A<String>();, I want to be able to get java.lang.String at one point - I have to use genericity because one of my methods will have to return a List<T>).
This seems quite easy but I do not see how to do it.
You can't do this in general because of type erasure - an instance of A<String> doesn't know the type of T. If you need it, one way is to use a type literal:
public class A<T>
{
private final Class<T> clazz;
public A<T>(Class<T> clazz)
{
this.clazz = clazz;
}
// Use clazz in here
}
Then:
A<String> x = new A<String>(String.class);
It's ugly, but that's what type erasure does :(
An alternative is to use something like Guice's TypeLiteral. This works because the type argument used to specify a superclass isn't erased. So you can do:
A<String> a = new A<String>() {};
a now refers to a subclass of A<String>, so by getting a.getClass().getSuperClass() you can eventually get back to String. It's pretty horrible though.
You can get the name of the generics from the subclass. See this example.
We Define a parent class like this:
public class GetTypeParent<T> {
protected String getGenericName()
{
return ((Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0]).getTypeName();
}
}
We then define its child class in this way:
public class GetTypeChild extends GetTypeParent<Integer> {
public static void main(String[] args) {
GetTypeChild getTypeChild = new GetTypeChild();
System.out.println(getTypeChild.getGenericName());
}
}
You can see that in the main method, or in any instance method, I am capable to get the name of the generics type, in this case the main will print: java.lang.Integer.
Short answer: Impossible.
Slightly longer answer: Once your code is compiled, the type parameters is discarded.
Thus, Java cannot know what you set there.
You could, however, pass the class in question to your object and operate on it:
public class Example<T> {
private final Class<T> clazz;
public Example(Class<T> clazz){
this.clazz = clazz;
}
...
}
As is normally the case, Apache has a solution for this one with TypeUtils:
https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/reflect/TypeUtils.html
A quick example from the above question:
TypeUtils.getTypeArguments(temp.getClass(), A.class).get(A.class.getTypeParameters()[0])
Disclaimer: I did not attempt building this first, but have used this utility in a similar fashion in the past.
Generics in Java are implemented by erasure, so no, you won't be able to get the name of the "type" which was used to create your generic collection at run-time. Also, why not just inspect the elements to know what type it belongs to?
If you're doing it in a subclass which has it's parent class defining the generic type, this is what worked for me:
// get generic type class name
String name = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].toString();
// then when you've got the name, you can make the Class<T> object
Class.forName(name.replace("class ", ""))
Reason why I couldn't do it with #getClass() instead of #toString() in the first snip is that I was always getting the "Class" class, which is useless to me.