Why does Arrays.asList(…).toArray().getClass() give different results in JDK 8 and 9? [duplicate]
This question already has an answer here:
array cast Java 8 vs Java 9
2 answers
Why does the following condition return true
with JDK 8, whereas it returns false
with JDK 9?
String.class == Arrays.asList("a", "b").toArray().getClass()
java java-8 java-9
marked as duplicate by Michael
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Dec 10 '18 at 9:43
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
add a comment |
This question already has an answer here:
array cast Java 8 vs Java 9
2 answers
Why does the following condition return true
with JDK 8, whereas it returns false
with JDK 9?
String.class == Arrays.asList("a", "b").toArray().getClass()
java java-8 java-9
marked as duplicate by Michael
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Dec 10 '18 at 9:43
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
add a comment |
This question already has an answer here:
array cast Java 8 vs Java 9
2 answers
Why does the following condition return true
with JDK 8, whereas it returns false
with JDK 9?
String.class == Arrays.asList("a", "b").toArray().getClass()
java java-8 java-9
This question already has an answer here:
array cast Java 8 vs Java 9
2 answers
Why does the following condition return true
with JDK 8, whereas it returns false
with JDK 9?
String.class == Arrays.asList("a", "b").toArray().getClass()
This question already has an answer here:
array cast Java 8 vs Java 9
2 answers
java java-8 java-9
java java-8 java-9
edited Dec 10 '18 at 9:36
Michael
19.9k83471
19.9k83471
asked Dec 9 '18 at 20:51
FelixFelix
41319
41319
marked as duplicate by Michael
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Dec 10 '18 at 9:43
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
marked as duplicate by Michael
StackExchange.ready(function() {
if (StackExchange.options.isMobile) return;
$('.dupe-hammer-message-hover:not(.hover-bound)').each(function() {
var $hover = $(this).addClass('hover-bound'),
$msg = $hover.siblings('.dupe-hammer-message');
$hover.hover(
function() {
$hover.showInfoMessage('', {
messageElement: $msg.clone().show(),
transient: false,
position: { my: 'bottom left', at: 'top center', offsetTop: -7 },
dismissable: false,
relativeToBody: true
});
},
function() {
StackExchange.helpers.removeMessages();
}
);
});
});
Dec 10 '18 at 9:43
This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
The List
type returned by asList
is Arrays$ArrayList
. The toArray
method in JDK 8 on that class is:
@Override
public Object toArray() {
return a.clone();
}
But in JDK 9+ it is:
@Override
public Object toArray() {
return Arrays.copyOf(a, a.length, Object.class);
}
In both cases a String
is passed to asList
, but in the JDK 8 case it is cloned, which retains its array type (String
), and in JDK 9+ it is copied using Arrays.copyOf
with the explicit new array type of Object
.
This difference means that in JDK 8 Arrays.asList("a", "b").toArray().getClass()
returns String
and in JDK 9+ it returns Object
, so in JDK 9+ your expression will evaluate to false
.
The reason for this change comes from JDK-6260652 with the motivation:
The Collection documentation claims that
collection.toArray()
is "identical in function" to
collection.toArray(new Object[0]);
However, the implementation of
Arrays.asList
does not follow this: If created with an array of a subtype (e.g.String
), itstoArray()
will return an array of the same type (because it useclone()
) instead of anObject
.
If one later tries to store non-Strings (or whatever) in that array, an
ArrayStoreException
is thrown.
So this change was made to fix the previous behaviour.
If this is a problem for you, the related release note offers this as a work-around:
If this problem occurs, rewrite the code to use the one-arg form
toArray(T)
, and provide an instance of the desired array type. This will also eliminate the need for a cast.
String array = list.toArray(new String[0]);
3
It’s so funny that theArrayList(Collection)
constructor contains a protection against this misbehavior with reference to this bug report (it’s from 2005) for a long time now, whereas no-one came to the idea of fixing the misbehavior in the first place, apparently…
– Holger
Dec 10 '18 at 9:28
Great, thanks for explanation. Unfortunately the method is called within a serialization code of GWT RPC 2.6.1 so I cannot easily switch to the parameterizedtoArray
overloading.
– Felix
Dec 11 '18 at 10:19
add a comment |
I would say that this was a bug in JDK 8 and before that has been fixed.
List<T>.toArray()
was always declared as returning Object
(see JavaDoc) - that it did in effect return String
in a special case was a mistake.
4
That's incorrect. The method has always returnedObject
(just look at its return type declaration). It never violated its declared type. Instead it violated its documented runtime behaviour. The difference is a nuance, but an important one.
– Konrad Rudolph
Dec 10 '18 at 8:58
2
The JDK 9 release note on this change is here: oracle.com/technetwork/java/javase/…
– Alan Bateman
Dec 10 '18 at 9:12
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
The List
type returned by asList
is Arrays$ArrayList
. The toArray
method in JDK 8 on that class is:
@Override
public Object toArray() {
return a.clone();
}
But in JDK 9+ it is:
@Override
public Object toArray() {
return Arrays.copyOf(a, a.length, Object.class);
}
In both cases a String
is passed to asList
, but in the JDK 8 case it is cloned, which retains its array type (String
), and in JDK 9+ it is copied using Arrays.copyOf
with the explicit new array type of Object
.
This difference means that in JDK 8 Arrays.asList("a", "b").toArray().getClass()
returns String
and in JDK 9+ it returns Object
, so in JDK 9+ your expression will evaluate to false
.
The reason for this change comes from JDK-6260652 with the motivation:
The Collection documentation claims that
collection.toArray()
is "identical in function" to
collection.toArray(new Object[0]);
However, the implementation of
Arrays.asList
does not follow this: If created with an array of a subtype (e.g.String
), itstoArray()
will return an array of the same type (because it useclone()
) instead of anObject
.
If one later tries to store non-Strings (or whatever) in that array, an
ArrayStoreException
is thrown.
So this change was made to fix the previous behaviour.
If this is a problem for you, the related release note offers this as a work-around:
If this problem occurs, rewrite the code to use the one-arg form
toArray(T)
, and provide an instance of the desired array type. This will also eliminate the need for a cast.
String array = list.toArray(new String[0]);
3
It’s so funny that theArrayList(Collection)
constructor contains a protection against this misbehavior with reference to this bug report (it’s from 2005) for a long time now, whereas no-one came to the idea of fixing the misbehavior in the first place, apparently…
– Holger
Dec 10 '18 at 9:28
Great, thanks for explanation. Unfortunately the method is called within a serialization code of GWT RPC 2.6.1 so I cannot easily switch to the parameterizedtoArray
overloading.
– Felix
Dec 11 '18 at 10:19
add a comment |
The List
type returned by asList
is Arrays$ArrayList
. The toArray
method in JDK 8 on that class is:
@Override
public Object toArray() {
return a.clone();
}
But in JDK 9+ it is:
@Override
public Object toArray() {
return Arrays.copyOf(a, a.length, Object.class);
}
In both cases a String
is passed to asList
, but in the JDK 8 case it is cloned, which retains its array type (String
), and in JDK 9+ it is copied using Arrays.copyOf
with the explicit new array type of Object
.
This difference means that in JDK 8 Arrays.asList("a", "b").toArray().getClass()
returns String
and in JDK 9+ it returns Object
, so in JDK 9+ your expression will evaluate to false
.
The reason for this change comes from JDK-6260652 with the motivation:
The Collection documentation claims that
collection.toArray()
is "identical in function" to
collection.toArray(new Object[0]);
However, the implementation of
Arrays.asList
does not follow this: If created with an array of a subtype (e.g.String
), itstoArray()
will return an array of the same type (because it useclone()
) instead of anObject
.
If one later tries to store non-Strings (or whatever) in that array, an
ArrayStoreException
is thrown.
So this change was made to fix the previous behaviour.
If this is a problem for you, the related release note offers this as a work-around:
If this problem occurs, rewrite the code to use the one-arg form
toArray(T)
, and provide an instance of the desired array type. This will also eliminate the need for a cast.
String array = list.toArray(new String[0]);
3
It’s so funny that theArrayList(Collection)
constructor contains a protection against this misbehavior with reference to this bug report (it’s from 2005) for a long time now, whereas no-one came to the idea of fixing the misbehavior in the first place, apparently…
– Holger
Dec 10 '18 at 9:28
Great, thanks for explanation. Unfortunately the method is called within a serialization code of GWT RPC 2.6.1 so I cannot easily switch to the parameterizedtoArray
overloading.
– Felix
Dec 11 '18 at 10:19
add a comment |
The List
type returned by asList
is Arrays$ArrayList
. The toArray
method in JDK 8 on that class is:
@Override
public Object toArray() {
return a.clone();
}
But in JDK 9+ it is:
@Override
public Object toArray() {
return Arrays.copyOf(a, a.length, Object.class);
}
In both cases a String
is passed to asList
, but in the JDK 8 case it is cloned, which retains its array type (String
), and in JDK 9+ it is copied using Arrays.copyOf
with the explicit new array type of Object
.
This difference means that in JDK 8 Arrays.asList("a", "b").toArray().getClass()
returns String
and in JDK 9+ it returns Object
, so in JDK 9+ your expression will evaluate to false
.
The reason for this change comes from JDK-6260652 with the motivation:
The Collection documentation claims that
collection.toArray()
is "identical in function" to
collection.toArray(new Object[0]);
However, the implementation of
Arrays.asList
does not follow this: If created with an array of a subtype (e.g.String
), itstoArray()
will return an array of the same type (because it useclone()
) instead of anObject
.
If one later tries to store non-Strings (or whatever) in that array, an
ArrayStoreException
is thrown.
So this change was made to fix the previous behaviour.
If this is a problem for you, the related release note offers this as a work-around:
If this problem occurs, rewrite the code to use the one-arg form
toArray(T)
, and provide an instance of the desired array type. This will also eliminate the need for a cast.
String array = list.toArray(new String[0]);
The List
type returned by asList
is Arrays$ArrayList
. The toArray
method in JDK 8 on that class is:
@Override
public Object toArray() {
return a.clone();
}
But in JDK 9+ it is:
@Override
public Object toArray() {
return Arrays.copyOf(a, a.length, Object.class);
}
In both cases a String
is passed to asList
, but in the JDK 8 case it is cloned, which retains its array type (String
), and in JDK 9+ it is copied using Arrays.copyOf
with the explicit new array type of Object
.
This difference means that in JDK 8 Arrays.asList("a", "b").toArray().getClass()
returns String
and in JDK 9+ it returns Object
, so in JDK 9+ your expression will evaluate to false
.
The reason for this change comes from JDK-6260652 with the motivation:
The Collection documentation claims that
collection.toArray()
is "identical in function" to
collection.toArray(new Object[0]);
However, the implementation of
Arrays.asList
does not follow this: If created with an array of a subtype (e.g.String
), itstoArray()
will return an array of the same type (because it useclone()
) instead of anObject
.
If one later tries to store non-Strings (or whatever) in that array, an
ArrayStoreException
is thrown.
So this change was made to fix the previous behaviour.
If this is a problem for you, the related release note offers this as a work-around:
If this problem occurs, rewrite the code to use the one-arg form
toArray(T)
, and provide an instance of the desired array type. This will also eliminate the need for a cast.
String array = list.toArray(new String[0]);
edited Dec 10 '18 at 9:38
Michael
19.9k83471
19.9k83471
answered Dec 9 '18 at 21:11
Jorn VerneeJorn Vernee
20.3k33658
20.3k33658
3
It’s so funny that theArrayList(Collection)
constructor contains a protection against this misbehavior with reference to this bug report (it’s from 2005) for a long time now, whereas no-one came to the idea of fixing the misbehavior in the first place, apparently…
– Holger
Dec 10 '18 at 9:28
Great, thanks for explanation. Unfortunately the method is called within a serialization code of GWT RPC 2.6.1 so I cannot easily switch to the parameterizedtoArray
overloading.
– Felix
Dec 11 '18 at 10:19
add a comment |
3
It’s so funny that theArrayList(Collection)
constructor contains a protection against this misbehavior with reference to this bug report (it’s from 2005) for a long time now, whereas no-one came to the idea of fixing the misbehavior in the first place, apparently…
– Holger
Dec 10 '18 at 9:28
Great, thanks for explanation. Unfortunately the method is called within a serialization code of GWT RPC 2.6.1 so I cannot easily switch to the parameterizedtoArray
overloading.
– Felix
Dec 11 '18 at 10:19
3
3
It’s so funny that the
ArrayList(Collection)
constructor contains a protection against this misbehavior with reference to this bug report (it’s from 2005) for a long time now, whereas no-one came to the idea of fixing the misbehavior in the first place, apparently…– Holger
Dec 10 '18 at 9:28
It’s so funny that the
ArrayList(Collection)
constructor contains a protection against this misbehavior with reference to this bug report (it’s from 2005) for a long time now, whereas no-one came to the idea of fixing the misbehavior in the first place, apparently…– Holger
Dec 10 '18 at 9:28
Great, thanks for explanation. Unfortunately the method is called within a serialization code of GWT RPC 2.6.1 so I cannot easily switch to the parameterized
toArray
overloading.– Felix
Dec 11 '18 at 10:19
Great, thanks for explanation. Unfortunately the method is called within a serialization code of GWT RPC 2.6.1 so I cannot easily switch to the parameterized
toArray
overloading.– Felix
Dec 11 '18 at 10:19
add a comment |
I would say that this was a bug in JDK 8 and before that has been fixed.
List<T>.toArray()
was always declared as returning Object
(see JavaDoc) - that it did in effect return String
in a special case was a mistake.
4
That's incorrect. The method has always returnedObject
(just look at its return type declaration). It never violated its declared type. Instead it violated its documented runtime behaviour. The difference is a nuance, but an important one.
– Konrad Rudolph
Dec 10 '18 at 8:58
2
The JDK 9 release note on this change is here: oracle.com/technetwork/java/javase/…
– Alan Bateman
Dec 10 '18 at 9:12
add a comment |
I would say that this was a bug in JDK 8 and before that has been fixed.
List<T>.toArray()
was always declared as returning Object
(see JavaDoc) - that it did in effect return String
in a special case was a mistake.
4
That's incorrect. The method has always returnedObject
(just look at its return type declaration). It never violated its declared type. Instead it violated its documented runtime behaviour. The difference is a nuance, but an important one.
– Konrad Rudolph
Dec 10 '18 at 8:58
2
The JDK 9 release note on this change is here: oracle.com/technetwork/java/javase/…
– Alan Bateman
Dec 10 '18 at 9:12
add a comment |
I would say that this was a bug in JDK 8 and before that has been fixed.
List<T>.toArray()
was always declared as returning Object
(see JavaDoc) - that it did in effect return String
in a special case was a mistake.
I would say that this was a bug in JDK 8 and before that has been fixed.
List<T>.toArray()
was always declared as returning Object
(see JavaDoc) - that it did in effect return String
in a special case was a mistake.
answered Dec 9 '18 at 21:11
Thomas KlägerThomas Kläger
6,3172718
6,3172718
4
That's incorrect. The method has always returnedObject
(just look at its return type declaration). It never violated its declared type. Instead it violated its documented runtime behaviour. The difference is a nuance, but an important one.
– Konrad Rudolph
Dec 10 '18 at 8:58
2
The JDK 9 release note on this change is here: oracle.com/technetwork/java/javase/…
– Alan Bateman
Dec 10 '18 at 9:12
add a comment |
4
That's incorrect. The method has always returnedObject
(just look at its return type declaration). It never violated its declared type. Instead it violated its documented runtime behaviour. The difference is a nuance, but an important one.
– Konrad Rudolph
Dec 10 '18 at 8:58
2
The JDK 9 release note on this change is here: oracle.com/technetwork/java/javase/…
– Alan Bateman
Dec 10 '18 at 9:12
4
4
That's incorrect. The method has always returned
Object
(just look at its return type declaration). It never violated its declared type. Instead it violated its documented runtime behaviour. The difference is a nuance, but an important one.– Konrad Rudolph
Dec 10 '18 at 8:58
That's incorrect. The method has always returned
Object
(just look at its return type declaration). It never violated its declared type. Instead it violated its documented runtime behaviour. The difference is a nuance, but an important one.– Konrad Rudolph
Dec 10 '18 at 8:58
2
2
The JDK 9 release note on this change is here: oracle.com/technetwork/java/javase/…
– Alan Bateman
Dec 10 '18 at 9:12
The JDK 9 release note on this change is here: oracle.com/technetwork/java/javase/…
– Alan Bateman
Dec 10 '18 at 9:12
add a comment |