【问题标题】:how to send an Object like I can send String using PrintWriter如何发送一个对象,就像我可以使用 PrintWriter 发送字符串一样
【发布时间】:2014-08-11 08:41:50
【问题描述】:

您好,我正在开发简单的客户端服务器应用程序,其中客户端可以使用文本绘制图片和聊天,按下按钮时发送文本,并且我想以相同的方式发送名为 ColorPointSize 的对象列表,它指的是列表然后在面板上绘制的点、颜色和点的大小。我可以像通过 PrintWriter 发送字符串一样简单地做到这一点,还是应该将它们转换为 toString(),然后以某种方式将其转换回 ColorPointSize 或使用序列化,但我真的不知道该怎么做我是初学者到Java,我感到困惑。

以下是部分代码: 向服务器发送消息

private void sendButtonActionPerformed(java.awt.event.ActionEvent evt) {                                           
    // TODO add your handling code here:
    String nothing = "";
    if ((inputTextArea.getText()).equals(nothing)) {
        inputTextArea.setText("");
        inputTextArea.requestFocus();
    } else {
        try {
           writer.println(username + ":" + inputTextArea.getText() + ":" + "Chat");
           //  here i want to send also an object of type shall i do it via changing toString() and then somehow converting it or what ???
           Date now = new Date();
           String temp=inputTextArea.getText();
           s_archiwum="\n"+s_archiwum+"\n"+now+" "+temp+"\n";
           writer.flush(); // flushes the buffer
        } catch (Exception ex) {
            chatTextArea.append("Message was not sent. \n");
        }
        inputTextArea.setText("");
        inputTextArea.requestFocus();
    }
    inputTextArea.setText("");
    inputTextArea.requestFocus();
}          

将连接用户的名称添加到在线用户列表我想以类似的方式添加 ColorPointSize。

public void userAdd(String data) {
    String message, add = ": :Connect", done = "Server: :Done", name = data;
    outputPane.append("Before " + name + " added. \n");
    onlineUsers.add(name);
    outputPane.append("After " + name + " added. \n");
    String[] tempList = new String[(onlineUsers.size())];
    onlineUsers.toArray(tempList);

    for (String token : tempList) {

        message = (token + add);
        tellEveryone(message);
    }
    tellEveryone(done);
}

绘制方法:(cps是ColorPointSize类型的对象列表)

private void drawRoundRectangles(Graphics2D g2d) {
    int x, y, x2, y2;
    synchronized (cps) {
        for (ColorPointSize p : cps) {
            g2d.setColor(p.color);
            x = (int) p.getX();
            y = (int) p.getY();
            x2 = (int) p.getX() - 1;
            y2 = (int) p.getY() - 1;

            g2d.drawLine(x, y, x2, y2);

            g2d.fillRoundRect(x, y, p.size, p.size, p.size, p.size);

            g2d.drawLine(x, y, x2, y2); // connectin' points wit' line

        }
    }
}

ColorPointSize 类(以防万一)

package paintalk;

import java.awt.Color;
import java.awt.Point;

public class ColorPointSize {
    public Color color;
    public Point point;
    public int size;

    public ColorPointSize(Color c, Point p, int s) {
        this.color = c;
        this.point = p;
        this.size = s;
    }

    ColorPointSize(Point p) {
        this.point = p;
    }

    double getX() {
        return point.getX();
    }

    double getY() {
        return point.getY();
    }

}

