I am developing a ComboBox (more for context than actual significance), and I would like to know if the "or" operator exists in Java generics. For now, the declaration looks something like that:
public class SComboBox<T extends ComboBoxItem> extends JPanel {
Where ComboBoxItem
is an interface I created for items that can be used in the ComboBox. However, I'd also like to accept String
as a type, which seems like a difficult task since:
String
is afinal class
so there's no way anyone could extend it.- I am not sure if you can put either something like "|" (or) operator, or just outright specify an acceptable class. Since there is an "and" operator (
<T extends A & B>
) I imagined it would make sense to have the "or" (|) as well.
My question is essentially point 2. Can I, in generics, specify a class I want to accept and/or use something like a "|"? If not, is there any workaround or should I ditch the idea of using generics?
CodePudding user response:
There is no "or" operator for generics, and for a simple reason.
The idea of stating the type at the beginning is to allow you to use methods from that type in your implementation of the class.
When you use the "and" operator (extends A & B
), you know that whatever object is passed to you, you can access any of the A
class's methods as well as any of the B
class's method.
But what would happen if it was an "or"? Then you are passed an object that can either be a ComboBoxItem
allowing you to use ComboBoxItem
's methods, or it is just a string, which means you can't use any such methods. At compile time, you don't know which object you are passed, so there is no point in giving the type.
The "Or" is not helpful. If you are not using any method from the object, you may as well not use extends
at all.
The real question here is what you are trying to do which can apply to strings as well as combo box items but not to anything else. It smells like a design issue.
CodePudding user response:
In short, this is not possible. A class cannot inherit from one of two interfaces, as it would be impossible to determine which class is actually implemented.
You could implement a string wrapper, as JayC667 mentioned, and have it implement your ComboBoxItem interface. I assume that you need some special functions introduced by ComboBoxItem anyway.
some example:
interface ComboBoxItem{
String getDisplayText();
default Color getBgColor(){
return Color.WHITE;
}
default Color getFgColor(){
return Color.BLACK;
}
default ImageIcon getIcon(){
return null;
}
default boolean useIcon(){
return false;
}
}
And with a simple implementation which just takes String input.
public class StringCbItem implements ComboBoxItem {
private final String text;
StringCbItem (String text){
this.text = text;
}
@Override
String getDisplayText(){
return text;
}
}
For the ComboBox I would probably just use the defaul JComboBox. You can override its display and rendering behavior by passing a custom ListCellRenderer implementation.
public class MyRenderer extends JLabel implements ListCellRenderer<ComboBoxItem> {
public MyRenderer () {
setOpaque(true);
}
public Component getListCellRendererComponent(JList<?> list,
ComboBoxItem value,
int index,
boolean isSelected,
boolean cellHasFocus) {
setText(value.getDisplayText());
setBackground(value.getBgColor());
setForeground(value.getFgColor());
if(value.useIcon()){
setIcon(value.getIcon());
}
return this;
}
}
This is just some example for how to do it and is only meant as a starting point!
You can read further into it here:
How to Use Combo Boxes
Interface ListCellRenderer