Test test1 = new Test();
here, new Test() means create new instance of class Test and assign it
to reference test1.
Class<Test> test2 = Test.class;
Test test2Instance = test2.newInstance();
I am not able to define (in words) 1st statement. On the other hand 2nd statement it pretty clear to me.
EDIT
String is an instance of the class Class.
A string literal (e.g. "I am a string.") is an instance of the class
String.
class literal (e.g. Hashtable.class) is an instance of the class
Class.
Class<Test> test2 = Test.class;
This statement declares a variable named test2, of type Class<Test>. It initializes this variable with the unique instance of this type, using the class literal expression Test.class which refers to the class Test.
Class<Test> test2 = Test.class;
means "give me the Class object representing the Test class and store it in the variable test2.
Aside from Class being generic, this has little to do with generics. It's about class objects.
Class<Test> is a specific type of a generic type. Literally you are defining a variable test2 which is of type Class<T> with T == Test.
Class<T> is a parametric type, it depends on T, if you add the constraint T == Test then you are talking about a variable of Class<Test> (which is a specific different type).
It's orthogonal compared to polymorphism by subtype. If you have
class Base { .. }
class Derived extends Base { .. }
and you write
Derived derived = ...
You have no problems in stating that you are declaring a variable named derived of type Derived. This is the same thing, but Class<Test> is not a subtype of Class<T> but a specialization of it.
Related
Every object in Java belongs to a certain class. That's why the Object class, which is inherited by all other classes, defines the getClass().
getClass() method returns the instance of Class class.
For example:
class Foo{}
class Sample{ class Foo instance = Foo(); Class obj = instance.getClass(); }
Another way of getting the instance of Class class is by saying Foo.class
My question:
I can see the definition of getClass() in Object class source code(File Object.java package java.lang). In which source file, can i see the member class which we are using as Foo.class?
No source file. class is a keyword (like this, instanceof, etc), not a member of any class, and is handled by the compiler, not in code.
If an instance of an object is available, then the simplest way to get its Class is to invoke Object.getClass()
Foo foo=new Foo();
Class c = foo.getClass();
If the type is available but there is no instance then it is possible to obtain a Class by appending .class to the name of the type. This is also the easiest way to obtain the Class for a primitive type.
boolean b;
Class c = boolean.class;
and this would produce compile-time error
Class c = b.getClass();
because a boolean is a primitive type and cannot be dereferenced
And for something like this
Foo foo=null;
note that you cannot use foo.getClass() in this case since it is not instantiated.
And finally for something like this
Foo foo=new FooChild();
Class c= foo.getClass(); //returns FooChild, evaluates at runtime
Class c= Foo.class;// returns Foo , evaluates statistically at compile-time.
Edit:- For .class its a static field inside every primitive type, static Class<Integer> ,The Class instance representing the Integer. you can see it here for Integer , here for Boolean. boolean, byte, char, short, int, long, float, and double all of them have a Class static field because like i said its always going to stay same and primitive types cannot be cannot be dereferenced. To see the source, if you see source of Integer you can see the class field as public static final Class<Integer> TYPE = (Class<Integer>) VMClassLoader.getPrimitiveClass('I'); , see here line 82. You can search and see for others too.
Is it possible to declare variable of a type (literal) stored in a collection?
Or that might be more of a feature/task for an interpreted, not a compiled language like Java?
For example:
import java.util.*;
class Base {}
class A1 extends Base{}
class A2 extends Base{}
public class Test{
public static void main(String[] args){
ArrayList<Class<? extends Base>> typeArrayList=new ArrayList<Class<? extends Base>>();
typeArrayList.add(A1.class);
typeArrayList.add(A2.class);
typeArrayList.add(A1.class);
typeArrayList.add(A1.class);
//etc. etc.
//now that all the types are nicely stored in a collection,
//could we somehow use them to declare variables of those types?
//e.g. declare something like:
//typeArrayList.get(1) someVariable;
}//main
}//Testlass
You can use:
Object o = typeVarArrayList.get(1).newInstance();
or
Type o = (Type) typeVarArrayList.get(1).newInstance();
But you need that the class have one constructor without parameters.
If you need a more specific constructor, please see here
You can use newInstance() if there is a default constructor available, if not then you will need to have people supply you with factory objects and then call a method in the factory to build your objects.
The Factory pattern is generally neater too for most implementations unless the objects being created really are just plain beans with nothing but default values as the factory allows you to properly set up the object.
//e.g. declare something like:
//typeArrayList.get(1) someVariable;
In short, no, type declarations must be explicit.
For example, the Java language defines these rules for local variable declarations:
LocalVariableDeclaration:
VariableModifiersopt Type VariableDeclarators
Type:
PrimitiveType
ReferenceType
ReferenceType:
ClassOrInterfaceType
TypeVariable
ArrayType
Drilling down to TypeVariable (because I'm not copying the entire language grammar) we get:
TypeVariable:
Identifier
An identifier is restricted to the things you'd expect in a class name.
Consider sample code below
public class Test {
public static void main(String args[]) {
Test t = new Test();
Class c2 = Test.class;
System.out.println(c2);
}
}
Test.class statically evaluates and returns compile time Class object. Looking at the Test.class syntax it looks like the variable class is of type java.lang.Class and is static and public. My question is where is this variable defined? It is not present in Test class (because I don't declare it) neither it is in the java.lang.Object class.
I saw an analogous method public final native Class<?> getClass();. This is present in java.lang.Object and is a native java method. This method returns the runtime Class of an object.
So my question is where is this public & static class variable defined?(Please correct me if I have mistaken) Is it again some native implementation? This is set at compile time and being static needs no class instance to be created. So if even this is some native implementation is it initialized by registerNatives() method in java.lang.Object?
These are called class literals and are defined by the language itself as per JLS §15.8.2 (there is no "class member"):
A class literal is an expression consisting of the name of a class, interface, array, or primitive type, or the pseudo-type void, followed by a '.' and the token class.
The type of C.class, where C is the name of a class, interface, or array type (§4.3), is Class<C>.
The type of p.class, where p is the name of a primitive type (§4.2), is Class<B>, where B is the type of an expression of type p after boxing conversion (§5.1.7).
The type of void.class (§8.4.5) is Class<Void>.
One indication that these constructs are intrinsically built into the language is that they even work with primitives!
System.out.println(int.class);
System.out.println(double.class);
// etc.
class is not normal static variable. It's a language construct which is replaced at compilation time.
Because class is a keyword it wouldn't even be possible to declare a variable with that name.
Your assumption that class is a static field of class Class is not exact. Assume that this is correct. In this case the value of this field will be exactly the same for all classes that is wrong.
Although MyClass.class syntactically looks like access to static field it is just a special syntax of language. Think about this as a kind of operator.
Probably JVM creates some kind of synthetic class that wraps real class and has such field but it is just an assumption about internal representation of classes in JVM.
In my textbook I can read:
If T is any Java type, then T.class is the matching class object. For example:
Class cl1 = Date.class; // if you import java.util.*;
Class cl2 = int.class;
Class cl3 = Double[].class;
Later on I'm reading:
The virtual machine manages a unique Class object for each type. Therefore, you can use the == operator to compare class objects. For example:
if (e.getClass() == Employee.class)
Could you help me find anything about this .class field in the documentation.
And another qutstion - I can't understand whether the e.getClass() == Employee.class is the same as e.class == Employee.class. I mean, if it is the same, why the author of the textbook used getClass here in the lefthand expression.
From JLS §15.8.2 - Class Literals:
A class literal is an expression consisting of the name of a class, interface, array, or primitive type, or the pseudo-type void, followed by a '.' and the token class.
The type of C.class, where C is the name of a class, interface, or array type (§4.3), is Class.
So, Date.class, int.class are nothing but class literals, which give appropriate Class objects for a class type.
I can't understand whether the e.getClass() == Employee.class is the same as e.class == Employee.class
No, they are not the same. In fact, e.class won't even compile. As per the definition of class literal above, since e is not a type but an object of Employee (I assume that), e.class is not a valid class literal. To get the Class object of a class, using it's instance, you need to use Object#getClass() method.
So, e.getClass() and Employee.class are two different ways to obtain the Class object for Employee class. Both to be used in different circumstances. When you know the class type, use 2nd version, and when you have an instance of your class, use the 1st version.
However, note that in case of inheritance, e.getClass() might not return the same Class object as Employee.class. The former would return the Class object of the actual subclass object, referred by the reference e, whereas the later would always give you Class<Employee>.
If you neither have the instance, nor the class type available, then you can also get the Class object for a class name in String form, using - Class#forName(String) method.
How you get a Class object depends on what you already know. If you have an object referenced by x, you can obtain the Class object for its class by x.getClass(). If you know, when you are writing your code, the name of a type T, you can use T.class to get the class object. There is a third approach, less convenient, that only requires run time access to the class name.
The getClass method is described as one of the Object methods, in the Object API documentation.
Class literals, the T.class form, are described in the Java Language Specification.
The third approach uses one of the static forName methods defined the API documentation for java.lang.Class.
I have been reading the answers to the question:
Create instance of generic type in Java?
I have implemented the approach suggested by Lars Bohl. I adapted his code as follows:
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class ParameterizedTypeEg<E> {
public Class<E> getTypeParameterClass() {
Type type = getClass().getGenericSuperclass();
ParameterizedType paramType = (ParameterizedType) type;
return (Class<E>) paramType.getActualTypeArguments()[0];
}
private static class StringHome extends ParameterizedTypeEg<String> {
private String _string;
StringHome (String string) {
_string = string;
}
}
public static void main(String[] args)
throws InstantiationException, IllegalAccessException {
String str = new StringHome("my string").getTypeParameterClass().newInstance();
String str2 = new ParameterizedTypeEg<String>().getTypeParameterClass().newInstance();
}
}
This approach works fine for the str variable. Then str2 is created with what appears to me to be the same type (ParameterizedTypeEg < String >, which is basically the same thing as a StringHome). However, the approach does not work for str2, and a ClassCastException is thrown when I try to cast (ParameterizedType) type.
Even though for str2, I have parameterized ParameterizedTypeEg with a String, getGenericSuperclass() returns something very different than for str. Also, within methods str2 shows 'this' as a ParameterizedTypeEg, whereas for str, 'this' is a ParameterizedTypeEg$StringHome. I suppose that is the root of the problem. Why does Java not see that the generic type has been determined for str2 also?
I have had what appears to be the same problem when the parameterized type is passed through multiple levels of hierarchy? That is, class B< T > contains A< T > and I instantiate a B. Within A, I cannot create a String object by determining the parameterized type of A using the above approach. The approach produces an exception in the case of a containment hierarchy as well. And this causes me a problem because I want to be able to pass the parameterized type through multiple levels of containment and/or inheritance and have the same approach produce an instance of the generic type in all cases.
Thanks,
John
With the following change your code will work:
from
String str2 = new ParameterizedTypeEg<String>().getTypeParameterClass().newInstance();
to
String str2 = new ParameterizedTypeEg<String>(){}.getTypeParameterClass().newInstance();
This creates an anonymous subclass of ParameterizedTypeEg. When you call
getClass().getGenericSuperclass();
on StringHome, you get a ParameterizedTypeEg < java.lang.String>, which is what you want. If you create str2 as you did, that call simply returns Object, so the attempt to cast it to a paremeterized type fails:
Exception in thread "main" java.lang.ClassCastException:
java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
Creating an anonymous subclass makes this return ParameterizedTypeEg < java.lang.String>
This is the same trick that's used in the Type Token class in the Google Guice Guave libraries, btw. You write, for example
new TypeToken<List<String>>() {}
and not
new TypeToken<List<String>>()
However, the approach does not work for str2, and a ClassCastException
is thrown when I try to cast (ParameterizedType) type........... Why
does Java not see that the generic type has been determined for str2
also?
As specified in oracle doc for ParameterizedType:
ParameterizedType represents a parameterized type such as
Collection<String>
But, super class of ParameterizedTypeEg is Object , which is not Generic Type. So, the Type returned by getClass().getGenericSuperclass(); is Class of Object itself. And type casting of non parametrized type to the ParameterizedType is giving you ClassCastException for str.
Why does Java not see that the generic type has been determined for
str2 also?
An object at runtime does not have any type parameter information. Basically, for you to do .newInstance() to create an object, you need to have the class object at runtime, which means you have to store it somewhere in a way to get it.
The reason it works for str is exactly because the type String is stored somewhere -- in the class metadata. Classes have metadata which includes the superclass and superinterfaces, enclosing class if it's an inner class, and the types of fields and methods (return type and parameter types of methods). All this information is stored, with generics, in the bytecode at runtime (the reason for this is that files in Java can be compiled separately, so when compiling one file that uses a class from an already compiled file, the compiler must be able to look at the class file and see the generics information), and is available at runtime via reflection on the class object.
So basically, the StringHome class acts as a "storage" for the String class object, because String was hard-coded as the type parameter of its superclass at compile-time. So at runtime you can get it out of this "storage".
That is, class B< T > contains A< T > and I instantiate a B. Within A,
I cannot create a String object by determining the parameterized type
of A using the above approach.
From my discussion above, you probably picked up that the key thing is to somehow "get" at runtime the class object for the class that is T. Making a class that subclasses A<T> will not help, because the point of that was that the actual class was hard-coded at compile-time, which requires knowing the class at compile-time. We don't know what class T is at compile-time, so we can't put it into the metadata; we can only put "T", i.e. a type variable.
So, again, the problem goes back to needing to find some way to pass or transmit the class object for the class that the type parameter represents. You cannot rely on any compile-time based mechanisms anymore. So you have to pass it in in an extra parameter or something.
getClass().getGenericSuperclass(); gives you the details of the super class. Therefore it will only work if you subclass a parameterized super class. It won't work if you instantiate a parameterized super class given type parameters.