Customize toString() for arrays...?

S

Simone

Hello,

maybe my question has already been asked here but I couldn't find a
precise answer for now...
Is it possible to customize the way the implicit "toString" method,
invoked e.g. by System.out.print(...), will produce the output string?

If I write the following code:

int[] vector = new int[] {1,2,3,4};
System.out.println( vector );

the output is:

v = [I@1d9f953d

corresponding to an internal java information about the object (the
hash code, I believe).
With a "classic" object of a class, I can rewrite the toString()
method and output the string that I want, simply writing e.g.
System.out.println( objectName ). Is there a way to rewrite the
"implicit" toString() method for arrays, so that I can write
System.out.println( "v =" + vector ) and obtain the output: v =
(1,2,3,4) ?

Many thanks in advance.


Simone.
 
S

Stefan Ram

Simone said:
int[] vector = new int[] {1,2,3,4};
System.out.println( vector );

See also:

java.lang.System.out.println( java.util.Arrays.toString( vector ));

.
 
S

Stefan Ram

Simone said:
Is it possible to customize the way the implicit "toString" method,
invoked e.g. by System.out.print(...), will produce the output string?

Not for arrays in Java.
With a "classic" object of a class, I can rewrite the toString()

Not with a class such as »java.lang.String«, you also
need some kind of ownership of the class' source code.

If you are willing to write a wrapper for java.lang.String
with a custom »toString« method, then you can write a
wrapper for arrays as well, similar to java.util.ArrayList
or so.
 
T

Tom Anderson

Is there a way to rewrite the "implicit" toString() method for arrays,
so that I can write System.out.println( "v =" + vector ) and obtain the
output: v = (1,2,3,4) ?

Sadly not.

The best sticking-plaster is usually to wrap the array in a list:

System.out.println(Arrays.asList(vector));

That method returns a lightweight wrapper around the array that, amongst
other things, implements a more sensible toString.

tom
 
S

Simone

First, thank you Stefan and Tom for your answers. I apologize for
answering so late.

I also noticed that the solution with Arrays.asList(vector) works only
if vector is an array of a wrapper class and not if it's an array of a
primitive type, in which case the output is, again, the hash code of
the array.

I'm using the solution Arrays.asList(vector) for now, maybe I'll write
a specific method... Or I'll write a wrapper class for my array with
my specific toString... unfortunately I'll lose the chance to use the
brackets for referring to elements.


Simone.
 
A

Alan Gutierrez

Simone said:
First, thank you Stefan and Tom for your answers. I apologize for
answering so late.

I also noticed that the solution with Arrays.asList(vector) works only
if vector is an array of a wrapper class and not if it's an array of a
primitive type, in which case the output is, again, the hash code of
the array.

I'm using the solution Arrays.asList(vector) for now, maybe I'll write
a specific method... Or I'll write a wrapper class for my array with
my specific toString... unfortunately I'll lose the chance to use the
brackets for referring to elements.

Don't top post.

Not sure what you're on about:

import java.util.Arrays;

public class AsList {
public static void main(String[] args) {
System.out.println(Arrays.asList(1, 2, 3));
}
}

[alan@postojna ~]$ javac AsList.java
[alan@postojna ~]$ java AsList
[1, 2, 3]
[alan@postojna ~]$
 
J

John B. Matthews

Simone said:
I also noticed that the solution with Arrays.asList(vector) works only
if vector is an array of a wrapper class and not if it's an array of a
primitive type, in which case the output is, again, the hash code of
the array.

Would this be an usable alternative?

int[] intArray = new int[]{ 1, 2, 3, 4 };
System.out.println(Arrays.toString(intArray));

For better or worse, the square brackets are included:

[1, 2, 3, 4]
 
M

markspace

Simone said:
I also noticed that the solution with Arrays.asList(vector) works only
if vector is an array of a wrapper class and not if it's an array of a
primitive type,


That's because List itself doesn't work with primitive types. You can't
you'd have to have use List<Integer>. said:
in which case the output is, again, the hash code of
the array.

Well, it's a list of one element, being the list you passed in. Type of
I'm using the solution Arrays.asList(vector) for now, maybe I'll write
a specific method


Not sure the best way to do this. A minimalist approach, one which
reuses as much code as possible, might be to convert the primitive array
to an array of objects, and then pass that to Arrays.asList().

I.e., convert int[] to Integer[] then use that on Arrays.asList().

Hmm.... I might want to do that...
 
M

markspace

markspace said:
Hmm.... I might want to do that...

This seems to work:


package test;
import java.lang.reflect.Array;

public class Util {

static public <T extends Number> T[] autoBox( Class<T> type,
Object array )
{
int length = Array.getLength( array );
Object retVal = Array.newInstance( type, length );
for( int i = 0; i < length; i++ ) {
Array.set( retVal, i, Array.get( array, i) );
}
return (T[])retVal;
}
}


Useage:

public static void main( String[] args )
{
int[] test = {1,2,3};
System.out.println( Arrays.asList( autoBox( Integer.class, test ) ) );
}

prints:
[1, 2, 3]
 
A

Alan Gutierrez

markspace said:
markspace said:
Hmm.... I might want to do that...

This seems to work:


package test;
import java.lang.reflect.Array;

public class Util {

static public <T extends Number> T[] autoBox( Class<T> type,
Object array )
{
int length = Array.getLength( array );
Object retVal = Array.newInstance( type, length );
for( int i = 0; i < length; i++ ) {
Array.set( retVal, i, Array.get( array, i) );
}
return (T[])retVal;
}
}


Useage:

public static void main( String[] args )
{
int[] test = {1,2,3};
System.out.println( Arrays.asList( autoBox( Integer.class, test ) ) );
}

prints:
[1, 2, 3]

Oh, I see the problem now...

import java.util.Arrays;

public class AsList {
public static void main(String[] args) {
Integer[] boxes = { 1, 2, 3 };
int[] primitives = { 1, 2, 3 };
System.out.println(Arrays.asList(boxes));
System.out.println(Arrays.asList(primitives));
}
}

[alan@postojna ~]$ javac AsList.java
[alan@postojna ~]$ java AsList
[1, 2, 3]
[[I@10d448]

Nice solution, Mark Space. I looked into removing the unsafe array cast,
but it appears as though it can't be helped.
 
T

Tom Anderson

I also noticed that the solution with Arrays.asList(vector) works only
if vector is an array of a wrapper class and not if it's an array of a
primitive type, in which case the output is, again, the hash code of the
array.

Aah, ya gots me.

Yes, in this case, you are largely stuffed. UNLESS you pay heed to my
super-wily suggestion:

public class ArrayWrapper extends AbstractList{
private Object[] array;

public ArrayWrapper(Object[] array) {
this.array = array;
}

@Override
public Object get(int index) {
Object object = array[index];
if (object instanceof Object[]) object = new ArrayWrapper((Object[]) object);
return object;
}

@Override
public int size() {
return array.length;
}
}

Try:

System.out.println(new ArrayWrapper(new Object[][] {{1, 2, 3}, {'a', 'b', 'c'}, {true, false, true}}));

This only works with arrays of objects, but you could write a family of
specialised versions for arrays of primitives, and create the appropriate
one in the getter.
 
M

markspace

Tom said:
Yes, in this case, you are largely stuffed. UNLESS you pay heed to my
super-wily suggestion: ....
This only works with arrays of objects, but you could write a family of
specialised versions for arrays of primitives, and create the
appropriate one in the getter.


I thought my autoBox() method was more wily, because it dealt with
primitives. But what the hay, more ideas is mo' bettah.
 
T

Tom Anderson

I thought my autoBox() method was more wily, because it dealt with
primitives.

You deal with primitives, but not nested lists, which is where i was
applying wiliness. We are disjointly wily. But we can unionise: in my
wrapper, change the type of the array instance variable to Object, and
rewrite the getter to use your reflective approach:

Object object = Array.get(array, index);
if (obj.getClass().isArray()) object = new ArrayWrapper(object);
return object;

Now we have something that handles primitives and nested lists, and does
so with minimal allocation (just small wrapper objects, never arrays), and
doesn't require a type parameter to be passed in.

It's not as generally useful as your unbox method could be, because it
isn't typesafe, but it will do for toString.

tom
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top