-
JAVA与正则表达式(一年级)
2011-05-05 22:56:14
转贴:http://blog.csdn.net/yqj2065/archive/2005/01/20/261790.aspx
§1黑暗岁月
有一个String,如何查询其中是否有y和f字符?最黑暗的办法就是:
程序1:我知道if、for语句和charAt()啊。
class Test{
public static void main(String args[]) {
String str="For my money, the important thing "+
"about the meeting was bridge-building";
char x='y';
char y='f';
boolean result=false;
for(int i=0;i<str.length();i++){
char z=str.charAt(i); //System.out.println(z);
if(x==z||y==z) {
result=true;
break;
}
else result=false;
}
System.out.println(result);
}
}
好像很直观,但这种方式难以应付复杂的工作。如查询一段文字中,是否有is?是否有thing或ting等。这是一个讨厌的工作。
§2 Java的java.util.regex包
按照面向对象的思路,把希望查询的字符串如is、thing或ting封装成一个对象,以这个对象作为模板去匹配一段文字,就更加自然了。作为模板的那个东西就是下面要讨论的正则表达式。先不考虑那么复杂,看一个例子:
程序2:不懂。先看看可以吧?
import java.util.regex.*;
class Regex1{
public static void main(String args[]) {
String str="For my money, the important thing "+
"about the meeting was bridge-building";
String regEx="a|f"; //表示a或f
Pattern p=Pattern.compile(regEx);
Matcher m=p.matcher(str);
boolean result=m.find();
System.out.println(result);
}
}
如果str匹配regEx,那么result为true,否则为flase。如果想在查找时忽略大小写,则可以写成:
Pattern p=Pattern.compile(regEx,Pattern.CASE_INSENSITIVE);
虽然暂时不知道Pattern(模板、模式)和Matcher(匹配器)的细节,程序的感觉就比较爽,如果先查询is、后来又要查询thing或ting,我们只需要修改一下模板Pattern,而不是考虑if语句和for语句,或者通过charAt()。
1、写一个特殊的字符串——正则表达式如a|f。
2、将正则表达式编译成一个模板:p
3、用模板p去匹配字符串str。
思路清楚了,现在看Java是如何处理的(Java程序员直到JDK1.4才能使用这些类。
§3 Pattern类与查找
①public final class java.util.regex.Pattern是正则表达式编译后的表达法。下面的语句将创建一个Pattern对象并赋值给句柄p:Pattern p=Pattern.compile(regEx);
有趣的是,Pattern类是final类,而且它的构造器是private。也许有人告诉你一些设计模式的东西,或者你自己查有关资料。这里的结论是:Pattern类不能被继承,我们不能通过new创建Pattern类的对象。
因此在Pattern类中,提供了2个重载的静态方法,其返回值是Pattern对象(的引用)。如:
public static Pattern compile(String regex) {
return new Pattern(regex, 0);
}
当然,我们可以声明Pattern类的句柄,如Pattern p=null;
②p.matcher(str)表示以用模板p去生成一个字符串str的匹配器,它的返回值是一个Matcher类的引用,为什么要这个东西呢?按照自然的想法,返回一个boolean值不行吗?
我们可以简单的使用如下方法:
boolean result=Pattern.compile(regEx).matcher(str).find();
呵呵,其实是三个语句合并的无句柄方式。无句柄常常不是好方式。后面再学习Matcher类吧。先看看regEx——这个怪咚咚。
§4 正则表达式之限定符
正则表达式(Regular Expression)是一种生成字符串的字符串。晕吧。比如说,String regEx="me+";这里字符串me+能够生成的字符串是:me、mee、meee、meeeeeeeeee等等,一个正则表达式可能生成无穷的字符串,所以我们不可能(有必要吗?)输出正则表达式产生的所有东西。
反过来考虑,对于字符串:me、mee、meee、meeeeeeeeee等等,我们能否有一种语言去描述它们呢?显然,正则表达式语言是这种语言,它是一些字符串的模式——简洁而深刻的描述。
我们使用正则表达式,用于字符串查找、匹配、指定字符串替换、字符串分割等等目的。
生成字符串的字符串——正则表达式,真有些复杂,因为我们希望由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)描述任意的字符串,而且要准确。
先搞几个正则表达式例子:
程序3:我们总用这个程序测试正则表达式。
import java.util.regex.*;
class Regex1{
public static void main(String args[]) {
String str="For my money, the important thing ";
String regEx="ab*";
boolean result=Pattern.compile(regEx).matcher(str).find();
System.out.println(result);
}
}//ture
①"ab*"——能匹配a、ab、abb、abbb……。所以,*表示前面字符可以有零次或多次。如果仅仅考虑查找,直接用"a"也一样。但想想替换的情况。 问题regEx="abb*"结果如何?
②"ab+"——能匹配ab、abb、abbb……。等价于"abb*"。问题regEx="or+"结果如何?
③"or?"——能匹配o和or。? 表示前面字符可以有零次或一次。
这些限定符*、+、?方便地表示了其前面字符(子串)出现的次数(我们用{}来描述):
x*
零次或多次 ≡{0,}
x+
一次或多次 ≡{1,}
x?
零次或一次 ≡{0,1}
x{n}
n次(n>0)
x{n,m}
最少n次至最多m次(0<n<m)
x{n,}
最少n次,
现在我们知道了连续字符串的查找、匹配。下面的是一些练习题:
①查找粗体字符串(不要求精确或要求精确匹配),写出其正则表达式:
str
regEX(不要求精确)
regEX(要求精确)
试一试
abcffd
b或bcff或bcf*或bc*或bc+
-
java按值传递还是按引用传递小结
2011-05-05 22:59:43
转贴:http://blog.csdn.net/yqj2065/archive/2008/11/12/3279116.aspxCSDN上的一篇《java按值传递还是按引用传递详细解说》,于是发了一个帖子,看看CSDN上的反映,
为什么? 关于Java只有按值传递
-----------------------------------------------------------------------------
Java只有按值传递,但是看见一些人反复讨论这个问题,不禁要问一下为什么?
1、说“按引用传递”的人也是经过思考的,是不是他们使用了不同的术语,或者他们的术语不同于我们的术语?
2、说“按引用传递”的人,有哪些典型人物?
我知道的有TIJ,忘记第几版了,最新版改了没有,知道的说一下。
还有CSDN上的一篇《java按值传递还是按引用传递详细解说》
有没有正规教材上说“按引用传递”的?
3、C语言也讨论“按引用传递”这个问题吗?
4、为什么“按引用传递”是错误的?[不要讨论它错误之处,而是问一问他们的思路为什么错误】?--------------------------------------------------------------------
反馈如下:
1、有人说:
1 我把房子搬着,然后把房子给你,这就是传值
2 我把写有房子地址的纸条给你,这就是传引用房子、纸条寓意很好,直观。可以借鉴。虽然他的概念错误。
2、《详细解说》不看也罢,都是术语混用带来的问题,一点不新鲜。
3、Thinking in Java作者居然在第4版还坚持“按引用传递”,有一天他会后悔的。关于Thinking in Java,假设世界上没有C++,只有C和fortran语言,我不知道他说的那些东西那里准确.
4、“问题还是出在java设计时的术语选择上,比如Object obj;把这个obj称为“引用”,同时强调传参数时不是"pass by reference",本身就怪怪的。”术语混用带来的问题,注意永远不能够混用变量和它的值。
int i;i是值吗?不是。
Object obj;obj是值(引用)吗?不是。要强调这一点!
5、我说的:Java中接口的术语也讨厌的很,因为我们在非Java的环境中广泛使用的接口概念遇到它的干扰。
虽然Java中接口的确是个很好的术语。6、【《java2入门经典》也说的是基本类型传的是值得副本,对象传的引用的副本。在那一页,我忘了,反正着本书讲的挺好的,用了3页讲这个知识点,还带图着呢,】传的引用的副本,没有问题。他理解出问题了。
7、注意:
对比几种译本 VS 原版讲解
基础概念 Vs 奇技淫巧(茴香豆的第五种写法)
8、传引用 VS 传的是Java引用foo(int i){}
obj.foo(jjjj)我送你一个盒子jjjj如果我把jjjj这个盒子搬着,然后把盒子给你,典型的传引用!
9、“无视这个问题就行了”,常见的说法,为什么会这样?考虑,,10、“他们有争议的,是这种传递方式的抽象命名而已.”
这是一句话就能够解决的问题,“按引用传递”是各种各样不同语言的传参数的方式之一,意思是方法操作实参本身.Java的引用和C语言的指针,它们都是copy后传递的.
11、“可能誤解,就由這種高深見解而來的
引用也是一個值,只是對引用的操作即是對引用所對應的實際對象進行操作而己
從來java中就不能直接對對象進行操,只能以引用進行
你何時傳遞過對象了?”这个正解。12、“我了解的是基本类型按值传递,对象是引用传递。”、“Java只有按值传递?谁说的???”毒害很广,
13、“JAVA中当然有搬房子啊! 比如数字1,作为参数传递时”,提醒了我,需要介绍参数传递的来源,它为什么重要?因为模块化。
int i =5;
A a = new A();
obj.doSth(i);//doSth把纸条加10
obj.doOtherSth(a);//doOtherSth把a指向我自己买的房子,
print(i);//5 VS 15?
a.装修();// 我自己 Vs 你写的
-
JAVA如何调用DOS命令
2011-09-13 22:54:05
用Java编写应用时,有时需要在程序中调用另一个现成的可执行程序或系统命令,这时可以通过组合使用Java提供的Runtime类和Process类的方法实现。下面是一种比较典型的程序模式:
...
Process process = Runtime.getRuntime().exec(".\\p.exe");
process.waitfor( );
...
在 上面的程序中,第一行的“.\\p.exe”是要执行的程序名,Runtime.getRuntime()返回当前应用程序的Runtime对象,该对象 的exec()方法指示Java虚拟机创建一个子进程执行指定的可执行程序,并返回与该子进程对应的Process对象实例。通过Process可以控制 该子进程的执行或获取该子进程的信息。第二条语句的目的等待子进程完成再往下执行。
但在windows平台上,如果处理不当,有时并不能得到预期的结果。下面是笔者在实际编程中总结的几种需要注意的情况:
1、执行DOS的内部命令
如 果要执行一条DOS内部命令,有两种方法。一种方法是把命令解释器包含在exec()的参数中。例如,执行dir命令,在NT上, 可写成exec("cmd.exe /c dir"),在windows 95/98下,可写成“command.exe /c dir”,其中参数“/c”表示命令执行后关闭Dos立即关闭窗口。另一种方法是,把内部命令放在一个批命令my_dir.bat文件中,在Java程序 中写成exec("my_dir.bat")。如果仅仅写成exec("dir"),Java虚拟机则会报运行时错误。前一种方法要保证程序的可移植性, 需要在程序中读取运行的操作系统平台,以调用不同的命令解释器。后一种方法则不需要做更多的处理。
2、打开一个不可执行的文件
打开一个不可执行的文件,但该文件存在关联的应用程序,则可以有两种方式。 以打开一个word文档a.doc文件为例,Java中可以有以下两种写法:
exec("start .\\a.doc");
exec(" c:\\Program Files\\Microsoft Office\\office\\winword.exe .\\a.doc");
显然,前一种方法更为简捷方便。
3、执行一个有标准输出的DOS可执行程序
在 windows平台上,运行被调用程序的DOS窗口在程序执行完毕后往往并不会自动关闭,从而导致Java应用程序阻塞在waitfor( )。导致该现象的一个可能的原因是,该可执行程序的标准输出比较多,而运行窗口的标准输出缓冲区不够大。解决的办法是,利用Java提供的Process 类提供的方法让Java虚拟机截获被调用程序的DOS运行窗口的标准输出,在waitfor()命令之前读出窗口的标准输出缓冲区中的内容。一段典型的程 序如下:
...
String ls_1;
Process process = Runtime.getRuntime().exec("cmd /c dir \\windows");
BufferedReader bufferedReader = new BufferedReader( \
new InputStreamReader(process.getInputStream());
while ( (ls_1=bufferedReader.readLine()) != null)
System.out.println(ls_1);
process.waitfor( );
...以上内容为转载~下面内容为原创!
今天在做客户端程序的自动更新,简单描述一下,就是从服务器上将更新包下载下来,然后在本地解压缩,最后删掉~功能很简单~
但 是问题出在使用JAVA的ZIP模块做文件的解压缩不是想象的那么简单,资源需要释放,一个不小心就没有办法删除掉原有ZIP文件了~资源的占用确实是个 大问题,但是好在,客户端程序更新完是要重启的,一切都烟消云散了~对于删除不掉ZIP文件的问题,我也流氓一下~用DEL硬删除~此处一定要注意!
Process process = Runtime.getRuntime().exec("cmd /c del f:\\aaa.doc");
这样的调用是没有问题~Process process = Runtime.getRuntime().exec("del f:\\aaa.doc");
这样写是不可能对的~ -
[转贴]马士兵Java学习笔记
2011-05-08 17:32:28
1115
键盘事件
当按下一个键时对应一个虚拟的码
例子:
import java.awt.*;
import java.awt.event.*;
public class TestKey {
}
class KeyFrame. extends Frame. {
}
KeyEvent类的方法public int getKeyCode()返回与此事件中的键关联的整数 keyCode。也就是判断敲击的是哪一个键,返回值是整形。
KeyEvent类的字段摘要public static final int VK_UP用于非数字键盘向上方向键的常量。
-
[转贴]马士兵Java学习笔记
2011-05-08 17:31:59
1113
Windows和匿名类
例一:
import java.awt.*;
import java.awt.event.*;
public class TestWindowClose {
public static void main(String args[]) { } }
class MyFrame55 extends Frame. {
MyFrame55(String s) { class MyWindowMonitor extends WindowAdapter {//此为内部类 } }
例二:
利用了匿名类,也叫局部类,匿名的内部类
逻辑较简单,语句较少,变动较少时可以使用内部类。很少使用。
import java.awt.*;
import java.awt.event.*;
public class TestWindowClose {
public static void main(String args[]) { } }
class MyFrame55 extends Frame. {
MyFrame55(String s) { } } -
[转贴]马士兵Java学习笔记
2011-05-08 17:31:22
1112
Adapter and repaint
软件包 java.awt.event 提供处理由 AWT 组件所激发的各类事件的接口和类。
比如ActionListener用于接收操作事件的侦听器接口。对处理操作事件感兴趣的类可以实现此接口,而使用该类创建的对象可使用组件的 addActionListener 方法向该组件注册。
比如KeyListener用于接收键盘事件(击键)的侦听器接口。
比如MouseListener用于接收组件上“感兴趣”的鼠标事件(按下、释放、单击、进入或离开)的侦听器接口
比如TextListener用于接收文本事件的侦听器接口。
比如WindowListener用于接收窗口事件的侦听器接口。
注意到这个问题:ActionListene接口有一个方法public void actionPerformed(ActionEvent
e) 所以实现这个接口时要重写这个方法。但是MouseListener接口有mouseClicked,mousePressed等五个方法,如果实现这个接口则要全部重写这五个方法。哪怕是没有用的,也要写空操作。为了解决这种麻烦可使用适配器Adapter。适配器都实现了相应的接口(相当于适配器是这些接口的子类)。比且在这些适配器里都有被实现的接口里的方法的空操作。使用适配器时根据自身需要重写某方法即可。比如java.awt.event.MouseAdapter实现MouseListener接口,可使用其子类(MouseAdapter)作为MouseEvent的监听器,只要重写其相应的方法即可,即public abstract class MouseAdapter extends Object implements MouseListener, MouseWheelListener, MouseMotionListener
接收鼠标事件的抽象适配器类。此类中的方法为空。此类存在的目的是方便创建侦听器对象。对于其他的监听器,也有对应的适配器。使用适配器可以避免监听器类定义没有必要的空方法。
例子:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class MyMouseAdapter{
public static void main(String args[]) { } }
class MyFrame. extends Frame. {
ArrayList points = null; MyFrame(String s) { points = new ArrayList(); setVisible(true);
this.addMouseListener(new Monitor());//给此Frame添加监听器。Frame的父类Component有此方法public void addMouseListener(MouseListener l) 添加指定的鼠标侦听器,以接收发自此组件的鼠标事件。参数:l - 鼠标侦听器} public void addPoint(Point p){ } }
class Monitor extends MouseAdapter {//不实现MouseListener而是继承MouseAdapter
public void mousePressed(MouseEvent e) { } }
分析f.repaint()。Component类的方法public void repaint()重绘此组件。在此f.repaint()使此Frame强制重画,若不repaint()那么你虽然点击了鼠标,但是看不见这些点,因为没有重画。深层原因:调用repaint()时先调用了update()再调用了paint()(这是双缓冲的基础)。
-
[转贴]马士兵Java学习笔记
2011-05-08 17:30:44
1110
内部类
利用内部类在1109的两个方法的基础上改进加法运算的实现
import java.awt.*;
import java.awt.event.*;
public class TFMath {
}
class TFFrame. extends Frame. {
{ //MyMonitor类声明在TFFrame类的内部,与成员变量的位置并列等同即声明在包装类内且方法外(注意不可以设置在TFFrame类的成员方法中)。这样就可以访问其包装类的成员变量和成员方法(这是内部类经常使用的方式)。这样做也避免了其他的类来访问监听器类,即保护了监听器类。也可声明为private class }
1111
Paint方法
Graphics
类是所有图形上下文的抽象基类,允许应用程序在组件(已经在各种设备上实现)以及闭屏图像上进行绘制。每个Component都有一个paint(
Graphics g
)用于实现绘图目的,每次重画该Component时都自动调用paint方法。什么是重画呢?就是需要再次显示这个Component时(比如一个Frame)比如在最小化,然后最大化或者复原时。因为在一个Component重新显示时,这些图像需要重新显示例子:
import java.awt.*;
public class TestPaint {
}
class PaintFrame. extends Frame. {
}
分析将Graphics想象为一个画笔类,那么g是一支画笔。
一定要注意paint()方法在哪个类里面,则画笔在哪个类中被使用。且这个paint方法是被自动调用的
paint()方法来自于Frame的父类Container类
Container类方法public void paint(Graphics
g) 绘制容器。该方法将 paint 转发给任意一个此容器子组件的轻量级组件 -
[转贴]马士兵Java学习笔记
2011-05-08 17:30:12
1109
持有对方引用
实现加法方法一:
import java.awt.*;
import java.awt.event.*;
public class TFMath {
}
class TFFrame. extends Frame. {
public void launchFrame() {//用来运行TFFrame
num1 = new TextField(10);//设置对话框宽度为10个字符 num2 = new TextField(10); num3 = new TextField(15); } Class MyMonitor implements ActionListener {//在等号上实现监听 num1,num2,num3; this.num2=num2;
this.num3=num3;
}
}
主要问题是要拿到num1和num2,但是ActionEvent e是来自于等号,与他们无关;所以通过e.getSource()时不可能的。所以通过Class MyMonitor implements ActionListener{}来实现。但是需要注意几个问题:1在等号实现监听时必须new出来一个以TFFrame 类中的num1,num2,num3为参数的监视器即MyMonitor btnEqual.addActionListener(new MyMonitor(num1,num2,num3))。只有这样才可以实现与Class MyMonitor implements ActionListener{}的连接,这也间接得到了num1,num2,num3。(再次强调:一定要注意num1,num2,num3就是class TFFrame的局部变量(成员变量)且是TextField类型的)2 在Class MyMonitor implements ActionListener{}中必须有三个TextField类型的成员函数。这样才可以实现形参和实参的匹配。
所以这种方法的主要问题就是在写监视器时要保留好多其他类的局部变量(成员变量)。这就是问题2体现出来的。
如果把TFFrame 类中的num1,num2,num3定义为成员变量则还有更好的办法,如方法二:在监听器对象里面持有TFFrame类的引用
实现加法方法二:
import java.awt.*;
import java.awt.event.*;
public class TFMath {
}
class TFFrame. extends Frame. {
}
注意:1、关于this参见0317
-
[转贴]马士兵Java学习笔记
2011-05-08 17:29:32
1107
事件模型2
范例
名称:Java事件处理举例 源文件名称:TestActionEvent2.java
要
import java.awt.*;
import java.awt.event.*;
public class TestActionEvent2 {
}
class Monitor2 implements ActionListener {
}
Button类的方法public void setActionCommand(String
command) 设置此按钮激发的动作事件的命令名称。在默认情况下,此动作命令设置为与按钮标签相匹配。Button类的方法public String getActionCommand()返回此按钮激发的动作事件的命令名称(与setActionCommand对应)。如果命令名称为 null(默认),则此方法返回按钮的标签。
1108
TextFiled类
Java.awt.TextFiled类用来创建文本框对象
例子:
import java.awt.*;
import java.awt.event.*;
public class TFActionEvent {
}
class TFFrame. extends Frame{
}
class TFActionListener implements ActionListener{
}
当某件事发生的时候,必须把此事封装成一个对象作为一个参数传递给监听器所实现接口里的特定方法。此例中当有输入时,它发出的这一件事叫ActionEvent e。所以可以在TFActionListener类中使用TFFrame类的局部变量tf。
ActionEvent 的父类EventObject 有方法public Object getSource( )返回:最初发生 Event 的对象。注意其返回值是Object
javax.swing.text.JTextComponent类的方法public String getText()返回此 TextComponent 中包含的文本
TextField类的方法public char getEchoChar( )获取用于回显的字符。*回显字符对于不应将用户输入回显到屏幕上的文本字段有用,例如输入密码的文本字段。例如tf.setEchoChar('*');将输入文本框tf的东西均显示为*
TextField类的方法public void setText(String
t) 将此文本组件显示的文本设置为指定文本。 -
[转贴]马士兵Java学习笔记
2011-05-08 17:28:59
1104
布局管理器2
FlowLayout例子:
import java.awt.*;
public class TestFlowLayout2 {
}
BorderLayout布局管理器
BorderLayout是Frame类的默认布局管理器
BorderLayout将这个容器分为,东西南北中五个区域,组件只能添加到指定的区域,默认的是中(CENTER)。每个区域只能添加一个组件,若再次添加则会覆盖。
例子:
import java.awt.*;
public class TestBorderLayout {
}
GridLayout布局管理器
GridLayout布局管理器将空间划分成规则的矩形网络,每个区域大小相等。排列顺序从左到右,从上至下
例子:
名称:GridLayout应用举例 import java.awt.*;
public class TestGridLayout {
}
1106
事件模型1
范例
名称:Java事件处理举例 源文件名称:TestActionEvent.java
要
import java.awt.*;
import java.awt.event.*;
public class TestActionEvent {
}
class Monitor implements ActionListener {//即Monitor要监听的是ActionListener类型的事件
}
要监听什么事,就得实现什么接口。所以事件有很多,接口也有很多,它们之间一一对应
当某件事情发生,事件源对象会调用实现了某种监听器接口的类的对象。所以实现了某种监听器接口的类的对象必须把自己注册到事件源对象,告知对方:我在监听
当某件事发生的时候,必须把此事封装成一个对象作为一个参数传递给监听器所实现接口里的特定方法
此例中当press me被点击时,它发出的这一件事叫ActionEvent e
Button类的方法public void addActionListener(ActionListener
l) 添加指定的动作侦听器,以接收发自此按钮的动作事件。当用户在此按钮上按下或释放鼠标时,发生动作事件。ActionEvent类指示发生了组件定义的动作的语义事件。当特定于组件的动作(比如被按下)发生时,由组件(比如 Button)生成此高级别事件。事件被传递给每一个 ActionListener 对象,这些对象是使用组件的 addActionListener 方法注册的,用以接收这类事件。
-
[转贴]马士兵Java学习笔记
2011-05-08 17:28:19
1101
GUI(Graphics User Interfaca)图形用户界面
AWT(Abstract Window Toolkit)包括许多类和接口用于实现GUI编程
Container和Component(可以显示的图形元素)是AWT的两个核心类。Container是Component的子类。Container用来容纳其他Component元素
Container包含Window(包含Frame和Dialog)和Panel。但是Window作为一个应用程序的出口可以独立显示出来,其表示对象自由停泊的顶级窗口;Panel不能作为一个应用程序的出口可以独立显示出来,要想显示得把自己装到其他的Container里(比如Window和Applet)。
Frame
例子:
范例名称:Frame 应用举例
源文件名称:TestFrame.java
要
点:Frame组件的创建及显示设置 import java.awt.*;
public class TestFrame. {
public static void main( String args[]) {
f.setLocation(300, 300);//指定Frame左上角的坐标
f.setSize( 170,100);//单位是像素
f.setBackground( Color.blue);
f.setResizable(false);//设置是否可以更改大小
f.setVisible( true);//设置可见
}
}
1102
Frame
例子:
import java.awt.*;
public class TestMultiFrame. {
}
class MyFrame. extends Frame{
}
Panel
Panel对象可以看成可以容纳Component的空间
Panel对象可以拥有自己的布局管理器
例一:
import java.awt.*;
public class TestPanel {
Frame. f = new Frame("Java Frame. with Panel"); }
例二:
import java.awt.*;
public class TestMultiPanel {
}
class MyFrame2 extends Frame{
p2 = new Panel(null); p4 = new Panel(null);//null表示此panel不带自己的布局管理器
add(p2);
add(p3);
add(p4);
}
1103
布局管理器1
Awt提供了五种布局管理器
FlowLayout
BorderLayout
GridLayout
CardLayout
GridBagLayout
FlowLayout是Panel类的默认布局管理器,逐行开始排列从左到右。FlowLayout默认对齐方式是居中
例子:
范例名称:FlowLayout 用法举例
源文件名称:TestFlowLayout.java
要
点: import java.awt.*;
public class TestFlowLayout {
}
-
[转贴]马士兵Java学习笔记
2011-05-08 17:27:41
1006利用UDP传送一个long类型的数,服务器端收到后再次将其转换为long类型
例子:
import java.net.*;
import java.io.*;
public class TestUDPClient{
}
import java.net.*;
import java.io.*;
public class TestUDPServer{
}
ByteArrayOutputStream类:实现了一个输出流,其中的数据被写入一个 byte 数组。
ByteArrayOutputStream类方法public byte[] toByteArray()创建一个新分配的 byte 数组。其大小是此输出流的当前大小,并且缓冲区的有效内容已复制到该数组中。返回:以 byte 数组的形式返回此输出流的当前内容。即拿到字节数组
DataOutputStream类:数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。
DataOutputStream类方法public final void writeLong(long
v)throws IOException 将一个 long 值以 8-byte 值形式写入基础输出流中,先写入高字节。DataInputStream类:数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型
DataInputStream类方法public final long readLong()throws IOException从包含的输入流中读取此操作需要的字节。返回:此输入流的下八个字节,将它们解释为一个 long。
DatagramSocket类构造方法public DatagramSocket(int
port)throws SocketException 创建数据报套接字并将其绑定到本地主机上的指定端口。DatagramSocket类方法public void receive(DatagramPacket
p)throws IOException 从此套接字接收数据报包。当此方法返回时,DatagramPacket 的缓冲区填充了接收的数据。数据报包也包含发送方的 IP 地址和发送方机器上的端口号。 此方法在接收到数据报前一直阻塞DatagramSocket类方法public void send(DatagramPacket
p)throws IOException 从此套接字发送数据报包。DatagramPacket 包含的信息指示:将要发送的数据、其长度、远程主机的 IP 地址和远程主机的端口号。DatagramPacket类构造方法public DatagramPacket(byte[]
buf,int 构造 DatagramPacket,用来接收长度为 length 的数据包。length 参数必须小于等于 buf.length。参数:buf - 保存传入数据报的缓冲区。len - 要读取的字节数。length) DatagramPacket类构造方法public DatagramPacket(byte[]
buf,int length,SocketAddress address) throws SocketException构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。length 参数必须小于等于 buf.length。
DatagramPacket类方法public int getLength()返回将要发送或接收到的数据的长度
String类构造方法public String(byte[]
bytes,int 通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。新 String 的长度是字符集的函数,因此可能不等于该子数组的长度。offset,int length) -
[转贴]马士兵Java学习笔记
2011-05-08 17:26:21
1005
UDP
严格来讲UDP没有客服端,服务器端的概念;它不区分这个
例子:
import java.net.*;
public class TestUDPClient{
}
import java.net.*;
public class TestUDPServer{
ds.receive(dp);//只要ds收到数据就扔到dp里面
}
DatagramSocket类构造方法public DatagramSocket(int
port)throws SocketException 创建数据报套接字并将其绑定到本地主机上的指定端口。DatagramSocket类方法public void receive(DatagramPacket
p)throws IOException 从此套接字接收数据报包。当此方法返回时,DatagramPacket 的缓冲区填充了接收的数据。数据报包也包含发送方的 IP 地址和发送方机器上的端口号。 此方法在接收到数据报前一直阻塞DatagramSocket类方法public void send(DatagramPacket
p)throws IOException 从此套接字发送数据报包。DatagramPacket 包含的信息指示:将要发送的数据、其长度、远程主机的 IP 地址和远程主机的端口号。DatagramPacket类构造方法public DatagramPacket(byte[]
buf,int 构造 DatagramPacket,用来接收长度为 length 的数据包。length 参数必须小于等于 buf.length。参数:buf - 保存传入数据报的缓冲区。len - 要读取的字节数。length) DatagramPacket类构造方法public DatagramPacket(byte[]
buf,int length,SocketAddress address) throws SocketException构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。length 参数必须小于等于 buf.length。
DatagramPacket类方法public int getLength()返回将要发送或接收到的数据的长度
String类构造方法public String(byte[]
bytes,int 通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。新 String 的长度是字符集的函数,因此可能不等于该子数组的长度。offset,int length) -
[转贴]马士兵Java学习笔记
2011-05-08 17:25:44
1003
TCP Socket通信模型
Server端
1新建一个ServerSocket s (指定端口)
2 s.accept( )//等待连接
3 将对方的连接封装为一个socket对象
4 它有自己的OutputStream和InputStream
5 socket.close( )
Client端
1 新建一个Socket(指定对方IP,指定对方端口号)
2 建立连接
3 通过自己的自己的OutputStream和InputStream和对方联系
4 socket.close( )
注意:socket两端都有自己的OutputStream和InputStream
范例名称:简单的client/server程序
源文件名:TestClient.java/TestServer.java
要
点: 例一:
import java.net.*;
import java.io.*;
public class TestServer {
bye-bye!");//获得客户端的IP和port }
import java.net.*;
import java.io.*;
public class TestClient {
}
ServerSocket类的方法
构造方法public ServerSocket(int
port)throws IOException 创建绑定到特定端口的服务器套接字方法public Socket accept()throws IOException侦听并接受到此套接字的连接。一定要注意它的返回值是Socket类型
Socket类的方法
构造方法public Socket(InetAddress
address,int 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。port)throws IOException 方法public InputStream getInputStream()throws IOException返回此套接字的输入流。
方法public OutputStream getOutputStream()throws IOException返回此套接字的输出流。
方法public InetAddress getInetAddress()返回套接字连接的地址。返回:此套接字连接到的远程 IP 地址;如果套接字是未连接的,则返回 null。
方法public int getPort()返回此套接字连接到的远程端口。返回:此套接字连接到的远程端口号;如果尚未连接套接字,则返回0。
DataInputStream类的方法
方法public final String readUTF()throws IOException从包含的输入流中读取此操作需要的字节
DataOutputStream类的方法
方法public final void writeUTF(String
str)throws IOException 以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。例二:
import java.io.*;
import java.net.*;
public class TestSockServer {
public static void main(String[] args) { } }
import java.net.*;
import java.io.*;
public class TestSockClient {
public static void main(String[] args) { } }
注意:若服务器先读入后写出,则客户端先写出后读入。否则容易堵塞
-
[转贴]马士兵Java学习笔记
2011-05-08 17:25:09
1001
网络基础
TCP(transmission control protocol)是专门设计用于在因特网上提供可靠的,端到端的字节流通信的协议。它是面向连接的协议,是可靠的即可靠但是慢。TCP连接是字节流而非报文流
UDP(user data protocol)向应用程序提供了一种发送封装的原始IP数据报的方法,并且发生时无需建立连接。是一种不可靠的连接;即不可靠但是快
以前学过谢希仁的《计算机网络》,所以这部分没有怎么做笔记
1002
Socket
两个应用程序可以通过一个双向的网络通信连接实现数据交换,这个双向链路的一端称为一个socket
Socket通常用来实现client—server连接
Java.net包中定义的两个类Socket和ServerSocket(实现TCP连接时才用的),分别用来实现双向连接的client和server端。
应用程序建立连接时需要计算机的IP地址和端口号(port number)
TCP,UDP的端口是分开的,各有65536个
例子:
import java.net.*;
import java.io.*;
public class TCPServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(6666);// 首先要建立一个ServerSocke类的对象,并且指定了端口号来监听连接。一旦建立便等着客户端来连接
while(true) {
Socket s = ss.accept();//接受客服端的连接,并且服务器端再建立一个socket来和一个特定的客户端连接。这样的话就处理了多个申请连接的情况。
System.out.println("a client connect!");
DataInputStream dis = new DataInputStream(s.getInputStream());//注意s.getInputStream()返回的是InputStream类型,即在InputStream类型上又包了一个DataInputStream类型的管道dis。
System.out.println(dis.readUTF());//readUTF()是阻塞式的,所以此时若客户端不发东西,那么它就一直在这里阻塞,也就是说这个while循环就停在这里了即其他的客户无法再连接进来。
dis.close();
s.close();
}
}
}
import java.net.*;
import java.io.*;
public class TCPClient {
public static void main(String[] args) throws Exception {
Socket s = new Socket("127.0.0.1", 6666);//指定了要建立连接的IP和端口号,127.0.0.1表本机
OutputStream s = s.getOutputStream( );
DataOutputStream dos = new DataOutputStream(os);//类似于服务器端的分析
dos.writeUTF("hello server!");
dos.flush();
dos.close();
s.close();
}
}
ServerSocket类的方法
构造方法public ServerSocket(int
port)throws IOException 创建绑定到特定端口的服务器套接字方法public Socket accept()throws IOException侦听并接受到此套接字的连接。一定要注意它的返回值是Socket类型
Socket类的方法
构造方法public Socket(InetAddress
address,int 创建一个流套接字并将其连接到指定 IP 地址的指定端口号。port)throws IOException 方法public InputStream getInputStream()throws IOException返回此套接字的输入流。
方法public OutputStream getOutputStream()throws IOException返回此套接字的输出流。
DataInputStream类的方法
方法public final String readUTF()throws IOException从包含的输入流中读取此操作需要的字节
DataOutputStream类的方法
方法public final void writeUTF(String
str)throws IOException 以与机器无关方式使用 UTF-8 修改版编码将一个字符串写入基础输出流。注意:(1)要先运行server再运行client。
( 2)accept()和readUTF()都是阻塞式的( 3)交流的信息,相对于服务器端是输入,相对于客户端是输出 -
[转贴]马士兵Java学习笔记
2011-05-08 17:24:36
0911
关于死锁的一道题目(3)
public class TT implements Runnable {
}
打印结果:1000,b=1000。1000是由System.out.println(tt.b);得到的,b=1000是由System.out.println("b = " + b);得到的。按理说先是t.start();输出b=1000然后是System.out.println(tt.b);所以输出2000。这是为什么呢?
马老师的分析过程:主函数执行到t.start();时产生一个新的线程,调用了start()即执行了m1( )方法。但是并没有给对象加锁。当然主函数继续往下执行,同时这个新的线程也是在执行的。接着执行tt.m2();当m2()执行的时候也锁定了当前对象,所以把b置为2000.当,m2()执行完了释放锁,m1()才可能执行。此时把b置为1000.因为m1()中Thread.sleep(5000)在这个时间段执行了主函数的System.out.println(tt.b);输出1000;然后执行m1()中的System.out.println("b = " + b);所以输出b=1000。逼人觉得马老师的这个过程有些不太准确,应该是这样的:
分析过程:主函数执行到t.start();时产生一个新的线程,调用了start()即执行了m1( )方法。并且给对象加锁,故此时b=1000,然后睡眠。当然主函数继续往下执行,同时这个新的线程也是在执行的(目前是睡眠状态)。接着执行tt.m2();m2()只有等待。然后执行主函数的System.out.println(tt.b);所以输出1000;然后执行m1()中的System.out.println("b = " + b);所以输出b=1000。然后才执行m2()。但是主函数没有输出语句了,所以虽然b的值在内存中再次被改变,但是没有显示
关于生产者消费者问题,没有仔细做笔记只是看了一遍视频。
0912
Wait和sleep的区别
Wait属于Object类
Sleep属于Thread类
Wait时别的线程也可以访问锁定的对象
Sleep时别的线程不可以访问锁定的对象
-
[转贴]马士兵Java学习笔记
2011-05-08 17:24:04
关于死锁的一道题目(1)
public class TT implements Runnable {
} } 问题:当一个线程执行m1( )时,另外的一个线程可以执行m2()么?测试程序如下:
public class TT implements Runnable {
}
分析:当执行tt.m2( );时另外的一个线程使b=1000,但是没有解锁。于是输出的是100,b=1000。但是输出的是1000,b=1000。其实是这样的
public synchronized void m1() throws Exception{
锁定当前对象只是锁住了这一段话即其他的线程不可以再访问这段话。但是其他线程完全可以访问那些没有被锁定的方法
补充一点孙鑫讲的东西:每一个对象有一个锁,或者叫监视器。除此,它还有一个等待队列(wait set),当一个对象创建的时候,它的等待队列是空的。
0909
关于死锁的一道题目(2)
public class TT implements Runnable {
}
问题:打印出来的结果是1000还是2000?结果是2000.它的原理还是:锁定当前对象只是锁住了这一段话即其他的线程不可以再访问这段话。但是其他线程完全可以访问那些没有被锁定的方法
加入修改为:public synchronized void m1() throws Exception{其余的不变};
public synchronized void m2() throws Exception{其余的不变};
这样的话m1先加锁,m2是无法再去锁住的(我们这几个例子里讨论的加锁对象都是b。所以输出的是b=1000.注意这里和修改前的
public synchronized void m1() throws Exception{其余的不变};
public void m2() throws Exception{其余的不变};
还不一样!修改前是可以执行m2()的,但是现在不可以。因为public synchronized void m2() throws Exception这样的写法是想去加锁,独占对象。
-
[转贴]马士兵Java学习笔记
2011-05-08 17:23:29
0905
线程的同步问题
线程的同步解决的是不同线程访问同一资源的数据处理和协调的问题
例子:
public class TestSync implements Runnable {
Timer timer = new Timer();//见下内存分析 public static void main(String[] args) { } public void run(){//因为实现了Runnable接口所以再实现run()方法 } }
class Timer{
private static int num = 0; public void add(String name){ } }
Thread类的方法public final void setName(String
name) 改变线程名称,使之与参数 name 相同。内存分析: TestSync test = new TestSync();当执行完词句后:stack中的test指向heap中的test对象。并且在heap中的test对象里存在一个timer引用,它指向heap里的另外一块内存即timer对象。之所以有这样的包含关系因为Timer timer = new Timer()是TestSync的成员变量。理解这点很重要
按理说输出结果是:t1你是第2使用timer的线程, t2你是第2使用timer的线程.但是结果不是这样的
分析原因:
class Timer{
private static int num = 0; public void add(String name){ }
当t1 执行num ++;后num变为1,此时t1睡眠(这时候t2有时间执行了),t2接着执行;t2把num变为2,此时t2睡眠,t1接着执行。于是打印出:t1你是第2使用timer的线程, t2你是第2使用timer的线程
出现问题的原因是在一个线程的执行过程中被另外一个线程打断了!
解决办法:在执行这个原子操作的过程中,把当前对象锁住即可;执行完以后再释放锁,即修改为
class Timer{
private static int num = 0; public synchronized void add(String name){ } } }
它的简便写法是:
class Timer{
private static int num = 0; public synchronized void add(String name){ //在执行这个方法的过程之中,当前对象被锁定 }
0907
关于死锁
当两个线程均需要锁住两个对象A,B才可以完成操作。但是线程1先锁住了A,线程2先锁住了B。于是两者均无法继续执行,出现了死锁。例子:
public class TestDeadLock implements Runnable {
System.out.println("flag=" + flag);
}
这个程序比较简单,主要体现了死锁的原理。
Thread类的构造方法public Thread(Runnable
target) 分配新的 Thread 对象。参数target:target的 run 方法被调用 -
[转贴]马士兵Java学习笔记
2011-05-08 17:22:56
0902
线程状态的转换
线程的状态有创建,就绪,运行,阻塞,终止。运行时可能阻塞,然后再回到就绪。
当线程类的对象调用start()时不是进入运行,而是就绪状态
Thread类的方法:
方法public final boolean isAlive( )测试线程是否处于活动状态。如果线程已经启动且尚未终止,则为活动状态。返回:如果该线程处于活动状态,则返回 true;否则返回 false。在此注意就绪,运行,阻塞算活着。
方法public final int getPriority( )返回线程的优先级。
方法public final void setPriority (int
newPriority) 更改线程的优先级。方法public static void sleep(long
millis)throws InterruptedException 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。注意它是一个静态的方法方法public final void join( )throws InterruptedException等待该线程终止。
方法public static void yield( )暂停当前正在执行的线程对象,并执行其他线程。即让出CPU,当前线程进入就绪队列等待调度
方法public void interrupt( )中断线程。
例一:
import java.util.*;
public class TestInterrupt {
public static void main(String[] args) { } }
class MyThread extends Thread {
} 前面的死循环,处理得不好,不太容易让它停下来,所以这样:
class MyThread extends Thread {
boolean flag=true
public void run(){
while(flag= =true) {其余不变}
然后写一个方法:
public void shutdown( ){
flag=false }
在主函数使用线程的对象调用shutdown( )则线程停止
0903
join方法
查阅API可知方法public final void join( )throws InterruptedException等待该线程终止。即合并线程
例子:
public class TestJoin {
public static void main(String[] args) { } }
class MyThread2 extends Thread {
MyThread2(String s){//调用了父类的构造方法给子类MyThread2的对象起名字。没什么用 } public void run(){ } }
Thread类的构造方法public Thread(String
name) 分配新的 Thread 对象。参数:name - 新线程的名称。yield( )方法
方法public static void yield( )暂停当前正在执行的线程对象,并执行其他线程。即让出CPU,当前线程进入就绪队列等待调度
例子:
public class TestYield {
}
class MyThread3 extends Thread {
super(s);
}
}
程序有三条路径在执行,有main,t1,t2
线程的优先级
优先级最低为1,最高为10,默认为5
例子:
public class TestPriority {
}
class T1 implements Runnable {
}
class T2 implements Runnable {
}
Thread类的构造方法public Thread(Runnable
target) 分配新的 Thread 对象。参数target:target的 run 方法被调用 -
[转贴]马士兵Java学习笔记
2011-05-08 17:22:21
0901
线程的基本概念
线程是一个程序里面不同的执行路径
例子:
public class {
}
这个程序只有一条执行路径,执行到main时调用m1,主函数停下来。m1调用m2,m1停下来,待m2返回时m1继续执行。m1调用m3, m1停下来,待m3返回时m1继续执行.随即主函数结束。
我们前面讲的东西都是这种情况:只有一个分支,就是main方法也叫主线程
当一个class(放在代码区)或者.exe放进内存还没有执行时,它是静态的。但是线程是一个程序里面不同的执行路径,它是动态的。
平时说的进程的执行指的是进程里面主线程(主函数)开始执行了
操作系统是支持多线程,多进程的。但是实际是在一个特定的时间点CPU只运行一个线程。
Java的线程是通过java.lang.Thread类来实现的。
虚拟机启动时会有一个由主方法(即main函数)所定义的线程
通过调用Thread类的start()方法来启动一个线程
线程创建的两个方法:
一:定义线程类实现Runnable接口
二:可以定义Thread的子类并且重写run( )方法,然后生成该类的对象。即使用了继承
通过下面的例子来看看方法调用和多线程的区别
例一:
public class TestThread1 {
}
class Runner1 implements Runnable {
注意例一只是方法的调用,根本不涉及多线程
例二:
public class TestThread1 {
}
class Runner1 implements Runnable {//实现了Runnable接口表明Runner1是一个线程类
Thread类的构造方法public Thread(Runnable
target) 分配新的 Thread 对象。参数target:target的 run 方法被调用Thread类的方法public void run( )如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。Thread 的子类应该重写该方法。
Thread类的方法public void start( )使该线程开始执行并且Java 虚拟机调用该线程的 run 方法。结果是两个线程并发地运行;当前线程(从调用返回给 start 方法)和另一个线程(执行其 run 方法)。多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。
接口 Runnable只有一个方法void run( )使用实现接口 Runnable 的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的 run 方法。
此例子就是线程创建的方法之定义线程类实现Runnable接口。一定要注意实现接口 Runnable时当要启动一个线程时,则要new一个Thread类的对象!!!由此对象来调用start()方法
例三:
public class TestThread1 {
}
class Runner1 extends Thread {//既然是继承了,那么Runner1就是一个线程。所以主函数中的Thread t = new Thread(r);和t.start();是多余的。直接r.start();即可
此例子就是线程创建的方法之使用继承。 综合上面两例,在线程创建时尽量使用实现接口会好些,因为Java只有单继承。一旦继承了Thread其余的就不可以再继承了。
标题搜索
我的存档
数据统计
- 访问量: 22861
- 日志数: 58
- 文件数: 1
- 建立时间: 2008-03-20
- 更新时间: 2011-09-13