posts - 24,  comments - 27,  trackbacks - 0
  2008年5月16日
字符串
1、获取字符串的长度
length()
2 、判断字符串的前缀或后缀与已知字符串是否相同
前缀 startsWith(String s)
后缀 endsWith(String s)
3、比较两个字符串
equals(String s)
4、把字符串转化为相应的数值
int型 Integer.parseInt(字符串)
long型 Long.parseLong(字符串)
float型 Folat.valueOf(字符串).floatValue()
double型 Double.valueOf(字符串).doubleValue()
4、将数值转化为字符串
valueOf(数值)
5、字符串检索
indexOf(Srting s) 从头开始检索
indexOf(String s ,int startpoint) 从startpoint处开始检索
如果没有检索到,将返回-1
6、得到字符串的子字符串
substring(int startpoint) 从startpoint处开始获取
substring(int start,int end) 从start到end中间的字符
7、替换字符串中的字符,去掉字符串前后空格
replace(char old,char new) 用new替换old
trim()
8、分析字符串
StringTokenizer(String s) 构造一个分析器,使用默认分隔字符(空格,换行,回车,Tab,进纸符)
StringTokenizer(String s,String delim) delim是自己定义的分隔符

nextToken() 逐个获取字符串中的语言符号
boolean hasMoreTokens() 只要字符串还有语言符号将返回true,否则返回false
countTokens() 得到一共有多少个语言符号


文本框和文本区

1、文本框
TextField() 构造文本框,一个字符长
TextField(int x) 构造文本框,x个字符长
TextField(String s) 构造文本框,显示s
setText(String s) 设置文本为s
getText() 获取文本
setEchoChar(char c) 设置显示字符为c
setEditable(boolean) 设置文本框是否可以被修改
addActionListener() 添加监视器
removeActionListener() 移去监视器
2、文本区
TextArea() 构造文本区
TextArea(String s) 构造文本区,显示s
TextArea(String s,int x,int y) 构造文本区,x行,y列,显示s
TextArea(int x,int y) 构造文本区,x行,y列
TextArea(String s,int x,ing y,int scrollbar)
scrollbar的值是:
TextArea.SCROLLBARS_BOTH
TextArea.SCROLLBARS_VERTICAL_ONLY
TextArea.SCROLLBARS_HORIZONTAL_ONLY
TextArea.SCROLLBARS_NONE
setText(String s) 设置文本为s
getText() 获取文本
addTextListener() 添加监视器
removeTextListener() 移去监视器
insert(String s,int x) 在x处插入文本s
replaceRange(String s,int x,int y) 用s替换从x到y处的文本
append(String s) 在文本的最后追加文本s
Int getCaretPosition(int n) 获取文本区中光标的位置

按钮

1、按钮
Button() 构造按钮
Button(String s) 构造按钮,标签是s
setLabel(String s) 设置按钮标签是s
getLabel() 获取按钮标签
addActionListener() 添加监视器
removeActionListener() 移去监视器

标签

1、标签
Label() 构造标签
Label(String s) 构造标签,显示s
Label(String s,int x)
x是对齐方式,取值:
Label.LEFT
Label.RIGHT
Label.CENTER
setText(String s) 设置文本s
getText() 获取文本
setBackground(Color c) 设置标签背景颜色
setForeground(Color c) 设置字体颜色


选择框

1、选择框
Checkbox() 构造选择框
Checkbox(String s) 构造选择框,给定标题s
Checkbox(String s,boolean b) b设定初始状态
Checkbox(String s,boolean b,CheckboxGroup g) g设定了所属的组(有了组就成为单选框)
addItemListener() 添加监视器
removeItemListener() 移去监视器
getState() 返回选择框的是否选中状态
setState(boolean b) 设置选择框的状态
getLabel() 获取选择框的标题
setLabel(String s) 设置选择框的标题为s

选择控件和滚动列表

1、选择控件
Choice() 构造选择控件
add(String s) 向选择控件增加一个选项
addItemListener() 添加监视器
removeItemListener() 移去监视器
getSelectedIndex() 返回当前选项的索引
getSelectedItem() 返回当前选项的字符串代表
insert(String s,int n) 在n处插入选项s
remove(int n)
removeAll()
2、滚动列表
List() 构造滚动列表
List(int n) 参数n是可见行数
List(int n,boolean b) 参数b是设置是否可以多项选择
add(String s) 向列表的结尾增加一个选项
add(String s,int n) 在n处增加一个选项
AddActionListener() 滚动列表添加监视器
addItemListener() 滚动列表上的选项添加监视器
remove(int n) 删除n初的选项
remnoveAll() 删除全部选项
getSelectedIndex() 返回当前选项的索引
getSelectedItem() 返回当前选项的字符串代表


3、组件类的一些常用方法
void setBackground(Color c) 设置组件背景颜色
void setForeground(Color c) 设置组件前景颜色
void setFonts(Font f) 设置组件字体
void setBounds(int x,int y,int w,int h) 设置坐标,x,y表示在容器中坐标,w,h表示宽和高
void setLocation(int x,int y) 移动到x,y 处
void setSize(int w,int h) 设置宽和高
void setVisible(boolean b) 设置组建是否可见
int getBounds().wigth 获取宽
int getBounds().height 获取高
int getBounds().x 获取x 坐标
int getBounds().y 获取y 坐标
Toolkit getToolkit() 获取工具包对
void setEnabled(boolean b) 设置是否可以使用(默认可以)

窗口和菜单
1、窗口
Frame() 构造窗口
Frame(String s) 窗口标题是s
setBounds(int x,int y,int w,int h) 窗口位置x,y,宽w,高y
setSize(int w,int h) 设置窗口位置(单位是像素)
setBackground(Color c) 设置背景颜色
setVisible(boolean b) 设置窗口是否可见
pack() 窗口出现时紧凑
setTitle(String s) 设置标题为s
getTitle() 获取标题
setResizable(boolean b) 设置窗口大小是否可以调整
2、菜单条
Menubar() 构造菜单条
setMenubar() 窗口添加菜单条
3、菜单
Menu() 构造菜单
Menu(String s) 构造菜单,标题s
add
add(MenuItem item) 菜单增加菜单选项item
add(String s) 向菜单增加选项s
getItem(int n) 获取n处的选项
getItemCount() 获取选项数目
insert(MenuItem item,int n) 在n处插入菜单选项item
insert(String s,int n) 在n处插入菜单选项
remove(int n) 删除菜单的n处的菜单选项
removeAll() 删除全部
4、菜单项
MenuItem() 构造菜单项
MenuItem(String s) 构造标题是s的菜单项
setEnabled(boolean b) 设置是否可以被选择
getLabel() 得到菜单选项名
addActionListener() 添加监视器
5、有关菜单的技巧
addSeparator() 增加菜单分割线
CheckboxMenuItem() 复选框菜单项
setShortcut(MenuShortcut k) 设置快捷键(k取值KeyEvent.VK_A----KeyEvent.VK_Z)



建立对话框
1、Dialog类
Dialog(Frame f,String s) 构造对话框,初始不可见,s是标题,f是对话框所依赖的窗口
Dialog(Frame f,String s,boolean b) b设置初始是否可见
getTitle() 获取对话框标题
setTitle(String s) 设置对话框标题
setModal(boolean b) 设置对话框模式
setSize(int w,int h) 设置对话框大小
setVisible(boolean b) 显示或隐藏对话框
2、FileDialog类
Filedialog(Frame f,String s,int mode) mode的值是fileDialog.LOAD或者fileDialog.SAVE
public String getDirectory() 获取当前文件对话框中显示的文件所属目录
public String getFile() 获取当前文件对话框中文件的字符串表示,不存在返回null

Java中的鼠标和键盘事件
1、使用MouseListener借口处理鼠标事件
鼠标事件有5种:按下鼠标键,释放鼠标键,点击鼠标键,鼠标进入和鼠标退出
鼠标事件类型是MouseEvent,主要方法有:
getX(),getY() 获取鼠标位置
getModifiers() 获取鼠标左键或者右键
getClickCount() 获取鼠标被点击的次数
getSource() 获取鼠标发生的事件源
事件源获得监视器的方法是addMouseListener(),移去监视器的方法是removeMouseListener()


处理事件源发生的时间的事件的接口是MouseListener 接口中有如下的方法
mousePressed(MouseEvent) 负责处理鼠标按下事件
mouseReleased(MouseEvent) 负责处理鼠标释放事件
mouseEntered(MouseEvent) 负责处理鼠标进入容器事件
mouseExited(MouseEvent) 负责处理鼠标离开事件
mouseClicked(MouseEvent) 负责处理点击事件
2、使用MouseMotionListener接口处理鼠标事件
事件源发生的鼠标事件有2种:拖动鼠标和鼠标移动
鼠标事件的类型是MouseEvent
事件源获得监视器的方法是addMouseMotionListener()
处理事件源发生的事件的接口是MouseMotionListener 接口中有如下的方法
mouseDragged() 负责处理鼠标拖动事件
mouseMoved() 负责处理鼠标移动事件
3、控制鼠标的指针形状
setCursor(Cursor.getPreddfinedCursor(Cursor.鼠标形状定义)) 鼠标形状定义见(书 P 210)
4、键盘事件
键盘事件源使用addKeyListener 方法获得监视器
键盘事件的接口是KeyListener 接口中有3个方法
public void keyPressed(KeyEvent e) 按下键盘按键
public void keyReleased(KeyEvent e) 释放键盘按键
public void keyTypde(KeyEvent e) 按下又释放键盘按键

Java多线程机制
1、Java的线程类与Runnable接口
Thread类
public Thread() 创建线程对象
public Thread(Runnable target) target 称为被创建线程的目标对象,负责实现Runnable接口
线程优先级
Thread类有三个有关线程优先级的静态常量:MIN_PRIORITY,MAX_PRIORITY,NORM_PRIORITY
新建线程将继承创建它的副相承的优先级,用户可以调用Thread类的setPriority(int a)来修改
a的取值:
Thread.MIN_PRIORITY,Thread.MAX_PRIORITY,Thread.NORM_PRIORITY
主要方法
启动线程 start()
定义线程操作 run()
使线程休眠 sleep()
sleep(int millsecond) 以毫秒为单位的休眠时间
sleep(int millsecond,int nanosecond) 以纳秒为单位的休眠时间
currentThread() 判断谁在占用CPU的线程
第二十章 输入输出流
1、FileInputStream类
FileInputStream(String name) 使用给定的文件名name创建一个FileInputStream对象
FileInputStream(File file) 使用File对象创建FileInpuStream对象
File类有两个常用方法:
File(String s) s确定文件名字
File(String directory,String s) directory是文件目录


