I don't understand why I get ClassCastException on below code in line:
for(int i = 0; i < k.t.length; i++)
So problem is that in method addElement I make replacing of array elements by objects with type T. In my opinion in array should be objects with type T. And compiler doesn't protest for that.
But in run-time JVM cannot cast despite in array is really objects with type T (in case below String), why JVM cannot use polymorphism?
But when I change the T[] t; to Object[] t;
and remove cast in constructor it run correctly without any errors, why?
public class MyCollection<T> {
T[] t;
MyCollection( int size){
t = (T[]) new Object[size];
}
boolean addElement(T e, int i){
if(i < t.length){
t[i] = e;
return true;
}
return false;
}
public static void main(String[] ss){
MyCollection<String> k = new MyCollection<String>(3);
k.addElement("a",0);
k.addElement("b",1);
k.addElement("c",2);
for(int i = 0; i < k.t.length; i++)
System.out.println(k.t[i]);
//for(String s : (String[])k.t)
// System.out.println(s);
}
}
The problem is that you're casting Object[] to T[], and then you're exposing the underlying array. The only reason this works altogether is because the type erasure of T is Object. But since in our case T is being interpreted as String, when we access the array externally, we're trying to cast it to String[], which is incorrect. In order to avoid this issue, you should make the array private and provide accessor methods to retrieve elements. By doing that, you only cast individual elements to their correct type without making assumptions about the underlying array.
public class MyCollection<T> {
private T[] t;
MyCollection( int size){
t = (T[]) new Object[size];
}
boolean addElement(T e, int i){
if(i < t.length){
t[i] = e;
return true;
}
return false;
}
T getElement(int index) {
return t[index];
}
int getLength() {
return t.length;
}
public static void main(String[] ss){
MyCollection<String> k = new MyCollection<String>(3);
k.addElement("a",0);
k.addElement("b",1);
k.addElement("c",2);
for(int i = 0; i < k.getLength(); i++)
System.out.println(k.getElement(i));
//for(String s : (String[])k.t)
// System.out.println(s);
}
}
Note that Java's Collection interface demonstrates the same behavior. Collection.toArray() returns Object[] regardless of the type of E. The only available workaround is Collection.toArray(T[]), where you're forced to pass an array with a fixed type, which can then be either be populated or copied.
Check again the line of the problem. In my opinion the exception will be thrown because of:
for(String s : (String[])k.t)
You`re trying to cast to String[] here, while the array is defined as Object[]:
t = (T[]) new Object[size];
you can Create a new instance of array using the reflection to avoid ClassCastException
example:
import java.lang.reflect.Array;
public class MyCollection<T> {
T[] t;
MyCollection(Class<T> clazz, int size) {
t = (T[]) Array.newInstance(clazz, size);
}
boolean addElement(T e, int i) {
if (i < t.length - 1) {
t[i] = e;
return true;
}
return false;
}
public static void main(String[] ss) {
MyCollection<String> k = new MyCollection<String>(String.class, 3);
k.addElement("a", 0);
k.addElement("b", 1);
k.addElement("c", 2);
for (int i = 0; i < k.t.length; i++)
System.out.println(k.t[0]);
}
}
Related
I was trying to construct a simple list class using generics.
However, it throws classcastexception when I was trying to print out the value. Is there any problem when I declare and initialize generic array?
class vector<E> {
static int MAX_LEN = 1234567;
E[] data;
int[] prv;
int to;
int size;
vector() {
data = (E[])new Object[MAX_LEN];
prv = new int[MAX_LEN];
to = -1;
size = 0;
for(int i = 0; i < MAX_LEN; ++i) {
prv[i] = -1;
}
}
void push_back(E e) {
data[size] = e;
prv[size] = to;
to = size;
++size;
}
}
public class Main {
public static void main(String[] args) throws Exception {
vector<Integer> v = new vector();
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
for(int i = v.to; i != -1; i = v.prv[i]) {
System.out.println(v.data[i]); //<- Exception here
}
}
}
There are a few things wrong with the code.
It looks like, you've missed a <> in the line vector<Integer> v = new vector();
A cast from Object[] to Integer[] will never succeed
Ex:
Integer[] a= (Integer[]) new Object[] {}; // this cast will never succeed
Infact you can only cast Object[] to Object or Object[].
currently when you are trying to access data in the main() method, the cast put in by the compiler for you Integer[] will fail at runtime. You don't need the data array, you just need the values from it, which you can get by adding the following method to the vector class.
E getData(int index) {
return data[index];
}
In this case, compiler will add the cast to individual elements and will provide you the correct values.
You really have two options here. Either use data array of Object[] type or create proper generic array. Here is how to create generic array.
vector(Class<E> clazz) {
data = (E[])Array.newInstance(clazz, MAX_LEN);
I'm facing an exception: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable; while I try to use the compareTo function in my generic class.
Here is my code and I'm facing this issue in the function of insert():
public class BinaryTreeArray<T extends Comparable<T>>{
T[] array;
int level, count;
final int capacity;
public BinaryTreeArray(int size)
{
capacity=size;
array=(T[]) new Object[capacity];
for(int i=0; i<capacity; i++)
array[i]=null;
}
public BinaryTreeArray(T val, int size) //val is the root in this case
{
capacity=size;
array=(T[]) new Object[capacity];
array[0]=val;
count=0;
for(int i=1; i<capacity; i++)
array[i]=null;
}
public void insert(T x)
{
int currentIndex = 0;
System.out.println("Adding: "+x);
while(true) {
if(array[currentIndex]==null)
{
array[currentIndex]=x;
System.out.println(" Inserted at index: "+currentIndex);
break;
}
else if(array[currentIndex].compareTo(x)<=0)
{
if(array[currentIndex] == x){
System.out.println("ERROR!-- Repeating element" );
break;
}else
System.out.print(" Right ");
currentIndex =(2*currentIndex) + 2;
}
else if(array[currentIndex].compareTo(x)>=0)
{
if(array[currentIndex] == x){
System.out.println( "ERROR!-- Repeating element");
break;
}else
System.out.println(" Left ");
currentIndex=1+(2 * currentIndex);
}
}
}
}
Any help would be appreciated. Thank you.
Since the erasure of T is Comparable, not Object, you can't create an Object[] and cast it to a T[].
Create a Comparable[] instead.
array=(T[]) new Comparable[capacity];
However, you don't really need to constrain your class to naturally comparable types: if you also pass a Comparator<? super T> to the constructor, and store that in a field to use when you compare elements, you can accept any type.
array[currentIndex].compareTo(x)
Would become
comparator.compare(array[currentIndex], x)
That would remove the upper bound extends Comparable<T> from T, and allow your Object[] array creation to work.
I am currently working on a small system where I will read certain values from a byte array. One of the types must be an array. The other types are primitives and strings.
The problem I am having is trying to create the and populate the array. The array gets populated from a method, lets call it next(). next() will return a non-null Object - this object will not be an array. The length is also dynamic and is loaded from another source, but for the following code it will merely be provided.
final Integer[][] array = readArray(Integer[][].class, 10);
//...
// T = Integer[][]
// S = Integer[]
public static <T, S> S[] readArray(final Class<T> cls, final int length) {
if (cls.isArray()) {
final Class<S> subCls = (Class<S>) cls.getComponentType();
final S[] array = (S[]) Array.newInstance(subCls, length);
for (int i = 0; i < length; i++) {
if (subCls.isArray()) {
array[i] = readArray(subCls, length);
} else {
array[i] = (S) next();
}
}
return array;
}
throw new IllegalArgumentException("Type of cls must be an array.");
}
So far, I have this. The problem at the moment is with the line:
array[i] = readArray(subCls, length);
The error is:
Error:(28, 41) java: incompatible types: no instance(s) of type variable(s) T,S exist so that S[] conforms to S
I've tried many ways around this. Including using a HelperArray<T, S> class, but even that did not work.
I would also like to point out that the type of the array may not be guaranteed. The only real guarantee is that the top-level component types for the array will either be a string or a primitive. For example, the following could very well happen:
Object[][]{String[]{}, Integer[]{}, byte[]{}}
Any help with this issue is greatly appreciated, thanks.
I have cobbled this together, does that help you?
For me the output is a 10x10 2D array with all ones.
public class Test {
public static void main(String[] args) {
Integer[][] array = readArray(Integer[][].class, 10);
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++)
System.out.print(array[i][j] + ",");
System.out.println();
}
}
// T = Integer[][]
// S = Integer[]
public static <T, S> S[] readArray(final Class<T> cls, final int length) {
if (cls.isArray()) {
final Class<S> subCls = (Class<S>) cls.getComponentType();
final S[] array = (S[]) Array.newInstance(subCls, length);
for (int i = 0; i < length; i++) {
if (subCls.isArray()) {
array[i] = (S) readArray((Class<?>) subCls, length);
} else {
array[i] = (S) next();
}
}
return array;
}
throw new IllegalArgumentException("Type of cls must be an array.");
}
private static Object next() {
// TODO Auto-generated method stub
return 1;
}
}
So, got it to work. Going to kill myself in 3 years when the legacy code breaks and I have to rewrite this, but I'll deal with that in the future. Technically, #Icewind was correct in his answer - I just forgot to account for primitives which made the problem - literally - exponentially harder.
Warning: Code Gore Ahead [NSFW]
public synchronized <T, S> T readArray(final Class<T> cls) {
if (next() != IDENTIFIER_ARRAY) {
throw new InvalidProtocolException(lastReadIndex);
}
final int nextID = next();
final int length = readRawInt();
final Class<S> component = (Class<S>) cls.getComponentType();
if (component.isPrimitive()) {
switch (component.getCanonicalName()) {
case "boolean":
return (T) readRawBooleanArray(length);
case "byte":
return (T) readRawByteArray(length);
case "short":
return (T) readRawShortArray(length);
case "char":
return (T) readRawCharArray(length);
case "int":
return (T) readRawIntArray(length);
case "float":
return (T) readRawFloatArray(length);
case "long":
return (T) readRawLongArray(length);
case "double":
return (T) readRawDoubleArray(length);
}
}
final S[] array = (S[]) Array.newInstance(component, length);
for (int i = 0; i < length; i++) {
if (component.isArray()) {
array[i] = (S) readArray((Class<?>) component); // Thanks Icewind!
} else {
array[i] = (S) readMethodFor(nextID);
}
}
return (T) array;
}
I tried to write the following method:
public static long[] deepDoubleToLong(double... original)
{
long[] ret = new long[original.length];
for(int i = 0; i < ret.length; i++)
if (original[i] instanceof double[])
ret[i] = deepDoubleToLong((double[])original[i]);
else
ret[i] = (long)original[i];
return ret;
}
bit I get this compile error:
Uncompilable source code - unexpected type
required: reference
found: double
at ArrayConversion.deepDoubleToLong(ArrayConversion.java:5)
How else, if not this way, can I tell if an item is an array?
If you change the parameter type to Object... original, use Class#isArray(), like this:
if (original[i].getClass().isArray())
I suspect you are looking for my Rebox class.
The problem (as the comment at the start describes) comes when you call a varargs method with an array as a parameter. This causes the array to be wrapped up and appears as an array of primitives in the first parameter - or something like that.
Anyway - use this - it does what you need.
/**
* Can rebox a boxed primitive array into its Object form.
*
* Generally I HATE using instanceof because using it is usually
* an indication that your hierarchy is completely wrong.
*
* Reboxing - however - is an area I am ok using it.
*
* Generally, if a primitive array is passed to a varargs it
* is wrapped up as the first and only component of an Object[].
*
* E.g.
*
* public void f(T... t) {};
* f(new int[]{1,2});
*
* actually ends up calling f with t an Object[1] and t[0] the int[].
*
* This unwraps it and returns the correct reboxed version.
*
* In the above example it will return an Integer[].
*
* Any other array types will be returned unchanged.
*
* #author OldCurmudgeon
*/
public class Rebox {
public static <T> T[] rebox(T[] it) {
// Default to return it unchanged.
T[] result = it;
// Special case length 1 and it[0] is primitive array.
if (it.length == 1 && it[0].getClass().isArray()) {
// Which primitive array is it?
if (it[0] instanceof int[]) {
result = rebox((int[]) it[0]);
} else if (it[0] instanceof long[]) {
result = rebox((long[]) it[0]);
} else if (it[0] instanceof float[]) {
result = rebox((float[]) it[0]);
} else if (it[0] instanceof double[]) {
result = rebox((double[]) it[0]);
} else if (it[0] instanceof char[]) {
result = rebox((char[]) it[0]);
} else if (it[0] instanceof byte[]) {
result = rebox((byte[]) it[0]);
} else if (it[0] instanceof short[]) {
result = rebox((short[]) it[0]);
} else if (it[0] instanceof boolean[]) {
result = rebox((boolean[]) it[0]);
}
}
return result;
}
// Rebox each one separately.
private static <T> T[] rebox(int[] it) {
T[] boxed = makeTArray(it.length);
for (int i = 0; i < it.length; i++) {
boxed[i] = (T) Integer.valueOf(it[i]);
}
return boxed;
}
private static <T> T[] rebox(long[] it) {
T[] boxed = makeTArray(it.length);
for (int i = 0; i < it.length; i++) {
boxed[i] = (T) Long.valueOf(it[i]);
}
return boxed;
}
private static <T> T[] rebox(float[] it) {
T[] boxed = makeTArray(it.length);
for (int i = 0; i < it.length; i++) {
boxed[i] = (T) Float.valueOf(it[i]);
}
return boxed;
}
private static <T> T[] rebox(double[] it) {
T[] boxed = makeTArray(it.length);
for (int i = 0; i < it.length; i++) {
boxed[i] = (T) Double.valueOf(it[i]);
}
return boxed;
}
private static <T> T[] rebox(char[] it) {
T[] boxed = makeTArray(it.length);
for (int i = 0; i < it.length; i++) {
boxed[i] = (T) Character.valueOf(it[i]);
}
return boxed;
}
private static <T> T[] rebox(byte[] it) {
T[] boxed = makeTArray(it.length);
for (int i = 0; i < it.length; i++) {
boxed[i] = (T) Byte.valueOf(it[i]);
}
return boxed;
}
private static <T> T[] rebox(short[] it) {
T[] boxed = makeTArray(it.length);
for (int i = 0; i < it.length; i++) {
boxed[i] = (T) Short.valueOf(it[i]);
}
return boxed;
}
private static <T> T[] rebox(boolean[] it) {
T[] boxed = makeTArray(it.length);
for (int i = 0; i < it.length; i++) {
boxed[i] = (T) Boolean.valueOf(it[i]);
}
return boxed;
}
// Trick to make a T[] of any length.
// Do not pass any parameter for `dummy`.
// public because this is potentially re-useable.
public static <T> T[] makeTArray(int length, T... dummy) {
return Arrays.copyOf(dummy, length);
}
}
I may be wrong though.
Use it like this:
public StringBuilder add(StringBuilder s, T... values) {
// Remember to rebox it in case it's a primitive array.
for (T v : Rebox.rebox(values)) {
add(s, v);
}
return s.append(fin());
}
In answer to your question title How can I tell if an item in an array is also an array? - use it[i].getClass().isArray()
The use of the variable argument operator (...) itself is creating an array local to your method (in this case dubbed "original"), so anything you pass to it will become an array. So are you planning on passing both multi and single dimensional arrays to this method, and then have the method distinguish between the types? If you are not declaring any multi dimensional arrays in your class, then checking for them would be entirely unnecessary. If you do have singles and multis that you want to type cast I might suggest overloading methods, and have the method arguments themselves do the separating.
So something like:
public static long[] doubleToLong(double[][] original, int index){
//your conversion logic here that will type cast your second dimension array
long[] ret = new long[original.length];
for(int i = 0; i < ret.length; i++)
ret[i] = (long)original[index][i];
return ret;
}
public static long[] doubleToLong(double[] original){
//your conversion logic here that type casts a single dimension array
long[] ret = new long[original.length];
for(int i = 0; i < ret.length; i++)
ret[i] = (long)original[i];
return ret;
}
That compiled for me, see if it does for you, and also test it to make sure it does what you want. But the method arguments will sort through which arrays are single, and which are multidimensional.
Hope it helps! Happy coding!
Here's a solution that worked for me:
import java.util.Arrays;
public class ArrayConversion
{
public static Object[] deepToDouble(Object[] original)
{
Object[] ret = new Object[original.length];
for(int i = 0; i < ret.length; i++)
if (original[i] instanceof Object[])
ret[i] = deepToDouble((Object[])original[i]);
else
ret[i] =
(
original[i] instanceof Number
? ((Number)original[i]).doubleValue()
: Double.NaN
);
return ret;
}
public static void main(String... args)
{
Object[] test = new Object[]{1, new Object[]{1, 2, 3}, 3};
System.out.println(Arrays.deepToString(test));
System.out.println(Arrays.deepToString(deepToDouble(new Object[]{1, new Object[]{1, 2, 3}, 3})));
}
}
And the output is:
[1, [1, 2, 3], 3]
[1.0, [1.0, 2.0, 3.0], 3.0]
I know it's still loosely typed as Object, but it is now an array of doubles, which is my end goal
I have about 10+ classes, and each one has a LUMP_INDEX and SIZE static constant.
I want an array of each of these classes, where the size of the array is calculated using those two constants.
At the moment i have a function for each class to create the array, something along the lines of:
private Plane[] readPlanes()
{
int count = header.lumps[Plane.LUMP_INDEX].filelen / Plane.SIZE;
Plane[] planes = new Plane[count];
for(int i = 0; i < count; i++)
planes[i] = new Plane();
return planes;
}
private Node[] readNodes()
{
int count = header.lumps[Node.LUMP_INDEX].filelen / Node.SIZE;
Node[] nodes = new Node[count];
for(int i = 0; i < count; i++)
nodes[i] = new Node();
return nodes;
}
private Leaf[] readLeaves()
{
int count = header.lumps[Leaf.LUMP_INDEX].filelen / Leaf.SIZE;
Leaf[] leaves = new Leaf[count];
for(int i = 0; i < count; i++)
leaves[i] = new Leaf();
return leaves;
}
etc.
There are 10 of these functions, and the only differences is the class type, so as you can see, there's a ton of duplication.
Does any one have any ideas on how to avoid this duplication?
Thanks.
(I asked a similar question before, but i guess the way i asked it was a bit off)
Use Java generics. That way, you can just write one generic method and specify a type parameter each time you use it.
Bala's solution is close. You can't access constants from the generic type though, so I'd create a getCount() (or whatever you want to name it) and have each subtype implement it with the appropriate constants.
interface LumpySize<L extends LumpySize> {
int getCount(); // subtypes return the appropriate header.lumps[Plane.LUMP_INDEX].filelen / Plane.SIZE;
T[] initializeArray();
abstract <T extends LumpySize> static class Base implements LumpySize<T> {
protected T[] initializeArray(Class<T> cls) {
int count = getCount();
T[] lumps = (T[]) Array.newInstance(cls, count);
for(int i = 0; i < count; i++) {
try {
lumps[i] = cls.newInstance();
} catch (Exception e) { // obviously this isn't good practice.
throw new RuntimeException(e);
}
}
return lumps;
}
}
}
class Plane extends LumpySize.Base<Plane> {
public int getCount() {
return header.lumps[Plane.LUMP_INDEX].filelen / Plane.SIZE; // assuming header is available somewhere
}
public Plane[] initializeArray() { return initializeArray(Plane.class); }
}
Okey doke ... I've tested this to make sure, and I believe it does what you're looking for.
You need an interface:
public interface MyInterface
{
public int getSize();
public int getLumpIndex();
}
Your classes implement that interface:
public class Plane implements MyInterface
{
...
public int getSize()
{
return SIZE;
}
public int getLumpIndex()
{
return LUMP_INDEX;
}
}
In the class that header is an instance of, you have ...
public <E extends MyInterface> E[]
getArray(Class<E> c, MyInterface foo)
{
int count = lumps[foo.getLumpIndex()].filelen / foo.getSize();
E[] myArray = (E[]) Array.newInstance(c, count);
for(int i = 0; i < count; i++)
myArray[i] = c.newInstance();
return myArray;
}
You could call it from say, your Plane class as:
Plane[] p = header.getArray(Plane.class, this);
I think? :) Can someone look at this and see if I'm off?
(EDIT: Becasue I've tested it now - That works)
On an additional note, you could eliminate the getters in each class by making getArray() take the size and index as arguments:
public <E extends MyInterface> E[]
getArray(Class<E> c, int size, int index)
{
int count = lumps[index].filelen / size;
E[] myArray = (E[]) Array.newInstance(c, count);
for(int i = 0; i < count; i++)
myArray[i] = c.newInstance();
return myArray;
}
And call it as:
Plane p[] = header.getArray(Plane.class, SIZE, LUMP_INDEX);
from inside your classes. The interface just becomes empty to provide the generic type and you don't have to define the getter methods.
OR (last edit I promise, but this does give you choices and explains a bit about generics)
Ditch the interface. What this removes is some sanity checking because the method doesn't care what type of object you give it:
public <E> E[]
getArray(Class<E> c, int size, int index)
{
...
Now you don't have to define the interface or implement it, you just call:
Plane p[] = header.getArray(Plane.class, SIZE, LUMP_INDEX);
Use generics, but you'll need to pass in some sort of factory object to construct instances to put in your collection, eg:
public class MyClass {
public <E> E[] getArray(IObjectFactory builder, int index, int size){
ArrayList<E> arrayList = new ArrayList<E>();
int count = header.lumps[index].filelen / size;//wasn'tsure where header was coming from...
for(int i = 0; i< count; i++){
E newInstance = builder.getNewInstance();
arrayList.add(newInstance);
}
return (E[]) arrayList.toArray();
}
}
interface IObjectFactory {
<E> E getNewInstance();
}