作者:100jq |
上节课留下了一个概念,自定义异常类。为什么要自己编写异常类,上节课做了简要的说明。如果jdk里面没有提供的异常,我们就要自己写。我们常用的类ArithmeticException,NullPointerException,NegativeArraySizeException,ArrayIndexoutofBoundsException,SecurityException这些类,都是继承着RuntimeException这个父类,而这个父类还有一个父类是Exception。那么我们自己写异常类的时候,也是继承Exception这个类的。实践:
class MyException extends Exception { //继承了Exception这个父类
private int detail;
MyException(int a) {
detail = a;}
public String toString() {
return "MyException[" + detail + "]";
}}
class ExceptionDemo {
static void compute(int a) throws MyException {
System.out.println("调用 compute(" + a + ")");
if(a > 10)
throw new MyException(a);
System.out.println("常规退出 ");
}
public static void main(String args[]) {
try {
compute(1);
compute(20);
} catch (MyException e) {
System.out.println("捕捉 " + e); //这样就可以用自己定义的类来捕捉异常了
}}}
像是上节课我们说了,如果你开发程序用到好多组件,或其它厂商的东西。那么出现的异常会是莫明其妙的,这样的话会给调试带来很大的不便。往往在开发的过程中会写很多自定义的异常类。
总结:
异常处理机制是保证java程序正常运行、具有较高安全性的重要手段。对于开发良好的编程习惯是非常重要的。
作者:100jq |
输入/输出(I/O)是每一项计算机语言,必须有的东西。不让人输入数据的话,计算机怎么处理数据呢?在java语言中,I/O的方式是流的方式。流(stream)这是个学习java输入输出的最基本的概念。流是字节从源到目的的有序序列。一方面是字节,一方面是有序的。流描述的是一个过程,顺序严格。一个需要键盘输入的程序可以用流来做到这一点。两种基本的流是:输入流和输出流。你可以从输入流读,但你不能对它写。要从输入流读取字节,必须有一个与这个流相关联的字符源。这些东西都放在java.io.*这个包里了。io是java的第一大包。在java.io 包中,有一些流是结点流,即它们可以从一个特定的地方读写,例如磁盘或者一块内存。其他流称作过滤流。一个过滤器输入流是用一个到已存在的输入流的连接创建的。此后,当你试图从过滤输入流对象读时,它向你提供来自另一个输入流对象的字符。
常见的几种流:
u 字节流:传字节的。以8位字节为单位进行读写,以InputStream与OutputStream为基础类
u 字符流: 传字符的。以16位字符为单位进行读写,以Reader与Writer为基础类
u 文件流: 传文件的。属于节点流,对文件读写,传输。里面的类很多。
u 序列化:传对象的。一个对象怎么读啊,只有变成二进制才可以读,这就是序列化。
实践: //这是一个字节流的例子,以InputStream与OutputStream为基础类
import java.io.*;
class ByteArrayOutputStreamDemo {
public static void main(String args[]) throws IOException {
ByteArrayOutputStream f = new ByteArrayOutputStream();
String s = "This should end up in the array";
byte buf[] = s.getBytes();
f.write(buf);
System.out.println("Buffer as a string");
System.out.println(f.toString());
System.out.println("Into array");
byte b[] = f.toByteArray();
for (int i=0; i<b.length; i++) {
System.out.print((char) b[i]);}
System.out.println("/nTo an OutputStream()");
//输出到文件test.txt中
OutputStream f2 = new FileOutputStream("test.txt");
f.writeTo(f2);
f2.close();
System.out.println("Doing a reset");
f.reset();
for (int i=0; i<3; i++)
f.write('X');
System.out.println(f.toString());}}
//字符流的例子,以Reader与Writer为基础类
import java.io.*;
public class CharArrayReaderDemo {
public static void main(String args[]) throws IOException {
String tmp = "abcdefghijklmnopqrstuvwxyz";
int length = tmp.length();
char c[] = new char[length];
tmp.getChars(0, length, c, 0);
CharArrayReader input1 = new CharArrayReader(c);
CharArrayReader input2 = new CharArrayReader(c, 0, 5);
int i;
System.out.println("input1 is:");
while((i = input1.read()) != -1) {
System.out.print((char)i);}
System.out.println();
System.out.println("input2 is:");
while((i = input2.read()) != -1) {
System.out.print((char)i);}
System.out.println();
}}
//文件流的例子
import java.io.*;
class FileInputStreamDemo {
public static void main(String args[]) throws Exception {
int size;
InputStream f =
new FileInputStream("FileInputStreamDemo.java");
System.out.println("Total Available Bytes: " +
(size = f.available()));
int n = size/40;
System.out.println("First " + n +
" bytes of the file one read() at a time");
for (int i=0; i < n; i++) {
System.out.print((char) f.read());
}
System.out.println("/nStill Available: " + f.available());
System.out.println("Reading the next " + n +
" with one read(b[])");
byte b[] = new byte[n];
if (f.read(b) != n) {
System.err.println("couldn't read " + n + " bytes.");
}
System.out.println(new String(b, 0, n));
System.out.println("/nStill Available: " + (size = f.available()));
System.out.println("Skipping half of remaining bytes with skip()");
f.skip(size/2);
System.out.println("Still Available: " + f.available());
System.out.println(" Reading " + n/2 + " into the end of array");
if (f.read(b, n/2, n/2) != n/2) {
System.err.println("couldn't read " + n/2 + " bytes.");
}
System.out.println(new String(b, 0, b.length));
System.out.println("/nStill Available: " + f.available());
f.close();
}
代码很多如有不明白的地方请访问技术论坛, 还有序列化的例子没有举出,序列化在java中是个很重要的概念哦。我们下节课。具体举例讲解。
作者:100jq |
上节课我们讲了4种流,只有序列化的这个没有细讲。它是传对象的,如果想把一个对象保存在硬盘上,就只能使用这种方式。它的关键是将它的状态以一种串行格式表示出来,以便以后读该对象时能够把它读出来。对象的串行化对于大多数java应用是非常重要的:
u java的远程方法调用(RMI),通过socket通信。这个东西我们会在后面的教程讲到。
u 对象永久化,就是把对象存硬盘上,或外存设备上。以便以后使用。
它的基础类是ObjectInputStream和ObjectOutputStream,这两个流称为对象流。
实践: //这是一个保存对象的例子
import java.io.*;
import java.util.Date;
public class SerializeDate {
SerializeDate() {
Date d = new Date ();
try {
FileOutputStream f =
new FileOutputStream ("date.ser"); //输出到date.ser这个文件中
ObjectOutputStream s =
new ObjectOutputStream (f);
s.writeObject (d); //写对象,将对象d写成是date.ser文件
s.close (); //关闭流
} catch (IOException e) {
e.printStackTrace ();
} }
public static void main (String args[]) {
new SerializeDate();
}}
如图所示23-1,执行之后
图23-1
在DOS窗口中没有看到结果,但是在这个文件夹内发现了一个date.ser的文件。它就是对象d写入磁盘的状态。如图23-2
图23-2
那么保存了之后怎么在把这个date.ser文件读出来呢?
实践:
import java.io.*;
import java.util.Date;
public class UnSerializeDate {
UnSerializeDate () {
Date d = null;
try { //使用FileInputStream类
FileInputStream f =
new FileInputStream ("date.ser");
ObjectInputStream s =
new ObjectInputStream (f);
d = (Date) s.readObject ();//读对象
s.close ();
} catch (Exception e) {
e.printStackTrace (); }
System.out.println(
"从date.ser文件,读取Date对象 ");
System.out.println("日期是: "+d);
}
public static void main (String args[]) {
new UnSerializeDate();
}}如图23-3所示读出时间
图23-3
对于一个可以被序列化的类,它会实现一个Serializable的接口。那是个空接口,什么方法也没有只是一个标志而已。这在J2EE,(现在叫java EE)中,使用EJB时是非常重要的。如果大家以后能继续学习学到EJB的时候,再具体了解。
作者:100jq |
还是那样的,java的概念就是多,有时候多的还没等你反应过来又给你出来一个新的概念。反射是个很重要的概念,这是一种机制,不只是java里面有,很多语言里面都有。这个概念是一个叫Smith的大师,由1982年提出来的。指的是一类应用,它们能够自描述和自控制。这样说太抽象了。我们看个例子,实践:
import java.lang.reflect.*;
public class Refl {
public static void main(String args[]) {
try {
//Class.forName() 这是反射的一种方式。将类在运行时自动加载进来
Class c = Class.forName(“java.lang.String”);
// getDeclaredMethods()获取这个类中定义了的方法列表
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
} catch (Throwable e) {
System.err.println(e);
}}}
执行的时候发现输出了,String 类的所有方法打印了出来。重要的是,Class.forName这句话它是反射的一种方式。就是在运行时改变Refl类的状态,通过”java.lang.String”改变。
java语言提供了一套反射类,java.lang.reflect.*;这些类可以用做:
l 构造新类实例和新数组
l 访问并修改对象(Object)和类的字段(Field)
l 调用对象和类中的方法(Method)
l 访问并修改数组的元素
反射是一种强大的工具,但也存在一些不足。一个主要的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。一边执行的时候,一边加载其它类,肯定会慢的。但是它有很强的扩展性,具有开放性的系统很多都采用这种机制,因为在安全允许的情况下它可以随意加载类,和调用方法。在windows编程里面的dll与它几乎是一个意思。
作者:100jq |
java语言中有一个重要的特性是支持多线程。多线程是java的一项高级技术,它涉及到操作系统里面的知识,层次贴近系统层面。对于普通程序员一般很少碰它。而且目前就是在java EE(原来的J2EE)的相关框架里,对线程这个东西都是尽量回避。程序员最理想的状态是专注业务逻辑,而不是天天想着线程这个东西怎么写。
思考一个问题程序的本质是什么?是CPU的指令序列的集合。到底什么顺序是程序员编写的让计算机赋值,它就赋值、写个循环它就循环、写个分支语句它就分支、写个跳转它就跳转。每个指令流就是一个线程,并发执行多个指令流就是多线程。大家想,只有一个CPU怎么可能同时发出多个指令流呢?是的,并发只是“逻辑”上的,物理上是不可能的除非是两个以上的CPU。
多线程和传统的单线程的区别是由于各个线程的控制流彼此独立,使得各个线程之间的代码是乱序执行的,出现了并发访问带来的一切问题。正像是三个和尚的故事,和尚多了未必是好事。也就是刚才说的,程序员一般都不让他们碰这个东西。
在java中如何写线程呢,在java中就是很简单了。有两种方法:第一、继承java.lang.Thread第二、实现Runnable接口。
实践:
//继承Thread而重写了run()方法
public class Hello extends Thread{
int i;
public void run(){
while(true){
System.out.println("Hello "+i++);
if(i==10) break;
}}}
public class HelloThread {
public static void main(String[] args){
Hello h1 = new Hello();
Hello h2 = new Hello();
h1.start(); //用两个线程执行那10次循环
h2.start();
}} 上面的例子是第一种方法,下面是第二种方法
public class TestThread {
public static void main(String args[]) {
Xyz r = new Xyz();
Xyz r1 = new Xyz();
Thread t1 = new Thread(r);
Thread t2 = new Thread(r1);
t1.start();//用两个线程执行那50次循环
t2.start();
}} //实现Runnable接口
class Xyz implements Runnable {
int i;
public void run() {
i = 0;
while (true) {
System.out.println("Hello " + i++);
if ( i == 50 ) {
break;
}}}}多个源码打包下载
上面两种方法继承Thread类,是比较简单的,代码也比较少。但是我们不提倡使用这种方法。而第二种实现Runnable接口,更符合面向对象思想,Thread是把虚拟的CPU看成一个对象,封装了CPU的细节。但是Thread的构造线程的子类的方法中与CPU不相关,没有必要把CPU的细节都继承来。而实现Runnable则不影响java.lang.Thread的体系。而且便于其它类的继承。
线程并发的代码和数据的执行顺序混乱,我们也需要自己调度和控制它们。请看附加教程,线程调度和并发。
作者:100jq |
java在网络编程这个地方做的很好,java的主要目的也是为了网络而生的,它能方便的访问网络上的资源。我们这节课来介绍网络通讯的两种机制:URL通信机制,Socket通信机制。
URL表示了Internet上一个资源的引用或地址。java网络应用程序也是使用URL来定位要访问的Internet的资源。在jdk里面java.net.URL也是一个类,它来封装URL的一些细节。目前大家可以把URL理解为网址,default.aspx 这就是个URL。http是协议名(超文本传输协议)用“://”隔开www.100jq.com 是主机名。Default.aspx是文件名。它的端口号没有写,默认是80。
实践:
import java.net.*;
public class ParseURL {
public static void main(String[] args) throws MalformedURLException{
URL url = new URL("http://www.100jq.com:45175/default.aspx");
System.out.println("协议是 "+url.getProtocol());
System.out.println("主机是 "+url.getHost());
System.out.println("文件名是 "+url.getFile());
System.out.println("端口号是 "+url.getPort());
}}
/*
URL这个对象中提供了很多方法像是
getProtocol()
getHost()
getFile()
getPort()
*/
我们可以通过URL对文件或资源读取,也可以通过URLConnection读取,也可以通过这个写入数据限于cgi脚本。
实践:
import java.net.*;
import java.io.*;
public class URLConnectionReader {
public static void main(String[] args) throws IOException {
URL google = new URL("");
URLConnection g = google.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(g.getInputStream()));
String inputLine;
while ((inputLine=in.readLine())!=null)
System.out.println(inputLine);
in.close();
}}
URL和URLConnection类提供了较高层次的网络访问。有时候需要进行较低层次的访问。编写C/S模型的程序时,就要使用Socket通信机制了。因为在网络上不一定非得访问文件。
实践://先写个客户端的应用
import java.net.*;
import java.io.*;
public class SimpleClient {
public static void main(String args[]) {
try {
// 在5432端口打开服务器连接
// 在这里用localhost与127.0.0.1是一个意思
Socket s1 = new Socket("127.0.0.1", 5432);
// 对这个端口连接一个reader,注意端口不能够占用别的
BufferedReader br = new BufferedReader(
new InputStreamReader(s1.getInputStream()));
// 读取输入的数据并且打印在屏幕上
System.out.println(br.readLine());
//当完成时关闭流和连接
br.close();
s1.close();
} catch (ConnectException connExc) {
System.err.println("Could not connect to the server.");
} catch (IOException e) {
// ignore
}}}
//这是服务端的应用
import java.net.*;
import java.io.*;
public class SimpleServer {
public static void main(String args[]) {
ServerSocket s = null;
// 注册服务端口为5432
try {
s = new ServerSocket(5432);
} catch (IOException e) {
e.printStackTrace();
}
// 运行监听器并接收,永远循环下去。因为服务器总要开启的
while (true) {
try {
// 等待一个连接的请求
Socket s1 = s.accept();
// 得到端口的输出流
OutputStream s1out = s1.getOutputStream();
Bufferedwriter bw = new Bufferedwriter(
new OutputStreamWriter(s1out));
// 发送一个字符串
bw.write("百家拳软件项目研究室欢迎您!/n");
// 关闭这个连接, 但不是服务端的socket
bw.close();
s1.close();
} catch (IOException e) {
e.printStackTrace();
}}}}上述例子打包下载
执行这个程序和其它的不太一样,先用javac将两个文件编译之后。然后敲start开启另一个窗口。用start命令开启的窗口继承了原来窗口的特性。如图26-1所示
图26-1
接着在原来的窗口上执行服务端程序java SimpleServer.在新窗口中执行java SimpleClient 就会看到结果了。注意如果如果在启动服务端的时候抛出bindException则说明5432这个端口已经被别的程序占用着,改成别的端口号就可以了。通常选用端口的时候,其数字最好不要小于1024,1024一下的端口很多都是专用的端口。
作者:100jq |
现在的java界,很多东西叫××let,××let的意思都是些小程序的意思。例如:applet应用程序的小程序,servlet服务器端的小程序,midlet手机中的小程序,portlet门户容器端的小程序。这节我们介绍applet。这个东西用的不是很多,但是在java的体系结构中是很有意义的。这个东西是能够在浏览器里运行的,可以潜入到HTML页面里。我们知道普通的Application要有main()作为入口点运行,而Applet要在浏览器里运行,或者开发时查看的时候用appletviewer运行。举个例子,实践:
import java.awt.*;
import java.applet.*;
@SuppressWarnings("serial") //抑制警告
//所有的Applet,都继承了java.applet.Applet
public class HelloApplet extends Applet {
public void paint(Graphics g){
g.drawString("百家拳软件项目研究室!",30,30);
}}
还需要建立一个html文件,因为刚才说了它可以嵌入在浏览器里面。用记事本建立一个hello.html代码如下:
<applet code="HelloApplet.class" width=150 height=150></applet>
之后照样用javac编译刚才那个类。最后在命令行中输入appletviewer hello.html可以看到结果。
这种小程序弥补了B/S模型的不足,用浏览器可以执行客户端的东西。因为它功能强大,所以是个不错的东西。可是功能太强大了,又引发了一些安全性的问题。所以浏览器也会对applet做了一些安全性的限制。Applet还有一种叫做沙箱模型的机制,它使得没有访问权限的资源,不能访问。保证了安全性。同时开发时也不是那么方便。Applet又跨平台的特性。
而且微软的IE浏览器里面在运行applet的时候速度不是很快,不如activex的方便。界面也不是太漂亮。不过它的这种在浏览器中运行的思想还是比较不错的。
再看个有意思的例子吧:如图27-1所示
图27-1
《全新java初学者实践教程(java SE5.0版)》主体课程至此结束。请大家关注附加教程。
作者:100jq |
这是附加教程的第一节,我们来介绍一下 ==和equals()的区别,==是相等,equals()也是相等。这两个词的区别是什么呢?这是找工作时很多面试官的问题。我们来解答一下。首先我们看这么个例子。实践:
public class TestEquals {
public static void main(String[] args) {
MyDate date1 = new MyDate(14, 3, 1976);
MyDate date2 = new MyDate(14, 3, 1976);
if ( date1 = = date2 ) {
System.out.println("date1 is identical to date2");
} else {
System.out.println("date1 is not identical to date2");
}
if ( date1.equals(date2) ) {
System.out.println("date1 is equal to date2");
} else {
System.out.println("date1 is not equal to date2");
}
System.out.println("设 date2 = date1;");
date2 = date1;
if ( date1 == date2 ) {
System.out.println("date1 is identical to date2");
} else {
System.out.println("date1 is not identical to date2");
}}}
这个例子中的MyDate类代码如下
public class MyDate {
private int day;
private int month;
private int year;
public MyDate(int day, int month, int year) {
this.day = day;
this.month = month;
this.year = year;
}
public boolean equals(Object o) {
boolean result = false;
if ( (o != null) && (o instanceof MyDate) ) {
MyDate d = (MyDate) o;
if ( (day == d.day) && (month == d.month)
&& (year == d.year) ) {
result = true;
}}
return result;
}
public int hashCode() {
return (day ^ month ^ year);
}} 上述例子下载
将这两个类放置到同一个文件夹中,只需要编译TestEquals类,就可以将MyDate一同编译了。然后执行java TestEquals查看结果。如图28-1所示
图28-1
也就是说date1 = = date2 虽然都是new MyDate(14, 3, 1976);但是new了两次就是两个对象了,不能==了。==是指引用是否相同。
那么用equals()呢,equals()是Object里的方法,任何对象都继承Object。所以equals()方法也适用于所有的类。为什么这回date1和date2就equals了呢?equals()是指值是否相等。因为都是(14,3,1976)所以相等。
我们把date1赋值给date2,结果当然是==了,都已经把引用赋给它了。还能不==吗?
作者:100jq |
这也是个比较重要的东西,因为String字符串的应用范围很广。但是有些时候使用StringBuffer更好一些。有些时候还不能用String。到了jdk5的时候,又补充了个东西StringBuilder。我们来看看他们的区别。
String 的长度是不可变的,StringBuffer的长度是可变的。如果对字符串中的长度经常进行操作,特别是内容要修改时,使用StringBuffer,如果最后需要String,那么使用StringBuffer的toString()方法。
当我们进行字符拼接时,请使用StringBuffer或StringBuilder类而非String类,因为前者将比后者性能高的多,在java语言的优化编程里面,这是一条比较重要的。
在使用String 的时候,拼接字符串时使用“+”这个东西在JVM上形成临时的StringBuffer对象,同时在每一个字符串上都建立一个对象,拼接了两个字符串居然创建了4个对象。(一个String,两个字符串,一个临时的StringBuffer)。
如果使用StringBuffer就好多了,它可以只需创建两个对象就可以了,一个StringBuffer和最后的String 。
StringBuilder是在jdk5中添加的一个类,它与StringBuffer功能一样。但是它不是线程安全的,就是说它不支持多线程。如果在不需要多线程的时候,使用StringBuilder比StringBuffer还要块的多。不支持线程同步当然要快了。
作者:100jq |
在我们学习数组那节课里,我们学会了用for迭代数组里面的各个元素,这是很方便的,也是在之前的jdk的版本中没有的功能。For语句除了循环和找数组之外还有,迭代集合类等等功能。这个for语句它抛弃了Iterator(迭代),使得遍历集合类变得简单。
看看以前版本的Iterator是怎么做的:
public void testIterator() throws IOException {
List list = getList(); //在某处初始化这个list
for(Iterator i = list.iterator();i.hasNext();){
Object listElement = i.next();
System.out.println(listElement.toString());
}} 写一个链表的迭代,需要这么多代码。
而现在就不用了
public void testFor() {
List list = getList();
for (Object listElement : list) {
System.out.println(listElement.toString());
}}看看新版本的是不是简单多了。
实践:
import java.io.IOException;
import java.io.PrintStream;
public class CustomObjectTester {
//一个继承List的对象
private GuitarManufacturerList manufacturers;
public CustomObjectTester() {
this.manufacturers = new GuitarManufacturerList();
}
public void testListExtension(PrintStream out) throws IOException {
//添加一些字符串
manufacturers.add("Epiphone Guitars");
manufacturers.add("Gibson Guitars");
// for迭代
for (String manufacturer : manufacturers) {
out.println(manufacturer);
}}
public static void main(String[] args) {
try {
CustomObjectTester tester = new CustomObjectTester();
tester.testListExtension(System.out);
} catch (Exception e) {
e.printStackTrace();
}}}还有一个类
import java.util.LinkedList;
@SuppressWarnings("serial")
public class GuitarManufacturerList extends LinkedList<String> {
public GuitarManufacturerList() {
super();
}
public boolean add(String manufacturer) {
if (manufacturer.indexOf("Guitars") == -1) {
return false;
} else {
super.add(manufacturer);
return true;
}}}几个此例子打包下载
如有问题请访问技术论坛
作者:100jq |
java这种语言可以编写很多程序,图形的程序自然不例外。AWT是java图形编程的基础。AWT就是抽象窗口工具集(Abstract Window Toolkit),是java中支持图形化界面GUI设计的一个工具集,也是绘制其它图形的基础部分。
java.awt.*是java语言中的第3大包,这里面包含着相当多的工具,像是字体,颜色,事件等等。首先我们看一个构造GUI程序的例子。实践:
import java.awt.*;
public class BorderExample {
private Frame f; //Frame是框架类,它起到布局的作用
private Button bn, bs, bw, be, bc; //按钮也是一个类每new一个Button对象就是一个按钮。
public BorderExample() {
f = new Frame("Border Layout");
bn = new Button("B1");
bs = new Button("B2");
bw = new Button("B3");
be = new Button("B4");
bc = new Button("B5");
}
public void launchFrame() {
f.add(bn, BorderLayout.NORTH); //后面大写的NORTH是表明位置
f.add(bs, BorderLayout.SOUTH); //Layout称为布局管理器
f.add(bw, BorderLayout.WEST);
f.add(be, BorderLayout.EAST);
f.add(bc, BorderLayout.CENTER);
f.setSize(200,200);
f.setVisible(true);
}
public static void main(String args[]) {
BorderExample guiWindow2 = new BorderExample();
guiWindow2.launchFrame();
}}
再看一个例子
import java.awt.*;
public class ComplexLayoutExample {
private Frame f;
private Panel p; //Panel是一个不能单独显示,必须放在Window或Frame中,是一个无边框的区域,其中可以放一些基本的组件。
private Button bw, bc;
private Button bfile, bhelp;
public ComplexLayoutExample() {
f = new Frame("GUI example 3");
bw = new Button("West");
bc = new Button("Work space region");
bfile = new Button("File");
bhelp = new Button("Help");
}
public void launchFrame() {
// 将bw和bc这两个按钮放在Frame边上
f.add(bw, BorderLayout.WEST);
f.add(bc, BorderLayout.CENTER);
// 为北侧的边上放按钮
p = new Panel();
p.add(bfile);
p.add(bhelp);
f.add(p, BorderLayout.NORTH);
//将Panel打包使他可见
f.pack();
f.setVisible(true);
}
public static void main(String args[]) {
ComplexLayoutExample gui = new ComplexLayoutExample();
gui.launchFrame();
}}
大家看到了一些按钮出现在了窗口上,但是这些按钮都没有什么意义,有人会发现关闭的按钮不能用了,放心这是正常的。可以在DOS下面用ctrl+c来结束这个程序。那么我们想让这些按钮,有些作用啊,怎么办呢?那就是需要AWT的事件处理了。我们再来看一个例子。实践:
import java.awt.event.*;
//要想响应一个事件首先实现一个ActionListener的接口
public class ButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("动作发生");
System.out.println("按钮的命令是: "
+ e.getActionCommand());
}}
import java.awt.*;
public class TestButton {
private Frame f;
private Button b;
public TestButton() {
f = new Frame("测试");
b = new Button("点击我!");
//将一个动作命令设置到一个按钮上
b.setActionCommand("按钮被按下");}
public void launchFrame() {
b.addActionListener(new ButtonHandler());
f.add(b,BorderLayout.CENTER);
f.pack();
f.setVisible(true);
}
public static void main(String args[]) {
TestButton guiApp = new TestButton();
guiApp.launchFrame();
}