类 FilterInputStream 和 FilterOutputStream 分别作为所有过滤输入流和输 出流的父类。 为了使用一个过滤流,必须首先把过滤流连接到某个输入/出流上,通常通过在构造方法的 参数中指定所要连接的输入/出流来实现。例如: FilterInputStream( InputStream in ); FilterOutputStream( OutputStream out ); 下面的类均是过滤流的例子 BufferedInputStream 和 BufferedOutputStream 缓冲流,用于提高输入/输出处理的效率。 DataInputStream 和 DataOutputStream 不仅能读/写数据流,而且能读/写各种的 java 语言的基本类型,如:boolean,int, float 等。 LineNumberInputStream 除了提供对输入处理的支持外,LineNumberInputStream 可以记录当前的行号。 PushbackInputStream 提供了一个方法可以把刚读过的字节退回到输入流中,以便重新再读一遍。 PrintStream 打印流的作用是把 Java 语言的内构类型以其字符表示形式送到相应的输出流。 10、什么是串行化,并举例 解:对象的寿命通常随着生成该对象的程序的终止而终止。有时候,可能需要将对象的状态 保存下来,在需要时再将对象恢复。我们把对象的这种能记录自己的状态以便将来再生的能 力,叫做对象的持续性(persistence)。对象通过写出描述自己状态的数值来记录自己,这 个过程叫对象的串行化(Serialization)。 串行化的目的是为 java 的运行环境提供一组特性,其主要任务是写出对象实例变量的数 值。 首先定义一个可串行化对象 public class Student implements Serializable{ int id; //学号 String name; //姓名 int age; //年龄 String department //系别 public Student(int id,String name,int age,String department){ this.id = id; this.name = name; this.age = age; this.department = department; } } 其次是构造对象的输入/输出流 java.io 包中,提供了 ObjectInputStream 和 ObjectOutputStream 将数据流功能扩展至可 读 写 对 象 。 在 ObjectInputStream 中 用 readObject() 方 法 可 以 直 接 读 取 一 个 对 象 , ObjectOutputStream 中用 writeObject()方法可以直接将对象保存到输出流中。 Student stu=new Student(981036,"Liu Ming",18, "CSD"); FileOutputStream fo=new FileOutputStream("data.ser"); //保存对象的状态 ObjectOutputStream so=new ObjectOutputStream(fo); try{ so.writeObject(stu); so.close(); }catch(IOException e ) {System.out.println(e);} FileInputStream fi=new FileInputStream("data.ser"); ObjectInputStream si=new ObjectInputStream(fi); //恢复对象的状态 try{ stu=(Student)si.readObject(); si.close(); }catch(IOException e ) {System.out.println(e); } 第十章 习题及思考题 1.什么是线程?它产生的背景是什么?线程有几种状态?说明状态变化调用的方法。 答:线程是一个进程在执行过程中产生的多条执行线索。每个线程有它产生、存在和消亡的 过程,是动态的。线程由线程内核对象和线程堆栈两部分组成,相对于组成进程的内核对象 及虚拟地址空间,线程使用的系统资源比进程少得多。 它产生的背景是:操作系统按照一定的策略(优先级、循环等)调度各个进程执行,以最大限 度地利用计算机的各种资源。一个进程运行期间,拥有的主要资源包括地址空间(存放 text,data,stack)、打开文件表、资源控制信息、核心栈。除了 text 可被其他进程共享外, 上述资源都属进程私有。因此 CPU 从运行一个进程转换到运行另一个进程时,为进程保存、 恢复的开销很大,并发效率低。如果把进程所占私有资源与进程中的运行代码相分离,在一 个地址空间中便可运行多个代码段,由此产生线程概念。 线程的状态有以下四种:(1)创建状态(New Thread) (2)运行状态(Runnable) (3)不可运行状态(Not Runnable) (4)死亡状态(Dead) 对于上面 4 种状态,各有特定的使线程返回可运行状态的方法与之对应,如下所述: (1)如果线程处于睡眠状态中,sleep()方法中的参数为休息时间,当这个时间过去后,线程 即为可运行的; (2)如果一个线程被挂起,需调用 resume()方法才能返回; (3)如果线程在等待条件变量,那么要停止等待的话,需要该条件变量的线程对象调用 notifyAll()方法; (4)如果在 I/O 流中发生线程阻塞,则特定的 I/O 完成可结束这种不可运行状态。 需要注意的是每种方法仅仅对相应的情况才有作用,例如当一个线程睡眠并且睡眠时间还没 有结束时,调用 resume()方法是无效的。 2、 实现两个定时线程,一个线程每隔 1 秒显示一次,一个线程每隔 3 秒显示一次。 答:源程序: import java.io.*; public class Time { static Lefthand left; //声明 静态的类的对象 static Righthand right; public static void main(String args[]) { left=new Lefthand() ; //创建两个线程。 right=new Righthand(); left.start(); //线程开始运行后, Lefthand 类中的 run 方法将被执行。 right.start(); } } class Lefthand extends Thread { public void run() { for(;;) { System.out.println("每 1 秒显示一次!"); Try { sleep(1000); 动线程睡眠 1 秒 } catch(InterruptedException e){} } } } class Righthand extends Thread { public void run() { for(;;) { System.out.println("每 3 秒显示一次!"); Try { sleep(3000); } catch(InterruptedException e){} } } } 运行结果: (这一列是注释) 每 1 秒显示一次 每 3 秒显示一次 每 1 秒显示一次 每 1 秒显示一次 每 3 秒显示一次 每 1 秒显示一次 每 1 秒显示一次 每 1 秒显示一次 每 3 秒显示一次 //lefthand 类继承 Thread 类 //使当前活 //捕捉异常 每 1 秒显示一次 每 1 秒显示一次 每 1 秒显示一次 每 3 秒显示一次 每 1 秒显示一次 每 1 秒显示一次 每 1 秒显示一次 每 3 秒显示一次 每 1 秒显示一次 每 1 秒显示一次 3、创建两个线程,每个线程打印出线程名字后再睡眠,给其它线程以执行的机会,主线程 也要打印出线程名字后再睡眠,每个线程前后共睡眠 5 次。要求分别采用从 Thread 中继承 和实现 Runnable 接口两种方式来实现程序。(即写两个程序) /*Creats two threads that write their names and sleep. The main thread also writes its /*name and sleeps. */ import java.io.*; public class NameThread extends Thread{ int time; //time in milliseconds to sleep public NameThread(String n,int t){ super(n); time=t; } public void run(){ for(int i=1;i<=5;i++){ System.out.println(getName()+" "+i); try{ Thread.sleep(time); }catch(InterruptedException e){return;} } } public static void main(String args[]){ NameThread bonnie=new NameThread("Bonnie",1000); bonnie.start(); NameThread clyde=new NameThread("Clyde",700); clyde.start(); for(int i=1;i<=5;i++){ System.out.println(Thread.currentThread().getName()+" "+i); try{ Thread.sleep(1100); }catch(InterruptedException e){return;} } } } 第十一章 习题及思考题 1、什么是 AWT,什么是 Swing? 答:AWT(Abstract Window Toolkit)是 Java 是进行可视化开发而提供的类库。AWT 提供 了基本的用户接口组件,如 label,button,menu,lists 等。另外也提供事件处理机制,支持 clipboard 及数据转换(datatransfer)以及图像操作。Swing 和 AWT 一样都是 Java 提供多 种图形用户接口包中的抽象窗口工具组件。 2、AWT 中包含了那些常用的组件,有什么用途? 解:AWT 中基本组件有:按钮(Button)、标签(Label)、复选框(Checkbox)、下拉列表框 (Choice)、列表框(List)、单选框(CheckboxGroup)、单行文本框(TextField)、多行文本 框(TextArea)和滚动条(Scrollbar)等。 AWT 用 Container 类来定义最基本的容器,所有可以作为容器的窗口对象都是 Container 类 的实例或子类所生成的对象。 AWT 提供了四个容器类。它们是 Window 类及其两个子类、Frame 类、Dia1og 类和 Panel 类。 除了 AWT 提供的容器外,Applet 类也是一个容器,它是 Panel 类的一个子类。 用户创建的每个新窗口都能有它们自己的菜单条,每个菜单条可以有一定数量的菜单,菜单 又可以有自己的菜单项。AWT 提供了一些类用于这些组件,它们分别是 MenuBar 类、Menu 类和 MenuItem 类。 java.awt 软件包不仅仅包含组件,还包含与绘图和事件处理有关的类。正如我们前面所讲 到的,组件是集中放置在容器中的。但我们没有提到每个容器如何使用布局管理器(Layout manager)来控制它所包含的组件尺寸和排放位置。java.awt 软件提供了几个布局管理器类 (BorderLayout 类、CardLaout 类等)。用户可根据需要选择适当的布局管理器对组件进行 布局。 java.awt 软件包还提供了几个类来表示尺寸和形状。例如:Dimension 类,它指定了一个 矩形区域的尺寸;Insets 类,它通常用来指定容器的周边与容器的显示区域之间的空白大 小;Shape 类则包含了点、矩形和多边形。 AWT 中的 Color 类在表示和调整颜色方面是十分有用的。它定义了一些常量来表示常用的颜 色,比如,Color.black 表示黑色,虽然它使用的颜色是 RGB(red-green-b1ue)格式,但它 也可以理解为 HSB(hue-saturation-brightness)格式。 AWT 中的 Image 类提供了图像数据的操作途径。Applet 可以通过 Applet 的 getImage()方法 获得 GIF(Graphic Information format)和 JPEG(Joint photographic Expert Group)图像 的对象,非 Applet 类则可以使用 Toolkit 类获得。Toolkit 类针对 AWT 的平台独立性,提 供了一个非独立于平台的接口。但是,大部分程序除了获得图像外,不能直接使用 Toolkit 对象。 用户还可以使用 Font 和 FontMetrics 类来控制所画文本的外观。Font 类使用户可以获得关 于字体的信息并创建不同的字体对象。FontMetrics 类,使用户可以获得一些特定字体在尺 寸上的细节信息。用户可以用 Componet 类和 Graphics 类的 setFont()方法设置一个组件所 使用的字体。 最后要提到的是 Graphics 类和 Event 类。Graphics 类和 Event 类对于 AWT 的绘画及事件处 理系统是非常重要的,没有 Graphics 对象,程序就不能往屏幕上画任何东西。而一个 Event 类则表示一个用户的动作,比如单击鼠标。 3、什么是事件?什么是委托事件处理模型? 解:用户接口的作用是使程序的使用者与程序之间进行交互,如果使用户接口具有交互能力, 就必须涉及到事件处理。所谓“事件”,就是指在系统中有某些我们所关心的事情(如:鼠 标移动,用户按下了某个键等)发生了,然后系统便通知我们去处理这些事情。这样的概念 一般在采用图形用户界面环境的操作系统中,是十分常见的。当用户在组件上作出动作时 (如:在组件上单击鼠标或按回车键),就创建了一个 Event 对象。 Java 事件处理模型有层次事件处理模型和委托事件处理模型。由于同一个事件源上可能 发生多种事件,因此 java 常采取了委托处理机制(Delegation Model),事件源可以把在其 自身所有可能发生的事件分别授权给不同的事件处理者来处理。比如在 Canvas 对象上既可 能发生鼠标事件,也可能发生键盘事件,该 Canvas 对象就可以授权给事件处理者一来处理 鼠标事件,同时授权给事件处理者二来处理键盘事件。有时也将事件处理者称为监听器,主 要原因也在于监听器时刻监听着事件源上所有发生的事件类型,一旦该事件类型与自己所负 责处理的事件类型一致,就马上进行处理。委托模型把事件的处理委托给外部的处理实体进 行处理,实现了将事件源和监听器分开的机制。事件处理者(监听器)通常是 一个类,该类如果要能够处理某种类型的事件,就必须实现与该事件类型相对的接口。例如 例 5.9 中 类 ButtonHandler 之 所 以 能 够 处 理 ActionEvent 事 件 , 原 因 在 于 它 实 现 了 与 ActionEvent 事件对应的接口 ActionListener。每个事件类都有一个与之相对应的接口。 4、编程包含一个标签和一个按钮,单击按钮时,标签的内容在"你好"和"再见"之间切换。 解: import java.awt.*; import java.awt.event.*; class but implements ActionListener { Frame f; Label label; Button b; public void begin() { f=new Frame("Label and Button ver1.0"); f.setSize(200,200); f.setLocation(100,100); f.setLayout(new FlowLayout(FlowLayout.LEFT,20,20)); label=new Label("Hello!",Label.CENTER); f.add(label); b=new Button("Press"); f.add(b); b.addActionListener(this); f.addWindowListener(new WinClose()); f.setVisible(true); } public void actionPerformed(ActionEvent e) { if(e.getSource()==b) { if(label.getText()=="Hello!") label.setText("Goodbye!"); else label.setText("Hello!"); } } } class WinClose extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } public class work1 { public static void main(String args[]) { (new but()).begin(); } } 5、编程包含一个复选按钮和一个普通按钮,复选按钮选中时,普通按钮的背景色为青色, 未选中时为灰色。 import java.awt.*; import java.awt.event.*; class choose implements ItemListener { Frame f; Checkbox c; Button b; public void begin() { f=new Frame("Checkbox"); f.setSize(200,200); f.setLayout(new FlowLayout()); c=new Checkbox("Color Change"); f.add(c); b=new Button(); b.setBackground(Color.GRAY); f.add(b); c.addItemListener(this); f.addWindowListener(new WinClose()); f.setVisible(true); } public void itemStateChanged(ItemEvent e) { if(e.getStateChange()==e.SELECTED&&b.getBackground()==Color.GRAY) b.setBackground(Color.BLUE); else b.setBackground(Color.GRAY); } } class WinClose extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } public class work3 { public static void main(String args[]) { (new choose()).begin(); } } 6、编程包含一个下拉列表和一个按钮,下拉列表中有 10、14、18 三个选项。选择 10 时, 按钮中文字的字号为 10,选择 14 时,按钮中文字的字号为 14,选择 18 时,按钮中文字的 字号为 18。 import java.awt.*; import java.awt.event.*; class WinClose extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } class choice implements ItemListener { Frame f; Choice c; Button b; public void begin() { f=new Frame("Choice"); f.setLayout(new GridLayout()); f.setSize(300,300); c=new Choice(); c.addItem("10"); c.addItem("14"); c.addItem("18"); f.add(c); b=new Button("Font"); b.setSize(50,50); f.add(b); f.addWindowListener(new WinClose()); c.addItemListener(this); f.setVisible(true); } public void itemStateChanged(ItemEvent e) { String str=c.getSelectedItem(); if(str=="10") b.setFont(b.getFont().deriveFont(Float.parseFloat(str))); if(str=="14") b.setFont(b.getFont().deriveFont(Float.parseFloat(str))); if(st r=="1 8") b.getFont().deriveFont(Float.parseFloat(str))); } } public class work5 { public static void main(String args[]) { (new choice()).begin(); } } b.set Font( 7、编程包含一个列表和两个标签,在第一个标签中显示列表中被双击的选项的内容,在第 二个标签中显示列表中被选中的所有选项的内容。 import java.awt.*; import java.awt.event.*; class WinClose extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } class list implements ItemListener,ActionListener { Frame f; Label lab1,lab2; List li; public void begin() { f=new Frame("List"); f.setLayout(new GridLayout()); f.setSize(400,400); f.addWindowListener(new WinClose()); lab1=new Label(); lab2=new Label(); lab1.setSize(100,100); lab2.setSize(100,100); f.add(lab1); f.add(lab2); li=new List(10,true); for(int i=0;i<10;i++) li.add(String.valueOf(i)); li.addActionListener(this); li.addItemListener(this); f.add(li); f.setVisible(true); } public void itemStateChanged(ItemEvent e) { String str=""; for(int row=0;row<10;row++) { if(li.isIndexSelected(row)) str=str+li.getItem(row); else continue; } lab2.setText(str); } public void actionPerformed(ActionEvent e) { lab1.setText(e.getActionCommand()); } } public class work6 { public static void main(String args[]) { (new list()).begin(); } 8、编程确定当前鼠标的位置坐标。 import java.awt.*; import java.awt.event.*; class WinClose extends WindowAdapter { public void windowClosing(WindowEvent e) { System.exit(0); } } class mouse implements MouseListener { Frame f; TextField t; public void begin() { f=new Frame("Mouse"); f.setSize(200,200); f.setLayout(new GridLayout()); f.addWindowListener(new WinClose()); t=new TextField(); f.add(t); f.setVisible(true); t.addMouseListener(this); } public void mouseClicked(MouseEvent e) { t.setText(String.valueOf(e.getX())+"," +String.valueOf(e.getY())); } public void mouseEntered(MouseEvent e){} public void mouseExited(MouseEvent e){} public void mousePressed(MouseEvent e){} public void mouseReleased(MouseEvent e){} } public class work7 { public static void main(String args[]) { (new mouse()).begin(); } } 9、编程创建一个 Frame,实现窗口的监听器接口。 import java.awt.*; import java.awt.event.*; class frame implements WindowListener { Frame f; Label lab; public void begin() { f=new Frame("Frame"); lab=new Label(); f.setLayout(new GridLayout()); f.setSize(100,100); f.addWindowListener(this); f.add(lab); f.setVisible(true); } public void windowActivated(WindowEvent e) { lab.setText("Window activated!"); } public void windowClosing(WindowEvent e) { System.exit(0); } public void windowOpened(WindowEvent e){} public void windowDeactivated(WindowEvent e) {lab.setText("Window deactivated!");} public void windowClosed(WindowEvent e){} public void windowIconified(WindowEvent e){} public void windowDeiconified(WindowEvent e){} } public class work8 { public static void main(String args[]) { (new frame()).begin(); } } 10、使用组件,制作一元二次方程求根的系统。要求: (1) 一元二次方程三个系数 a,b,c 输入界面 (2) 显示检查 b*b-4*a*c 的值 (3) 显示求出的根 解: package equation; import java.awt.*; import java.awt.event.*; import java.applet.*; import javax.swing.*; import com.borland.jbcl.layout.*; public class Fangcheng extends Applet { private boolean isStandalone = false; JLabel jLabel1 = new JLabel(); JTextField jTextField1 = new JTextField(); JLabel jLabel3 = new JLabel(); JLabel jLabel2 = new JLabel(); JLabel jLabel4 = new JLabel(); JLabel jLabel5 = new JLabel(); JLabel jLabel6 = new JLabel(); JTextField jTextField2 = new JTextField(); JTextField jTextField3 = new JTextField(); JButton jButton1 = new JButton(); JTextArea jTextArea1 = new JTextArea(); float x1,x2,x3,x4; float a,b,c; float check; //Get a parameter value public String getParameter(String key, String def) { return isStandalone ? System.getProperty(key, def) : (getParameter(key) != null ? getParameter(key) : def); } //Construct the applet public Fangcheng() { } //Initialize the applet public void init() { try { jbInit(); } catch(Exception e) { e.printStackTrace(); } } //Component initialization private void jbInit() throws Exception { jLabel1.setFont(new java.awt.Font("Dialog", 1, 19)); jLabel1.setForeground(Color.red); jLabel1.setText("简易一元二次求解系统"); jLabel1.setBounds(new Rectangle(100, 8, 200, 27)); this.setLayout(null); jLabel3.setText("求解结果:"); jLabel3.setBounds(new Rectangle(230, 45, 80, 20)); jLabel2.setText("方程参数:"); jLabel2.setBounds(new Rectangle(60, 45, 80, 20)); jLabel4.setText("a:"); jLabel4.setBounds(new Rectangle(38, 80, 27, 16)); jLabel5.setText("b:"); jLabel5.setBounds(new Rectangle(38, 130, 26, 20)); jLabel6.setText("c:"); jLabel6.setBounds(new Rectangle(38, 180, 28, 20)); jButton1.setBackground(SystemColor.desktop); jButton1.setBounds(new Rectangle(128, 245, 116, 27)); jButton1.setText("求 解"); jButton1.addActionListener(new Fangcheng_jButton1_actionAdapter(this)); this.setBackground(UIManager.getColor("Button.focus")); jTextArea1.setBackground(SystemColor.desktop); jTextArea1.setForeground(Color.yellow); jTextArea1.setBounds(new Rectangle(185, 90, 175, 100)); jTextField1.setBackground(SystemColor.desktop); jTextField1.setForeground(Color.yellow); jTextField1.setCaretColor(Color.black); jTextField1.setBounds(new Rectangle(70, 75, 60, 30)); jTextField2.setBackground(SystemColor.desktop); jTextField2.setForeground(Color.yellow); jTextField2.setCaretColor(Color.black); jTextField2.setBounds(new Rectangle(70, 125, 60, 30)); jTextField3.setBackground(SystemColor.desktop); jTextField3.setForeground(Color.yellow); jTextField3.setCaretColor(Color.black); jTextField3.setBounds(new Rectangle(70, 175, 60, 30)); this.add(jLabel1, null); this.add(jTextField1, null); this.add(jLabel3, null); this.add(jLabel2, null); this.add(jLabel4, null); this.add(jLabel5, null); this.add(jLabel6, null); this.add(jTextField2, null); this.add(jTextField3, null); this.add(jButton1, null); this.add(jTextArea1, null); } //Get Applet information public String getAppletInfo() { return "Applet Information"; } //Get parameter info public String[][] getParameterInfo() { return null; } boolean Abandon() { int value = JOptionPane.showConfirmDialog(this, "你输入的参数 a=0,这样方程 就不是一元二次方程!请重新输入正确的参数!", "", JOptionPane.YES_OPTION) ; switch (value) { case JOptionPane.YES_OPTION: jTextField1.setText(""); jTextField2.setText(""); jTextField3.setText(""); jTextArea1.setText(""); break; } return true; } public void result() { a = Integer.parseInt(jTextField1.getText()); b = Integer.parseInt(jTextField2.getText()); c = Integer.parseInt(jTextField3.getText()); check=b*b-4*a*c; if (check >= 0) { float d; d = (float) (Math.sqrt(check)); x1 = ( -b + d) / (2 * a); x2 = ( -b - d) / (2 * a); if(check==0) { jTextArea1.setText("b*b-4*a*c=0 \n\n" + "x1="+ x1 +"\n" + "x2=" + x2); } else { jTextArea1.setText("b*b-4*a*c>0 \n\n" + "x1=" + x1 +"\n"+ "x2=" + x2); } } else { //计算复根 float d; d = (float) (Math.sqrt( -check)); x3 = -b / (2 * a); x4 = d / (2 * a); jTextArea1.setText("b*b-4*a*c<0 \n\n"+"x1=" + x3+"+" + x4 + "i"+"\n" + "x2=" + x3 +"-"+ x4 + "i"); } } void jButton1_actionPerformed(ActionEvent e) { if(Integer.parseInt(jTextField1.getText())==0) { Abandon(); return; } result(); } } class Fangcheng_jButton1_actionAdapter implements java.awt.event.ActionListener { Fangcheng adaptee; Fangcheng_jButton1_actionAdapter(Fangcheng adaptee) { this.adaptee = adaptee; } public void actionPerformed(ActionEvent e) { adaptee.jButton1_actionPerformed(e); } } 第十二章 习题及思考题 1. 以在屏幕上显示“您好!”为例,简述 Java 小应用程序 Applet 的开发的步骤。 源程序: import java.awt.*; import java.awt.event.*; import java.applet.*; public class hello extends Applet //继承 Appelet 类,这是 Applet 程序的特点。 { public void paint(Graphics g ) { g.drawString("你好!",60,60);//显示 } } 运行结果: Java 小应用程序 Applet 程序开发主要步骤如下: (1)利用 EDIT 或 Windows Notepad 作为编辑器建立 Java Applet 源程序。Java 源程序文 件的扩展名为 java,例如 JavaWorld.java。 (2)把 Applet 的源程序转换为字节码文件。 (3)编制使用 JavaWorld.class 的 HTML 文件。在 HTML 文件内放入必要的 语句。利用 Jbuild 开发 Applet 是非常方便的,详情见第 12 章例,它可以自动生成 Applet 的 HTML 文件。 2、浏览器采取哪些办法,保证 Applet 安全运行。 答:远程浏览 Applet,服务器必须安装了个人 Web 服务器(windows98 为 PWS,widows NT 为ⅡS)。由于 Applet 从远程服务器上下载而在本地机上运行的特殊性,安全问题显得十分 重要,为此,Applet 在运行时要受到更多的限制,诸如: 1) Applet 永远无法运行本地机上的可执行程序; 2) Applet 除了与所在的服务器联系以外,无法再同任何其他的服务器取得联系; 3) Applet 无法对本地机上的文件系统进行读写操作。(目前 Netscape 是这样的,以后也许 会有其他的浏览器减少这方面的限制,因为 Sun 公司并没有把这一点作为 Java 规范的一部 分。); 4) Applet 无法获得除了本地机使用的 Java 版本号、操作系统名称及版本号、文件名分隔 符(‘/’或‘\’)和路径以外有关本地机的其他信息。Applet 也无法获得使用者的名字 和 E-mail 地址等。 3、 实现一个 Applet, 使其可以用用三个按钮控制: (1)从服务器下载音乐播放 (2)不停地运行一个动画; 使上述动画和音乐协调播放。 package sound; import java.awt.*; import java.awt.event.*; import java.applet.*; import java.net.*; import java.util.*; import java.io.*; public class SoundImage extends Applet implements Runnable { Button button1 = new Button();//初始化 3 个按钮 Button button2 = new Button(); Button button3 = new Button(); Random RandomNumber=new Random( );//初始化随机数 RandomNumber Thread ShapeThread=null; Color ImageColor;//初始化颜色对象 AudioClip audioclip1;//初始化声音对象 public void start( ) { if (ShapeThread==null) { ShapeThread=new Thread(this); ShapeThread.start( ); } } public void run() { while (true) { switch (RandomNumber.nextInt(6)) { //把随机数转换为 0~4 之间的值 case 0: ImageColor = Color.black; break; case 1: ImageColor = Color.blue; break; case 2: ImageColor = Color.cyan; break; case 3: ImageColor = Color.magenta; break; case 4: ImageColor = Color.orange; break; case 5: ImageColor = Color.white; break; case 6: ImageColor = Color.green; break; default: ImageColor = Color.red; } try { ShapeThread.sleep(100); //线程睡眠 repaint(); } catch (InterruptedException e) { //忽略异常 repaint(); } } } public void init() { this.setSize(new Dimension(400, 300));//设置大小 this.setBackground(Color.yellow); //设定背景颜色 button1.setLabel("打开音乐");//设置按钮的名字 button2.setLabel("播放音乐");//设置按钮的名字 button3.setLabel("停止播放");//设置按钮的名字 this.add(button1); //将按钮 button1 加到 Applet 中 this.add(button2); //将按钮 button2 加到 Appelt 中 this.add(button3); //将按钮 button3 加到 Appelt 中 button1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { audioclip1 = getAudioClip(getCodeBase(), "music2.au");// 当 按 钮 button1 触发时加载音乐文件 showStatus("音乐文件已下载,请按“播放音乐”按钮!");//提示 } }); button2.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { audioclip1.loop(); //循环播放音乐 showStatus("声音播放中");//提示 } }); button3.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { audioclip1.stop();//停止播放音乐 showStatus("停止播放");//提示 } }); } public void paint(Graphics g) { g.setColor(ImageColor); switch (RandomNumber.nextInt(3)) { //获取随机数与 2 整除的余数 case 0:g.fillRect(120,60, 150, 200); //添充一个矩形 break; case 1:g.fillOval(140,80, 100, 100); //添充一个矩形 break; case 2:g.fillRect(120,60, 150, 180); //添充一个矩形 break; default:g.fillOval(120,60, 160, 200); //添充一个椭圆 break; } } } 第十三章 习题及思考题 1.如何建立数据库的连接? 答:通过 JDBC 访问数据库,首先是与数据库建立连接,用户得到一个 java.sql.Connection 类的对象。对这个数据库的所有操作都是基于这个对象。为了与数据库建立连接,JDBC 必 须加载驱动程序。驱动程序可以是 JDBC-ODBC 桥驱动程序,或由数据库厂商提供的驱动程 序 , 或 通 过 设 置 Java 属 性 中 的 sql.driver 来 指 定 驱 动 程 序 。 DriverManager 类 的 getConnection 方法用于建立与某个数据源的连接。若与由 URL 指定的数据源建立连接成功, 则 返 回 一 个 Connection 类 的 对 象 。 以 后 对 于 这 个 数 据 源 的 操 作 都 是 基 于 这 个 对 象 。 getConnection 方法是 DriverManager 类中的静态方法。所以使用时不构造 DriverManager 类的对象,直接使用类名 DriverManager 调用就可以了。 2、有哪写方法可以发送访问、操作数据库的 SQL 语句? 答 : JDBC 中 查 询 语 句 执 行 方 法 可 分 为 三 类 : Statement , PreparedStatement 和 CallableStatement 对象。在 Statement 对象上,可以使用 execQuery 方法来执行一查询语 句。execQuery 的参数是一个 String 对象,即一个 SELECT 语句。他的返回值是一个 ResultSet 类的对象。PreparedStatement 对象也使用 execQuery 方法来执行语句。CallableStatement 类使用父类 PreparedStatement 类的 execQuery 方法或 execute 方法来执行存储过程的。 3.如何处理对数据库访问操作的结果? 答:ResultSet 对象包括一个由查询语句返回的一个表,这个表中包含所有的查询结果。对 ResultSet 对象的处理必须逐行进行,而对每一行中的各个列,可以按任何顺序处理。 ResultSet 对象维持一个指向当前记录的指针。第一次使用 next 方法将指针指向结果集的 第一个记录,这时可以对第一个记录数据项进行处理。处理完毕后,使用 next 方法,使这 个指针指向下一记录,继续处理该记录的数据。next 方法返回的是一个 boolean 值,若为 true,则说明指针成功地移向下一记录,可以对该记录的数据进行处理,相反若为 false, 则说明没有下一记录,即结果集处理完毕。 4、如何获得关于数据库的信息? 答:在对数据库进行连接以后,得到一个 Connection 类的对象,可以从这个对象获得有关 数据源的各种信息,包括关于数据库中的各种表,表中的各个列,数据类型和存储过程等各 方面的信息.根据这些信息,JDBC 程序可以访问一个事先并不了解的数据库。获取这些信息 的方法都是在 DatabaseMetaData 类的对象上实现的。下面的语句可以在一个联接的基础上 创建一个对象:DatabaseMetaData dbma=con.getMetaData();DatabaseMetaData 类中提 供了许多方法用于获得数据源的各个方面的连系,通过这些可以非常方便地了解数据库结 构。 第十四章 习题及思考题 1. 组建模型提供哪些服务? 2.简单回答 JavaBean 的 5 个特性? 3.JavaBean 属性类型? 4.编写一个表示银行账户的 JavaBean,名称叫 AccountBean,分别设计一个绑 定属性和限制属性;取款时,如果账户余额不足,不能取款;存款时,自动 通知用户现在新的存款余额。 解答: (略) 第十五章 习题及思考题 1.套接口作用是什么?端口有什么意义? 答:套接口(Socket),是传送层提供的网络进程通信接口。通讯的主动方是顾客,它 利用 Socket,向服务器(接收方)发送请求,服务器接收顾客请求,返回服务结果。进程 之间想通信首先要建立各自的套接口。端口同一台网络计算机的一个特定进程关联,与进程 建立的套接口绑定在一起。客户程序必须事先知道自己要求的那个服务进程的壹 IP 地址和 端口号。程序员在创建自己的应用服务程序时一般自己指定一个端口号,也可以由系统分配 一个端口号。客户通过这个端口号连接该服务进程。客户端应用进程象服务进程一样,也有 自己的端口号,通过该端口客户端应用进程与服务进程通信。 2.什么是 URL?一个 URL 由哪此部分组成? 答:URL(Uniform Resource Locator)是 WWW 资源统一资源定位器的简写。它规范了 WWW 资源网络定位地址的表示方法。一个 URL 的组成部分有:WWW 资源的特征及读其内容的方法。 URL 的基本表示格式是:protocol://hostname:/resourcename#anchor;其中:protocol(使 用的协议):它可以是 http、ftp、news、telnet 等;hostname(主机名):指定域名服务器 (DNS)能访问到的 WWW 服务的计算机;port(端口号):是可选的,表示所连的端口号,如 缺省,将连接到协议缺省的端口;Resourcename(资源名):是主机上能访问到的目录或文 件;anchor(标记):也是可选的,它指定文件中的有特定标记的位置。 3.编程读出中国矿业大学主页的 html 文件,判断主页的 html 文件有无关于“教学改 革”的内容。上面的程序中用到了哪些有关 URL 操作的方法?各起什么作用?中国矿业大学 URL 为:http://www.cumt.edu.cn. 答:源程序: import java.net.*; import java.io.*; public class ReadURLConnection{ static public void main(String args[]) { try { //根据绝对 URL 地址构造 URL 对象 URL cumtURL=new URL("http://www.cumt.edu.cn");//蓝色标示的是 URL //利用 cumtURL 建立一个 URLConnection 对象 URLConnection cumtConnection=cumtURL.openConnection(); //获取 cumtConnection 对象的数据输入流 DataInputStream din=new DataInputStream(cumtConnection .getInputStream()); String inputLine; //从输入流 din 读入一行数据 while((inputLine=din.readLine())!=null) { //将数据信息显示到系统标准输出上 System.out.println(inputLine); } //关闭输入流 din.close(); } catch(MalformedURLException me){} catch(IOException ioe){} } } 生成的结果文件比较长,有兴趣请下载查看,查看中国矿业大学主页的 html 文件后, 没有看到“教学改革”的内容,有的超链接现在用的是图片,所以有些目录的名不能直接看 到。 本程序中用到的方法有: (1)URL cumtURL=new URL("http:// "); 作用:根据绝对 URL 地址构造 URL 对象 (2)URLConnection cumtConnection=cumtURL.openConnection(); 作用:利用 cumtURL 建立一个 URLConnection 对象 ( 3 ) DataInputStream DataInputStream(cumtConnection .getInputStream()); 作用:获取 cumtConnection 对象的数据输入流 din=new 4、顾客和服务者通过套接口通讯,描述基于有连接和无连接通讯时的流程图。 答:TCP(Transport Control Protocol)传输控制协议是面向连接的、可靠的点对点 的连接的协议。 TCP 是一种可靠的、基于连接的网络传输协议,当两个网络进程准备进行通信时,都必 须首先建立各自的一个套接口,其中服务器建立套接口后,侦听来自网络的客户连接请求, 客户通过套接口,指定服务器的 IP 地址和端口号,便可与服务器通信。 服务程序运行在服务器主机的某个端口上,一旦启动服务,它将在这个端口上倾听,等 待客户程序发来的请求。服务器的套接口用服务器套接口类(ServerSocket)来建立。方法 accept() 使服务者等待,直到有客户连接到该端口。一旦有客户送来正确请求,连接至该 端口, accept()方法就返回一个新的套接口对象 soc,表示已建立好连接。服务者使用它 们从客户接受输入信息和向客户程序发送信息所用,同样,在客户端也应该建立这两个对象, 用来与服务程序进行双向通信。服务者向输出流发送的所有信息都成为客户的输入信息,而 客户程序的输出都送入服务者的输入流。 UDP(User Datagram Protocol)用户数据报协议是无连接的传输不可靠的协议。 UDP 协议把要发送的数据及对方的 IP 地址、对方端口号构成报文,不与对方连接就把 报文一个个独立地地发送出去。UDP 协议本身不能保证数据报一定到达目的地,不能保证数 据报到达目的地顺序。但是,这种服务的可靠性可以有应用层来实现。 服务器利用 UDP 协议实现客户和服务器之间通信,首先建立数据报套接口对象,自己指 定一个端口号,也可以由系统自动确定端口号。利用无参的构造方法 DatagramSocket() 系统自动确定端口号,这时必须利用 getLocalPort())方法获取该数据报端口号。这个端口 号及服务器的 IP 地址对客户方发送报文来说是必须知道的。否则,客户方无法发送报文。 客户方利用 UDP 协议实现客户和服务器之间通信,首先也要建立数据报套接口对 象,一般使用无参的构造方法 DatagramSocket(),这时,系统自动确定一个端口号,然后 利用发送报文缓冲区、服务器的 IP 地址及服务器的端口号建立发送数据包 DatagramPacket 对象。利用建立的数据报套接口发送该 DatagramPacket 对象。 5、利用 Java 网络包 java.io 中套接口类 Socket 和服务者套接口类(ServerSocket) 分别实现有连接和无连接的通讯。 答:TCP 协议实现有连接的通讯 服务器端程序: import java.io.*; import java.net.*; public class Tcpserver { static public void main(String args[]) throws IOException { ServerSocket svrsoc=null; Socket soc=null; DataInputStream in=null; PrintStream out=null; InetAddress clientIP=null; String str=null; try { svrsoc=new ServerSocket(8000); // 构造 rverSockets 对象,端口为 8000 soc=svrsoc.accept(); //服务者等待一个连接,返回新套接口 soc in=new DataInputStream(soc.getInputStream());//在 新 套 接 口 soc 上 构 造 //DataInputStream 对象 in out=new PrintStream(soc.getOutputStream());// 在 新 套 接 口 soc 上 构 造 // //PrintStream 对象 out clientIP=soc.getInetAddress(); //得到顾客方 IP 地址 System.out.println("客户端的 IP 地址为:"+clientIP); out.println("欢迎你访问服务器!"); str=in.readLine(); //在 in 上读一行 while(!str.equals("quit")) //如读出的不是“quit”,继续读 { System.out.println("客户端:"+str); str=in.readLine(); } System.out.println("客户端想要下线."); } catch(Exception e) { System.out.println("Error:"+e); } } } 客户端程序: import java.net.*; import java.io.*; public class tcpclient { static public void main(String args[]) throws IOException { Socket soc=null; BufferedReader in=null; PrintWriter out=null; String strin=null; String strout=null; try { soc=new Socket("localhost",8000); System.out.println("已成功连接到服务器"); in=new BufferedReader( new InputStreamReader( soc.getInputStream())); out=new PrintWriter( new BufferedWriter( new OutputStreamWriter( soc.getOutputStream())),true); strin=in.readLine(); System.out.println("服务器:"+strin); byte bmsg[] = new byte[100]; System.in.read(bmsg); String msg=new String(bmsg,0); msg=msg.trim(); while(!msg.equals("quit")) { out.println(msg); System.in.read(bmsg); msg=new String(bmsg,0); msg=msg.trim(); out.println(msg); } out.println(strout); } catch (Exception e) { System.out.println("Error: "+e); } finally { in.close(); out.close(); soc.close(); System.exit(0); } } } 运行结果: 服务器进程窗口中显示: 客户端的 IP 地址为:/127.0.0.1 客户端:Hello!We love Java! 客户端想要下线. 客户端进程窗口中: 已成功连接到服务器 服务器:欢迎你访问服务器! Hello!We love Java! Quit UDP 协议实现无连接通讯 服务器端程序: import java.net.*; import java.io.*; public class UDPServer { public static void main(String[] args) { byte[] buf = new byte[1024]; //报文缓冲区 try { //构造 DatagramSocket 类对象,端口号 6789 DatagramSocket serversocket = new DatagramSocket(6789); //建立数据报套 接口 System.out.println("服务器在等待中......"); while (true) { //构造 DatagramPacket 类对象,用来从数据报套接字接收数据 报 DatagramPacket serverpacket = new DatagramPacket(buf, 1024);//等待接 收数据报 serversocket.receive(serverpacket);//字节数组转换成字符串 String data = new String(buf, 0, serverpacket.getLength()); if (data.equals("")) continue; if (data.equals("quit")) break; System.out.println("客户端:" + data);//接收的字符串转换成大写 String strToSend = data.toUpperCase(); InetAddress clientIP = serverpacket.getAddress(); //获得客户地址 int clientPort = serverpacket.getPort(); //获得客户端口 byte[] msg = strToSend.getBytes(); // DatagramPacket clientpacket = new DatagramPacket(msg, strToSend.length(), clientIP, clientPort);//将数据打包发送给客户 serversocket.send(clientpacket); } serversocket.close(); System.out.println("服务器已关闭!"); } catch (Exception e) { e.printStackTrace(); } } } 客户端程序: import java.net.*; import java.io.*; public class UDPClient { public static void main(String[] args) { try{ String strToSend; byte[] bufsend; //发送报文缓冲区 byte[] bufrec; //接收报文缓冲区 DatagramPacket clientPacket; //构造 DatagramSocket 类对象 clientSocket DatagramSocket clientSocket=new DatagramSocket(); // 构 造 DataInputStream 类对象//sysin ,与 System.in 绑定 DataInputStream sysin=new DataInputStream(System.in ); while(true) { System.out.print("等待输入:");//从 sysin 输入一行 strToSend=sysin.readLine();//把字符串转换为字节数组 bufsend=strToSend.getBytes();// 构 造 DatagramPacket 类 对 象 clientpacket ,服务器端口号约定为 6789 DatagramPacketclientpacket=new DatagramPacket(bufsend,strToSend.length() ,InetAddress.getLocalHost(),6789); //输入一行后打包发送给服务器 clientSocket.send(clientpacket) ; //如输入字符串是 quit,停止发送 if(strToSend.equals("quit")) break; bufrec=new byte[1024]; DatagramPacket receivePacket=new DatagramPacket(bufrec,1024);//接收 数据报 clientSocket.receive(receivePacket); String received=new String(receivePacket.getData(),0); System.out.println("服务器:"+ received );//以上构造数据报接收服务器 端发来的数据 } clientSocket.close (); }catch(Exception e)//异常处 { e.printStackTrace(); } } } 运行结果: 服务器端进程窗口中显示: 服务器在等待中...... 客户端:hello! I miss you! 服务器已关闭! 客户端进程窗口中显示: 等待输入:hello! I miss you! 服务器:HELLO! I MISS YOU! 等待输入:quit 第十六章 习题及思考题 1) (简答题) 简单回答对计算机系统的攻击方法? 2) 什么是对称密码技术和非对称密码技术? 3) 简述数字签名的基本原理? 4) 简述 Java2 的安全模型? 5) 简述 Application 和 Applet 安全性的区别? 6) 简述 SecurityManager 和 AccessController 的作用? 7) 简单回答 Keytool 的作用? 8) (设计题)编写一个计算器小程序,对其进行数字签名和部署,能够在浏览 器中执行。 9) 给定一个文件,编写一个程序,对其使用 AES 算法进行加密,并解密。 10) 给定一个文件,编写一个程序,用 RSA 算法对其进行加密,并解密。 解答: (略) 第十七章 web 服务器编程 一、 选择 1、关于 Servlet 的论述,正确的有 A Servlet 就是一般的 Java 程序,没有什么特点 B Servlet 可以通过 java servlet-name 直接运行 C 有些 Servlet 是需要在客户端运行的 D 我们常说的 Servlet 是继承 HttpServlet 类的服务器端 Java 程序 2、HTTP 协议在进行网络传输时使用的编码方式是 A GB2312 B UNICODE C ISO-8859-1 D GBK 3、一个 session 的生命周期的作用范围为 A Web 服务器一个发布目录下的文件 B 整个 Web 服务器的所有发布目录 C 发布目录下某一个目录下的所有文件 D 只对应第一次访问的那个文件 4、关于 JSP 的论述,正确的有 A JSP 是 JavaScript 的简称 B JSP 可以直接编译成 class 文件 C JSP 是被解释成 HttpServlet 后再编译的 D JSP 是被解释成 HttpJspPage 后再编译的 解答:选择第 1 题 D 选择第 2 题 C 选择第 3 题 A 选择第 4 题 D 二、多项选择 1、对所有 HTTP 请求都适用的方法是 A getParameterValues B getParameter C getQueryString D getForm 2、静态页面和动态页面的区在于 A 动态页面能够有动画,静态没有 B 动态页面能够根据不同用户产生不同的响应,静态的不行 C 动态页面是经常在改变的,静态的常年不变 D 动态页面能够接收用户输入,并在服务器端作处理,静态的不行 3、能够实现 Session 功能的方法有 A Cookies B 隐藏的表单域 C Servlet 提供的 session 类 D 使用 Web Server 的 application 对象 4、关于 session 的论述正确的有 A 一个 session 可以对应数个用户 B 一个 session 只能对应一个用户 C 可以手动关闭一个 session D session 如果不手动关闭,会一直存在 Server 中 解答: 多项选择第 1 题 AB 多项选择第 2 题 BD 多项选择第 3 题 ABC 多项选择第 4 题 BC