Java:使用剪贴板在同一应用程序的不同实例之间复制粘贴java对象

我试图在同一个应用程序的不同实例之间实现对象的复制粘贴。 目前它只能在一个应用程序中工作(我的意思是,在同一个应用程序实例中复制和粘贴),但在不同的实例之间不起作用。

复制代码:

// MyObject is a class of objects I want to copy/paste; // MyObjectSelection is a class that impements Transferable and ClipboardOwner interfaces Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); MyObject data = new MyObject(selectedItems); MyObjectSelection dataSelection = new MyObjectSelection(data); clipboard.setContents(dataSelection, this); 

之后,我可以检查剪贴板的内容,如下:

 Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable clipboardContent = clipboard.getContents(this); DataFlavor[] flavors = clipboardContent.getTransferDataFlavors(); System.out.println("flavors.length=" + flavors.length); for (int i = 0; i < flavors.length; i++){ System.out.println("flavor=" + flavors[i]); } 

如果我从我复制对象的同一个应用程序实例中执行此操作,它的工作原理是: flavors.length1 ,mimetype是application/x-java-serialized-object ,而且,它有效。

但是如果我打开应用程序,执行复制,然后再次打开相同的应用程序(第一个没有关闭,即两个实例同时运行),并尝试从那里检查剪贴板内容,然后flavors.length0

我检查了文档和这些例子: 一 , 二 ,但我仍然无法找到我的实现中的错误。

我错过了什么?


UPD:我添加了sscce: clipboard_test.zip 。

这是测试应用程序(我使用Eclipse构建它),包含3个源文件:

  • ClipboardTest.java – 主app类
  • MyObject.java – 要复制/粘贴的对象的类(此类仅包含String数组)
  • MyObjectSelection.java – 实现TranserableClipboardOwner接口的类

    有两个按钮:“复制”,“测试”。

    按“复制”按钮时,将创建MyObject的新实例并将其放入剪贴板。

    当您按下“测试”按钮时,剪贴板内容将被检查并回显到控制台(支持的DataFlavor和每个DataFlavor

    所以,复制这些步骤:

  • 开始申请

  • 按“复制”按钮:您将在日志中看到"object copied"消息
  • 按“测试”按钮:您将看到剪贴板的内容:

      flavors.length = 1 flavor[0] = java.awt.datatransfer.DataFlavor[mimetype=application/x-java-serialized-object;representationclass=MyObject] 
  • 启动应用程序的另一个实例(不要关闭第一个实例)

  • 按“测试”按钮:您将看到剪贴板为空:

      flavors.length = 0 

这是为什么?


UPD2: sscce直接在这里发布:

  import java.awt.BorderLayout; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.ClipboardOwner; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.Toolkit; import javax.swing.JButton; import javax.swing.SwingUtilities; import javax.swing.JFrame; public final class ClipboardTest implements Runnable, ClipboardOwner { public static void main(String[] args) { SwingUtilities.invokeLater (new ClipboardTest()); } public void run() { JFrame f = new JFrame ("Clipboard test"); f.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE); //-- Create "copy" button. // When you click it, new object "test_items" becomes created // and put to the clipboard. { JButton button_copy = new JButton("copy"); button_copy.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ String[] test_items = { "one", "two", "three" }; Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); MyObject data = new MyObject(test_items); MyObjectSelection dataSelection = new MyObjectSelection(data); clipboard.setContents(dataSelection, ClipboardTest.this); System.out.println("object copied"); } }); f.add(button_copy, BorderLayout.NORTH); } //-- Create "test" button. // When you click it, clipboard contents are checked // and echoed to the console (count of supported DataFlavor's, and each DataFlavor) { JButton button_test = new JButton("test"); button_test.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable clipboardContent = clipboard.getContents(this); DataFlavor[] flavors = clipboardContent.getTransferDataFlavors(); System.out.println("flavors.length = " + flavors.length); for (int i = 0; i < flavors.length; i++){ System.out.println("flavor[" + i + "] = " + flavors[i]); } } }); f.add(button_test, BorderLayout.SOUTH); } f.pack(); f.setVisible(true); } // ClipboardOwner implementation @Override public void lostOwnership(Clipboard clipboard, Transferable transferable){ System.out.println("ClipboardTest: Lost ownership"); } /* ***************************************************************************************** * Object that I want to copy/paste * ****************************************************************************************/ public static class MyObject { private String[] items; public MyObject(String[] items){ this.setItems(items); } public String[] getItems(){ return this.items; } public void setItems(String[] items){ this.items = items; } } public static class MyObjectSelection implements Transferable, ClipboardOwner { private static DataFlavor dmselFlavor = new DataFlavor(MyObject.class, "Test data flavor"); private MyObject selection; public MyObjectSelection(MyObject selection){ this.selection = selection; } // Transferable implementation @Override public DataFlavor[] getTransferDataFlavors(){ System.out.println("getTransferDataFlavors"); DataFlavor[] ret = {dmselFlavor}; return ret; } @Override public boolean isDataFlavorSupported(DataFlavor flavor){ return dmselFlavor.equals(flavor); } @Override public synchronized Object getTransferData (DataFlavor flavor) throws UnsupportedFlavorException { if (isDataFlavorSupported(flavor)){ return this.selection; } else { throw new UnsupportedFlavorException(dmselFlavor); } } // ClipboardOwner implementation @Override public void lostOwnership(Clipboard clipboard, Transferable transferable){ System.out.println("MyObjectSelection: Lost ownership"); } } } 

引用本教程 :

使用此机制传输数据使用Object序列化,因此用于传输数据的类必须实现Serializable接口,因为必须使用它序列化。 如果所有内容都不可序列化,您将在删除或复制到剪贴板期间看到NotSerializableException

您的MyObject不可Serializable ,因此无法工作。 框架显然检测到这一事实(与可序列化父类的不可序列化子类的情况相反,或者仅在进程中检测到不可序列化的类似情况),因此它甚至不会向其他进程提供这种风格。

通常,同一个Java应用程序的两个实例不会具有相同的地址空间,因此它们不能简单地访问彼此的内存。 因此,您传输的所有内容都必须序列化。