Generics and ArrayList.toArray(T[] a)

I

Ian Wilson

I don't see how to elegantly satisfy toArray(T[] a) in an abstract class.

The code below works but I'd rather avoid the need for the setType()
which instantiates an T[] for .toArray(). Obviously I cant instantiate
an T[] in the abstract class.

Is there a better way?

----------------------------------------------------
import java.util.ArrayList;

public class ArrayListProblem {
public static void main(String[] args) {
FooModel model = new FooModel();
String[] fooCodes = model.getCodes();
for(int i = 0; i<fooCodes.length; i++) {
System.out.println(fooCodes);
}
}
}

abstract class AbstractCodeModel<T> {
private ArrayList<T> codes = new ArrayList<T>();
private T[] type;

void addCode(T item) {
codes.add(item);
}

void setType(T[] t) {
this.type = t;
}

public T[] getCodes() {
return codes.toArray(type);
}
}

class FooModel extends AbstractCodeModel<String> {
FooModel() {
setType(new String[0]);
addCode("A");
addCode("B");
}
}
 
T

Tom Hawtin

Ian said:
The code below works but I'd rather avoid the need for the setType()
which instantiates an T[] for .toArray(). Obviously I cant instantiate
an T[] in the abstract class.
void setType(T[] t) {
this.type = t;
}

Setting that in the construct would probably be better. As would
supplying a Class<T> rather than a T[].

Tom Hawtin
 
D

Daniel Pitts

Ian said:
I don't see how to elegantly satisfy toArray(T[] a) in an abstract class.

The code below works but I'd rather avoid the need for the setType()
which instantiates an T[] for .toArray(). Obviously I cant instantiate
an T[] in the abstract class.

Is there a better way?

----------------------------------------------------
import java.util.ArrayList;

public class ArrayListProblem {
public static void main(String[] args) {
FooModel model = new FooModel();
String[] fooCodes = model.getCodes();
for(int i = 0; i<fooCodes.length; i++) {
System.out.println(fooCodes);
}
}
}

abstract class AbstractCodeModel<T> {
private ArrayList<T> codes = new ArrayList<T>();
private T[] type;

void addCode(T item) {
codes.add(item);
}

void setType(T[] t) {
this.type = t;
}

public T[] getCodes() {
return codes.toArray(type);
}
}

class FooModel extends AbstractCodeModel<String> {
FooModel() {
setType(new String[0]);
addCode("A");
addCode("B");
}
}


Try this instead:
abstract class AbstractCodeModel<T> {
private List<T> codes = new ArrayList<T>();

void addCode(T item) {
codes.add(item);
}

public List<T> getCodes() {
return new ArrayList<T>(codes);
}
}

Why deal with an array at all? Primative obsession is a bad thing.
You could also use:
return java.util.Collections.unmodifiableList(codes);
If you wanted an unmodifiable view into codes.

If the clients really want an array, they can get it from
getCodes().toArray(...);
 
I

Ian Wilson

Tom said:
Ian said:
The code below works but I'd rather avoid the need for the setType()
which instantiates a T[] for .toArray(). Obviously I can't instantiate
a T[] in the abstract class.

void setType(T[] t) {
this.type = t;
}


Setting that in the construct would probably be better.

Thanks Tom.
As would supplying a Class<T> rather than a T[].

This bit I don't understand although I tried it and couldn't get
..toArray to accept a Class<T>. Could you elaborate a little?
 
I

Ian Wilson

Daniel said:
Ian said:
I don't see how to elegantly satisfy toArray(T[] a) in an abstract class.

Try this instead:
abstract class AbstractCodeModel<T> {
private List<T> codes = new ArrayList<T>();

void addCode(T item) {
codes.add(item);
}

public List<T> getCodes() {
return new ArrayList<T>(codes);
}
}

Why deal with an array at all? Primative obsession is a bad thing.
You could also use:
return java.util.Collections.unmodifiableList(codes);
If you wanted an unmodifiable view into codes.

If the clients really want an array, they can get it from
getCodes().toArray(...);

Thanks for the feedback, I've pondered it a little ...

The array is for JComboBox. It would be nice if JComboBox were
generified and worked better with Collections like List. AFAIK JComboBox
likes arrays for its constructor.

Oh dear, I can see it is time to learn about ComboBoxModels.


Whilst I'm doing that, some background:

I have an app that allows users to modify records in database tables.
some tables contain foreign keys

Fictitious example:

table Dog contains columns name, owner-id, breed-id ...
table Breed contains columns breed-id, breed-name ...

My form for editing a Dog record has a JComboBox for breed which shows
the user the breed-names rather than the breed-ids. But what I retrieve
from and store into the Dog table is the breed-id.

So I have a BreedModel class that retrieves lists of ids and names and
has methods for
- returning a String[] for JComboBox constructors.
- translating between id and name and index
for JComboBox.setSelectedIndex() and .getSelectedIndex().

The client code is something like

JComboBox breedCombo = new JComboBox(BreedModel.getBreedNames());

If BreedModel.getBreedNames returns a List then my code for constructing
a JComboBox gets longer

JComboBox breedCombo = new JComboBox(
BreedModel.getBreedNames().toArray());

So I'm keen to be JComboBox-friendly.

Does this make sense?


My code for setting and obtaining values is something like

breedCombo.setSelectedIndex(
BreedModel.getIndex(thisDog.getBreedId()));
...
amendedDog = new Dog(
nameField.getText(),
BreedModel.getId(breedCombo.getSelectedIndex()),
... )

N.B. by working with JComboBox Indexes rather than Items I avoid
"unsafe" and ugly type-casts like
BreedModel.getIdFromName(
(String) breedCombo.getSelectedItem() ),

Since I will have a lot of update forms with JComboBoxes for foreign
keys, I wanted to work out a way to abstract out all the common code for
"models" for lots of different foreign keys. Since some foreign keys are
Strings and some are ints, I need to use Generics.

If anyone is still reading this overlong essay :-( I'd welcome comments!
 
T

Tom Hawtin

Ian said:
As would supplying a Class<T> rather than a T[].

This bit I don't understand although I tried it and couldn't get
.toArray to accept a Class<T>. Could you elaborate a little?

I mean doing something like this:


abstract class AbstractCodeModel<T> {
private final List<T> codes = new ArrayList<T>();
private final Class<T> type;

protected AbstractCodeModel(Class<T> type) {
if (type.isPrimitive()) {
throw new IllegalArgumentException();
}
this.type = type;
}

void addCode(T item) {
//assert item==null || type.isInstance(item);
codes.add(item);
}

public T[] getCodes() {
return codes.toArray(type.newInstance(type, codes.length()));
}
}

Create as, say:

class StringCodeModel extends AbstractCodeModel<String> {
public StringCodeModel() {
super(String.class);
}
}

Tom Hawtin
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top