例如:
File f=new File("Myfile.dat");
FileInputStream istream=new FileInputStream(f);
处理I/O异常
当出现I/O错误的时候,Java生成一个IOException(I/O异常)对象来表示这个错误的信号。
程序必须使用一个catch检测这个异常
例如:
try{
FileInputStream ins= new FileInputStream("Myfile.dat");
}
catch(IOException e){
System.out.println("File read Error:"+e);
}
从输入流中读取字节
int read() 返回0~255之间一个整数,如果到输入流末尾,则返回-1
int read(byte b[]) 读取字节数组
int read(byte b[],int off,int len) off指定把数据存放在b中什么地方,len指定读取的最大字节数
关闭流
close()
2、FileOutputStream类
FileOutputStream(String name) 使用指定的文件名name创建FileOutputStream对象
FileOutputStream(File file) 使用file对象创建FileOutputStream对象
FileOutputStream(FileDescriptor fdobj) 使用FileDescriptor对象创建FileOutputStream对象
3、FileReader类和FileWriter类
FileReader(String filename)


FileWriter(String filename)
处理时需要FileNotFoundException异常
4、RandomAccessFile类
RandomAccessFile不同于FileInputStream和FileOutputStream,不是他们的子类
当我们想对一个文件进行读写操作的时候,创建一个指向该文件的RandomAccessFile流就可以了
RandomAccessFile类有两个构造方法:
RandomAccessFile(String name, String mode) name是文件名,mode取r(只读)或rw(读写)
RandomAccessFile(File file,String mode) file给出创建流的源
seek(long a) 移动RandomAccessFile流指向文件的指针,a确定指针距文件开头的位置
getFilePointer() 获取当前文件的指针位置
close() 关闭文件
getFD() 获取文件的FileDescriptor
length() 获取文件长度
read() 读取一个字节数据
readBoolean() 读取一个布尔值
readByte() 读取一个字节
readChar()
readFloat()
readFully(byte b[])
readInt()
readLine()
readLong()
readUnsignedShort()
readUTF() 读取一个UTF字符串
setLength(long newLength) 设置文件长度
skipByte(int n) 在文件中跳过给定数量的字节
write(byte b[]) 写b.length个字节到文件
writeBoolean(bolean b)
writeByte(int v)
writeChar(char c)
writeChars(String s)
writeDouble(double d)
writeFloat(float v)
writeInt(int i)
writeLong(long l)
writeShort(int i)
writeUTF(String s)
5、管道流
PipedInputStream类
PipedInputStream() 创建一个管道输入流
PipedInputStream(PipedOutputStream a) 连接到输出流a的输入流
read() 从输入流中读取一个字节
read(byte b[],int off,int len) off是在b中的开始位置,len是字节长度
PipedOutputStream类
PipedOutputStream() 创建一个输出流
PipedOutputStream(PipedInputStream a) 连接到输入流a的输出流
write(int b)
write(byte b[],int off,int len)
counnect() 连接输入输出流
close() 关闭流
在使用的时候要捕获IOException异常。
6、数据流
DataInputStream类(数据输入流)
DataInputStream(InputStream in) 将数据输入流指向一个由in指定的输入流
DataOutputStream类(数据输出流)
DataOutputStream(OutputStream out) 将数据输出流指向一个由out指定的输出流
主要方法:
close()
read() 读取一个字节数据
readBoolean() 读取一个布尔值
readByte() 读取一个字节
readChar()
readFloat()
readFully(byte b[])
readInt()
readLine()
readLong()
readUnsignedShort()
readUTF() 读取一个UTF字符串
skipByte(int n) 在文件中跳过给定数量的字节
write(byte b[]) 写b.length个字节到文件
writeBoolean(bolean b)
writeByte(int v)
writeChar(char c)
writeChars(String s)
writeDouble(double d)
writeFloat(float v)
writeInt(int i)
writeLong(long l)
writeShort(int i)
writeUTF(String s)
7、对象流
ObjectInputStream类和ObjectOutputStream类分别是DataInputStream类和DataOutputStream类的子类
8、回压输入流
PushbackInputStream类
PushbackInputStream(InputStream in)
PushbackReader类
PushbackReader(Reader in)
unread(char c) 回压一个字符
unread(char c[]) 回压数组c中全部字符
unread(char c[],offset,int n) 回压c中从offset开始的n个字符

