1.TCP/IP协议要求信息必须在块(chunk)中发送和接收,而块的长度必须是8位的倍数,因此,我们可以认为TCP/IP协议中传输的信息是字节序列。如何发送和解析信息需要一定的应用程序协议。
吴江网站建设公司创新互联,吴江网站设计制作,有大型网站制作公司丰富经验。已为吴江上1000+提供企业网站建设服务。企业网站搭建\成都外贸网站制作要多少钱,请找那个售后服务好的吴江做网站的公司定做!
2.信息编码:
首先是Java里对基本整型的处理,发送时,要注意:1)每种数据类型的字节个数;2)这些字节的发送顺序是怎样的?(little-endian还是
big-endian);3)所传输的数值是有符号的(signed)还是无符号的(unsigned)。具体编码时采用位操作(移位和屏蔽)就可以了。
具体在Java里,可以采用DataOutputStream类和ByteArrayOutputStream来实现。恢复时可以采用
DataInputStream类和ByteArrayInputStream类。
其次,字符串和文本,在一组符号与一组整数之间的映射称为编码字符集(coded character
set)。发送者与接收者必须在符号与整数的映射方式上达成共识,才能使用文本信息进行通信,最简单的方法就是定义一个标准字符集。具体编码时采用
String的getBytes()方法。
最后,位操作。如果设置一个特定的设为1,先设置好掩码(mask),之后用或操作;要清空特定一位,用与操作。
3.成帧与解析
成帧(framing)技术解决了接收端如何定位消息的首位位置的问题。
如果接收者试图从套接字中读取比消息本身更多的字节,将可能发生以下两种情况之一:如果信道中没有其他消息,接收者将阻塞等待,同时无法处理接收
到的消息;如果发送者也在等待接收端的响应消息,则会形成死锁(dealock);另一方面,如果信道中还有其他消息,则接收者会将后面消息的一部分甚至
全部读到第一条消息中去,这将产生一些协议错误。因此,在使用TCP套接字时,成帧就是一个非常重要的考虑因素。
有两个技术:
1.基于定界符(Delimiter-based):消息的结束由一个唯一的标记(unique
marker)指出,即发送者在传输完数据后显式添加的一个特殊字节序列。这个特殊标记不能在传输的数据中出现。幸运的是,填充(stuffing)技术
能够对消息中出现的定界符进行修改,从而使接收者不将其识别为定界符。在接收者扫描定界符时,还能识别出修改过的数据,并在输出消息中对其进行还原,从而
使其与原始消息一致。
2.显式长度(Explicit length):在变长字段或消息前附加一个固定大小的字段,用来指示该字段或消息中包含了多少字节。这种方法要确定消息长度的上限,以确定保存这个长度需要的字节数。
接口:
Java代码 import java.io.IOException; import java.io.OutputStream; public interface Framer { void frameMsg(byte [] message,OutputStream out) throws IOException; byte [] nextMsg() throws IOException; }
定界符的方式:
Java代码 import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class DelimFramer implements Framer { private InputStream in;//data source; private static final byte DELIMTER=(byte)'\n';//message delimiter public DelimFramer(InputStream in){ this.in=in; } @Override public void frameMsg(byte[] message, OutputStream out) throws IOException { //ensure that the message dose not contain the delimiter for(byte b:message){ if(b==DELIMTER) throw new IOException("Message contains delimiter"); } out.write(message); out.write(DELIMTER); out.flush(); } @Override public byte[] nextMsg() throws IOException { ByteArrayOutputStream messageBuffer=new ByteArrayOutputStream(); int nextByte; while((nextByte=in.read())!=DELIMTER){ if(nextByte==-1){//end of stream? if(messageBuffer.size()==0){ return null; }else{ throw new EOFException("Non-empty message without delimiter"); } } messageBuffer.write(nextByte); } return messageBuffer.toByteArray(); } }
显式长度方法:
Java代码 import java.io.DataInputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class LengthFramer implements Framer { public static final int MAXMESSAGELENGTH=65535; public static final int BYTEMASK=0xff; public static final int SHOTMASK=0xffff; public static final int BYTESHIFT=8; private DataInputStream in;// wrapper for data I/O public LengthFramer(InputStream in) throws IOException{ this.in=new DataInputStream(in); } @Override public void frameMsg(byte[] message, OutputStream out) throws IOException { if(message.lengthMAXMESSAGELENGTH){ throw new IOException("message too long"); } //write length prefix out.write((message.lengthBYTEMASK)BYTEMASK); out.write(message.lengthBYTEMASK); //write message out.write(message); out.flush(); } @Override public byte[] nextMsg() throws IOException { int length; try{ length=in.readUnsignedShort(); }catch(EOFException e){ //no (or 1 byte) message; return null; } //0=length=65535; byte [] msg=new byte[length]; in.readFully(msg);//if exception,it's a framing error; return msg; } }
下面的是键盘和鼠标的各种事件,看一下是不是你要的!
鼠标监听器
鼠标监听器mouseListener监听鼠标事件MouseEvent。相应事件和处理方法如下表:
鼠标事件 处理方法
MOUSE_CLICKED MouseClicked (MouseEvent) 鼠标点击(单或双)
MOUSE_PRESSED MousePressed (MouseEvent) 鼠标按下
MOUSE_RELEASED MouseReleased(MouseEvent) 鼠标松开
MOUSE_ENTERED MouseEntered (MouseEvent) 鼠标进入(某组件区域)
MOUSE_EXITED MouseExited (MouseEvent) 鼠标离开(某组件区域)
鼠标事件MouseEvent常用方法
int getClickCount() 得到点击次数1 OR 2;
int getX(), int getY() 得到鼠标的(象素)位置。
对于鼠标的移动和拖放,另外用鼠标运动监听器mouseMotionListener。因为许多程序不需要监听鼠标运动,把两者分开可简化程序。有两个方法处理鼠标运动事件:
MOUSE_MOVED MouseMoved (MouseEvent) 鼠标在移动MOUSE_DRAGGED MouseDragged(MouseEvent) 鼠标被拖动
下面的例程演示简单的鼠标监听,并在屏幕上输出鼠标操作的信息。
例2
下面是讨论MouseMotionListener的使用时机,它提供的下面的两个方法,可让你随时掌握鼠标的坐标,并处理拖曳鼠标的操作。
MouseMotionListener mouseDragged(MouseEvent e)
mouseMoved(MouseEvent e)
-----------------------------------------------------------------------
下面的范例让你知道鼠标在JFrame上的坐标,并拖曳出直线来。
MouseDemo3.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/*为了达到画线的功能,我们分别implements MouseListener与MouseMotionListener.
*/
public class MouseDemo3 extends JFrame implements MouseListener,MouseMotionListener{
int flag;//flag=1代表Mouse Moved,flag=2代表Mouse Dragged
int x=0;
int y=0;
int startx,starty,endx,endy;//起始坐标与终点坐标
public MouseDemo3(){
Container contentPane=getContentPane();
contentPane.addMouseListener(this);
contentPane.addMouseMotionListener(this);
setSize(300,300);
show();
addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
}
);
}
/*由mousePressed(),mouseReleased()取得示拖曳的开始与结束坐标*/
public void mousePressed(MouseEvent e){
startx=e.getX();
starty=e.getY();
}
public void mouseReleased(MouseEvent e){
endx=e.getX();
endy=e.getY();
}
public void mouseEntered(MouseEvent e){ }
public void mouseExited(MouseEvent e){ }
public void mouseClicked(MouseEvent e){ }
/*mouseMoved(),mouseDragged()取得鼠标移动的每一个坐标,并调用repaint()方法*/
public void mouseMoved(MouseEvent e){
flag=1;
x=e.getX();
y=e.getY();
repaint();
}
public void mouseDragged(MouseEvent e){
flag=2;
x=e.getX();
y=e.getY();
repaint();
}
public void update(Graphics g){
g.setColor(this.getBackground());
g.fillRect(0,0,getWidth(),getHeight());
paint(g);
}
public void paint(Graphics g){
g.setColor(Color.black);
if (flag==1){
g.drawString("鼠标坐标:("+x+","+y+";)",10,50);
g.drawLine(startx,starty,endx,endy);
}
if (flag==2){
g.drawString("拖曳鼠标价坐标:("+x+","+y+";)",10,50);
g.drawLine(startx,starty,x,y);
}
}
public static void main(String[] args){
new MouseDemo3();
}
}
例3
实现一个简单的鼠标控制程序MouseController。程序功能很简单:随机移动鼠标并点击左键。
代码如下:
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.util.Random;
/**
*
*/
/**
* @Create date 2007-11-6
*/
public class MouseController implements Runnable {
private Dimension dim;
private Random rand;
private Robot robot;
private volatile boolean stop = false;
public MouseController() {
dim = Toolkit.getDefaultToolkit().getScreenSize();
rand = new Random();
try {
robot = new Robot();
} catch (AWTException ex) {
ex.printStackTrace();
}
}
public void run() {
while(!stop) {
int x = rand.nextInt(dim.width);
int y = rand.nextInt(dim.height);
robot.mouseMove(x, y);
robot.mousePress(InputEvent.BUTTON1_MASK);
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
public synchronized void stop() {
stop = true;
}
public static void main(String[] args) {
MouseController mc = new MouseController();
Thre
$False$
ad mcThread = new Thread(mc);
System.out.println("Mouse Controller start");
mcThread.start();
try {
Thread.sleep(60000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
mc.stop();
System.out.println("Mouse Controller stoped");
}
}
例4 本例程演示鼠标监听器,鼠标点击和运动的监听。
///
// MouseEvt.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MyPanel extends JPanel implements MouseMotionListener{
public MyPanel() {
addMouseListener(new MouseAdapter() {
publicvoid mouseClicked(MouseEvent evt) {
if (evt.getClickCount() = 2)
System.out.println("\n双击鼠标");
int x = evt.getX(); int y = evt.getY();
System.out.println("点击鼠标的位置\nX:" + x + "\ty: " + y);
}
});
addMouseMotionListener(this);
}
publicvoid mouseMoved(MouseEvent evt){
System.out.println("\n鼠标正在移动");
}
publicvoid mouseDragged(MouseEvent evt){
System.out.println("\n鼠标正在拖动");
}
}
class MyFrame extends JFrame{
public MyFrame(){
setTitle("鼠标事件示例程序");
setSize(300, 200);
addWindowListener(new WindowAdapter(){
publicvoid windowClosing(WindowEvent e){
System.exit(0);
}
} );
Container contentPane = getContentPane();
contentPane.add(new MyPanel());
}
}
publicclass MouseEvt{
publicstaticvoid main(String[] args){
JFrame frame = new MyFrame();
frame.setVisible(true);
}
}
///
简要说明
在MyPanel的构建器中添加了鼠标适配器来监听鼠标点击数和位置。也添加了运动监听器来处理移动和拖放操作。
鼠标双击事件
鼠标的单双击事件在很多时候对我们帮助很大,但是在JAVA中却没有给出鼠标双击事件.我们可以通过事件源e.getClickCount()==2来判断鼠标点击次数来实现鼠标双击事件,例如: public class MyMouseListener
extends java.awt.event.MouseAdapter ...{
public void mouseClicked(MouseEvent e) ...{
System.out.println("clicked");
int clickTimes = e.getClickCount();
if (clickTimes == 2) ...{
System.out.println("Doublc Clicked!");
}
}
}
但是这样并没有达到我们的要求,因为在每次触发双击事件的同时会触发单击事件.所以我们试图改进以上方案,不使用系统提供的e.getClickCount()方法.可以考虑当第一次单击鼠标的时候让鼠标单击事件延时0.2秒执行,而在这段时间里等待第二次单击,如果有第二次单击,那么我们执行双击事件任务,取消单击任务;如果在这段时间没有等到再次单击,那么执行单击任务.
下面是用定时器延时单击事件实现鼠标双击事件,单击和双击事件互不影响!
public class MyMouseListener
extends java.awt.event.MouseAdapter ...{
private static boolean flag=false;//用来判断是否已经执行双击事件
private static int clickNum=0;//用来判断是否该执行双击事件
public void mouseClicked(MouseEvent e) ...{
final MouseEvent me=e;//事件源
this.flag=false;//每次点击鼠标初始化双击事件执行标志为false
if (this.clickNum == 1) ...{//当clickNum==1时执行双击事件
this.mouseDoubleClicked(me);//执行双击事件
this.clickNum=0;//初始化双击事件执行标志为0
this.flag=true;//双击事件已执行,事件标志为true
return;
}
//定义定时器
java.util.Timer timer=new java.util.Timer();
//定时器开始执行,延时0.2秒后确定是否执行单击事件
timer.schedule(new java.util.TimerTask() ...{
private int n=0;//记录定时器执行次数
public void run() ...{
if(MyMouseListener.flag)...{//如果双击事件已经执行,那么直接取消单击执行
n=0;
MyMouseListener.clickNum=0;
this.cancel();
return;
}
if (n == 1) ...{//定时器等待0.2秒后,双击事件仍未发生,执行单击事件
mouseSingleClicked(me);//执行单击事件
MyMouseListener.flag = true;
MyMouseListener.clickNum=0;
n=0;
this.cancel();
return;
}
clickNum++;
n++;
}
},new java.util.Date(),500);
}
/** *//**
* 鼠标单击事件
* @param e 事件源参数
*/
public void mouseSingleClicked(MouseEvent e)...{
System.out.println("Single Clicked!");
}
/** *//**
* 鼠标双击事件
* @param e 事件源参数
*/
public void mouseDoubleClicked(MouseEvent e)...{
System.out.println("Doublc Clicked!");
}
}
//Test.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Test extends JFrame{
public Test(){
super("test");
init();
this.setSize(800,600);
this.setVisible(true);
}
private void init(){
JButton b=new JButton("button");
b.setBounds(50,50,100,30);
this.getContentPane().setLayout(null);
this.getContentPane().add(b);
b.addMouseListener(new MyMouseListener());
}
public static void main(String args[]){
new Test();
}
}
键盘监听器
键盘监听器KeyListener用来监听键盘事件。键盘事件有三种:KEY_PRESSED键按下了,KEY_RELEASED键松开了,KEY_TYPED键按过了。每个键都有一个键码,普通键的键码就是ASCII码。键码可通过int getKeyCode()方法获得。Java设置了一种“虚拟键码”(Virtual Key Code),用“VK_”作为前缀,例如VK_G。下面是某些特殊键的虚拟键码。
键码 含义 键码 含义
VK_LEFT/VK_RIGHT 左右方向键 VK_CONTROL Ctrl键
VK_KP_UP 小键盘向上 VK_ATL Alt键
VK_PAUSE 暂停键 VK_SHIFT Shift键
VK_NUMBER0 小键盘数字0 VK_F1 功能键F1
VK_0 数字键0 VK_B 字母键B
虚拟键码对应的是键位,不区分大小写。要想知道大小写还必须查看修饰键(modifier key)。这由输入事件InputEvent的getModifere()方法得到,把返回值与常量SHIFT_MASK, CONTROL_MASK, ALT_MASK比较,用以判定哪个修饰键处于“同时按下”状态。
监听器KeyListener有三个方法keyPressed(KeyEvent evt),keyReleased(KeyEvent evt),keyTyped(KeyEvent evt),分别用于相应事件发生后的处理。下面的例程中给自己的键盘监听器建立了showKeyEventMsg方法来显示按键信息。
除了getKeyCode()方法得到键码外,还可用getKeyChar()方法得到输入的字符,用getKeyText(code)方法得到输入的字符串。用isShiftDown()判断shift键是否被按下等。当按下Control键时getKeyText返回的是“ctrl",Alt和Shift也类似。
下面的例子演示得到键码和字符的方法,在命令行上显示结果。
例1 本例程演示键盘监听器后键码的用法。
///
// KeyEvt.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MyKeyListener implements KeyListener{
publicvoid keyPressed(KeyEvent evt) {
System.out.println("\n按键被按下");
showKeyEventMsg(evt);
}
publicvoid keyReleased(KeyEvent evt){ }
publicvoid keyTyped(KeyEvent evt) { }
privatevoid showKeyEventMsg(KeyEvent evt){//显示按键事件信息
//得到按键对应的整型数
int code = evt.getKeyCode();
//返回按键事件所代表的字符
char c = evt.getKeyChar();
//得到代表按键的字符串
String szText = evt.getKeyText(code);
if (code != KeyEvent.VK_UNDEFINED)
System.out.println("\n按键对应的整型数:"+code);
if (c != KeyEvent.CHAR_UNDEFINED)
System.out.println("\n与按键相联系的字符:"+c);
if (evt.isShiftDown())
System.out.println("\n按键Shift被按下");
System.out.println("\n按键本身的字符串:"+szText);
}
}
class ButtonPanel extends JPanel{
public ButtonPanel() {
//新建一个文本域组件
tf = new JTextField(20);
add(tf);
//指定用来处理该按钮事件的监听器对象为JPanel本身
myListener = new MyKeyListener();
tf.addKeyListener(myListener);
}
private JTextField tf;
private MyKeyListener myListener;
}
class ButtonFrame extends JFrame{
public ButtonFrame() {
setTitle("键盘事件示例程序");
setSize(300, 200);
setLocation(100,100);
addWindowListener(new WindowAdapter() {
publicvoid windowClosing(WindowEvent e)
{ System.exit(0);
}
});
Container ctPane = getContentPane();
ctPane.add(new ButtonPanel());
}
}
publicclass KeyEvt{
publicstaticvoid main(String[] args) {
JFrame frame = new ButtonFrame();
frame.setVisible(true);
}
}
///简要说明
程序建立了自己的键盘监听器MyKeyListener,定义了一个新方法showKeyEventMsg用来在标准输出设备上显示有关的键盘信息。
在面版ButtonPanel上建立文本框并加键盘监听器。把面版ButtonPanel放到窗口ButtonFrame中。
这个地方有问题,第一,你必须写入newLine,要不会造成阻塞;第二,你必须先flush后才能读服务器;第三,你从控制台输入应该有个结束标志,要不你在while里面把bw关闭了,你还怎么循环
客户端这个地方重写一下,
while(true) {
temp=br.readLine();
if(temp.equals("over")){
break;
}
bw.write(temp);
bw.newLine();//如果没有,使用readLine则会造成莫名等待
bw.flush();
}
不一定改全了,你先试试这些改动,如有问题再找
以下从技术角度就常见的保护措施 和常用工具来看看如何有效保护java代码:1. 将java包装成exe 特点:将jar包装成可执行文件,便于使用,但对java程序没有任何保护。不要以为生成了exe就和普通可执行文件效果一样了。这些包装成exe的程序运行时都会将jar文件释放到临时目录,很容易获取。常用的工具有exe4j、jsmooth、NativeJ等等。jsmooth生成的exe运行时临时目录在exe所在目录中或是用户临时目录 中;exe4j生成的exe运行时临时目录在用户临时目录中;NativeJ生成的exe直接用winrar打开,然后用zip格式修复成一个jar文件,就得到了原文件。如果只是为了使用和发布方便,不需要保护java代码,使用这些工具是很好的选择。2. java混淆器特点:使用一种或多种处理方式将class文件、java源代码进行混淆处理后生成新的class,使混淆后的代码不易被反编译,而反编译后的代码难以阅 读和理解。这类混淆器工具很多,而且也很有成效。缺点:虽然混淆的代码反编译后不易读懂,但对于有经验的人或是多花些时间,还是能找到或计算出你代码中隐藏的敏感内容,而且在很多应用中不是全部代码都能混淆的,往往一些关键的库、类名、方法名、变量名等因使用要求的限制反而还不能混淆。3. 隔离java程序到服务端特点:把java程序放到服务端,让用户不能访问到class文件和相关配套文件,客户端只通过接口访问。这种方式在客户/服务模式的应用中能较好地保护java代码。缺点是:必须是客户/服务模式,这种特点限制了此种方式的使用范围;客户端因为逻辑的暴露始终是较为薄弱的环节,所以访问接口时一般都需要安全性认证。4. java加密保护特点:自定义ClassLoader,将class文件和相关文件加密,运行时由此ClassLoader解密相关文件并装载类,要起到保护作用必须自定 义本地代码执行器将自定义ClassLoader和加密解密的相关类和配套文件也保护起来。此种方式能很有效地保护java代码。缺点:可以通过替换JRE包中与类装载相关的java类或虚拟机动态库截获java字节码。 jar2exe属于这类工具。5. 提前编译技术(AOT) 特点:将java代码静态编译成本地机器码,脱离通用JRE。此种方式能够非常有效地保护java代码,且程序启动比通用JVM快一点。具有代表性的是GNU的gcj,可以做到对java代码完全提前编译,但gcj存在诸多局限性,如:对JRE 5不能完整支持、不支持JRE 6及以后的版本。由于java平台的复杂性,做到能及时支持最新java版本和JRE的完全提前编译是非常困难的,所以这类工具往往采取灵活方式,该用即时编译的地方还是 要用,成为提前编译和即时编译的混合体。缺点:由于与通用JRE的差异和java运用中的复杂性,并非java程序中的所有jar都能得到完全的保护;只能使用此种工具提供的一个运行环境,如果工具更新滞后或你需要特定版本的JRE,有可能得不到此种工具的支持。 Excelsior JET属于这类工具。6. 使用jni方式保护特点:将敏感的方法和数据通过jni方式处理。此种方式和“隔离java程序到服务端”有些类似,可以看作把需要保护的代码和数据“隔离”到动态库中,不同的是可以在单机程序中运用。缺点和上述“隔离java程序到服务端”类似。7. 不脱离JRE的综合方式保护特点:非提前编译,不脱离JRE,采用多种软保护方式,从多方面防止java程序被窃取。此种方式由于采取了多种保护措施,比如自定义执行器和装载器、加密、JNI、安全性检测、生成可执行文件等等,使保护力度大大增强,同样能够非常有效地保护java代码。缺点:由于jar文件存在方式的改变和java运用中的复杂性,并非java程序中的所有jar都能得到完全的保护;很有可能并不支持所有的JRE版本。 JXMaker属于此类工具。8. 用加密锁硬件保护特点:使用与硬件相关的专用程序将java虚拟机启动程序加壳,将虚拟机配套文件和java程序加密,启动的是加壳程序,由加壳程序建立一个与硬件相关的 受保护的运行环境,为了加强安全性可以和加密锁内植入的程序互动。此种方式与以上“不脱离JRE的综合方式保护”相似,只是使用了专用硬件设备,也能很好地保护java代码。缺点:有人认为加密锁用户使用上不太方便,且每个安装需要附带一个。从以上描述中我们可以看出:1. 各种保护方式都有其优缺点,应根据实际选用2. 要更好地保护java代码应该使用综合的保护措施3. 单机环境中要真正有效保护java代码,必须要有本地代码程序配合当然,安全都是相对的,一方面看你的保护措施和使用的工具能达到的程度,一方面看黑客的意愿和能力,不能只从技术上保护知识产权。总之,在java 代码保护方面可以采取各种可能的方式,不可拘泥于那些条条框框。
你在Hobby和Person之间徘徊,造成一个死循环了,我觉你不应该是这样映射,这样会好麻烦的
package association;
import java.util.*;
public class Hobby {
/* Hobby类的属性hobbyname,一个vector型的persons */
private String hobbyname;
private Vector persons = new Vector();
/* 构造函数 */
public Hobby(String hobbyname, Person person) {
this.hobbyname = hobbyname;
persons.add(person);
/**
* 一个业余爱好可以对应多个人,但只对应一次
*/
if (!persons.contains(person))
person.addHobby(hobbyname);
}
/* 得到hobbyname */
public String getHobbyname() {
return hobbyname;
}
/* 一个hobby可以有多个person,添加person的方法 */
public void addPerson(String personname, int age) {
persons.add(new Person(personname, age));
}
/* 输出hobbyname,并将有hobbyname的人名全部输出 */
public String toString() {
String s = "hobbyname:" + hobbyname + "\n";
s += " persons:";
Object[] o = persons.toArray();
Person[] p = new Person[o.length];
for (int i = 0; i p.length; i++) {
p[i] = (Person) o[i];
s += p[i].getPersonname() + " " + p[i].getAge() + "; ";
}
return s;
}
/* 用于测试的主函数 */
public static void main(String arg[]) throws Exception {
Person p1 = new Person("mary", 20);
p1.addHobby("Biking");
Hobby h2 = new Hobby("Swimming", p1);
String s = p1.toString() + "\n";
s += h2.toString() + "\n";
System.out.print(s);
}
}
class Person {
/* person类的属性personname,age和一个vector型的hobbies */
private String personname;
private int age;
private Vector hobbies = new Vector();
/* 构造函数 */
public Person(String personname, int age) {
this.age = age;
this.personname = personname;
}
/* 得到personname */
public String getPersonname() {
return personname;
}
/* 得到age */
public int getAge() {
return age;
}
/* 添加hobby的方法 */
public void addHobby(String hobbyname) {
hobbies.add(new Hobby(hobbyname, this));
}
/* 输出person,并将其爱好全部输出 */
public String toString() {
String s = "personname:" + personname + "\n";
s += " hobbies:";
Object[] o = hobbies.toArray();
Hobby[] h = new Hobby[o.length];
for (int i = 0; i h.length; i++) {
h[i] = (Hobby) o[i];
s += h[i].getHobbyname() + " ";
}
return s;
}
}