Part1:
Junit根据名称来识别一个测试方法,所以测试方法的命名要遵从下面的标准:
1. 方法必须声明为public
2. 方法的返回值必须为void
3. 方法的名字必须以小写test为前缀
4. 方法不能接受任何参数
命名约定:
Java用称为’驼峰模式”的命名方式,可以把多个单词直接连接起来组成一个名字或者标志符.除了第一个单词,标识符中的每一个单词都以大写字母开头.
并且对于类第一个字母为大写StudentDirectory,对于方法第一个字母为小写firstNameString
不能用数字作为开头,避免下滑线’_’,除了类常量和为了避免因为冲突而在一个命名前面加一个前缀’_’或者直接加一个其他字母前缀或者是只有这个命名的首字母
避免缩写
Java对大小写是敏感的
在junt里面存在断言机制assertEquals(“Joe”,studentName);来对比2个参数是否相等,如果不相等就junt出现红条
字符串常量的定义
final String firstStudentName = “Jane Doe”;
语句开头的关键字final,表明这个字符串引用是不可修改的.
刚学习的开发循环是:
1. 编写一个小的测试,来断言某些功能正确与否
2. 运行测试,如果结果是失败
3. 编写代码,使测试通过
4. 重构测试和代码.清楚重复的概念,确保代码富于表现力
Java编译器允许成员变量的名字和参数的名字相同,甚至和局部变量的名字相同.编译代码的时候,Java试着弄明白name代表什么.编译器的解决方案就是就近原则,使用最近定义的name就是说是形式参数的name
如果是非必要最好不要把成员变量暴露给其他变量
Part2:
记住:面向对象系统是行为建模.行为通过向对象发送消息产生作用—让对象做某件事情或者从对象获取数据
Java的int型允许的整形数字范围是-2147483648到2147483647
Java虚拟机总是先执行某个赋值语句右边的代码,Java虚拟机计算出等号右边表达式的值,然后将结果赋值给左边
public classAllTesrs {
public static junit.framework.TestSuite suite(){
junit.framework.TestSuitesuite = newjunit.framework.TestSuite();
suite.addTestSuite(StudentText.class);
suite.addTestSuite(CourseSessionTest.class);
return suite;
}
}
一个测试类套件将会用junit测试2个类.
不然只会有一个类得到测试,存在如果这个2个类有关联的话一个类通过,另外一个类不通过
运用静态的目的是为了让junit能识别
java.util.ArrayList
可以用这种方法来调用JDK的向量
Java的每个类都直接或间接地继承自java.lang.Object
向量增量的语句是add(变量)
在java中可以用import来把一个包/类包含进你的代码,如果再次用到这个类就可以直接调用,不需要写出该类具体的地方
import junit.framework.TestCase;
import java.util.ArrayList;//这里再最后类的指明处可以用通配符*就是指整个包
在使用的时候就可以直接用
ArrayList
每个类都默认继承了基础类,并且每个类只要调用了String就会自动添加这个库进去
class ClassName extends java.lang.Object
约定所有的包名都是小写字母
不能用java或者javax作为包名的开始,因为sun已经在使用它们
如果你在setUp方法中编写代码,JUint将在执行每个测试方法之前先执行setUp方法中的代码,你可以将公共的测试初始化代码放在setUp中
所以可以用setUp来测试是否申请成功
private CourseSession session;
public void setUp(){
session = new CourseSession("ENGL","101");
}
在CourseSessionTest类中测试CourseSession类是否申请内存空间成功
注意在声明的时候不要吧session的声明放在setUp方法中,这样会变成一个局部变量
并且在CourseSessionTest中,添加成员变量session,并将setUp方法中新建的CourseSession赋值给该变量.这样,测试方法testCreate和testEnrollStudents就不再需要初始化代码,两个测试方法会得到各自独立的CourseSession实例.两个测试方法都是在同一个类里面的
尽管你可以创建构造函数,并在构造函数中编写公共的初始化代码,但这样做是相当差的实践.最好是在setUp方法中完成测试初始化
作为原则,你永远不要赋值给参数,而且,你应该很少应该为局部对象的引用重新赋值.
如果可以,最好消除代码中的重复部分,包括字符串的重复
按照约定,用大写字母来定义类常量,当所有字母都是大写,用”驼峰模式”来标记就不大可能,所以标准方法是采用下划线来’_‘分割单词
class ChessBoard{
staticfinal int SQUARES_PER_STDE = 8;
}
你还将了解,等到代码与系统中的其他部分纠缠在一起的时候,再修改代码中的问题,比一开始就去修改,要付出更多的代价,不要等太久!
多行注释可以内嵌单行注释,但是多行注释不能内嵌其他多行注释
Javadoc注释用来文档化类和方法,是告诉程序员如何使用使用这个类
@param 是用来描述参数,@return 用来描述返回值
你可能不需要支持超过双字节范围的字符,但是如果你需要,java允许使用int类型来处理字符
Java用’\’’’来代表双引号
避免使用String b = newString(“abc”);
因为这种方式创建了两个String对象
你可以将一个字符串和另一个字符串连接起来,从而生成第三个字符串
assertEquals(“abcd”,”ab”.concat(“cd”));
或者:
assertEquals(“abcdef”,”abc” + “def”);
assertEquals(“abcdef”,”abc” + “de” + “f”);这种 + 的用法被称为操作符重载
String不能改变字符串的长度,也不能改变字符串所包含的任何字符,这样做是为了字符串的最优化
可以改变的字符串是StringBuilder
在类java.lang.StringBuilder中可以用append增加字符,或者toString来得到String
可以用.NEWLINE方法来代替’\n’因为在不同的系统中这个的意思有差别
Java中的for用法可以用
for(Student student:students){}来遍历students容器里面的所有元素
将集合students中的每一个对象赋值给一个类型为Student的引用,该引用的名字是student,然后在这个上下稳重执行循环体.
面向对象有一个最基本的设计原则:一个类只做好一件事情.由于只做一件事情,所以改变类应该只有一个动机.这就是单职责原则
如果某个类没有指定访问修饰符,那么该类拥有包访问级别,这也是默认的访问级别,意味着,同一个包中的其他类可以引用这个类,但是,不同的包中的类不能访问这个类
可以向测试套件发送addTest消息,这样就可以直接测试那个套件
suit.addTest(sis.report.AllTests.suite());
如果一个.java中定义了两个类,则编译后将产生两个字节码文件.class,.在这种情况下,同一Java源文件中最多只能定义一个public类,如果定义了public类,则要求源程序的文件名必须与public类的名称相同
可以通过用Apple类来对代码嵌入到HTML里
import java.awt.*;
import java.applet.Applet;
public classJavaApplet extends Applet{
public void paint(Graphics g){
g.drawString(JavaApplet!,40, 80);
g.setColor(Color.red);
g.drawLine(30,40, 130, 40);
g.drawOval(30,40, 100, 100);
}
}
然后在编写HTML的时候可以用
那么就会在浏览器上现实出这段代码编译出来的图画
也可以用JDK中提供的AppletViewer.exe来运行查看结果
在命令行方式下,输出字符串是通过换行定位,在图形方式下,绘制字符串通过坐标定位
标识符不能出现’#’’-‘和数字开头.
Java所有的关键字均为小写字母表示
goto和const任然为java的关键字,虽然没有用
java的布尔类型是boolean
可以用Byte.MIN_VALUE,Byte.MAX_VALUE来获得byte的取值范围,也可以用到double,char,float等
系统自动转换的顺序是
byte->short->char->int->long->float->double
在以上的顺序上不需要强制转换,系统会自动进行转换
强制转换格式为
变量 = (数据类型)表达式
int li = (int)4.25;
若输入一个常实数都将默认为双精度型例如float f = 3.14;编译会报错,要float f =3.14f;才可以
C++上的运算符在java上基本适用
~op结果是op按比特位求反
op1>>op2将op1右移op2个位(带符号)
op1>>>op2将op1右移op2个位(不带符号)
op1^op2两个值是不同值
instanceof用来决定第一个运算对象是否为第二个运算对象的一个实例
String x = “hello world!”;
if(x instanceof String)
Syste.out.println(“sis a instance of String”);
System.out.read();是从键盘读一个”字节”具体要转换成什么要强制转换,要包含java.io.*;
可以用BufferReaderin = new BufferedReader(new InputStreamReader(System.in));
String s = “”;
s = in.readLine();//来读取一行字符
可以用
String x = “123”;
int m = Interger.parseInt(x);
x = “123.41”;
double n = Double.parseDouble(x);
这种方法获得整形和双精度型
Math.pow(x,n)用来计算x的n次方
Java可以定义标签用break 标签可以调到这个标签上,可以用于跳到哪个for上
如果是对类,那么对形参类的修改也会对实参修改,基本类型就不会
可以用packagetest;放在类头,然后创建一个test子目录来建立这个包
如果存在用import中的类在2个引用中都出现的时候就需要指定具体在哪个包的路径
子类在自己定义的构造方法中如果没有用super明确调用父类的构造方法,则在创建对象时,将自动调先执行父类的无参构造方法,然后再执行自己定义的构造方法
public classStudent extends Person{
Stringno;
public Student(Stringname1,String address1,int age1,String no1){
super(name1,adress1,age1);
no=no1;
}
}
用protected修饰的成员可以被3中类所引用
1. 该类本身
2. 与该类在同一个包中的其他类
3. 在其他包中的该类的子类
在继承中使用final修饰符修饰的方法不能被覆盖
可以通过super.来调用父类被覆盖的方法
用abstract关键字来指明这个类是抽象类,一样不能实例化
可以用implements来实现接口interface
abstract public class Rectangle implementsShape{…}//shape是一个接口
有内嵌类的类生成的文件名字是outerOne$innerOne.class
内嵌类可以访问外层类的成员,也可以外层类访问内嵌类的成员,但是要同对象来访问(非静态),静态不用
外层类中this要加上外层类的名字outerOne.this.
编写Applet需要继承java.applet.Applet类
init()方法用来对Applet对象初始化
start()方法用来启动Applet主线程运行,在init()方法运行结束后运行,以后每次Applet激活都会调用它,默认内容为空
paint()方法用来绘制文字,图形等,利用Graphics参数来发送消息
stop()方法用来暂停Applet主线程
destroy()方法用来释放资源,如果是调用了特殊资源就要调用方法
repaint(int x, int y, int width, int height)指定坐标重绘
可以调整字体的属性
Font myFont = new Font(“TimesRoman”,Font.BOLD + Font.ITALIC, 28);
g.setFont(myFont);
来设置,第一个参数是字体名,第二个参数是风格,第三个参数是字号
字体风格有Font.PLAIN,Font.ITALIC,Font.BOLD分别代表普通,斜体和粗体
也可以使用FontMetrics类来获得当前字体的属性,首先用getFontMetrics(Font)方法来获得一个FontMetrics对象引用,然后:
intstringWidth(String str);
intgetHeight();
intcharwidth(char ch);
在所有的图形部件的父类Component中有如下方法可以获得Applet的宽度和高度
getHeight();getWidth();
Math.floor方法得到的是一个不大于参数的最大整数,返回的是双精度值
Math.floor(Math.random()* 256);
可以用
来在HTML中获得2个参数
getImage(getDocumentVase(),”images\\img00”+ (i+1) + “.gif”);获得图片,循环获取
play(getDocmentBase(),“passport.mid”);获得播放文件
AudioClip接口:
publicvoid play();开始播放
publicvoid loop();循环播放当前声音文件
publicvoid stop();停止播放当前的声音文件
可以用Applet类的getAudioClip(URL,String)来获得当前AudioClip类型的对象
AWT工具集是抽象的,因为Java设计成跨平台的,因为每个平台的外观不同
intx = Integer.parseInt(s, 2); s代表的二进制串转换成十进制
网格
public GridLayout(int rows,int cols,int hgap,int vgap)
rows - 行数,0 表示每列可有任意行。
cols - 列数,0 表示每行可有任意列。
hgap - 水平间距。
vgap - 垂直间距。
importjava.awt.*;
importjava.awt.event.*;
publicclass converToDec extends Frame implements ActionListener{
Label dec;
TextField input;
publicconverToDec(){
super("binary to decimal");//用于定义标题,实为父类的构造函数
dec = new Label("...结果...");
input = new TextField(15);
Button convert = new Button("转换");
setLayout(new FlowLayout());//指定按流式布局排列部件
add(input);
add(convert);
add(dec);
convert.addActionListener(this);
}
publicvoid actionPerformed(ActionEvent e){
String s = input.getText();
int x = Integer.parseInt(s, 2);
dec.setText("result =" + x);
}
publicstatic void main(String args[]){
Frame x= new converToDec();
x.setSize(400, 100);
x.setVisible(true);
}
}
运用继承Frame来实现,也可以通过创建Frame对象来实现
importjava.awt.*;
importjava.awt.event.*;
publicclass converToDec extends Panel implements ActionListener{
Label dec;
TextField input;
publicconverToDec(){
//super("binaryto decimal");
dec = new Label("...结果...");
input = new TextField(15);
Button convert = new Button("转换");
setLayout(new FlowLayout());
add(input);
add(convert);
add(dec);
convert.addActionListener(this);
}
publicvoid actionPerformed(ActionEvent e){
String s = input.getText();
int x = Integer.parseInt(s, 2);
dec.setText("result =" + x);
}
publicstatic void main(String args[]){
Frame x= newFrame("binary to decimal");
x.add(new converToDec());
x.setSize(400, 100);
x.setVisible(true);
}
面板(Panel)是一种常用的GUI容器,在面板上可以不知各种GUI部件,包括将一块面板放在另一块面板中,以实现某些复杂的嵌套布局
事件处理包括如下3个对象
1. 事件源:发生时间的GUI部件
2. 事件:用户对事件源进行操作触发事件
3. 事件监听者:负责对时间的处理
给事件源对象注册监听者
事件监听者是在事件发生时要对事件进行处理的对象,AWT定义了各种类型的事件,每一种事件有相应的事件监听者接口,在接口中描述了处理相应事件应实现的基本行为..若事件类名为XxxEvent,则事件监听接口的命名为XxxListener,给部件注册监听者的方法为addXxxListener(XxxListenera).例如,按钮动作事件ActionEvent的监听者接口为ActionListener,给按钮注册监听者的方法为addActionListener(ActionListenera).
Java的事件处理机制称为委托事件处理,事件源发生事件时由监听者处理.监听者中定义事件处理方法,事件源不需要实现任何接口,但其内部有个列表记录该事件源注册了哪些监听者,从而保证发生事件时能去调用监听者的方法
以按钮事件源为例,在发生事件时,事件源将给其注册的所有监听者发送消息,实际上就是调用监听者对象的actionPerformed()方法,从而完成事件的处理
一个事件源对象可以注册多个监听者,一个监听者也可以监视多个事件源.
import java.awt.*;
import java.awt.event.*;
public classTwoButton extends Panel implements ActionListener{
Buttonb1,b2;
Paneldraw;
public TwoButton(Panel draw){//得到绘图面板要引用绘图面板
this.draw = draw;
b1 = new Button("circle");
b2 = new Button("rectangle");
add(b1);
add(b2);
b1.addActionListener(this);
b2.addActionListener(this);
}
public voidactionPerformed(ActionEvent e){
Graphicsg = draw.getGraphics();//得到绘图面板的回避对象
g.setColor(draw.getBackground());
g.fillRect(0,0,draw.getSize().width, draw.getSize().height);
g.setColor(Color.blue);
Stringlabel = e.getActionCommand();//取得事件按钮的标签
if(label.equals("circle"))
g.drawOval(20,20, 50, 50);
else
g.drawRect(20,20, 40, 60);
}
public static void main(String args[]){
Framef = newFrame("two Button event Test");
Paneldraw = newPanel();//创建绘图面板
TwoButtontwo = newTwoButton(draw);//创建控制面板
f.setLayout(new BorderLayout());//采用边界布局
f.add("North",two);//控制面板放在下方
f.add("Center",draw);//绘图面板放在中央
f.setSize(300,300);
f.setVisible(true);
}
}
不少事件的监听者接口中定义了多个方法,而程序员往往只关心其中的一两个方法,为了符合接口的实现要求,却必须将其他方法写出来并为其提供空的方法体.为此,Java中为那些具有多个方法的监听者接口提供了时间适配器类,这个类通常命名为XxxAdapter,在该类中以空方法体实现了相应接口的所有方法,程序员设计可通过继承适配器类来编写监听者类.在类中只需给出关心的方法,从而减轻了工作量.
dispose()为关闭窗体的方法
java.awt包中共定义了5种布局管理器,与之对应有5种布局策略:流式布局(FlowLayout),边缘或方位布局(BorderLayout),网格布局(GridLayout),卡片式布局(CardLayout),网格快布局(GridBagLayout),通过setLayout()方法可以设置容器的布局方式
如果不进行设定,则各种容器采用默认的布局管理器,窗体容器默认采用BorderLayout,而面板容器默认采用FlowLayout
FlowLayout布局方式将组件按照加入的先后顺序从左到右排放,放不下再换至下一行,同时按照参数要求安排部件间的纵横间隔和对齐方式
可以在Frame窗体中现实Applet面板
最用FlowLayout布局的一个重要特点是布局管理器不会改变控件的大小
BordLayout党容器仅有有个部件时,如果部件加入在北方,则它仅占用北区,其他地方为空白,但如果是加入到中央,则部件将占满整个容器
import java.applet.*;
import java.awt.*;
public classBorderLayoutExample extends Applet{
Stringborders[]= {"North","East","South","West","Center"};
public void init(){
this.setLayout(new BorderLayout(10, 10));
for(int i = 0;i < 5; i ++){
this.add(borders[i], new Button(borders[i]));//通过这个函数来加入,不同的风格的参数不同
}
}
public static void main(String args[]){
Framex = newFrame("FlowLayout");//为了能在应用程序上现实出来加上主函数
BorderLayoutExampley = newBorderLayoutExample();
x.add(y);
x.setSize(200,100);
x.setVisible(true);
}
}
BorderLayout的特点是组件尺寸被布局管理器强行控制,即与其所在区域的尺寸相同.如果某个区域无部件,则其他局域将按缩放规则自动占用其位置
GridLayout布局的特点是组件整齐排列,行列位置关系固定,如果调整容器的大小,组件的大小也将发生变化
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public classCardLayoutExample extends Applet{
public void init(){
final CardLayout cardlayout = new CardLayout(10, 10);
this.setLayout(cardlayout);
ActionListenerlistener = newActionListener(){//创建监听者对象
public voidactionPerformed(ActionEvent e){//事件处理
cardlayout.next(CardLayoutExample.this);
}
};
for(int i = 1; i <= 9;i ++){
Buttonb = newButton("Button #" + i);
b.addActionListener(listener);//给按钮注册监听者
this.add("Button"+ i,b);
}
}
public static void main(String args[]){
Framex = newFrame("FlowLayout");
CardLayoutExampley = newCardLayoutExample();
x.add(y);
x.setSize(200,100);
x.setVisible(true);
}
}
基本控制部件被安放在容器中的某个位置,用来完成一种具体的与用户交叉的功能.使用基本控制部件的步骤为:
1. 创建某种基本控制部件类的对象,指定该对象的属性,如外观,大小等;
2. 将该对象加入到某个容器的合适位置
3. 为该对象注册事件监听者
可以通过setEchoChar(char)来设置文本框的回显字符
TextFieldpass = new TextField(8);
Pass.setEchoChar(‘*’);
把CheckboxGroup加入容器时必须将每个Checkbox对象逐一加入容器,不能使用CheckboxGroup对象一次加入
与单选按钮不同的是,下拉列表是作为一个整体加入到容器,各个列表元素不是独立的操作对象
列表产生的可以产生两种事件
1. ItemEvent类选择事件,当单机某选项时触发
2. ActionEvent类动作事件,当双击某选项时触发
值得注意的是,双击事件不能覆盖单击事件,当用户双击一个选项时,首相产生一个双击,然后产生一个单击
低级语义事件会比高级语义事件先执行
哪个监听就要有方法实行,要实现某监听接口
吧事件源注册给能处理该类型事件的监听者
异常处理:
1. try语句块用来启动java的异常处理机制.一个try可以引导多个catch块
2. 异常发生后,try块中的剩余语句将不再执行.
3. 异常对象是依靠以catch语句为标志的异常处理语句块来捕捉和处理的.catch块中的代码要执行的条件是,首先在try块中发生了异常,其次异常的类型与catch块要捕捉的一致,在此情况下,运行系统会将异常对象传递给catch中的参变量,在catch块中可以通过该对象获取异常的具体信息
4. 在该结构中,可以无finally部分,但如果存在,则无论异常发生与否,finally部分的语句均要执行,即使是try或catch块中嵌套退出方法的语句return,也不能住址finally代码块的执行,也就是先执行finally块,然后再返回.除非遇到System.exit(0)时将停止程序运行.
所有的系统定义的运行异常都可以由系统在运行系统过程中自动抛出.而用户设计的异常,则要在程序中通过throw语句抛出,异常本质上是对象,因此throw关键词后面跟的是new运算符来创建一个异常对象
publicclass TestException{
public static void main(Sring a[]){
try{
throw new MyException(“一个测试异常”);
}
catch(MyExceptione){
System.out.Println(e);
}
}
}
Throw语句和throws字句的差异性,一个是抛出异常,另一个是声明方法产生某个异常(throws)
在编写类继承代码时要主义,子类在覆盖父类带throws字句的方法时,子类的方法声明中的throws字句抛出的异常不能超出父类方法的异常范围,因此,throws字句可以限制子类的行为.换句话说,子类方法抛出的异常可以是父类方法中抛出异常的子类,子类方法也可以不抛出异常,但不能出现父类对应方法的throws字句中没有的异常类型
用户自定义异常必须继承Exception类,在方法中课通过throw抛出异常,对未处理异常课通过方法头的throws字句声明该方法将产生异常.在其他方法中调用会产生异常的方法必须对异常进行处理或在自己的方法头中声明抛出异常
数据的读取通常是按照顺序逐个字节进行访问,在某些特殊情况下,要重复处理某个字节可以通过mark()加标记,以后用reset()返回该标记处再处理
要从键盘得到整数只能先读取字符串,再利用其他方法,如:Integer.parseInt(String)将数字字符串转化为整数.
FileOutStreamfile = new FileOutStream(“x.dat”);
DataOutStreamout = new DataOutputStream(file);
首先创建一个FileOutStream文件输出流,如果对应名称的文件不存在,系统会自动新建一个该名字的文件,.而后,针对该文件,创建了一个DataOutputStream流,这样可以利用该流给文件写入各种基本类型的数据.
publicvoid write(int c);往一个文件写入一个字符,它是将证书的低16位对应的数据写入文件,高16位忽略.
当输入源的数据不符合对象规范或无数据时将产生IOException异常
调用对象输入流的readObiect()方法必须捕捉ClassNotFound异常
为了实现用户自定义对象的串行化,相应的类必须实现Serializable接口,否则,不能以对象形式正确写入文件
创建新线程必须编写一个线程类,用java编写多线程代码有两种方式:第一种方式是直接继承java的线程类Thread;第二种方式是实现Runnable接口.无论采用哪种方式均需要在程序中编写run()方法,线程在运行时要完成的任务在该方法中实现
下面几种情况下,当前线程会放弃CPU:
1. 当前时间片用完
2. 线程在执行时调用了yield()或sleep()方法主动放弃
3. 进行i/o访问,等待用户输入,导致线程阻塞,或者为等候一个条件变量,线程调用wait()方法
4. 有高优先级的线程参与调度
注意在程序中不要直接调用run()方法,而是调用线程对象的start()方法启动线程,让其进入可调度状态,线程获得调度时自动执行run()方法
import java.applet.*;
import java.awt.*;
class countbutton extends Button implements Runnable{
int count = 0;
public countbutton(String s){
super(s);
}
public void run(){
while(count < 10000){
try{
this.setLabel("" + count ++);
Thread.sleep((int)(10000 * Math.random()));
}
catch(Exception e){}
}
}
}
public classCountApplet extends Applet{
public void init(){
setLayout(null);
countbuttont1 = newcountbutton("first");
t1.setBounds(30,10, 80, 40);
add(t1);
countbuttont2 = newcountbutton("second");
t2.setBounds(130,10, 80, 40);
add(t2);
(new Thread(t1)).start();//创建线程,将计数按钮传递给线程
(new Thread(t2)).start();
}
}
运行程序将发现两个按钮的标签上现实的数字不断增加,这里的按钮由于实现了Runnable接口,具备线程运行的方法要求,将该”按钮”对象作为Thread的参数可以创建线程,线程运行时将执行”按钮”对象的run方法.另外,该程序没有采用布局管理器,而是通过部件的setBounds方法来规定位置,宽,高
调用yield()的效果等于调度程序认为该线程已经执行了足够的时间从而转到另一个线程
通过执行suspend()方法可以让线程无限等待(Suspending),直到其他线程向这个线程发送resume()消息让其恢复运行.就是让线程阻塞,并且不会恢复
线程在进行输入/输出时将等待外界提供数据,这种行为称为阻塞(不占用CPU时间)
设置为哪种线程的方法是setDaemon(Boolean on),该方法必须在线程启动前执行
只有程序存在用户线程时,程序才能保持运行.如果所有的用户线程均终止了执行,则所有的看守线程也将结束运行
在main方法中创建的线程默认为用户线程
执行main方法的线程是用户级线程
如果希望main方法结束时,终止整个程序的运行,则可以将所有线程指定为看守线程,这样在main结束的时候就不存在用户线程了
多个线程共享的数据称为临界资源,
可以采用synchronized给调用方法的对象加锁,保证一个方法处理的对象资源不会因其他方法的执行而改变,这就不会出现在调用这个资源的时候被其他代码运用这个资源,要等这个代码运行完其他代码才能用这个资源,所以叫做给这个资源加锁
Synchronized关键字的使用方法有两种:
1. 用在对象面前,限制一段代码的执行,表示执行该段代码必须取得对象锁
2. 在方法前面,表示该方法为同步方法,执行该方法必须取得对象锁
wait()方法使得线程进入阻塞状态,执行notify()方法时将释放相应对象占用的锁,从而可使因对象资源锁而处于等待的线程得到运行的机会.
wait()方法和notify()方法在概念上有如下特征:
1. 这对方法必须在synchronized方法或块中调用,只有在同步代码段中才存在资源锁定
2. 这对方法直接隶属于Object类,而不是Thread类.也就是说,所有对象都拥有这一对方法
在java.net包中提供了邓黻的网络功能,例如,用InetAddress类表示IP地址,用URL类封装对网络资源的访问,用ServerSocket和Socket类实现面向连接的网络通信,用DatagramPacket和DatagramSocket实现数据报的收发
一个简单的连接程序
服务器程序:
import java.net.*;
import java.io.*;
public classSimpleServer {
public static void main(String args[]){
ServerSockets = null;
try{
s= newServerSocket(5432);//规定服务端口
}catch(IOException e){}
while(true){
try{
Sockets1 = s.accept();//等待客户连接
OutputStreams1out = s1.getOutputStream();//取得Socket的输出流
DataOutputStreamdos = newDataOutputStream(s1out);
dos.writeUTF("Hello World!");
System.out.println("a client is conneted...");
s1.close();
}catch(IOException e){}
}
}
}
客户程序:
import java.net.*;
import java.io.*;
public classSimpleClient {
public static void main(String args[])throws IOException{
Sockets = newSocket("localhost",5432);//申请与服务器的5432端口连接
InputStreamsIn = s.getInputStream();//取得Socket的输入流
DataInputStreamdis = newDataInputStream(sIn);
Stringmessage = newString(dis.readUTF());//读取服务器发送的数据
System.out.println(message);
s.close();
}
}