java网络的基本知识
1、使用URL(统一资源定位)
例如:
try
{
url=new URL("http://www.sina.com.cn";
}
catch(MalformedURLException e)
{
System.out.println("Bad URL:"+url);
}
在Applet 中链接向另外的Web页面,使用代码:
getAppletContext().showDocument(url);
2、套接字
客户建立到服务器的套接字(Socket)
Socket(String host,int port) host是服务器的IP地址,port是端口号
建立了套接字后可以使用getInputStream()获得输入流
还可以使用getOutputStream()获得一个输出流
服务器建立接受客户套接字的服务器套接字(ServerSocket)
ServerSocket(int port) port是端口号
建立了套接字连接后可以使用accept()接收客户的套接字
可以使用getOutputStream()获得一个输出流
还可以使用getInputStream()获得一个输入流
3、InetAddress类
getByName(String )
3、InetAddress类
getByName(String s) 获取Internet上主机的地址
getHostName() 获取InetAddress对象所包含的域名
getHostAddress() 获取InetAddress对象所包含的IP地址


getLocalHost() 获取本地地址
4、UDP数据报
发送数据包,即使用DatagramPacket类将数据打包,有两种构造方法
DatagramPacket(byte data[],int length,InetAddress address,int port)
?含有data数组的数据
?该数据包将发送到地质是address,端口是port的主机上
DatagramPacket(byte data[],int offset,int length,InetAddress address,int port)
?含有data数组的从offset开始,length长度的数据
?该数据包将发送到地质是address,端口是port的主机上
接收数据包,即使用DatagramSocket(int port)创建一个对象,port必须和待接收的数据包的端口相同
例如:
如果发送方的数据包端口是5566
DatagramSocket mail=new DatagramSocket(5566);
然后对象mail可以使用方法receive(Datagrampacket pack)接收数据包
在使用参数pack 接收数据包前,必须创建pack
byte data[]=new byte[100];
int length=90;
DatagramPacket pack=new DatagramPataet(data,length);
mail.receive(pack);
该数据包pack将接收长度是length的数据放入data,注意数据长度不要超过8192KB
pack还可以调用方法getPort()获取所接受数据包是从什么端口发出的


调用方法InetAddress getAddress()可以获知数据包来自哪个主机

Java与图像
1、java支持的图像类型:GIF,JPEG,BMP
2、Image类
首先申请一个Image对象
Image img =getImage(URL url,String name) url是图像地址,name是图片名称
通常使用:
Image img =getImage(getCodBase(),String name) getCodBase()获取当前小应用程序的URL,也就是在同一目录下
图像被加载后,就可以在paint()中绘制了
drawImage(Image img,int x,int y,ImageObserver observer)
img是上面获取的图像, x,y是指定图像左上角的位置,observer是加载图像时的图像观察器
Applet类已经实现了ImageObserver接口,所以可以直接使用this作为最后一个参数
drawImage(Image img,int x,int y,int width,int height,ImageObserver observer)
width和height是要绘制的图像的宽和高
可以使用img.getHeight(this)和img.getWidth(this)来获取被加载的图像的宽和高
3、设置Java窗口图标
Frame对象可以使用setIconImage(Image img)方法设置左上角图标,默认图标是咖啡杯

Java数据库连接(JDBC)
1、JDBC-ODBC桥接器
建立JDBC-ODBC桥接器
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch(ClassNotFoundException e){}
连接到数据库
try
{
Connection con=DriverManager.getConnection("jdbcdbc:数据源名称","数据源的login name",
"数据源的password");
}
catch(SQLException e){}
向数据库发送SQL语句
try
{
Statement sql=con.createStatement();
}
catch(SQLException e){}
处理查询结果
ResultSet rs=sql.executeQuery("SQL语句");
第二十四章 Java与多媒体
1、在小程序中播放声音
java可以播放au,aiff,wav,midi,rfm格式的音频
可以调用Applet的一个静态方法:
newAudioClip(URL url,String name) url是地址,name是音频名称
也可以用Applet类的实例方法:
getAudioClip(URL url,String name)
根据url地址和声音文件name,获得一个用于播放的音频对象,这对象可以使用下面的方法来处理声音:
play() 播放声音文件name
loop() 循环播放name
stop() 停止播放name
2、Java媒体框架(JMF)
创建播放器

try
{
URL url=new URL(getDocumenBase(),视频文件名称);
player player=Manager.createPlayer(url);
}
catch(IOException e){}
向播放器注册控制监视器
player.addControllerListener(监视器);
创建监视器必须使用接口ControllerListener ,该接口中的方法是
public void controllerUpdate(ControllerEvent e)
让播放器对媒体进行预提取
player.prefetch()
启动播放器
player.start();
停止播放器
player.stop();
停止播放器后必须释放内存中的资源
player.deallocate();

Java Swing基础
1、Jcomponent类
Jcomponent类 是所有轻量组件的父类,主要的子类有:
JButton 创建按钮对象,而且可以创建在图标的按钮
JComboBox 创建组合框对象,和Choice相似
JCheckBox 创建复选框对象
JFileChooser 创建文件选择器
JInternalFrame 创建内部窗体
JLabel 创建标签
JMenu 创建菜单对象
JMenuBar 创建菜单条对象
JMenuItem 创建菜单项对象
JPanel 创建面板对象
JPasswordField 创建口令文本对象
JPopupMenu 创建弹出式菜单

JProgressBar 创建进程条
JRadioButton 创建单选按钮
JScrollBar 创建滚动条
JScrollPane 创建滚动窗格
JSlider 创建滚动条
JSplitPane 创建拆分窗格
JTable 创建表格
JTextArea 创建文本区
JTexPane 创建文本窗格
JToolBar 创建工具条
JToolTip 创建工具提示对象
JTree 创建树对象
2、JFrame类
JFrame类及其子类创建的对象是窗体
(1)JFrame类及其子类创建的窗体是swing窗体
(2)不可以把组件直接加到swing窗体中,应该把组件加到内容面板中
(3)不能为swing窗体设置布局,而应当为内容面板设置布局
(4)swing窗体通过调用getContentPane()方法得到它的内容面板
3、JApplet类
(1)不可以把组件直接添加到小程序容器中,也应该添加到内容面板中
(2)不能为小程序设置布局
(3)小程序容器通过调用getContenPane()方法得到内容面板
4、JDialog类
(1)不可以把组件直接添加到对话框容器中,也应该添加到内容面板中
(2)不能为对话框设置布局
(3)对话框容器通过调用getContenPane()方法得到内容面板
5、JPanel面板
JPanel()
JPanel(布局对象)
6、滚动窗口JScrollPane
JScrollPane()
JScrollPane(component c)
7、拆分窗口JSplitPane
JSplitPane(int a,Component b,Component c)
a的取值是HORIZONTAL_SPLIT或者VERTICAL_SPLIT决定水平拆分还是垂直拆分
JSplitPane(int a,boolean b ,Component b,Component c) b的取值决定拆分线移动的时候组件是否连续变化
8、内部窗体JInternalFrame
JInternalFrame(String title,boolean resizable,booleam closable,boolean max,boolean min)
参数的意义分别是窗口名称,是否能调整大小,是否有关闭按钮,最大化按钮,最小化按钮
(1)不能把组件直接加到窗体中,而是加到内容面板中
(2)必须先把内部窗体加到一个容器中(JDesktopPane),该容器是专门为内部窗体服务的
9、按钮(JButton)
JButton() 创建按钮
JButton(String s) s是按钮的名字
JButton(Icon icon) icon是按钮上的图标
JButton(String s,Icon icon)
getText() 获取按钮名字
getIcon() 获取按钮图标
setIcon(Icon icon) 设置按钮图标
setHorizontalTextposition(int a) a确定按钮上图标的位置,取值:
AbstractButton_CENTR,AbstractButton_LEFT,AbstractButton_RIGHT
setVerticalTextposition(int a) a确定按钮上名字相对图标的位置,取值:
AbstractButton.TOP,AbstractButton.BOTTOM,AbstractButton.CENTR
setMnemonic(char c) 设置按钮的键盘操作方式是字符c(Alt+c)
setEnabled(boolean b) b决定按钮是否可以被单击
posted @ 2008-05-16 18:43 矿矿 阅读(478) | 评论 (0)编辑 收藏
  2008年5月8日
17.你需要学习企业级JavaBeans(EJB)以及它们的不同组件模式:Stateless/StatefulSessionBeans,EntityBeans(包含Bean- ManagedPersistence[BMP]或者Container-ManagedPersistence[CMP]和它的EJB-QL),或者 Message-DrivenBeans(MDB)。

  18.你需要学习如何管理与配置一个J2EE应用程序服务器,如WebLogic,JBoss等,并且利用它的附加服务,例如簇类,连接池以及分布式处理支援。你还需要了解如何在它上面封装和配置应用程序并且能够监控、调整它的性能。

  19.你需要熟悉面向方面的程序设计以及面向属性的程序设计(这两个都被很容易混淆的缩写为AOP),以及他们的主流JAVA规格和执行。例如AspectJ和AspectWerkz。

  20.你需要熟悉对不同有用的API和framework等来为你服务。例如Log4J(logging/tracing),Quartz (scheduling),JGroups(networkgroupcommunication),JCache(distributedcaching), Lucene(full-textsearch),JakartaCommons等等。

21.如果你将要对接或者正和旧的系统或者本地平台,你需要学习JNI (JavaNativeInterface) and JCA (JavaConnectorArchitecture)。

  22.你需要熟悉JINI技术以及与它相关的分布式系统,比如掌握CROBA。

  23.你需要JavaCommunityProcess(JCP)以及他的不同JavaSpecificationRequests(JSRs),例如Portlets(168),JOLAP(69),DataMiningAPI(73),等等。

  24.你应该熟练掌握一种JAVAIDE例如sunOne,netBeans,IntelliJIDEA或者Eclipse。(有些人更喜欢VI或EMACS来编写文件。随便你用什么了:)

  25.JAVA(精确的说是有些配置)是冗长的,它需要很多的人工代码(例如EJB),所以你需要熟悉代码生成工具,例如XDoclet。

  26.你需要熟悉一种单元测试体系(JNunit),并且学习不同的生成、部署工具(Ant,Maven)。

  27.你需要熟悉一些在JAVA开发中经常用到的软件工程过程。例如RUP(RationalUnifiedProcess)andAgilemethodologies。

  28.你需要能够深入了解加熟练操作和配置不同的操作系统,比如GNU/linux,sunsolaris,macOS等,做为跨平台软件的开发者。

  29.你还需要紧跟java发展的步伐,比如现在可以深入的学习javaME,以及各种java新规范,技术的运用,如新起的web富客户端技术。

  30.你必需要对opensource有所了解,因为至少java的很多技术直接是靠开源来驱动发展的,如java3D技术。

posted @ 2008-05-08 15:08 矿矿 阅读(818) | 评论 (3)编辑 收藏
17.你需要学习企业级JavaBeans(EJB)以及它们的不同组件模式:Stateless/StatefulSessionBeans,EntityBeans(包含Bean- ManagedPersistence[BMP]或者Container-ManagedPersistence[CMP]和它的EJB-QL),或者 Message-DrivenBeans(MDB)。

  18.你需要学习如何管理与配置一个J2EE应用程序服务器,如WebLogic,JBoss等,并且利用它的附加服务,例如簇类,连接池以及分布式处理支援。你还需要了解如何在它上面封装和配置应用程序并且能够监控、调整它的性能。

  19.你需要熟悉面向方面的程序设计以及面向属性的程序设计(这两个都被很容易混淆的缩写为AOP),以及他们的主流JAVA规格和执行。例如AspectJ和AspectWerkz。

  20.你需要熟悉对不同有用的API和framework等来为你服务。例如Log4J(logging/tracing),Quartz (scheduling),JGroups(networkgroupcommunication),JCache(distributedcaching), Lucene(full-textsearch),JakartaCommons等等。

21.如果你将要对接或者正和旧的系统或者本地平台,你需要学习JNI (JavaNativeInterface) and JCA (JavaConnectorArchitecture)。

  22.你需要熟悉JINI技术以及与它相关的分布式系统,比如掌握CROBA。

  23.你需要JavaCommunityProcess(JCP)以及他的不同JavaSpecificationRequests(JSRs),例如Portlets(168),JOLAP(69),DataMiningAPI(73),等等。

  24.你应该熟练掌握一种JAVAIDE例如sunOne,netBeans,IntelliJIDEA或者Eclipse。(有些人更喜欢VI或EMACS来编写文件。随便你用什么了:)

  25.JAVA(精确的说是有些配置)是冗长的,它需要很多的人工代码(例如EJB),所以你需要熟悉代码生成工具,例如XDoclet。

  26.你需要熟悉一种单元测试体系(JNunit),并且学习不同的生成、部署工具(Ant,Maven)。

  27.你需要熟悉一些在JAVA开发中经常用到的软件工程过程。例如RUP(RationalUnifiedProcess)andAgilemethodologies。

  28.你需要能够深入了解加熟练操作和配置不同的操作系统,比如GNU/linux,sunsolaris,macOS等,做为跨平台软件的开发者。

  29.你还需要紧跟java发展的步伐,比如现在可以深入的学习javaME,以及各种java新规范,技术的运用,如新起的web富客户端技术。

  30.你必需要对opensource有所了解,因为至少java的很多技术直接是靠开源来驱动发展的,如java3D技术。

posted @ 2008-05-08 15:08 矿矿 阅读(666) | 评论 (0)编辑 收藏
  2008年5月7日
封装数据库操作,目的就是为了隐藏java.sql包内的类,在编码中去掉核心的数据库操作代码。以杜绝直接数据库操作容易带来的资源未释放问题。同时也减少了数据库操作的编码量。

  但是很多网友在封装时,却喜欢返回结果集(ResultSet对象),那么这个封装就没有意义了。

  1. 又是直接操作核心数据库类,跟封装前几乎没什么变化。

  2. 结果集总是依赖于它使用的连接(Connection)对象。因此当连接对象在方法内被关闭后,你返回的ResultSet就没有用了。

  如果真的要获得查询数据库的结果集,就把结果集对象内的所有数据,转储到以Map为元素的List对象内。

  当然,这种方式,不能适应大数据量的查询,不过如果真的碰到大数据量的查询,那用什么封装都不好,还是得直接数据库操作. :)))

  下面是简单的数据库操作Javabean的代码

  DbWrapper.java

  import java.sql.*;

  import java.util.*;

  public class DbWrapper

  {

  // 定义连接池对象为静态变量,将一直存在,直到工作目录关闭。

  private static DataSource ds = null;

  // 1.用连接池的方式获得连接

  // 如果不是做多数据库程序,推荐使用此方法

  // 相关内容:在tomcat管理界面配置连接池

  public static Connection openConnection() throws Exception

  {

  // 只需要初始化1次

  if ( ds == null )

  {

  Context initContext = new InitialContext();

  Context envContext = (Context) initContext.lookup("java:/comp/env");

  DataSource ds = (DataSource) envContext.lookup("jdbc/MyDataSource");

  }

  return ds.getConnection();

  }

  // 2.用jdbc驱动获得连接

  // 相关内容:JSP数据库连接大全

  public static Connection openConnection(

  String driver,

  String url,

  String username,

  String password)

  throws Exception

  {

  Class.forName(driver).newInstance();

  return DriverManager.getConnection(url, username, password);

  }

  public static void closeConnection(Connection conn) throws Exception

  {

  if ( conn != null )

  {

  conn.close();

  }

  }

  public static int executeUpdate(String sql) throws Exception

  {

  int count = 0;

  Connection conn = null;

  Statement stmt = null;

  try

  {

  conn = openConnection();

  stmt = conn.createStatement();

  count = stmt.executeUpdate(sql);

  }

  catch ( Exception e )

  {

  throw e;

  }

  finally

  {

  closeConnection(conn);

  }

  return count;

  }

  public static List executeQuery(String sql) throws Exception

  {

  List list = new ArrayList();

  Connection conn = null;

  Statement stmt = null;

  ResultSet rs = null;

  try

  {

  conn = openConnection();

  stmt = conn.createStatement();

  rs = stmt.executeQuery(sql);

  ResultSetMetaData rsmd = rs.getMetaData();

  while ( rs.next() )

  {

  Map map = new HashMap();

  for ( int i = 1; i < = rsmd.getColumnCount(); i++ )

  {

  map.put(rsmd.getColumnName(i), rs.getObject(i));

  }

  list.add(map);

  } }

  catch ( Exception e )

  {

  e.printStackTrace();

  }

  finally

  {

  if ( rs != null ) rs.close();

  closeConnection(conn);

  }

  return list; }

  }

  使用示例:

  // 1.对于insert, update, delete语句int count = DbWrapper.executeUpdate(sql);

  // 2.对于selete语句

  java.util.List list = DbWrapper.executeQuery(sql);

  // 方法一:按名字取值,注意大小写是严格区分的

  for ( int i = 0; i < list.size(); i++ )

  {

  java.util.Map map = (java.util.Map)list.get(i);

  out.println(mag.get("column_name").toString());

  }

  // 方法二:遍历取值

  for ( int i = 0; i < list.size(); i++ )

  {

  java.util.Map map = (java.util.Map)list.get(i);

  for (java.util.Iterator it = map.keySet().iterator(); it.hasNext();)

  {

  String column_name = it.next().toString()); // 取值时注意null判断

  out.println(column_name + " = " + map.get(column_name) == null ? "" : map.get(column_name).toString());

  }

  }

