"new E" is not allowed because the compiler has no
way
to know
if "E" has a noargs constructor. "new E[]" is not
allowed
because the compiler doesn't have enough
information
to actually
allocate an array of the correct type.
Follow code work fine:
List lArray = new List[size];
lArray[0] = new ArrayList();
lArray[1] = new LinkedList();
This mean, that you can use new Object[] to initialize
array.
You're confusing the directions; your example assigns an array of a subclass to an array of the superclass. That's safe and sound. If we translate this
E[] a = new E[10]
to this
E[] a = new Object[10];
then we're assigning an array of the superclass to an array of the subclass, which isn't statically sound or dynamically typesafe.
I made available a brief explanation of some issues
related to arrays in generic Java. Perhaps it aids
understanding. It's on my website at
http://www.langer.camelot.de/Articles/Java/JavaGenerics
ArraysInJavaGenerics.htm. It's nothing complete or
comprehensive, just an excerpt from some teaching
material that I'm currently working on.
Wonderful! I'd love to see more of the course materials.
You're confusing the directions; your example assigns
an array of a subclass to an array of the superclass.
That's safe and sound. If we translate this
E[] a = new E[10]
to this
E[] a = new Object[10];
then we're assigning an array of the superclass to an
array of the subclass, which isn't statically sound or
dynamically typesafe.
But this is used in generics 2.2... as i already said, the form of array initializing follow:
E[] eArray = (E[])new Object[size];
And my question, "why in generics disallow to use simplicity array initialization, but you can use cast initialization for arrays, like above?".
The compiler "realy" don't know about type of array, but it type is always java.lang.Object. As far as it use in generics core sources, maybe it's good to use similar to array initialization:
arrays of type variables and parameterized types
Aug 5, 2003 1:04 AM
(reply 18
of 34) (In reply to
#16 )
I made available a brief explanation of some issues
related to arrays in generic Java. Perhaps it aids
understanding. It's on my website at
http://www.langer.camelot.de/Articles/Java/JavaGenerics/ArraysInJavaGenerics.htm.
It's nothing complete or
comprehensive, just an excerpt from some teaching
material that I'm currently working on.
Wonderful! I'd love to see more of the course
materials.
... but we still do not know whether arrays of type variables and parameterized types are permitted or not. The spec allows them, the compiler rejects them. What is the intent?
Usually the spec captures the intent. So, despite of the issues, arrays of type variables and parameterized types are allowed in generic Java. Correct?
Re: arrays of type variables and parameterized types
Aug 5, 2003 9:03 AM
(reply 19
of 34) (In reply to
#18 )
The intent, as I understand it, it to allow arrays of types parameterized on wildcards only in Java 1.5. That is:
new String[10]; // legal
new Set<?>[10]; // legal
new Set<String>[10]; // not legal
new Map<?,?>[10]; // presumably legal
new A<?>.B[10]; // presumably legal
new A.B<?>[10]; // presumably legal
It's on my website at http://www.langer.camelot.de/Articles/Java/JavaGenerics/ArraysInJavaGenerics.htm. It's nothing complete or comprehensive, just an excerpt from some teaching material that I'm currently working on.
Wow, fancy meeting you here. I thought your name looked familiar. We both ended up in the same issue of Java Solutions for CUJ - I did an article on "The Tattletale Technique" and you co-authored an article on "Implementing equals for Mixed-Type Comparison"
(Not that you really care, but it's always neat to realize you have some sort of relationship to someone, even if tenuous).
Re: arrays of type variables and parameterized types
Aug 5, 2003 5:58 PM
(reply 21
of 34) (In reply to
#18 )
... but we still do not know whether arrays of type
variables and parameterized types are permitted or
not. The spec allows them, the compiler rejects them.
What is the intent?
The intent is that they're not allowed.
I just captured a snapshot of the spec as a work in progress. This and
many other issues are not covered.
Re: arrays of type variables and parameterized types
Aug 6, 2003 12:32 AM
(reply 23
of 34) (In reply to
#22 )
The intent, as I understand it, it to allow arrays of
types parameterized on wildcards only in Java 1.5.
Yes, that's right, ...
"wildcard only" means "Wildcard without bound"?
Do I understand the intent correctly? We are talking of parameterized types in array creation expressions, right? The intent is that we cannot create arrays of parameterized types (with or without wildcards). Can we declare variables of those types?
List<Integer>[] ref = null; // fine ???
ref = new List<Integer>[10]; // error
similarly
List<? extend Number>[] ref = null; // fine ???
ref = new List<? extend Number>[10]; // error
similarly
List<?>[] ref = null; // fine ???
ref = new List<?>[10]; // fine ???
Why will List<?>[] be allowed, but List<? super Number>[] and List<? extends Number>[] are illegal?
I mean, so far all forms of wildcard instantiations are treated the same. The are not types; they denote a set of types. For this reason:
- I can't use them as supertypes.
- I can't use them in new expressions.
- I can't use them as explicit type arguments of parameterized methods.
- Perhaps I can't use them in casts and instanceof expressions either.
- I can use one of them (List<?>) for array creation, but not the other two forms.
Why does that make sense? Is it because a List<?>[] is basically a List[]? Following that line of logic I would expect that I can use the wildcard instantiation List<?> in all places where the raw type List can be used.
be unsafe?
As far as I understand, type variable statements like
class MyType<E extends LowerBoundType> {
// .........
E[] a = new E[size];
}
gets erased to:
class MyType {
// .........
LowerBoundType[] a = new LowerBoundType[size];
}
by the compiler.
Its just like creating a bunch of references to
E
initialized to null. i.e. No objects of type E
are created, therefore no type info is needed. The array elements are upcasted to the type parameter when they are returned to the user.
Why this is unsafe is beyond my understanding.
Also creating generic arrays are a fundamental part of creating generic containers. Without them we would get an annoying warning about an 'unsafe operation' whenever we compile a generic container.
If you look at the source for ArrayList in 1.5 you will see code like
be unsafe?
As far as I understand, type variable statements like
class MyType<E extends LowerBoundType> {
// .........
E[] a = new E[size];
}
gets erased to:
class MyType {
// .........
LowerBoundType[] a = new LowerBoundType[size];
}
by the compiler.
Its just like creating a bunch of references to
E
initialized to null. i.e. No objects of
type E
are created, therefore no type info is needed. The
array elements are upcasted to the type parameter when
they are returned to the user.
Why this is unsafe is beyond my understanding.
If the newly created array were solely used within the scope of the generic class's functions, it would be typesafe. But how can you prevent the class from returning the array to the "outside world"?
Outside of the generic class, any attempt to access the array as a E[] would fail at runtime!
If you look at the source for ArrayList in 1.5 you
will see code like
E[] a = (E[])new
Object[size];
that generates warnings.
How can these be good programming practices?
They're obviously not good programming practices.
The code relies on the assumption that a cast involving a type parameter is effectively a no-op.
The codeer took it for granted that the above code would be compiled (after erasure) to
Object a = new Object[size];
IMHO, it would probably be better "programming style" to declare and use the Object[] as such and only apply casts to individual elements if necessary.
IMHO the only valid solution would be to use the runtime class of type parameter E for array creation. Sadly E.class is not available, if it were available
Maybe the runtime class of a type parameter could be passed into the constructors of a generic class in a hidden fashion, then you could store it in a field and use it later on:
private Class classE<E>;
public ArrayList() {
classE = E.class;
}
public E[] toArray() {
E[] a = (E[]) java.lang.reflect.Array.newInstance(E.class, size);
//...
}
Note that the cast would not be required if Array.newInstance() had proper type parameters:
publicstatic <E> E[] newInstance(Class<E> componentType,
int length)
throws NegativeArraySizeException