I'm looking at a tutorial found on: http://www.ibm.com/developerworks/library/j-dyn0603/
In particular there is a section where it gives the following example:
Class[] types = new Class[] { String.class, String.class };
Constructor cons = TwoString.class.getConstructor(types);
Object[] args = new Object[] { "a", "b" };
TwoString ts = (TwoString)cons.newInstance(args);
I don't quite follow what Class[] represents. The way I read it, this says 'an array of Class objects called types]. I'm also somewhat unfamiliar with the syntax used in the new statements - how does new Class[] { String.class, String.class} work?
If someone can help break this down for me I would appreciate it.
Yes the literal meaning is exactly what you are thinking it is
Class[] types = new Class[] { String.class, String.class }; is a declaration and initialization in one line. It says create an array that holds objects of type Class and initialize it with two objects of type Class, namely String.class and String.class.
A similar example would be
int[] nums = new int[]{1,2,3};
or
float[] decimals = new float[]{1.2, 3.1, 5.2}
A Class is an Object that describes a java class (or interface). A Class[] is an array of these objects.
The syntax <ClassName>.class (e.g. String.class) returns the Class for a particular java class (or interface).
A new array can be created through a few syntax. new Class[i] creates a new array of Class with length i and filled with default values (null references). new Class[]{a, b, c} creates a new array of Class containing the given elements a, b and c. It's length is 3 because 3 elements were given.
That's an array of the type Class
The
new Class[] {...}
Creates and array of type Class whose contents are listed inside.
In general
Type[] means, an "array of..." just like you thought.
It turns out the type here is Class which in Java is a representation of a running class or interface.
Probably you shouldn't go for advanced features like reflection without knowing first the basics.
It is an array of Objects which share the super type Class.
In Java, everything is an Object. This means that if you want to have in-code awareness of class types, you need to create an Object which can encapsulate the details of the class. Java calls this Object a Class.
Note the capitalization and be aware that since Class is an Object, you can call all Object methods on class, like x.getClass(), x.wait(), and x.hashcode().
Class[] items = { String.class, Integer.class };
means create an array called items which contains Class objects. Initialize the array with the Objects representing the class of String and the class of Integer.
Since Class objects represent class types, often the two are used interchangeably in informal speech.
Class is actually a class named, uhmm.. Class.
Instances of the class Class represent classes and interfaces in a running Java application.
new Class[] works. It initializes an array of Class references. But, as usual with object arrays, the references are null.
Class Class does not have a public constructor. So you can not say new Class()
Class is a java class that represents ... a class and related metadata. so Class[] is an array of Class objects.
Each class in java has a static member variable named class of type Class and here what you're doing is
creating a Class[] containing two
members each of which is an object of
type Class and specifically the Class
representing java.lang.String
looking up via reflection the
reference to the constructor in the
class TwoString that takes two
java.lang.String objects =>
TwoString(String, String)
creating an object array to feed to
the constructor with the values "a"
and "b"
finally you're creating an instance
of TwoString ts by invoking the
constructor you looked up in (b) and
args you initialized in (c)
This is equivalent to:
TwoString ts = new TwoString("a","b");
but the way you've posted is using Reflection/Introspection.
I am not sure if this is what you are looking for, but the Class[] in the example is mimicking the constructor in that TwoString class. To me it would have been clearer if they would have used two different types. So if the TwoString class looked like this:
public class TwoString {
private String m_s1;
private Integer m_s2;
public TwoString(String s1, Integer s2) {
m_s1 = s1;
m_s2 = s2;
}
}
The class name would not make since anymore, but I think that is easy to fix. The rest of the code example would become:
Class[] types = new Class[] { String.class, Integer.class };
Constructor cons = TwoString.class.getConstructor(types);
Object[] args = new Object[] { "a", 1 };
TwoString ts = (TwoString)cons.newInstance(args);
So the class array is to set up the constructor to use. The steps line by line are:
The class array sets up what constructor to use.
Then you find the constructor.
The you set up what values to pass into the constuctor.
Then you call the constructor to create the instance.
Related
Begining Java
Can someone break down whats going on here
protected Class<?>[] getServletConfigClasses() {
// TODO Auto-generated method stub
return new Class[] {
WebApplicationContextConfig.class
};
}
My understanding is that this is a method which expects its return to be an array of Class object of an unknown type
But what is the return?
An instantiation of an anonymous Class object array without a constructor and its implementation block at the same time?
What's the name of this for further reading and I can't seem to find this subject area?
There is no anonymous Class object. Class is a java class like any other, but with a name that is bound to confuse Java beginners.
the statement
return new Class[] {
WebApplicationContextConfig.class
};
is equivalent to
Class [] result = new Class[1];
result[0] = WebApplicationContextConfig.class;
return result;
WebApplicationContextConfig.class is called a class literal, and here is a some discussion about them.
It is an array declared with default values. In Java it is short-hand way of making arrays.
String[] names = {"Arvind","Aarav"}; // initialization
Now to re-assign a completely new array.
names = new String[]{"Rajesh","Amit","Mahesh"}; //re-initalization
Same thing with methods, let us say, returning days of week
public String[] weekdays(){
String[]days={"Sun","Mon","Tue"};
return days;
}
OR
public String[] weekdays(){
return new String[]{"Sun","Mon","Tue"};
}
Now about Class[], for type Class possible value is null and SomeClassName.class.
Class stringClass = String.class;
Class[] moreClasses = {Long.class, Boolean.class, java.util.Date.class};
It's just declaring an Array of Class and initialize it with one element (The Class definition of WebApplicationContextConfig)
It is array of wildcard type. See this for more
This is an array initializer. When you say
new Something[] { x1, x2, x3 }
it creates a new array of the Something class, and initializes the values to whatever you tell it in the curly braces. The length of the new array is the number of values.
I think you might be confusing it with a very similar syntax:
new Something() { class declarations, method overrides, etc. }
This one creates an anonymous subclass of Something, and it's used a lot for creating anonymous subclasses that implement interfaces. It's not at all related to the array initializer syntax, even though the appearance is pretty close.
As part of learning, here is the pathological example below that am trying to understand,
class C{}; interface I{}; class S extends C implements I{};
class B{};
With these declarations, I can say that, class C class B are immediate subclass of Object class and can access all methods of Object class from within those classes. But,
1) When i declare interface I{}; How is interface I related to Object class?
In continuation, Below are some assignment to array types, followed by subclass to super class assignment and vice-verse.
C[] c = new C[4];
S[] s = new S[6];
I[] i = new S[0];
B[] b = new B[2];
//i = new C[2]; Compile error
i =s; c=s; s = (S[])c; i = (I[])c;
i = (I[])b; //Run-time error
I learnt that arrays are 'first class objects' and immediate subclass of Object class,
Object o = c; // i mean `I i = c;` will not work `I[] i =c;` works
2) With respect to above definition(syntax), What is the meaning of 'arrays are first class objects'?Because Object[] oa = c; make sense to me as class C is immediate subclass of Object class.
When i declare interface I{}; How is interface I related to Object class?
From the Java Language Specification:
If an interface has no direct superinterfaces, then the interface implicitly declares a public abstract member method m with signature s, return type r, and throws clause t corresponding to each public instance method m with signature s, return type r, and throws clause t declared in Object, unless a method with the same signature, same return type, and a compatible throws clause is explicitly declared by the interface.
How would i consider reference variable o pointing to array c
As stated in the comments, the array is itself a subclass of Object, so the following assignment is valid:
Object o = c;
The relevant part from the Java Language Specification says:
In the Java programming language, arrays are objects (§4.3.1), are dynamically created, and may be assigned to variables of type Object (§4.3.2).
This is also what is meant by "arrays are first class objects". In Java, an array is not a special type or some special construct - it is essentially a sub class of Object with additional fields (in particular length) (and some additional compiler support to be able to syntactically describe and initialize an array).
If I have an ArrayList<Shape>, I'm under the impression that within that list I can store objects of class Shape or objects that are subclasses of Shape.
I've also seen a lot of notation around with things like ArrayList<T> or ArrayList<?>. Are these the same things? A T superclass and all its subclasses can be stored, and the ? is just a placeholder?
Basically, how does something like ArrayList<CLASSNAME> differ from ArrayList<T> where you just have the one letter.
First, the difference is not whether it is one letter as you might think. It is whether T is the name of a generic argument or not. If you declare a method like:
public <T> void method()
as opposed to:
public void method()
or a class like:
public class Whatever<T>
as opposed to:
public class Whatever
then T is a generic argument. You then get to use T anywhere you want as if it were a real class name, and a real class name will be substituted for T at compile time. But this is not the best picture of it, so let's say that the type of T is whatever type was passed to the arguments of type T. So, at any given moment, T has a value that is a real class name.
So, the difference between ArrayList<T> and ArrayList<Shape> is that ArrayList<T> holds objects of type T, whereas ArrayList<Shape> holds objects of type Shape. The trick is that T is whatever type was passed to arguments of type T, so it can vary.
Disclaimer: The type T does not actually change over time. In most cases, the compiler replaces it with Object. However, the compiler is good at hiding that, and it is a good idea to think of T changing.
First of all, ArrayList can't reference any subclass of Shape like this:
ArrayList<Shape> blah = new ArrayList<Square>
But you can do it this way:
ArrayList<? extends Shape> blah = new ArrayList<Square>
Polymorphism doesn't work with type parameter. It only works with objects such as:
Collection<String> blah = new ArrayList<String>
But you have to understand the purpose of using T. T is used to declare a type parameter for class and methods.
Such that when you declare a class with parameter T:
public class ArrayList <T>
T acts as a placeholder when the class is instantiated as object.
So in this case:
ArrayList<String>
you are replacing T with String in the ArrayList class.
Btw, you aren't suppose to use T as a type for argument. Because T isn't really defined, it is only a placeholder.
You express ArrayList<T> when you're declaring the type / class and ArrayList<String> when you're creating an instance of ArrayList and associate it with the type parameter String.
For example:
// class declaration
public class ArrayList<T> extends ... implements ... {
...
// Creating an arraylist of string
ArrayList<String> stringArray = new ArrayList<String>
You can think of generics as a type variable. Hence instead of creating a class which only works with String:
public class MyArray {
String get(int index) { ... }
}
You can create an array class that works with any arbitrary type
public class MyArray<T> {
T get(int index) { .. }
}
public class GenericClass<T> {
class MyClass {
}
public GenericClass(final T[] param) {
MyClass myObject = new MyClass(); // OK
MyClass[] myArray = { new MyClass(), new MyClass() }; // Cannot create a generic array of GenericClass<T>.MyClass
}
}
This is not creating a generic array. The compiler should have no problems understanding/determining MyClass, isn't it?
Inner classes "know" which instance of the enclosing class created them, and can access fields/members of this instance. It is as if they have a second this variable whose type is the concrete type of the enclosing class (such as GenericClass<String>).
To overcome this predicament you can make MyClass static. This will make it completely decoupled of any instance of the enclosing class (that is: it will not have that second this) so they can be instantiated freely:
public class GenericClass<T> {
static class MyClass {
}
public GenericClass(final T[] param) {
MyClass myObject = new MyClass(); // OK
MyClass[] myArray = { new MyClass(), new MyClass() };
}
}
Here's some additional information. From the link ...
Java arrays carry runtime type information that identifies the type of
the elements contained
to the compiler your code looks like this:
MyClass[] myArray = {new GenericClass<T>.MyClass(), ..} //T is unknown
The JLS section that covers this is 10.6. Specifically, it's because:
It is a compile-time error if the ClassOrInterfaceType does not denote a reifiable type (§4.7). Otherwise, the ClassOrInterfaceType may name any named reference type, even an abstract class type (§8.1.1.1) or an interface type (§9).
The rules above imply that the element type in an array creation expression cannot be a parameterized type, other than an unbounded wildcard.
Because MyClass is non-static it is dependent on the outer class; it's actually GenericClass<T>.MyClass and therefore a parameterized type. Declaring it static removes that dependency and solves the problem.
Where it gets weird is if you do this;
class MyClass<T> {
}
public GenericClass(final T[] param) {
MyClass[] myArray = { new MyClass(), new MyClass() };
}
It's legal. Screwy, kind of clumsy, but legal. Because you redeclare the type, it hides the outer one. Then ... arrays and generics don't mix ... unless you use raw types. For backward compatibility you can have a rawtype array which ends up holding MyClass<Object>. It's a really awful thing, but it does compile. You can get away with creative casting here but in the end ... just ... don't.
{ new MyClass(), new MyClass() }; //new MyClass() => new GenericClass<T>.MyClass()
Above code will be treated as array of object as T is unknown ,due to the way generics are implemented (by erasure), the type of the array is not well-defined. On one hand, it should be an array of MyClass , on the other hand, it should be an array of Object
Create array of object type and cast it to your type
Object[] arr=new Object[]{this.new MyClass(), this.new MyClass()};
MyClass[] myArray = Arrays.copyOf(arr,arr.length, Item.MyClass[].class);
If you make it static it will work because-
A static nested class or nested interface (which is always static, by the way) has no relation to its outer class (or interface) apart from namespace nesting and access to private variables.
As an example in the standard API, look for the interface Map.Entry, nested inside the interface Map, yet has no access to its type parameters and needs to declare them again.
The problem here is that the compiler cannot determine at compile time the information of the array myArray. It is considered generic because (as eclipse shows you) it is converted in {new GenericClass<T>.MyClass(), ...}. This is because you're putting the class MyClass inside a generic class.
This code doesn't work either:
package my.stuff;
public class GenericClass<T> {
class MyClass {
static MyClass[] myArray = { new MyClass(), new MyClass() };;
}
public GenericClass(final T[] param) {
MyClass myObject = new MyClass();
}
}
but this code works:
package my.stuff;
public class GenericClass<T> {
public GenericClass(final T[] param) {
MyClass myObject = new MyClass();
MyClass[] myArray = { new MyClass(), new MyClass() };
}
}
class MyClass {
}
Because you're not using generics in your MyClass, the best thing to do is probably the second one.
If you declare it static, the compiler knows that MyClass is not generic and it knows what to do.
Besides, the only way to create a generic array in java is create a raw type and then cast it to generics (see here: "Cannot create generic array of .." - how to create an Array of Map<String, Object>?). So, if you absolutely need myClass inside the generic one, you should turn it in MyClass<T>, and then you use the trick: create a raw type and cast it to MyClass<T>:
package my.stuff;
public class GenericClass<T> {
class MyClass<T> {
}
#SuppressWarnings("unchecked")
public GenericClass(final T[] param) {
MyClass<T> myObject = new MyClass<T>();
MyClass<T>[] myArray = new MyClass[]{ new MyClass<T>(), new MyClass<T>() };
}
}
even it you don't use T inside the class MyClass.
#ItayMaman has the right reason. Basically, MyClass is not a reifiable type.
MyClass is a non-static inner class. Since it is non-static, it is within the scope of the type parameters of its enclosing class. And every time you write MyClass by itself in an instance method of GenericClass, it is actually short for GenericClass<T>.MyClass. So even though it may not look it, MyClass (by itself) is actually a parameterized type (parameterized by T), similar to List<String>. And so when you do new MyClass[2], you are trying to create an array of a parameterized type, just like new List<String>[2]. And I think you already know that this is not allowed.
What should you do? It all depends on what your intention is. One thing that people suggest is to make MyClass static. Of course, that will take it out of the scope of T. But that may or may not be what you want, because it completely changes its relation to GenericClass. A non-static inner class has access to an instance of the enclosing class, which is perhaps why you made it that way in the first place. If you never intended for it to be non-static (and did it by mistake), then this is obviously the way to go.
If a non-static inner class is what you want, and you simply wants to create an array of this type, let's consider how you would usually deal with arrays of parameterized types, e.g. List<String>[].
One solution is to instead create an array of the raw type, e.g. List[] foo = new List[2];. The equivalent way to do this for our case would be GenericClass.MyClass[] foo = new GenericClass.MyClass[2];. Notice what we did here. In order to write the raw type, we had to explicitly qualify MyClass with the unparameterized outer class name. If we didn't explicitly qualify it, then it would be implicitly qualified with GenericClass<T>, as explained above, which is not what we want. Translating this to the code in your example, you would write GenericClass.MyClass[] myArray = { new MyClass(), new MyClass() };
Similarly, if we want to avoid raw types, we could create an array of the wildcarded type, e.g. List<?>[] foo = new List<?>[2];. The equivalent way to do this for our case would be GenericClass<?>.MyClass[] foo = new GenericClass<?>.MyClass[2];. So translating this to the code in your example, you would write GenericClass<?>.MyClass[] myArray = { new MyClass(), new MyClass() };
Finally, we might instead want to create an array of the wildcarded type, but then cast back into an array of the parameterized type, for convenience of use later on. e.g. List<String>[] foo = (List<String>[])new List<?>[2];. The equivalent way to do this for our case would be MyClass[] myArray = (MyClass[])new GenericClass<?>.MyClass[] { new MyClass(), new MyClass() };. Note the the cast is an unchecked cast. The advantage of this is now when you get things out of myArray, it will be type MyClass, instead of raw type GenericClass.MyClass or wildcarded type GenericClass<?>.MyClass from the methods above.
I have a question about Generics in Java, namely using wildcards. I have an example class GenClass like this:
public class GenClass<E> {
private E var;
public void setVar(E x) {
var = x;
}
public E getVar() {
return var;
}
}
I have another simple class:
public class ExampleClass {
}
I have written the following test class:
public class TestGenClass {
public static void main(String[] str) {
ExampleClass ec = new ExampleClass();
GenClass<ExampleClass> c = new GenClass<ExampleClass>();
c.setVar(ec);
System.out.println(c.getVar()); // OUTPUT: ExampleClass#addbf1
}
}
Now, if I use a wildcard and write in the test class this:
GenClass<?> c = new GenClass<ExampleClass>();
on the place of:
GenClass<ExampleClass> c = new GenClass<ExampleClass>();
the compiler has no problem with this new statement, however, it complains about
c.setVar(ec);
It says that "the method (setVar()) is not applicable for the arguments (ExampleClass)". Why do I get this message?
I thought that the way I have used the wildcard, makes the reference variable c be of type GenClass, which would accept as parameter any class - on the place of E I would have any class. This is just the declaration of the variable. Then I initialize it with
new GenClass<ExampleClass>()
which means that I create an object of type GenClass, which has as parameter a class of type ExampleClass. So, I think that now E in GenClass will be ExampleClass, and I would be able to use the method setVar(), giving it as argument something of type ExampleClass.
This was my assumption and understanding, but it seems that Java does not like it, and I am not right.
Any comment is appreciated, thank you.
This exact situation is covered in the Java Generics Tutorial.
Notice that [with the wildcard], we can still read elements from [the generic Collection] and give them type Object. This is always safe, since whatever the actual type of the collection, it does contain objects. It isn't safe to add arbitrary objects to it however:
Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
Since we don't know what the element type of c stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.
(emphasis mine)
mmyers has the correct answer, but I just wanted to comment on this part of your question (which sounds like your rationale for wanting to use the wildcard):
I thought that the way I have used the wildcard, makes the reference variable c be of type GenClass, which would accept as parameter any class - on the place of E I would have any class. This is just the declaration of the variable. Then I initialize it with
If you really want to accomplish this, you could do something like without compilation errors:
GenClass<Object> gc = new GenClass<Object>();
gc.setVar(new ExampleClass());
But then again, if you want to declare an instance of GenClass that can contain any type, I'm not sure why you'd want to use generics at all - you could just use the raw class:
GenClass raw = new GenClass();
raw.setVar(new ExampleClass());
raw.setVar("this runs ok");