posted @ 2008-05-07 18:52 矿矿 阅读(20) | 评论 (0)编辑 收藏
封装数据库操作,目的就是为了隐藏java.sql包内的类,在编码中去掉核心的数据库操作代码。以杜绝直接数据库操作容易带来的资源未释放问题。同时也减少了数据库操作的编码量。

  但是很多网友在封装时,却喜欢返回结果集(ResultSet对象),那么这个封装就没有意义了。

  1. 又是直接操作核心数据库类,跟封装前几乎没什么变化。

  2. 结果集总是依赖于它使用的连接(Connection)对象。因此当连接对象在方法内被关闭后,你返回的ResultSet就没有用了。

  如果真的要获得查询数据库的结果集,就把结果集对象内的所有数据,转储到以Map为元素的List对象内。

  当然,这种方式,不能适应大数据量的查询,不过如果真的碰到大数据量的查询,那用什么封装都不好,还是得直接数据库操作. :)))

  下面是简单的数据库操作Javabean的代码

  DbWrapper.java

  import java.sql.*;

  import java.util.*;

  public class DbWrapper

  {

  // 定义连接池对象为静态变量,将一直存在,直到工作目录关闭。

  private static DataSource ds = null;

  // 1.用连接池的方式获得连接

  // 如果不是做多数据库程序,推荐使用此方法

  // 相关内容:在tomcat管理界面配置连接池

  public static Connection openConnection() throws Exception

  {

  // 只需要初始化1次

  if ( ds == null )

  {

  Context initContext = new InitialContext();

  Context envContext = (Context) initContext.lookup("java:/comp/env");

  DataSource ds = (DataSource) envContext.lookup("jdbc/MyDataSource");

  }

  return ds.getConnection();

  }

  // 2.用jdbc驱动获得连接

  // 相关内容:JSP数据库连接大全

  public static Connection openConnection(

  String driver,

  String url,

  String username,

  String password)

  throws Exception

  {

  Class.forName(driver).newInstance();

  return DriverManager.getConnection(url, username, password);

  }

  public static void closeConnection(Connection conn) throws Exception

  {

  if ( conn != null )

  {

  conn.close();

  }

  }

  public static int executeUpdate(String sql) throws Exception

  {

  int count = 0;

  Connection conn = null;

  Statement stmt = null;

  try

  {

  conn = openConnection();

  stmt = conn.createStatement();

  count = stmt.executeUpdate(sql);

  }

  catch ( Exception e )

  {

  throw e;

  }

  finally

  {

  closeConnection(conn);

  }

  return count;

  }

  public static List executeQuery(String sql) throws Exception

  {

  List list = new ArrayList();

  Connection conn = null;

  Statement stmt = null;

  ResultSet rs = null;

  try

  {

  conn = openConnection();

  stmt = conn.createStatement();

  rs = stmt.executeQuery(sql);

  ResultSetMetaData rsmd = rs.getMetaData();

  while ( rs.next() )

  {

  Map map = new HashMap();

  for ( int i = 1; i < = rsmd.getColumnCount(); i++ )

  {

  map.put(rsmd.getColumnName(i), rs.getObject(i));

  }

  list.add(map);

  } }

  catch ( Exception e )

  {

  e.printStackTrace();

  }

  finally

  {

  if ( rs != null ) rs.close();

  closeConnection(conn);

  }

  return list; }

  }

  使用示例:

  // 1.对于insert, update, delete语句int count = DbWrapper.executeUpdate(sql);

  // 2.对于selete语句

  java.util.List list = DbWrapper.executeQuery(sql);

  // 方法一:按名字取值,注意大小写是严格区分的

  for ( int i = 0; i < list.size(); i++ )

  {

  java.util.Map map = (java.util.Map)list.get(i);

  out.println(mag.get("column_name").toString());

  }

  // 方法二:遍历取值

  for ( int i = 0; i < list.size(); i++ )

  {

  java.util.Map map = (java.util.Map)list.get(i);

  for (java.util.Iterator it = map.keySet().iterator(); it.hasNext();)

  {

  String column_name = it.next().toString()); // 取值时注意null判断

  out.println(column_name + " = " + map.get(column_name) == null ? "" : map.get(column_name).toString());

  }

  }

posted @ 2008-05-07 18:52 矿矿 阅读(20) | 评论 (0)编辑 收藏
  2008年5月6日
XML是eXtensible Markup Language的缩写。扩展标记语言XML是一种简单的数据存储语言,使用一系列简单的标记描述数据,而这些标记可以用方便的方式建立,虽然XML占用的空间比二进制数据要占用更多的空间,但XML极其简单易于掌握和使用。

XML与Access,Oracle和SQL Server等数据库不同,数据库提供了更强有力的数据存储和分析能力,例如:数据索引、排序、查找、相关一致性等,XML仅仅是展示数据。事实上XML与其他数据表现形式最大的不同是:他极其简单。这是一个看上去有点琐细的优点,但正是这点使XML与众不同。

XML的简单使其易于在任何应用程序中读写数据,这使XML很快成为数据交换的唯一公共语言,虽然不同的应用软件也支持其它的数据交换格式,但不久之后他们都将支持XML,那就意味着程序可以更容易的与Windows、Mac OS, Linux以及其他平台下产生的信息结合,然后可以很容易加载XML数据到程序中并分析他,并以XML格式输出结果。

XML的前身是SGML(The Standard Generalized Markup Language),是自IBM从60年代就开始发展的GML(Generalized Markup Language)

HTML一样, XML (可扩展标识语言)是通用标识语言标准(SGML)的一个子集,它是描述网络上的数据内容和结构的标准。尽管如此,XML不象HTML,HTML仅仅提供了在页面上显示信息的通用方法(没有上下文相关和动态功能) ,XML则对数据赋予上下文相关功能,它继承了SGML的大部分功能,却使用了不太复杂的技术。.

为了使得SGML显得用户友好,XML重新定义了SGML的一些内部值和参数,去掉了大量的很少用到的功能,这些繁杂的功能使得SGML在设计网站时显得复杂化。XML保留了SGML的结构化功能,这样就使得网站设计者可以定义自己的文档类型,XML同时也推出一种新型文档类型,使得开发者也可以不必定义文档类型。

因为XML是W3C制定的,XML的标准化工作由W3C的XML工作组负责,该小组成员由来自各个地方和行业的专家组成,他们通过email交流对XML标准的意见,并提出自己的看法 (www.w3.org/TR/WD-xml)。因为XML 是个公共格式, (它不专属于任何一家公司),你不必担心XML技术会成为少数公司的盈利工具,XML不是一个依附于特定浏览器的语言

XML(可扩展标记语言)是从称为SGML(标准通用标记语言)的更加古老的语言派生出来的。SGML的主要目的是定义使用标签来表示数据的标记语言的语法。

标签由包围在一个小于号(<)和一个大于号(>)之间的文本组成,例如<tag>。起始标签(start tag)表示一个特定区域的开始,例如<start>;结束标签(end tag)定义了一个区域的结束,除了在小于号之后紧跟着一个斜线(/)外,和起始标签基本一样,例如</end>。SGML还定义了标签的特性(attribute),它们是定义在小于号和大于号之间的值,例如<img src="picture.jpg">中的src特性。如果你觉得它看起来很熟悉的话,应该知道,基于SGML的语言的最著名实现就是原始的HTML。

SGML常用来定义针对HTML的文档类型定义(DTD),同时它也常用于编写XML的DTD。SGML的问题就在于,它允许出现一些奇怪的语法,这让创建HTML的解析器成为一个大难题:

1  某些起始标签不允许出现结束标签,例如HTML中<img>标签。包含了结束标签就会出现错误。

2  某些起始标签可以选择性出现结束标签或者隐含了结束标签,例如HTML中<p>标签,当出现另一个<p>标签或者某些其他标签时,便假设在这之前有一个结束标签。

3  某些起始标签要求必须出现结束标签,例如HTML中<script>标签。

4  标签可以以任何顺序嵌套。即使结束标签不按照起始标签的逆序出现也是允许的,例如,<b>This is a <i> sample </b> string</i>是正确的。

5  某些特性要求必须包含值,例如<img src="picture.jpg">中的src特性。

6  某些特性不要求一定有值,例如<td nowrap>中的nowrap特性。

7  定义特性的两边有没有加上双引号都是可以的,所以<img src="picture.jpg">和<img src=picture.jpg>都是允许的。

      这些问题使建立一个SGML语言的解析器变成了一项艰巨的任务。判断何时应用以上规则的困难导致了SGML语言的定义一直停滞不前。以这些问题作为出发点,XML逐渐步入我们的视野。

      XML去掉了之前令许多开发人员头疼的SGML的随意语法。在XML中,采用了如下的语法:

8  任何的起始标签都必须有一个结束标签。

9  可以采用另一种简化语法,可以在一个标签中同时表示起始和结束标签。这种语法是在大于符号之前紧跟一个斜线(/),例如<tag />。XML解析器会将其翻译成<tag></tag>。

10  标签必须按合适的顺序进行嵌套,所以结束标签必须按镜像顺序匹配起始标签,例如<b>this is a <i>sample</i> string</b>。这好比是将起始和结束标签看作是数学中的左右括号:在没有关闭所有的内部括号之前,是不能关闭外面的括号的。

