Can someone explain this casting behaviour?

Ok, so there are two classes, C1 and C2.

C1 contains the following method:

protectedstaticfinal PersistentCheckBoxMenuItem[] getCollections(){

Component components[] = ((JMenu)menubar.getComponent(3)).getMenuComponents();

return (PersistentCheckBoxMenuItem[]) Arrays.copyOfRange(components, 6, components.length);;

}

C2 contains the following Action:

protectedclass CollectionsStateChangeActionextends AbstractAction{

privateboolean state;

protected CollectionsStateChangeAction(String title, String desc,

Integer accelerator, Integer mask,boolean state){

/* initializer code left out for purpose of example */

this.state = state;

}

publicvoid actionPerformed(ActionEvent e){

// obtain current menu collection list

// (PersistentCheckBoxMenuItem extends JCheckBox)

PersistentCheckBoxMenuItem colls[] = Silk.getCollections();

// loop through list and (de)select every item

for (int i = 5; i < colls.length; i++){

colls[i].setSelected(state);

}

}

}

Trying to fire the action gives the following exception:

Exception in thread"AWT-EventQueue-0" java.lang.ClassCastException: [Ljava.awt.Component; cannot be cast to [Lsilk.PersistentCheckBoxMenuItem;

BUT, here's what I don't get.

If I change the above code chunks so the cast occurs in the Action instead:

C1:

protectedstaticfinal Component[] getCollections(){

Component components[] = ((JMenu)menubar.getComponent(3)).getMenuComponents();

return Arrays.copyOfRange(components, 5, components.length);

}

C2:

protectedclass CollectionsStateChangeActionextends AbstractAction{

privateboolean state;

protected CollectionsStateChangeAction(String title, String desc,

Integer accelerator, Integer mask,boolean state){

/* initializer code left out for purpose of example */

this.state = state;

}

publicvoid actionPerformed(ActionEvent e){

// obtain current menu collection list

Component colls[] = Silk.getCollections();

// loop through list and (de)select every item

for (int i = 0; i < colls.length; i++){

((PersistentCheckBoxMenuItem)colls[i]).setSelected(state);

}

}

}

..then now everything works fine!

Why on earth would shifting the cast to the Action make things work? I tried putting the 'Arrays.copy....' result in C1's method into a Component[] variable andthen casting it and returning it, and that doesn't work either.

I'm on JRE 6, and I'm puzzled :)

[4421 byte] By [677939KomodoDavea] at [2007-11-26 12:18:16]
# 1

It's because in the first case you are casting an array and in the second you are casting an object.

The array is declared as JComponent[]. This means it may hold any instance of JComponent. You cannot cast that to a PersistentCheckBoxMenuItem[] since doing so would require that it cannot, for example, store a JLabel.

However, the items which are stored in that array do all just happen to be instances of PersistentCheckBoxMenuItem, so individually they will cast just fine.

And your code gives me the creeps by the way - all those magic numbers and casts, it's a maintenance nightmare :o)

551768itchyscratchya at 2007-7-7 14:57:34 > top of Java-index,Archived Forums,Socket Programming...
# 2

Thanks for the explanation itchy :)

and lol@maintenance comment! The numbers will be final field references, it's just I put actually numbers in for the purpose of trying to fix that, because I wanted to make sure no separators I had in the pre-cloned menu were getting through to the Action :D

677939KomodoDavea at 2007-7-7 14:57:34 > top of Java-index,Archived Forums,Socket Programming...
# 3
Yeah, sorry, I just come out in a rash when I see that stuff ;o)
551768itchyscratchya at 2007-7-7 14:57:34 > top of Java-index,Archived Forums,Socket Programming...