【问题讨论】:

    标签: java client-server draw send


    【解决方案1】:

    这一切都归结为序列化和反序列化数据,您可能已经创建了PrintWriter 来写入某种OutputStream(甚至可能是System.out,这只是一个方便的OutputStream)。

    java.io 实际上提供了一组简洁的类:java.io.ObjectInputStreamjava.io.ObjectOutputStream。您可以将它们作为一对来发送任意 Java 对象,只要它们将“实现 Serializable”添加到它们的类定义中——实现“Serializable”实际上并不添加任何方法,它只是用作 Java 的特殊标记允许将对象归结为低级字节,并且只要对象中的每个项目也使用“实现可序列化”定义即可。尝试以下示例,将其命名为 Test.java 并运行“java Test”;我用“implements Serializable”修改了你的 ColorPointSize 类,但它没有改变:

    import java.io.*;
    import java.awt.Color;
    import java.awt.Point;
    
    class ColorPointSize implements Serializable {
      public Color color;
      public Point point;
      public int size;
    
      public ColorPointSize(Color c, Point p, int s){
        this.color=c;
        this.point=p;
        this.size=s;
      }
      ColorPointSize(Point p){
        this.point=p;
      }
    
      double getX(){
        return point.getX();
      }
    
      double getY(){
        return point.getY();
      }
    }
    
    public class Test {
      public static void main(String[] args) throws Exception {
        ColorPointSize foo = new ColorPointSize(
            new Color(123, 222, 111), new Point(42, 24), 50);
        System.out.println(foo.color);
        System.out.println(foo.point);
        System.out.println(foo.size);
    
        ObjectOutputStream fout = new ObjectOutputStream(
            new FileOutputStream(new File("foo.dat")));
        fout.writeUnshared(foo);
        fout.close();
    
        ObjectInputStream fin = new ObjectInputStream(
            new FileInputStream(new File("foo.dat")));
        ColorPointSize bar = (ColorPointSize) fin.readUnshared();
        fin.close();
    
        System.out.println(bar.color);
        System.out.println(bar.point);
        System.out.println(bar.size);
      }
    }
    

    如果您运行该示例,您将看到该示例成功地将您的 ColorPointSize 实例的所有内部内容写入文件,然后将其读回,恢复其所有设置。请注意,如果您尝试在 ColorPointSize 类中放入根本上不可序列化的东西,例如 Socket 对象,这将不起作用。

    现在,您可以将 ObjectOutputStream 包装在任何其他类型的 OutputStream 周围,例如由网络套接字提供的输出流,而不是像示例中那样将 ObjectOutputStream 包装在 FileOutputStream 周围,如果编写 Client/服务器应用程序。

    一般来说,编写原始对象可能很方便,但它可能并不总是最有效的方式。同样,有时你的类不能直接序列化,你会想要更好的控制。一种常见的模式是简单地将方法添加到您的类中以进行序列化和反序列化,如下所示:

    class ColorPointSize {
      public Color color;
      public Point point;
      public int size;
    
      public void deserializeFrom(DataInputStream in) {
        this.color = new Color(in.readInt(), in.readInt(), in.readInt());
        this.point = new Point(in.readInt(), in.readInt());
        this.size = in.readInt();
      }
    
      public void serializeTo(DataOutputStream out) {
        out.writeInt(color.getRed());
        out.writeInt(color.getGreen());
        out.writeInt(color.getBlue());
        out.writeInt(point.getX());
        out.writeInt(point.getY());
        out.writeInt(size);
      }
    }
    

    或者更高效:

    class ColorPointSize {
      public Color color;
      public Point point;
      public int size;
    
      public void deserializeFrom(DataInputStream in) {
        this.color = new Color(in.readInt());
        this.point = new Point(in.readInt(), in.readInt());
        this.size = in.readInt();
      }
    
      public void serializeTo(DataOutputStream out) {
        out.writeInt(color.getRGB());
        out.writeInt(point.getX());
        out.writeInt(point.getY());
        out.writeInt(size);
      }
    }
    

    然后,您可以使用new DataOutputStream(new FileOutputStream("foo.dat")) 代替new ObjectOutputStream,同样在输入端使用new DataInputStream。通常,您需要将每个通信通道的输入端和输出端视为一对,然后您可以真正选择任何策略,以某种可以轻松恢复的方式将数据保存到流中另一端。在上面的示例中,如果您希望您的序列化格式是人类可读的,您可以很容易地使用“toString()”方法的一些组合。

    【讨论】:

      猜你喜欢
      • 2022-08-18
      • 2012-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-14
      • 1970-01-01
      • 2018-02-17
      相关资源
      最近更新 更多