11  所有的特性都必须有值。

12  所有的特性都必须在值的周围加上双引号。

这些规则使得开发一个XML解析器要简便得多,而且也除去了解析SGML中花在判断何时何地应用那些奇怪语法规则上的工作。仅仅在XML出现后的前六年就衍生出多种不同的语言,包括MathML、SVG、RDF、RSS、SOAP、XSLT、XSL-FO,而同时也将HTML改进为XHTML。

如果需要关于SGML和XML具体技术上的对比,请查看W3C的注解,位于:http://www.w3. org/TR/NOTE-sgml-xml.html

如今,XML已经是世界上发展最快的技术之一。它的主要目的是使用文本以结构化的方式来表示数据。在某些方面,XML文件也类似于数据库,提供数据的结构化视图。这里是一个XML文件的例子:


每个XML文档都由XML序言开始,在前面的代码中的第一行便是XML序言,<?xml version="1.0"?>。这一行代码会告诉解析器和浏览器,这个文件应该按照前面讨论过的XML规则进行解析。第二行代码,<books>,则是文档元素(document element),它是文件中最外面的标签(我们认为元素(element)是起始标签和结束标签之间的内容)。所有其他的标签必须包含在这个标签之内来组成一个有效的XML文件。XML文件的第二行并不一定要包含文档元素;如果有注释或者其他内容,文档元素可以迟些出现。

范例文件中的第三行代码是注释,你会发现它与HTML中使用的注释风格是一样的。这是XML从SGML中继承的语法元素之一。

页面再往下的一些地方,可以发现<desc>标签里有一些特殊的语法。<![CDATA[ ]]>代码用于表示无需进行解析的文本,允许诸如大于号和小于号之类的特殊字符包含在文本中,而无需担心破坏XML的语法。文本必须出现在<![CDATA[和]]>之间才能合适地避免被解析。这样的文本称为Character Data Section,简称CData Section。

下面的一行就是在第二本书的定义之前的:

<?page render multiple authors ?>

虽然它看上去很像XML序言,但实际上是一种称为处理指令(processing instruction)的不同类型的语法。处理指令(以下简称PI)的目的是为了给处理页面的程序(例如XML解析器)提供额外的信息。PI通常情况下是没有固定格式的,唯一的要求是紧随第一个问号必须至少有一个字母。在此之后,PI可以包含除了小于号和大于号之外的任何字符串序列。

最常见的PI是用来指定XML文件的样式表:



这个PI一般会直接放在XML序言之后,通常由Web浏览器使用,来将XML数据以特殊的样式显示出来。
posted @ 2008-05-06 14:09 矿矿 阅读(31) | 评论 (0)编辑 收藏
XML是eXtensible Markup Language的缩写。扩展标记语言XML是一种简单的数据存储语言,使用一系列简单的标记描述数据,而这些标记可以用方便的方式建立,虽然XML占用的空间比二进制数据要占用更多的空间,但XML极其简单易于掌握和使用。

XML与Access,Oracle和SQL Server等数据库不同,数据库提供了更强有力的数据存储和分析能力,例如:数据索引、排序、查找、相关一致性等,XML仅仅是展示数据。事实上XML与其他数据表现形式最大的不同是:他极其简单。这是一个看上去有点琐细的优点,但正是这点使XML与众不同。

XML的简单使其易于在任何应用程序中读写数据,这使XML很快成为数据交换的唯一公共语言,虽然不同的应用软件也支持其它的数据交换格式,但不久之后他们都将支持XML,那就意味着程序可以更容易的与Windows、Mac OS, Linux以及其他平台下产生的信息结合,然后可以很容易加载XML数据到程序中并分析他,并以XML格式输出结果。

XML的前身是SGML(The Standard Generalized Markup Language),是自IBM从60年代就开始发展的GML(Generalized Markup Language)

HTML一样, XML (可扩展标识语言)是通用标识语言标准(SGML)的一个子集,它是描述网络上的数据内容和结构的标准。尽管如此,XML不象HTML,HTML仅仅提供了在页面上显示信息的通用方法(没有上下文相关和动态功能) ,XML则对数据赋予上下文相关功能,它继承了SGML的大部分功能,却使用了不太复杂的技术。.

为了使得SGML显得用户友好,XML重新定义了SGML的一些内部值和参数,去掉了大量的很少用到的功能,这些繁杂的功能使得SGML在设计网站时显得复杂化。XML保留了SGML的结构化功能,这样就使得网站设计者可以定义自己的文档类型,XML同时也推出一种新型文档类型,使得开发者也可以不必定义文档类型。

因为XML是W3C制定的,XML的标准化工作由W3C的XML工作组负责,该小组成员由来自各个地方和行业的专家组成,他们通过email交流对XML标准的意见,并提出自己的看法 (www.w3.org/TR/WD-xml)。因为XML 是个公共格式, (它不专属于任何一家公司),你不必担心XML技术会成为少数公司的盈利工具,XML不是一个依附于特定浏览器的语言

XML(可扩展标记语言)是从称为SGML(标准通用标记语言)的更加古老的语言派生出来的。SGML的主要目的是定义使用标签来表示数据的标记语言的语法。

标签由包围在一个小于号(<)和一个大于号(>)之间的文本组成,例如<tag>。起始标签(start tag)表示一个特定区域的开始,例如<start>;结束标签(end tag)定义了一个区域的结束,除了在小于号之后紧跟着一个斜线(/)外,和起始标签基本一样,例如</end>。SGML还定义了标签的特性(attribute),它们是定义在小于号和大于号之间的值,例如<img src="picture.jpg">中的src特性。如果你觉得它看起来很熟悉的话,应该知道,基于SGML的语言的最著名实现就是原始的HTML。

SGML常用来定义针对HTML的文档类型定义(DTD),同时它也常用于编写XML的DTD。SGML的问题就在于,它允许出现一些奇怪的语法,这让创建HTML的解析器成为一个大难题:

1  某些起始标签不允许出现结束标签,例如HTML中<img>标签。包含了结束标签就会出现错误。

2  某些起始标签可以选择性出现结束标签或者隐含了结束标签,例如HTML中<p>标签,当出现另一个<p>标签或者某些其他标签时,便假设在这之前有一个结束标签。

3  某些起始标签要求必须出现结束标签,例如HTML中<script>标签。

4  标签可以以任何顺序嵌套。即使结束标签不按照起始标签的逆序出现也是允许的,例如,<b>This is a <i> sample </b> string</i>是正确的。

5  某些特性要求必须包含值,例如<img src="picture.jpg">中的src特性。

6  某些特性不要求一定有值,例如<td nowrap>中的nowrap特性。

7  定义特性的两边有没有加上双引号都是可以的,所以<img src="picture.jpg">和<img src=picture.jpg>都是允许的。

      这些问题使建立一个SGML语言的解析器变成了一项艰巨的任务。判断何时应用以上规则的困难导致了SGML语言的定义一直停滞不前。以这些问题作为出发点,XML逐渐步入我们的视野。

      XML去掉了之前令许多开发人员头疼的SGML的随意语法。在XML中,采用了如下的语法:

8  任何的起始标签都必须有一个结束标签。

9  可以采用另一种简化语法,可以在一个标签中同时表示起始和结束标签。这种语法是在大于符号之前紧跟一个斜线(/),例如<tag />。XML解析器会将其翻译成<tag></tag>。

10  标签必须按合适的顺序进行嵌套,所以结束标签必须按镜像顺序匹配起始标签,例如<b>this is a <i>sample</i> string</b>。这好比是将起始和结束标签看作是数学中的左右括号:在没有关闭所有的内部括号之前,是不能关闭外面的括号的。

11  所有的特性都必须有值。

12  所有的特性都必须在值的周围加上双引号。

这些规则使得开发一个XML解析器要简便得多,而且也除去了解析SGML中花在判断何时何地应用那些奇怪语法规则上的工作。仅仅在XML出现后的前六年就衍生出多种不同的语言,包括MathML、SVG、RDF、RSS、SOAP、XSLT、XSL-FO,而同时也将HTML改进为XHTML。

如果需要关于SGML和XML具体技术上的对比,请查看W3C的注解,位于:http://www.w3. org/TR/NOTE-sgml-xml.html

如今,XML已经是世界上发展最快的技术之一。它的主要目的是使用文本以结构化的方式来表示数据。在某些方面,XML文件也类似于数据库,提供数据的结构化视图。这里是一个XML文件的例子:


每个XML文档都由XML序言开始,在前面的代码中的第一行便是XML序言,<?xml version="1.0"?>。这一行代码会告诉解析器和浏览器,这个文件应该按照前面讨论过的XML规则进行解析。第二行代码,<books>,则是文档元素(document element),它是文件中最外面的标签(我们认为元素(element)是起始标签和结束标签之间的内容)。所有其他的标签必须包含在这个标签之内来组成一个有效的XML文件。XML文件的第二行并不一定要包含文档元素;如果有注释或者其他内容,文档元素可以迟些出现。

范例文件中的第三行代码是注释,你会发现它与HTML中使用的注释风格是一样的。这是XML从SGML中继承的语法元素之一。

页面再往下的一些地方,可以发现<desc>标签里有一些特殊的语法。<![CDATA[ ]]>代码用于表示无需进行解析的文本,允许诸如大于号和小于号之类的特殊字符包含在文本中,而无需担心破坏XML的语法。文本必须出现在<![CDATA[和]]>之间才能合适地避免被解析。这样的文本称为Character Data Section,简称CData Section。

下面的一行就是在第二本书的定义之前的:

<?page render multiple authors ?>

虽然它看上去很像XML序言,但实际上是一种称为处理指令(processing instruction)的不同类型的语法。处理指令(以下简称PI)的目的是为了给处理页面的程序(例如XML解析器)提供额外的信息。PI通常情况下是没有固定格式的,唯一的要求是紧随第一个问号必须至少有一个字母。在此之后,PI可以包含除了小于号和大于号之外的任何字符串序列。

最常见的PI是用来指定XML文件的样式表:



这个PI一般会直接放在XML序言之后,通常由Web浏览器使用,来将XML数据以特殊的样式显示出来。
posted @ 2008-05-06 14:09 矿矿 阅读(30) | 评论 (0)编辑 收藏
  2008年4月21日
