我们知道ComboBoxModel
接口用于创建一个女巫类,我们可以指定如何将对象集合(模型)与组合框相关联,基本上通过提供必要的“信息”检索项目并设置当前项目。 通常我写这些类声明为成员Collection <of a concrete type>
,只是将一些功能委托给实现方法中的集合对象。 当所有包含对象的实际类都是Not-Proxied对象时,一切都很好(当然,我们有90%的时间会出现这种情况),但这次面对引用Proxied Objects和事情的事实会出现奇怪的错误。 JComboBox行为出错,因为它无法更改当前选择。带有动态代理对象的ComboBoxModel
我想获得一些更多的信息,但现在我只知道,当周围有代理对象的方法ComboBoxModel
接口setSelectedItem
,任何具体的类实现不调用。这是我的问题:发生了什么,更重要的是它是否可以修复?
我留下一个例子,准备好自己看看。
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
/**
*
* @author Administrador
*/
public class AComboBoxWithProxyProblem extends JFrame implements ActionListener
{
ComboBoxModel modelWithProxies = new ItemComboBoxModelWithProxies();
ComboBoxModel modelWithoutProxies = new ItemComboBoxModelWithoutProxies();
public AComboBoxWithProxyProblem()
{
final JComboBox comboBox = new JComboBox();
comboBox.addActionListener(this);
getContentPane().setLayout(new BoxLayout(this.getContentPane(),BoxLayout.LINE_AXIS));
getContentPane().add(comboBox);
JRadioButton btnProxy = new JRadioButton("Proxy model");
btnProxy.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e)
{
comboBox.setModel(modelWithProxies);
comboBox.setSelectedIndex(0);
}
});
getContentPane().add(btnProxy);
JRadioButton btnNoProxy = new JRadioButton("Non Proxy model");
btnNoProxy.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e)
{
comboBox.setModel(modelWithoutProxies);
comboBox.setSelectedIndex(0);
}
});
getContentPane().add(btnNoProxy);
ButtonGroup group = new ButtonGroup();
group.add(btnProxy);
group.add(btnNoProxy);
setTitle("Mmmm...");
}
@Override
public void actionPerformed(ActionEvent e)
{
JComboBox comboBox = (JComboBox)e.getSource();
Item item = (Item)comboBox.getSelectedItem();
System.out.println("[actionPerformed] - " + item.getId() + " : " + item.getDescription());
}
interface ItemInterface
{
String getDescription();
int getId();
@Override
String toString();
}
class Item implements AComboBoxWithProxyProblem.ItemInterface
{
private int id;
private String description;
public Item(int id, String description)
{
this.id = id;
this.description = description;
}
@Override
public int getId()
{
return id;
}
@Override
public String getDescription()
{
return description;
}
@Override
public String toString()
{
return description;
}
}
private class ItemComboBoxModelWithoutProxies extends AbstractListModel implements ComboBoxModel
{
List<ItemInterface> foos;
ItemInterface selected;
public ItemComboBoxModelWithoutProxies()
{
foos = new ArrayList<>();
foos.add(new Item(1,"One"));
foos.add(new Item(2,"Two"));
foos.add(new Item(3,"Three"));
}
@Override
public Object getSelectedItem()
{
return selected;
}
@Override
public void setSelectedItem(Object tournament)
{
System.out.println("[setSelectedItem] " + tournament);
selected = (ItemInterface) tournament;
}
@Override
public int getSize()
{
return this.foos.size();
}
@Override
public Object getElementAt(int i)
{
return this.foos.get(i);
}
}
private class ItemComboBoxModelWithProxies extends AbstractListModel implements ComboBoxModel
{
List<ItemInterface> foos;
Object selected;
public ItemComboBoxModelWithProxies()
{
foos = new ArrayList<>();
ItemInterface item;
item = (ItemInterface) Proxy.newProxyInstance(Item.class.getClassLoader(),
Item.class.getInterfaces(),
new ItemInvocationHandler (new Item(1,"One")));
foos.add(item);
item = (ItemInterface) Proxy.newProxyInstance(Item.class.getClassLoader(),
Item.class.getInterfaces(),
new ItemInvocationHandler (new Item(2,"Two")));
foos.add(item);
item = (ItemInterface) Proxy.newProxyInstance(Item.class.getClassLoader(),
Item.class.getInterfaces(),
new ItemInvocationHandler (new Item(3,"Three")));
foos.add(item);
}
@Override
public Object getSelectedItem()
{
return selected;
}
@Override
public void setSelectedItem(Object tournament)
{
System.out.println("[setSelectedItem] " + tournament);
selected = (ItemInterface) tournament;
}
@Override
public int getSize()
{
return this.foos.size();
}
@Override
public Object getElementAt(int i)
{
return this.foos.get(i);
}
private class ItemInvocationHandler implements InvocationHandler {
Item item;
public ItemInvocationHandler(Item item)
{
this.item = item;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
return method.invoke(this.item, args);
}
}
}
public static void main(String[] args)
{
JFrame frame = new AComboBoxWithProxyProblem();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
那么,这就是全部!
谢谢!
Victor。
非常完成答案。所以,让我清楚的事情...我们在这里面临的事实是JComboBox的代码可以将代理“A”与代理对象“B”进行比较,此外,代理“A”实际上代表对象“B”,等于到它们属于不同类别的事实(任何合理的等价实现都应该返回false)。顺便说一句,我设法做一些变通.. returing被代理的对象(在getSelectedItem和getElementAt),并有一个对象 - >代理的映射(为了检索代理,将对象传递为键) – Victor
是的,这是基本的。如果你尝试并执行'proxyA.equals(proxyB)',它实际上并没有比较两个代理对象,比较'proxyA.objectBeginProxied'和'proxyB',它永远不能返回'true'。这是一个有趣的工作,你可能想要更新你的问题与周围的工作,为任何其他人有同样的问题 – MadProgrammer