//frame版程序源代码如下,疏漏之处,望批评指正。
//数字分组没有编写,科学型计算器没有编写,其他已经完善。
import java.awt.*;
import java.lang.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.text.DecimalFormat;
public class Calculator
implements ActionListener { //导入动作监听接口
//设计面板中的单位
JFrame frame;
JTextField textAnswer;
JPanel panel, panel1, panel2, panel3;
JMenuBar mainMenu;
JTextField textMemory;
JLabel labelMemSpace; //labelMemSpace单纯做摆设,控制面板的形状
JButton buttonBk, buttonCe, buttonC;
JButton button[];
JButton buttonMC, buttonMR, buttonMS, buttonMAdd;
JButton buttonDot, buttonAddAndSub, buttonAdd, buttonSub, buttonMul,
buttonDiv, buttonMod;
JButton buttonSqrt, buttonDao, buttonEqual;
JMenu editMenu, viewMenu, helpMenu;
JMenuItem copyItem, pasteItem, tItem, sItem, numberGroup, topHelp, aboutCal;
DecimalFormat df; //设置数据输出精度
boolean clickable; //控制当前能否按键
double memoryd; //使用内存中存储的数字
int memoryi;
double vard, answerd; //用来保存double型数据的中间值(vard)和最后结果(answerd)
short key = -1, prekey = -1; //key用来保存当前进行何种运算,prekey用来保存前次进行何种运算
String copy; //做复制用
JTextArea help; //帮助
JScrollPane scrollHelp;
//构造函数
public Calculator() {
clickable = true;
answerd = 0;
frame = new JFrame("计算器");
df = new DecimalFormat("0.##############"); //设置数据输出精度(对于double型值)
textAnswer = new JTextField(15);
textAnswer.setText("");
textAnswer.setEditable(false);
textAnswer.setBackground(new Color(255, 255, 255));
panel = new JPanel();
frame.getContentPane().add(panel);
panel1 = new JPanel();
panel2 = new JPanel();
panel.setLayout(new BorderLayout());
//设计整个面板
mainMenu = new JMenuBar();
editMenu = new JMenu("编辑(E)");
viewMenu = new JMenu("查看(V)");
helpMenu = new JMenu("帮助(H)");
copyItem = new JMenuItem(" 复制(C) Ctrl+C");
copyItem.addActionListener(this);
pasteItem = new JMenuItem(" 粘贴(V) Ctrl+V");
pasteItem.addActionListener(this);
editMenu.add(copyItem);
editMenu.add(pasteItem);
tItem = new JMenuItem("●标准型(T)");
tItem.addActionListener(this);
sItem = new JMenuItem(" 科学型(S)");
sItem.addActionListener(this);
numberGroup = new JMenuItem(" 数字分组(I)");
numberGroup.addActionListener(this);
viewMenu.add(tItem);
viewMenu.add(sItem);
viewMenu.add(numberGroup);
topHelp = new JMenuItem(" 帮助主题(H)");
topHelp.addActionListener(this);
help = new JTextArea(5, 20);
scrollHelp = new JScrollPane(help);
help.setEditable(false);
help.append("执行简单计算\n");
help.append("1. 键入计算的第一个数字。\n");
help.append("2. 单击“+”执行加、“-”执行减、“*”执行乘或“/”执行除。\n");
help.append("3. 键入计算的下一个数字。\n");
help.append("4. 输入所有剩余的运算符和数字。\n");
help.append("5. 单击“=”。\n");
aboutCal = new JMenuItem(" 关于计算器(A)");
aboutCal.addActionListener(this);
helpMenu.add(topHelp);
helpMenu.add(aboutCal);
mainMenu.add(editMenu);
mainMenu.add(viewMenu);
mainMenu.add(helpMenu);
panel.add(mainMenu, BorderLayout.NORTH);
panel.add(textAnswer, BorderLayout.CENTER);
panel.add(panel1, BorderLayout.SOUTH);
panel1.setLayout(new BorderLayout());
textMemory = new JTextField(3);
textMemory.setEditable(false);
textMemory.setBackground(new Color(217, 217, 217));
labelMemSpace = new JLabel(" ");
buttonBk = new JButton("Backspace");
buttonBk.setForeground(new Color(255, 0, 0));
buttonCe = new JButton("CE");
buttonCe.setForeground(new Color(255, 0, 0));
buttonC = new JButton("C");
buttonC.setForeground(new Color(255, 0, 0));
buttonBk.addActionListener(this);
buttonCe.addActionListener(this);
buttonC.addActionListener(this);
panel1.add(panel2, BorderLayout.NORTH);
panel2.setLayout(new FlowLayout(FlowLayout.RIGHT));
panel2.add(textMemory);
panel2.add(labelMemSpace);
panel2.add(buttonBk);
panel2.add(buttonCe);
panel2.add(buttonC);
panel3 = new JPanel();
panel1.add(panel3, BorderLayout.CENTER);
button = new JButton[10];
for (int i = 0; i < button.length; i++) {
button[i] = new JButton(Integer.toString(i));
button[i].setForeground(new Color(0, 0, 255));
}
buttonMC = new JButton("MC");
buttonMC.setForeground(new Color(255, 0, 0));
buttonMR = new JButton("MR");
buttonMR.setForeground(new Color(255, 0, 0));
buttonMS = new JButton("MS");
buttonMS.setForeground(new Color(255, 0, 0));
buttonMAdd = new JButton("M+");
buttonMAdd.setForeground(new Color(255, 0, 0));
buttonDot = new JButton(".");
buttonDot.setForeground(new Color(0, 0, 255));
buttonAddAndSub = new JButton("+/-");
buttonAddAndSub.setForeground(new Color(0, 0, 255));
buttonAdd = new JButton("+");
buttonAdd.setForeground(new Color(255, 0, 0));
buttonSub = new JButton("-");
buttonSub.setForeground(new Color(255, 0, 0));
buttonMul = new JButton("*");
buttonMul.setForeground(new Color(255, 0, 0));
buttonDiv = new JButton("/");
buttonDiv.setForeground(new Color(255, 0, 0));
buttonMod = new JButton("%");
buttonMod.setForeground(new Color(0, 0, 255));
buttonSqrt = new JButton("sqrt");
buttonSqrt.setForeground(new Color(0, 0, 255));
buttonDao = new JButton("1/x");
buttonDao.setForeground(new Color(0, 0, 255));
buttonEqual = new JButton("=");
buttonEqual.setForeground(new Color(255, 0, 0));
//将所有行为与监听绑定
panel3.setLayout(new GridLayout(4, 6));
panel3.add(buttonMC);
buttonMC.addActionListener(this);
panel3.add(button[7]);
button[7].addActionListener(this);
panel3.add(button[8]);
button[8].addActionListener(this);
panel3.add(button[9]);
button[9].addActionListener(this);
panel3.add(buttonDiv);
buttonDiv.addActionListener(this);
panel3.add(buttonSqrt);
buttonSqrt.addActionListener(this);
panel3.add(buttonMR);
buttonMR.addActionListener(this);
panel3.add(button[4]);
button[4].addActionListener(this);
panel3.add(button[5]);
button[5].addActionListener(this);
panel3.add(button[6]);
button[6].addActionListener(this);
panel3.add(buttonMul);
buttonMul.addActionListener(this);
panel3.add(buttonMod);
buttonMod.addActionListener(this);
panel3.add(buttonMS);
buttonMS.addActionListener(this);
panel3.add(button[1]);
button[1].addActionListener(this);
panel3.add(button[2]);
button[2].addActionListener(this);
panel3.add(button[3]);
button[3].addActionListener(this);
panel3.add(buttonSub);
buttonSub.addActionListener(this);
panel3.add(buttonDao);
buttonDao.addActionListener(this);
panel3.add(buttonMAdd);
buttonMAdd.addActionListener(this);
panel3.add(button[0]);
button[0].addActionListener(this);
panel3.add(buttonAddAndSub);
buttonAddAndSub.addActionListener(this);
panel3.add(buttonDot);
buttonDot.addActionListener(this);
panel3.add(buttonAdd);
buttonAdd.addActionListener(this);
panel3.add(buttonEqual);
buttonEqual.addActionListener(this);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.pack();
frame.show();
}
//设置各个按钮行为
public void actionPerformed(ActionEvent event) {
boolean sign = false; //判断是否是double型数参与运算,是为true,不是为false
Object temp = event.getSource();
try {
//如果按下数据按钮,将按下的按钮代表的数据插入的当前文本框字符串之后
for (int i = 0; i <= 9; i++)
if (temp == button[i] && clickable == true)
textAnswer.setText(textAnswer.getText() + Integer.toString(i));
//按下'.'按钮时,判断当前文本框内字符串中含不含'.',如果已含,则不允许再插入'.'
if (temp == buttonDot && clickable == true) {
boolean isDot = false;
if (textAnswer.getText().length() == 0)
isDot = true;
for (int i = 0; i < textAnswer.getText().length(); i++)
if ('.' == textAnswer.getText().charAt(i)) {
isDot = true;
break;
}
if (isDot == false)
textAnswer.setText(textAnswer.getText() + ".");
}
if ( (temp == buttonAdd || temp == buttonSub || temp == buttonMul ||
temp == buttonDiv) && clickable == true) {
//'+'操作
if (temp == buttonAdd) {
switch (prekey) {
case 0:
answerd += Double.parseDouble(textAnswer.getText());
break;
case 1:
answerd -= Double.parseDouble(textAnswer.getText());
break;
case 2:
answerd *= Double.parseDouble(textAnswer.getText());
break;
case 3:
if (Double.parseDouble(textAnswer.getText()) == 0) {
textAnswer.setText("除数不能为零");
clickable = false;
}
else
answerd /= Double.parseDouble(textAnswer.getText());
break;
default:
answerd = Double.parseDouble(textAnswer.getText());
}
textAnswer.setText("");
prekey = key = 0;
}
//'-'操作
if (temp == buttonSub) {
switch (prekey) {
case 0:
answerd += Double.parseDouble(textAnswer.getText());
break;
case 1:
answerd -= Double.parseDouble(textAnswer.getText());
break;
case 2:
answerd *= Double.parseDouble(textAnswer.getText());
break;
case 3:
if (Double.parseDouble(textAnswer.getText()) == 0) {
textAnswer.setText("除数不能为零");
clickable = false;
}
else
answerd /= Double.parseDouble(textAnswer.getText());
break;
default:
answerd = Double.parseDouble(textAnswer.getText());
}
textAnswer.setText("");
prekey = key = 1;
}
//'*'操作
if (temp == buttonMul) {
switch (prekey) {
case 0:
answerd += Double.parseDouble(textAnswer.getText());
break;
case 1:
answerd -= Double.parseDouble(textAnswer.getText());
break;
case 2:
answerd *= Double.parseDouble(textAnswer.getText());
break;
case 3:
if (Double.parseDouble(textAnswer.getText()) == 0) {
textAnswer.setText("除数不能为零");
clickable = false;
}
else
answerd /= Double.parseDouble(textAnswer.getText());
break;
default:
answerd = Double.parseDouble(textAnswer.getText());
}
textAnswer.setText("");
prekey = key = 2;
}
//'/'操作
if (temp == buttonDiv) {
switch (prekey) {
case 0:
answerd += Double.parseDouble(textAnswer.getText());
break;
case 1:
answerd -= Double.parseDouble(textAnswer.getText());
break;
case 2:
answerd *= Double.parseDouble(textAnswer.getText());
break;
case 3:
if (Double.parseDouble(textAnswer.getText()) == 0) {
textAnswer.setText("除数不能为零");
clickable = false;
}
else
answerd /= Double.parseDouble(textAnswer.getText());
break;
default:
answerd = Double.parseDouble(textAnswer.getText());
}
textAnswer.setText("");
prekey = key = 3;
}
}
//'='操作
if (temp == buttonEqual && clickable == true) {
//如果连续按'=',则进行连续运算
if (prekey == 5) {
if (key == 0) {
answerd += vard;
textAnswer.setText(df.format(answerd));
}
if (key == 1) {
answerd -= vard;
textAnswer.setText(df.format(answerd));
}
if (key == 2) {
answerd *= vard;
textAnswer.setText(df.format(answerd));
}
if (key == 3) {
if (Double.parseDouble(textAnswer.getText()) == 0) {
textAnswer.setText("除数不能为零");
clickable = false;
}
else {
answerd /= vard;
textAnswer.setText(df.format(answerd));
}
}
}
else {
vard = Double.parseDouble(textAnswer.getText());
if (key == 0) {
prekey = -1;
answerd += Double.parseDouble(textAnswer.getText());
textAnswer.setText(df.format(answerd));
}
if (key == 1) {
prekey = -1;
answerd -= Double.parseDouble(textAnswer.getText());
textAnswer.setText(df.format(answerd));
}
if (key == 2) {
prekey = -1;
answerd *= Double.parseDouble(textAnswer.getText());
textAnswer.setText(df.format(answerd));
}
if (key == 3) {
prekey = -1;
if (Double.parseDouble(textAnswer.getText()) == 0) {
textAnswer.setText("除数不能为零");
clickable = false;
}
else {
answerd /= Double.parseDouble(textAnswer.getText());
textAnswer.setText(df.format(answerd));
}
}
}
prekey = 5;
}
//'%'操作,对第二个操作数除以100
if (temp == buttonMod && clickable == true) {
if (answerd == 0) {
String s = textAnswer.getText();
textAnswer.setText(s);
}
else {
boolean isDot = false;
for (int i = 0; i < textAnswer.getText().length(); i++)
if ('.' == textAnswer.getText().charAt(i)) {
isDot = true;
break;
}
//如果是double数,除100
if (isDot == true) {
double dtemp = Double.parseDouble(textAnswer.getText());
dtemp = dtemp / 100.0;
textAnswer.setText(Double.toString(dtemp));
}
else {
//如果是int数但能被100整除,则去掉末尾两个零
if (Integer.parseInt(textAnswer.getText()) % 100 == 0) {
int itemp = Integer.parseInt(textAnswer.getText());
itemp /= 100;
textAnswer.setText(Integer.toString(itemp));
}
//如果是int数,但不能被100整除,则按double数处理
else {
double dtemp = Double.parseDouble(textAnswer.getText());
dtemp = dtemp / 100.0;
textAnswer.setText(Double.toString(dtemp));
}
}
}
}
//开根号运算
if (temp == buttonSqrt && clickable == true) {
String s = textAnswer.getText();
if (s.charAt(0) == '-') {
textAnswer.setText("负数不能开根号");
clickable = false;
}
else
textAnswer.setText(Double.toString(java.lang.Math.sqrt(Double.
parseDouble(textAnswer.getText()))));
}
//倒数运算
if (temp == buttonDao && clickable == true) {
if (textAnswer.getText().charAt(0) == '0' &&
textAnswer.getText().length() == 1) {
textAnswer.setText("零不能求倒数");
clickable = false;
}
else {
boolean isDec = true;
int i, j, k;
String s = Double.toString(1 / Double.parseDouble(textAnswer.getText()));
for (i = 0; i < s.length(); i++)
if (s.charAt(i) == '.')
break;
for (j = i + 1; j < s.length(); j++)
if (s.charAt(j) != '0') {
isDec = false;
break;
}
if (isDec == true) {
String stemp = "";
for (k = 0; k < i; k++)
stemp += s.charAt(k);
textAnswer.setText(stemp);
}
else
textAnswer.setText(s);
}
}
//按下'+/-'按钮时处理
if (temp == buttonAddAndSub && clickable == true) {
boolean isNumber = true;
String s = textAnswer.getText();
for (int i = 0; i < s.length(); i++)
if (! (s.charAt(i) >= '0' && s.charAt(i) <= '9' || s.charAt(i) == '.' ||
s.charAt(i) == '-')) {
isNumber = false;
break;
}
if (isNumber == true) {
//如果当前字符串首字母有'-'号,代表现在是个负数,再按下时,则将首符号去掉
if (s.charAt(0) == '-') {
textAnswer.setText("");
for (int i = 1; i < s.length(); i++) {
char a = s.charAt(i);
textAnswer.setText(textAnswer.getText() + a);
}
}
//如果当前字符串第一个字符不是符号,则添加一个符号在首字母处
else
textAnswer.setText('-' + s);
}
}
//计算器有关内存操作
//'MC'的操作,将内存清0
if (temp == buttonMC && clickable == true) {
memoryd = memoryi = 0;
textMemory.setText("");
}
//'MS'的操作,将当前文本框内容保存入内存,显示'M'
if (temp == buttonMS && clickable == true) {
boolean isDot = false;
textMemory.setText(" M");
for (int i = 0; i < textAnswer.getText().length(); i++)
if ('.' == textAnswer.getText().charAt(i)) {
isDot = true;
break;
}
//如果是double,则存入memoryd(double存储器)
if (isDot == true) {
memoryd = Double.parseDouble(textAnswer.getText());
memoryi = 0; //保证存储器中存放最新的值
}
//如果是int,则存入memoryi(int存储器)
else {
memoryi = Integer.parseInt(textAnswer.getText());
memoryd = 0; //保证存储器中存放最新的值
}
}
//'MR'的操作,将存储器中的信息输出
if (temp == buttonMR && clickable == true) {
if (memoryd != 0)
textAnswer.setText(Double.toString(memoryd));
if (memoryi != 0)
textAnswer.setText(Integer.toString(memoryi));
}
//'M+'的功能,将当前文本框里的数据和存储器中数据相加后,再存入存储器
if (temp == buttonMAdd && clickable == true) {
boolean isDot = false;
for (int i = 0; i < textAnswer.getText().length(); i++)
if ('.' == textAnswer.getText().charAt(i)) {
isDot = true;
break;
}
if (memoryi != 0) { //存储中是一个int型数
if (isDot == false) //被加数是一个int型数
memoryi += Integer.parseInt(textAnswer.getText());
else { //被加数是一个double型数,则将int存储器中数传入double存储器与当前数相加,int存储器清零
memoryd = memoryi + Double.parseDouble(textAnswer.getText());
memoryi = 0;
}
}
else
memoryd += Double.parseDouble(textAnswer.getText());
}
//按下'Backspace'键,利用循环将当前字符串中的最后一个字母删除
if (temp == buttonBk && clickable == true) {
String s = textAnswer.getText();
textAnswer.setText("");
for (int i = 0; i < s.length() - 1; i++) {
char a = s.charAt(i);
textAnswer.setText(textAnswer.getText() + a);
}
}
//按下'CE'按钮,将当前文本框内数据清除
if (temp == buttonCe) {
textAnswer.setText("");
clickable = true;
}
//按下'C'按钮,文本框内数据清除,同时var,answer清0
if (temp == buttonC) {
vard = answerd = 0;
textAnswer.setText("");
clickable = true;
}
//按下'复制'菜单栏
if (temp == copyItem) {
copy = textAnswer.getText();
}
//按下'粘贴'菜单栏
if (temp == pasteItem) {
textAnswer.setText(copy);
}
if (temp == sItem) {
JOptionPane.showMessageDialog(panel, "当前是标准型计算器,\n科学型计算器有待更新。");
}
//按下'帮助主题'菜单栏
if (temp == topHelp) {
JOptionPane.showMessageDialog(panel, scrollHelp);
}
//按下'数字分组'菜单栏
if (temp == numberGroup) {
if (numberGroup.getText().compareTo(" 数字分组(I)") == 0)
numberGroup.setText("√数字分组(I)");
else
numberGroup.setText(" 数字分组(I)");
}
//按下'关于'菜单栏
if (temp == aboutCal) {
JOptionPane.showMessageDialog(panel, "计算器1.00版\n开发者:矿矿");
}
}
//输入中如果有操作非法,比如按下两次'+',捕获异常
catch (Exception e) {
textAnswer.setText("操作非法");
clickable = false;
}
}
//主函数
public static void main(String args[]) {
new Calculator();
}
}
posted @ 2008-04-21 20:44 矿矿 阅读(601) | 评论 (2)编辑 收藏
  2008年4月18日
package t06;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Toolkit;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;

public class Demo extends JFrame{

    Container contentPane;
    ImageIcon img = new ImageIcon("002.jpg");
   
    JPanel paneTop = new JPanel();
    JPanel paneMid = new JPanel();
    JPanel paneBut = new JPanel();
    JPanel paneAll = new JPanel();
   
    JLabel lblTop = new JLabel();
    JLabel lblName = new JLabel();
    JLabel lblPwd = new JLabel();
    JLabel lblApply = new JLabel();
    JLabel lblForget = new JLabel();
    JLabel lblModel = new JLabel();
    JLabel lblNull = new JLabel();
   
    JTextField txtName = new JTextField(15);
    JPasswordField txtPwd = new JPasswordField(15);
   
    JComboBox cmb = new JComboBox();
   
    JCheckBox chk = new JCheckBox();
   
    JButton btnKill = new JButton("查杀木马");
    JButton btnSet = new JButton("设置");
    JButton btnLogin = new JButton("登录");
   
   
   
    Demo(){
        lblTop.setIcon(img);
        paneTop.add(lblTop);
       
        lblName.setText("QQ帐号:");
        lblApply.setText("申请帐号   ");
        lblPwd.setText("QQ密码:");
        lblForget.setText("忘记密码?");
        lblModel.setText("状态:");
       
        String[] s1 = {"隐身","在线","忙碌"};
        cmb.addItem(s1[0]);
        cmb.addItem(s1[1]);
        cmb.addItem(s1[2]);
       
        chk.setText("自动登录");
       
        paneMid.add(lblName);
        paneMid.add(txtName);
        paneMid.add(lblApply);
       
        paneMid.add(lblPwd);
        paneMid.add(txtPwd);
        paneMid.add(lblForget);
       
        paneMid.add(lblModel);
        paneMid.add(cmb);
        paneMid.add(chk);
       
        paneBut.add(btnKill);
        paneBut.add(btnSet);
        paneBut.add(btnLogin);
       
        contentPane = this.getContentPane();
       
        contentPane.add(paneTop,BorderLayout.NORTH);
        contentPane.add(paneMid,BorderLayout.CENTER);
        contentPane.add(paneBut,BorderLayout.SOUTH);
       
       
       
        setTitle("欢迎使用QQ");
        setSize(330,240);
        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
        setLocation((screen.width - getSize().width)/2,(screen.height - getSize().height)/2 );
        setVisible(true);
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);       
    }
   
    public static void main(String args[]){
        Demo d = new Demo();
    }
   
}


posted @ 2008-04-18 21:42 矿矿 阅读(1673) | 评论 (10)编辑 收藏
  2008年4月8日
Java语言中, abstract class 和在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的对系统设计人员来讲就不那么重要了;而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程我想就是指按照这种思想来编程吧!实际上,在日常工作中,你已经按照接口编程了,只不过如果你没有这方面的意识,那么你只是在被动的实现这一思想;表现在频繁的抱怨别人改的代码影响了你(接口没有设计到),表现在某个模块的改动引起其他模块的大规模调整(模块接口没有很好的设计)等等。

  Booch先生那天谈到Interaction Designer,它就是指做这类设计的人,只不过层次更高一些。我想目前我们的软件设计队伍中,这类人是最缺乏的人才之一。

  非接口编程?是不是就是面向过程的编程思想?

  1.关于接口的理解。

  接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。

  我们在一般实现一个系统的时候,通常是将定义与实现合为一体,不加分离的,我认为最为理解的系统设计规范应是所有的定义与实现分离,尽管这可能对系统中的某些情况有点繁烦。

  接口的本身反映了系统设计人员对系统的抽象理解。

  接口应有两类:第一类是对一个体的抽象,它可对应为一个抽象体(abstract class);

  第二类是对一个体某一方面的抽象,即形成一个抽象面(interface);

  一个体有可能有多个抽象面。

  抽象体与抽象面是有区别的。

  2.设计接口的另一个不可忽视的因素是接口所处的环境(context,environment),系统论的观点:环境是系统要素所处的空间与外部影响因素的总和。任何接口都是在一定的环境中产生的。因此环境的定义及环境的变化对接口的影响是不容忽视的,脱离原先的环境,所有的接口将失去原有的意义。

  3.按照组件的开发模型(3C),它们三者相辅相成,各司一面,浑然一体,缺一不可。

  面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法

  面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现

  接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题

  我认为:UML里面所说的interface是协议的另一种说法。并不是指com的interface,CORBA的interface,Java的interface,Delphi的interface,人机界面的interface或NIC的interface。

  在具体实现中,是可以把UML的interface实现为语言的interface,分布式对象环境的interface或其它什么interface,但就理解UML的interface而言,指的是系统每部分的实现和实现之间,通过interface所确定的协议来共同工作。

  所以我认为,面向interface编程,原意是指面向抽象协议编程,实现者在实现时要严格按协议来办。也就是Bill Joy同志说的,一边翻rfc,一边写代码的意思。面向对象编程是指面向抽象和具象。抽象和具象是矛盾的统一体,不可能只有抽象没有具象。一般懂得抽象的人都明白这个道理。 但有的人只知具象却不知抽象为何物。

  所以只有interface没有实现,或只有实现而没有interface者是没有用的,反OO的。

  所以还是老老实实面向对象编程,面向协议编程,或者什么都不面向,老老实实编程。

是支持抽象类定义的两种机制。正是由于这两种机制的存在,才赋予了Java强大的 面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的相似性,甚至可以相互替换,因此很多开发者在进 行抽象类定义时对于abstract class和interface的选择显得比较随意。其实,两者之间还是有很大的区别的,对于它们的选择甚至反映出对 于问题领域本质的理解、对于设计意图的理解是否正确、合理。本文将对它们之间的区别进行一番剖析,试图给开发者提供一个在二者之间进行选择的依据。

  理解抽象类

  abstract class和interface在Java语言中都是用来进行抽象类(本文 中的抽象类并非从abstract class翻译而来,它表示的是一个抽象体,而abstract class为Java语言中用于定义抽象类的一种方法, 请读者注意区分)定义的,那么什么是抽象类,使用抽象类能为我们带来什么好处呢?

  在 面向对象的概念中,我们知道所有的对象都是通过类来描绘的,但是反过来却不是这样。并不是 所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类往往用来表征我们在对问题领域进行分析、 设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。比如:如果我们进行一个图形编辑软件的开发,就会发现问题领域存在着圆、 三角形这样一些具体概念,它们是不同的,但是它们又都属于形状这样一个概念,形状这个概念在问题领域是不存在的,它就是一个抽象概念。正是因为抽象的概念 在问题领域没有对应的具体概念,所以用以表征抽象概念的抽象类是不能够实例化的。

  在面向对象领域,抽象类主要用来进行类型隐藏。 我们可以构造出一个固定的一组行为的抽象描 述,但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类,而这一组任意个可能的具体实现则表现为所有可能的派生类。模块可以操作一个 抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允许修改的;同时,通过从这个抽象体派生,也可扩展此模块的行为功能。熟悉OCP的读者一定知 道,为了能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle),抽象类是其中的关键所在。

  从语法定义层面看abstract class 和 interface

  在语法层面,Java语言对于abstract class和interface给出了不同的定义方式,下面以定义一个名为Demo的抽象类为例来说明这种不同。

  使用abstract class的方式定义Demo抽象类的方式如下:

abstract class Demo{
abstract void method1();
abstract void method2();


  使用interface的方式定义Demo抽象类的方式如下:

interface Demo{
void method1();
void method2();

}

  在abstract class方式中,Demo可以有自己的数据成员,也可以有非 abstract的成员方法,而在interface方式的实现中,Demo只能够有静态的不能被修改的数据成员(也就是必须是static final 的,不过在interface中一般不定义数据成员),所有的成员方法都是abstract的。从某种意义上说,interface是一种特殊形式的 abstract class。

  从编程的角度来看,abstract class和interface都可以用来实现 "design by contract" 的思想。但是在具体的使用上面还是有一些区别的。

  首先,abstract class 在 Java 语言中表示的是一种继承关系,一个类只能使用一次继承关系(因为Java不支持多继承 -- 转注)。但是,一个类却可以实现多个interface。也许,这是Java语言的设计者在考虑Java对于多重继承的支持方面的一种折中考虑吧。

  其次,在abstract class的定义中,我们可以赋予方法的默认行为。但是在interface的定义中,方法却不能拥有默认行为,为了绕过这个限制,必须使用委托,但是这会增加一些复杂性,有时会造成很大的麻烦。

  在 抽象类中不能定义默认行为还存在另一个比较严重的问题,那就是可能会造成维护上的麻烦。因 为如果后来想修改类的界面(一般通过 abstract class 或者interface来表示)以适应新的情况(比如,添加新的方法或者给已用的方法中添 加新的参数)时,就会非常的麻烦,可能要花费很多的时间(对于派生类很多的情况,尤为如此)。但是如果界面是通过abstract class来实现的,那 么可能就只需要修改定义在abstract class中的默认行为就可以了。

  同样,如果不能在抽象类中定义默认行为,就会导致同样的方法实现出现在该抽象类的每一个派生类中,违反了 "one rule,one place" 原则,造成代码重复,同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心。

  从设计理念层面看 abstract class 和 interface

  上面主要从语法定义和编程的角度论述了abstract class和interface的区 别,这些层面的区别是比较低层次的、非本质的。本小节将从另一个层面:abstract class和interface所反映出的设计理念,来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概念的本质所在。

  前面已经提到过,abstract class在Java语言中体现了一种继承关系,要想使得 继承关系合理,父类和派生类之间必须存在"is-a"关系,即父类和派生类在概念本质上应该是相同的。对于interface来说则不然,并不要求interface的实现者和interface定义在概念本质上是一致的, 仅仅是实现了interface定义的契约而已。为了使论述便于理解,下面将通过一个简单的实例进行说明。

  考虑这样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Door具有执行两个动作open和close,此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型,定义方式分别如下所示:

  使用abstract class方式定义Door:

abstract class Door{
abstract void open();
abstract void close();
}

  使用interface方式定义Door:

interface Door{
void open();
void close();
}

  其他具体的Door类型可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract class和interface没有大的区别。

  如果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢(在本例中, 主要是为了展示 abstract class 和interface 反映在设计理念上的区别,其他方面无关的问题都做了简化或者忽略)?下面将罗列出可能的解 决方案,并从设计理念层面对这些不同的方案进行分析。

  解决方案一:

  简单的在Door的定义中增加一个alarm方法,如下:

abstract class Door{
abstract void open();
abstract void close();
abstract void alarm();
}

  或者

interface Door{
void open();
void close();
void alarm();
}

  那么具有报警功能的AlarmDoor的定义方式如下:

class AlarmDoor extends Door{
void open(){…}
void close(){…}
void alarm(){…}
}

  或者

class AlarmDoor implements Door{
void open(){…}
void close(){…}
void alarm(){…}

  这种方法违反了面向对象设计中的一个核心原则 ISP (Interface Segregation Principle),在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方 法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变(比如:修改alarm方法的参数)而改变,反 之依然。

  解决方案二:

  既然open、close和alarm属于两个不同的概念,根据ISP原则应该把它们分别定 义在代表这两个概念的抽象类中。定义方式有:这两个概念都使用 abstra