J2SE入门

来源:互联网 发布:淘宝商城下载到手机上 编辑:程序博客网 时间:2024/04/20 05:06

J2SE入门:
1.       预备知识
2.       存储方式和操作控制
3.       面向对象技术
4.       常用数据结构
5.       异常处理机制
6.       图像处理和音频操作
7.       图形化界面(swing)
8.       多线程技术
9.       I/O操作
10.   基本网络技术

 
预备知识
㈠Java的历史背景不用多说了
㈡环境变量设置及原理
开发Java程序的第一步必须设置环境变量,它主要包括PATH和CLASSPATH的设置,理解PATH和CLASSPATH的作用对于Java程序的运行是有一定好处的。
PATH:操作系统执行某一命令时都会通过PATH进行搜索;如果将Java的一些工具诸如Java、Javac、Javadoc等的路径也加入PATH,则当运行Java的编译器或解释器时系统就可以搜索到这些工具并执行操作,这些工具都在jdk目录下的bin目录下。
PATH的设置如下(设jdk装在C:/j2sdk1.4.2/):
PATH=%PATH%;C:/j2sdk1.4.2/bin;
注:%PATH%表示将原来的PATH路径保留,也可不设此项而直接将jdk路径加到原PATH路径下。;为Windows下的分隔符(Linux下为:)。
CLASSPATH:为一个路径列表,用于搜索Java编译或者运行时需要用到的类。虚拟机按以下顺序搜索并装载所有需要的类:
    引导类: 组成 java 平台的类, 包含 rt.jar 和 i18n.jar 中的类.
    扩展类: 使用 java 扩展机制的类, 都是位于扩展目录($JAVA_HOME/jre/lib/ext)中的 .jar 档案包.
       用户类: 开发者定义的类或者没有使用 java 扩展机制的第三方产品. 
CLASSPATH的设置如下:
CLASSPATH=.;C:/j2sdk1.4.2/lib/tools.jar; C:/j2sdk1.4.2_05/jre/lib/rt.jar
注:.表示当前目录,如果觉得这个目录名太繁琐,可以先设一个JAVA_HOME,并令JAVA_HOME=C:/j2sdk1.4.2/,然后再设CLASSPATH的格式为:%JAVA_HOME%lib/tools.jar等就可以了。dt.jar是关于运行环境的类库,tools.jar是关于一些工具的类库
 
注意事项:
程序与类
Java源程序中只能有一个public类,但可以有任意个普通类,且此程序文件名必须与public类的类名相同。
包操作
一般为方便管理都将Java的类各自作成一个文件,再放入一个Package中,即一个包中包含若干类包括主类和普通类。运行编译后的程序格式为:
       java 包名.主类名
编码习惯
       Java开发过程中一定要养成良好的编码习惯(要从娃娃抓起^_^),如编写见文识义的标识符、代码缩进格式、标准而详细的注释等等。
 

 
 
存储方式和操作控制
       所谓的存储方式和操作控制其实就是数据结构的选择和算法的设计。程序写多了这方面的能力自然能慢慢提高。
㈠存储方式指的是Java的数据类型,在程序设计时变量的选择也是很重要的,在符合要求的情况下应尽量考虑性能。
简单数据类型包括:
     整数类型(Integer):byte, short, int, long
     浮点类型(Floating):float,double
     字符类型(Textual):char
     布尔类型(Logical):boolean

复合数据类型包括:
               字符串类型:String
数组
  class
interface
     
㈡操作方法主要是指程序设计中经常用到的顺序、转移、循环等控制语句。无论再复杂的程序,都离不开这些控制语句。因此熟练掌握这些语句的运用,才能写出优美而高效的代码。
顺序执行
 
条件转移
Ⅰ     if(exp) {
 
}else(exp) {
 
}
Ⅱ     switch(exp) {
               case ? :           break;
               case ? :           break;
               …….
               default :          break;
}
 
循环操作
Ⅰ     for(  ;      ;      ) {
 
}
Ⅱ     while(exp) {
 
}
    跳转指令
Ⅰ  break;
Ⅱ  continue;
Ⅲ  return;
 
注:
在操作中有些技巧可以采用:如在循环操作时可将判断结束条件设为死循环的类型(如while(true)),再在程序段内部设置条件break。
break与continue的区别:break语句是跳出它所指定的块,不再进行终止条件的判断,并从紧跟该块的第一条语句处执行;continue语句用来结束本次循环,跳过循环体中下面尚未执行的语句,接着进行终止条件的判断,以决定是否继续循环。
 
 

 
 
面向对象技术
OO是一门高深的思想,也是现代软件设计的常用思想。OO中有许多前人总结的原则,应该尽量借鉴。比如优先使用类聚合而非继承、针对接口编程、力求松耦合高内聚等等。《设计模式精解》一书中的第一章对于OO和设计模式入门非常不错,讲得深入浅出。一般OO和设计模式配合进行软件设计能够发挥令人出乎意料的效果,所以力荐OO和设计模式一起学,在此再介绍一本设计模式的圣经《设计模式--可复用面向对象软件的基础》(虽然是用C++实现的,不过思想与语言无关),书中所介绍的23种模式是对以往软件开发中的一些解决方案的精炼萃取,让人耳目一新,值得一读。
 
㈠OO基本思想是使用类、对象、继承、封装、消息等基本概念来进行程序设计。
基本特性为封装性、继承性、多态性:
封装性:将对象的属性和操作结合成一个实体,对外尽量隐藏内部细节,只对类用户提供接口。基本原则是不对外提供public的成员变量,而利用bean的特点提供存取成员变量的set、get方法。
继承性:可以不太准确地归结为父类拥有共性,子类拥有特性,如客轮是轮船和客运工具的特殊类,轮船是父类,客轮是实现客运功能的子类。
多态性:对象的多态性是指在一般类中定义的属性或服务被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。如:"几何图形"的"绘图"方法,"椭圆"和"多边形"都是"几何图"的子类,其"绘图"方法功能不同。
 
㈡关键性技术:
类、对象
类和对象的关系就像模具和铸件的关系。
类声明:
[public][abstract|final] class className [extends superclassName]
[implements interfaceNameList] {
成员变量;
成员方法;
}
成员变量:
       [public | protected | private ] [static]
  [final] [transient] [volatile] type variableName;                 
  变量声明中限定词的含义:
  static: 静态变量(类变量);相对于实例变量
  final: 常量
  transient: 暂时性变量,用于对象存档
  volatile: 贡献变量,用于并发线程的共享
成员方法:
       [public | protected | private ] [static]
  [final | abstract] [native] [synchronized]
  returnType methodName([paramList]) [throws exceptionList] {statements}
  方法声明中的限定词的含义:
  static: 类方法,可通过类名直接调用
  abstract: 抽象方法,没有方法体,由子类实现
  final: 方法不能被重写
  native: 集成其它语言的代码
  synchronized: 控制多个并发线程的访问
类中的限定词:
private
类中限定为private的成员,只能被这个类本身访问。如果一个类的构造方法声明为private,则其它类不能生成该类的一个实例。
Default
类中不加任何访问权限限定的成员属于缺省的(default)访问状态,可以被这个类本身和同一个包中的类所访问。
protected
类中限定为protected的成员,可以被这个类本身、它的子类(包括同一个包中以及不同包中的子类)和同一个包中的所有其他的类访问。
public
类中限定为public的成员,可以被所有的类访问
      
构造方法:
构造方法是一个特殊的方法。Java 中的每个类都有构造方法,用来初始化该类的一个对象。构造方法具有和类名相同的名称,而且不返回任何数据类型。
重载经常用于构造方法。构造方法只能由new运算符调用。
 
方法重载和方法重写:
方法重载是指多个方法享有相同的名字,但是这些方法的参数必须不同,或者是参数的个数不同,或者是参数类型不同。返回类型不能用来区分重载的方法。
方法重写是指具有继承关系的父子类的方法享有相同名字,子类中重写的方法和父类中被重写的方法要具有相同的名字,相同的参数表和相同的返回类型,只是函数体不同。java运行时系统根据调用该方法的实例,来决定调用哪个方法。对子类的一个实例,如果子类重写了父类的方法,则运行时系统调用子类的方法;如果子类继承了父类的方法(未重写),则运行时系统调用父类的方法。
方法重写时应遵循的原则:
1)改写后的方法不能比被重写的方法有更严格的访问权限(可以相同)。
2)改写后的方法不能比重写的方法产生更多的例外。
注:重载用于同一个类中的同名方法,重写用于具有继承关系的父子类的同名方法。
 
常用关键字释疑
1)static
static变量:所有此类实例共享此静态变量,也就是说在类装载时,只分配一块存储空间,所有此类的对象都可以操控此块存储空间。
static方法:无需本类的对象即可调用此方法,调用一个静态方法就是“类名.方法名”。
static类:通常一个普通类不允许声明为静态的,只有一个内部类才可以。这时这个声明为静态的内部类可以直接作为一个普通类来使用,而不需实例一个外部类。
2)final
final成员:对基本类型来说是其值不可变,而对于对象变量来说其引用不可再变。初始化可以在两个地方,一是其定义处,也就是说在final变量定义时直接给其赋值,二是在构造函数中。这两个地方只能选其一,要么在定义时给值,要么在构造函数中给值,不能同时既在定义时给了值,又在构造函数中给另外的值。
final方法:将方法声明为final,那就说明你已经知道这个方法提供的功能已经满足你要求,不需要进行扩展,并且也不允许任何从此类继承的类来覆写这个方法,但是继承仍然可以继承这个方法,也就是说可以直接使用。
final类:final类与普通类的使用几乎没有差别,只是它失去了被继承的特性。
3)super、this(常用于构造方法中)
super的用法:
访问父类被隐藏的成员变量,如:
super.variable;
调用父类中被重写的方法,如:
super.Method([paramlist]);
调用父类的构造函数,如:
super([paramlist]);
this通常指代当前对象,super通常指代父类。在构造方法中super后加参数的是用来调用父类中具有相同形式的构造函数;this后加参数则调用的是当前具有相同参数的构造函数
 
对象的操作控制
对象的生成:
声明:声明并不为对象分配内存空间,而只是分配一个引用空间;对象的引用类似于指针,是32位的地址空间,它的值指向一个中间的数据结构,它存储有关数据类型的信息以及当前对象所在的堆的地址,而对于对象所在的实际的内存地址是不可操作的,这就保证了安全性。实例化:运算符new为对象分配内存空间,它调用对象的构造方法,返回引用;一个类的不同对象分别占据不同的内存空间。
对象的使用:
由于封装性的基本原则是指对外提供接口而尽量不提供public的成员变量,所以一般也只能使用“.”来引用类中的成员方法。对象的使用实际是传递消息以改变某些属性或进行某些操作。
对象的清除:
Java的垃圾收集器自动扫描对象的动态内存区,把没有引用的对象作为垃圾收集起来并释放。System.gc( ); 当系统内存用尽或调用System.gc( )要求垃圾回收时,垃圾回收线程与系统同步运行。
 
继承(抽象类)、接口
抽象类:
abstract class abstractClass{ …} //抽象类
  abstract returnType abstractMethod([paramlist]) //抽象方法
抽象类必须被继承,抽象方法必须被重写。抽象方法只需声明,无需实现;抽象类不能被实例化,抽象类不一定要包含抽象方法。若类中包含了抽象方法,则该类必须被定义为抽象类。
接口:
       [public] interface interfaceName[extends listOfSuperInterface] { … }
接口是抽象类的一种,只包含常量和方法的定义,而没有变量和方法的实现,且其方法都是抽象方法。
注:
一个类只能使用一次继承关系,但却可以有多个接口。
抽象类表示的是"is a"关系,接口表示的是"like a"关系。(涉及到设计模式)
 
内部类
内部类是在一个类的内部嵌套定义的类,它可以是其它类的成员,也可以在一个语句块的内部定义,还可以在表达式内部匿名定义。   
匿名类是一种特殊的内部类,它是在一个表达式内部包含一个完整的类定义(消息响应类等)。
内部类优缺点比较:
  ◇ 优点:节省编译后产生的字节码文件的大小
  ◇ 缺点:使程序结构不清楚
 
 

 
 
常用数据结构
Vector
ArrayList
List
Queue
Map
Tree
Stack
Hashtable
Enumeration
等等。。。
注:一般这些数据结构中的数据存取都是以Oject为对象的,因此从其中取出的数据要进行类型转换,另int等不能直接存入这些数据结构中,必须使用外覆类(如Integer等)进行重新包装才能存入。
 
Java比C++更易于使用的一方面应该就是Java提供了丰富的数据结构给用户而不必让用户自己设计半天数据结构,最后搞了半天却发现还是错误百出,郁闷不已。由于Sun将这些数据结构封装得很好,所以只要理解这些数据结构的特点和了解他们的接口方法就可以使用他们了。
一般在学习开发中可以在需要时查帮助文档就可以搞定了,不过只有深刻地理解这些数据结构的特性才能选择最佳的数据结构开发出优秀的代码。
 
 
 
 
异常处理机制
异常实际上是程序中错误导致中断了正常的指令流的一种事件。
所有的例外类都直接或间接地继承于Throwable类。Throwable又分为两大子类Error和Exception,其中Error由虚拟机直接处理,部分Exception由用户处理。
 
捕获例外的一般框架:
try{
  ......
}catch( ExceptionName1 e ){
   ......            
System.out.println( "message: " + e.getMessage() );  //e.getMessage( )是类Throwable所提供的方法,用来得到有关异常事件的信息。
}catch( ExceptionName2 e ){
   ......     
     e.printStackTrace( System.out );   //e.printStackTrace( )用来跟踪异常事件发生时执行堆栈的内容。
}
   ......
}finally{
   ......             //此部分无论是否产生例外均需执行,除非System.exit(0)
}
 
当Java运行时系统得到一个例外对象时,它将会沿着方法的调用栈逐层回溯,寻找处理这一例外的代码。找到能够处理这种类型的例外的方法后,运行时系统把当前例外对象交给这个方法进行处理,这一过程称为捕获(catch)例外。
注:捕获例外的顺序和catch语句的顺序有关,当捕获到一个例外时,剩下的catch语句就不再进行匹配。因此,在安排catch语句的顺序时,首先应该捕获最特殊的例外,然后再逐渐一般化。也就是一般先安排子类,再安排父类。
 
throws与throw
throw是语句抛出一个异常,throws是方法抛出一个异常。
throw:throw<异常对象>
throws:[<修饰符>]<返回值><方法名>([<参数列表>])[throws<异常类>]
声明抛弃例外
如果在一个方法中生成了一个例外,但是这一方法并不确切地知道该如何对这一异常事件进行处理,这时,一个方法就应该声明抛弃例外,使得例外对象可以从调用栈向后传播,直到有合适的方法捕获它为止。声明抛弃例外是在一个方法声明中的throws子句中指明的。例如:
  public int read () throws IOException {
        ......
  }
 
抛出例外
抛出例外就是产生例外对象的过程,首先要生成例外对象,例外或者由虚拟机生成,或者由某些类的实例生成,也可以在程序中生成。在方法中,抛出例外对象是通过throw语句实现的。
  例如:
  IOException e = new IOException();
  throw e ;  //人为抛出异常
 
注:throw是明确抛出一个异常给上层;throws是标明一个方法可能抛出的各种异常。
throws可以单独使用,throw不能。
 
自定义异常
异常是一个类,用户定义的异常必须继承自Throwable或Exception类,建议用Exception类。
 
常见的异常
ArithmeticException
ArrayIndexOutOfBandsException
ArrayStoreException
IOException
FileNotFoundException
NullPointerException
MalformedURLException
NumberFormatException
OutOfMemoryException
 
 
 
 
图像处理和音频操作
图像处理
Java在桌面程序的功能不是非常的强大,因此较少用于开发桌面程序,但这方面的知识还是需要了解一下。一般图像处理分为应用程序中和Applet中:
应用程序中的图像一般都封装成ImageIcon,在将其贴到Button、Label上,如:
JButton btn = new JButton();
ImageIcon img = new ImageIcon(path);
btn.setIcon(img);
Applet中一般直接从文件从取出图像直接使用,如:
Image img = new Image();
Img = getImage(getDocumentBase(),imageFile);
……..
2D绘图一般都在Applet中实现,通过复写paint方法实现。在应用程序中也可自己new一个Graphics得到绘图句柄。具体的平移、翻转等算法不再此述。
注:awt中一般用paint,swing中则用paintComponent
双缓冲,有时图像在刷新时会产生闪烁,可以用双缓冲进行改善。双缓冲是在图像进行update时再创建一个绘图句柄进行绘图。
 
音频操作
音频操作和图像处理也是类似的,一般也用于Applet中实现,如:
AudioClip first = getAudioClip(getDocumentBase(),"first.au");
first.play();
如果要在应用程序中实现音频操作,可以通过Applet转换,如:
Audio audio = Applet.newAudioClip(audio_path);
audio.play();
注:Java实现的音频操作是很弱的,一般只用于播放midi、au等格式的音频文件,而对于mp3等若要播放必须有解码器,但实现起来是很不划算的(比较复杂)。
 
 
 
 
图形化界面(swing)
Swing简介
Swing是由100%纯Java实现的,Swing组件是用Java实现的轻量级( light-weight)组件,没有本地代码,不依赖操作系统的支持,这是它与AWT组件的最大区别。
Swing采用了一种MVC的设计范式,即"模型-视图-控制"(Model-View-Controller),其中模型用来保存内容,视图用来显示内容,控制器用来控制用户输入。
 
Swing的类层次结构
在javax.swing包中,定义了两种类型的组件:顶层容器(JFrame,JApplet,JDialog和JWindow)和轻量级组件。Swing组件都是AWT的Container类的直接子类和间接子类。
   java.awt.Component
    -java.awt.Container
       -java.awt.Window
          -java.awt.Frame-javax.swing.JFrame
          -javax.Dialog-javax.swing.JDialog
          -javax.swing.JWindow
       -java.awt.Applet-javax.swing.JApplet
       -javax.swing.Box
       -javax.swing.Jcomponet
 
MVC(Model-View-Control)体系结构
在一个MVC用户界面中,存三个通讯对象:模型、视图和控件。模型是指定的逻辑表示法,视图是模型的可视化表示法,而控件则指定了如何处理用户输入。当模型发生改变时,它会通知所有依赖它的视图,视图使用控件指定其相应机制。MVC是现有的编程语言中制作图形用户界面的一种通用的思想,其思路是把数据的内容本身和显示方式分离开,这样就使得数据的显示更加灵活多样。
 
在Swing组件中,使用JComponent类的registerKeyboardAction()方法,能使用户通过键盘操作来替代鼠标驱动GUI上Swing组件的相应动作。
 
Swing程序结构简介
Swing的程序设计一般可按照下列流程进行:
  1. 引入Swing包
  2. 选择"外观和感觉"
  3. 设置顶层容器
  4. 设置按钮和标签
  5. 向容器中添加组件
  6. 在组件周围添加边界
  7. 进行事件处理
 
组件的分类:
组件从功能上分可分为:
①顶层容器:JFrame,JApplet,JDialog,JWindow共4个
②中间容器:JPanel,JScrollPane,JSplitPane,JToolBar 
③特殊容器:在GUI上起特殊作用的中间层,如JInternalFrame,JLayeredPane,JRootPane.④基本控件:实现人际交互的组件,如Jbutton, JComboBox, JList, JMenu, JSlider, JtextField。
⑤不可编辑信息的显示:向用户显示不可编辑信息的组件,例如JLabel, JProgressBar, ToolTip。
⑥可编辑信息的显示:向用户显示能被编辑的格式化信息的组件,如JColorChooser, JFileChoose, JFileChooser,Jtable, JtextArea。
 
JComponent类的特殊功能又分为:
  1) 边框设置:使用setBorder()方法可以设置组件外围的边框,使用一个EmptyBorder对象能在组件周围留出空白。
  2) 双缓冲区:使用双缓冲技术能改进频繁变化的组件的显示效果。与AWT组件不同,JComponent组件默认双缓冲区,不必自己重写代码。如果想关闭双缓冲区,可以在组件上施加setDoubleBuffered(false)方法。
  3) 提示信息:使用setTooltipText()方法,为组件设置对用户有帮助的提示信息。
  4) 键盘导航:使用registerKeyboardAction( ) 方法,能使用户用键盘代替鼠标来驱动组件。JComponent类的子类AbstractButton还提供了便利的方法--用setMnemonic( )方法指明一个字符,通过这个字符和一个当前L&F的特殊修饰共同激活按钮动作。
  5) 可插入L&F:每个Jcomponent对象有一个相应的ComponentUI对象,为它完成所有的绘画、事件处理、决定尺寸大小等工作。 ComponentUI对象依赖当前使用的L&F,用UIManager.setLookAndFeel( )方法可以设置需要的L&F.
  6) 支持布局:通过设置组件最大、最小、推荐尺寸的方法和设置X、Y对齐参数值的方法能指定布局管理器的约束条件,为布局提供支持。
 
使用Swing的基本规则
与AWT组件不同,Swing组件不能直接添加到顶层容器中,它必须添加到一个与Swing顶层容器相关联的内容面板(content pane)上。内容面板是顶层容器包含的一个普通容器,它是一个轻量级组件。基本规则如下:
  (1)把Swing组件放入一个顶层Swing容器的内容面板上
  (2)避免使用非Swing的重量级组件。
对JFrame添加组件有两种方式:
  1) 用getContentPane( )方法获得JFrame的内容面板,再对其加入组件:frame.getContentPane().add(childComponent)
  2) 建立一个Jpanel或 JDesktopPane之类的中间容器,把组件添加到容器中,用setContentPane()方法把该容器置为JFrame的内容面板:
    Jpanel contentPane=new Jpanel( );
     ......                      //把其它组件添加到Jpanel中;
    frame.setContentPane(contentPane);
                                 //把contentPane对象设置成为frame的内容面板
 
各种容器面板和组件
根面板
根面板由一个玻璃面板(glassPane)、一个内容面板(contentPane)和一个可选择的菜单条(JMenuBar)组成,而内容面板和可选择的菜单条放在同一分层。玻璃面板是完全透明的,缺省值为不可见,为接收鼠标事件和在所有组件上绘图提供方便。
根面板提供的方法:
  Container getContentPane(); //获得内容面板
  setContentPane(Container); //设置内容面
  JMenuBar getMenuBar( ); //活动菜单条
  setMenuBar(JMenuBar); //设置菜单条
  JLayeredPane getLayeredPane(); //获得分层面板
  setLayeredPane(JLayeredPane); //设置分层面板
  Component getGlassPane(); //获得玻璃面板
  setGlassPane(Component); //设置玻璃面板
 
分层面板
Swing提供两种分层面板:JlayeredPane和JDesktopPane。 JDesktopPane是JLayeredPane的子类,专门为容纳内部框架(JInternalFrame)而设置。向一个分层面板中添加组件,需要说明将其加入哪一层,指明组件在该层中的位置:
  add(Component c, Integer Layer, int position)。
 
滚动窗口(JScrollPane)
 
分隔板(JSplitPane)
 
选项板(JTabbedPane)
 
工具栏(JToolBar)
 
内部框架(JInternalFrame)
内部框架JInternalFrame就如同一个窗口在另一个窗口内部,其特点如下:
1) 必须把内部框架添加到一个容器中(通常为JDesktopPane),否则不显示;
2) 不必调用show()或setVisible()方法,内部框架随所在的容器一起显示;
3) 必须用setSize()或pack()或setBounds方法设置框架尺寸,否则尺寸为零,框架不能显示;
4) 可以用setLocation()或setBounds( ) 方法设置内部框架在容器中的位置,缺省值为0,0,即容器的左上角;
5) 象顶层JFrame一样,对内部框架添加组件也要加在它的内容面板上;
6) 在内部框架中建立对话框,不能使用JDialog作为顶层窗口,必须用JOptionPane或JInternalFrame;
7) 内部框架不能监听窗口事件,可以通过监听与窗口事件类似的内部框架(JInternalFrameEvent)处理内部框架窗口的操作。
 
按钮(JButton)
 
复选框(JCheckBox)
 
单选框(JRadioButton)
 
选择框(JComboBox)
 
文件选择器(JFileChooser)
 
标签(JLabel)
 
列表(List)
 
菜单(JMenu)
 
进程条(JProgressBar)
 
滑动条(JSlider)
 
表格(JTable)
 
树(JTree)
 
布局管理器
Swing虽然有顶层容器,但是我们不能把组件直接加到顶层容器中,Swing窗体中含有一个称为内容面板的容器(ContentPane),在顶层容器上放内容面板,然后把组件加入到内容面板中BoxLayout布局管理器按照自上而下(y轴)或者从左到右(x轴)的顺序布局依次加入组件。建立一个BoxLayout对象,必须指明两个参数:被布局的容器和BoxLayout的主轴。缺省情况下,组件在纵轴方向上居中对齐。
设置布局管理器的方法如下:
  pane.setLayout(new BoxLayout(pane,BoxLayout.Y-AXIS));
 
图形化界面需要了解但不必花太大精力,因为这方面知识更新太快,而且也不是主流技术。最近又兴SWT了,不知会否代替Swing成为开发人员的新欢。而且随着开发工具的发展,图形化界面将变得非常简单易用(不只会不会做得和Delphi一样),JBuider就做得不错,所以最好还是将精力花在其它技术上,对于图形界面的美化在需要的时候再即学即用为好,个人观点。
 
 
多线程技术
㈠线程的实现
Thread类
定义一个线程类,它继承线程类Thread并重写其中的方法 run(),这时在初始化这个类的实例时,目标target可为null,表示由这个实例来执行线程体。由于Java只支持单重继承,用这种方法定义的类不能再继承其它父类。
直接继承Thread类:
1) 不能再从其他类继承;
2) 编写简单,可以直接操纵线程,无需使用Thread.currentThread()。
Runnable接口:
提供一个实现接口Runnable的类作为一个线程的目标对象,在初始化一个Thread类或者Thread子类的线程对象时,把目标对象传递给这个线程实例,由该目标对象提供线程体 run()。这时,实现接口Runnable的类仍然可以继承其它父类。
使用Runnable接口:
   1) 可以将CPU、代码和数据分开,形成清晰的模型;
   2) 还可以从其他类继承;
   3) 保持程序风格的一致性。
例:
Thread t1 = new MyThread("T1");              //extends
clockThread = new Thread(this, "Clock");   //Runnable
 
㈡线程的调度
线程调度器按线程的优先级高低选择高优先级线程(进入运行中状态)执行。线程的优先级用数字来表示范围从1到10,即Thread.MIN_PRIORITY到Thread.MAX_PRIORITY。一个线程的缺省优先级是5,即Thread.NORM_PRIORITY。
例:void setPriority(int newPriority);
 
线程的控制
终止线程
stop()来终止线程
测试线程状态
通过Thread 中的isAlive() 方法来获取线程是否处于活动状态
线程的暂停和恢复
1) sleep() 方法
2) join()
线程的互斥与同步
为解决操作的不完整性问题,在Java 语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。关键字synchronized 来与对象的互斥锁联系。
例:
public void push(char c) {
        synchronized(this) {      //this表示Stack的当前对象
               data[idx] = c;
               idx++;
        }
}
public char pop() {
        synchronized(this) {
               idx--;
               return data[idx];
        }
}
synchronized还可修饰方法和类
注意:
wait、nofity、notifyAll必须在已经持有锁的情况下执行,所以它们只能出现在synchronized作用的范围内,也就是出现在用synchronized修饰的方法或类中。
线程组
线程是被个别创建的,但可以将它们归类到线程组中,以便于调试和监视。只能在创建线程的同时将它与一个线程组相关联。在使用大量线程的程序中,使用线程组组织线程可能很有帮助。
线程间通信
当线程在继续执行前需要等待一个条件时,仅有 synchronized 关键字是不够的。虽然 synchronized 关键字阻止并发更新一个对象,但它没有实现线程间发信。Object 类为此提供了三个函数:wait()、notify() 和 notifyAll()。

 
 
I/O操作
两大基类:InputStream和OutputStream、Reader和Writer
Ⅰ字节流:
从InputStream和OutputStream派生出来的一系列类。这类流以字节(byte)为基本处理单位。
  ◇ InputStream、OutputStream
  ◇ FileInputStream、FileOutputStream
  ◇ PipedInputStream、PipedOutputStream
  ◇ ByteArrayInputStream、ByteArrayOutputStream
  ◇ FilterInputStream、FilterOutputStream
  ◇ DataInputStream、DataOutputStream
  ◇ BufferedInputStream、BufferedOutputStream
Ⅱ字符流:
从Reader和Writer派生出的一系列类,这类流以16位的Unicode码表示的字符为基本处理单位。
  ◇ Reader、Writer  //抽象基类
  ◇ InputStreamReader、OutputStreamWriter
  ◇ FileReader、FileWriter
  ◇ CharArrayReader、CharArrayWriter
  ◇ PipedReader、PipedWriter
  ◇ FilterReader、FilterWriter
  ◇ BufferedReader、BufferedWriter
  ◇ StringReader、StringWriter
Ⅲ对象流
  ◇ ObjectInputStream、ObjectOutputStream
Ⅳ其它
  ◇ 文件处理:
  File、RandomAccessFile;
  ◇ 接口
  DataInput、DataOutput、ObjectInput、ObjectOutput;
 
类File提供了一种与机器无关的方式来描述一个文件对象的属性。
 
类FileInputStream和FileOutputStream用来进行文件I/O处理,由它们所提供的方法可以打开本地主机上的文件,并进行顺序的读/写。
 
随机访问文件则允许对文件内容进行随机读/写。在java中,类RandomAccessFile 提供了随机访问文件的方法。
 
过滤流在读/写数据的同时可以对数据进行处理,它提供了同步机制,使得某一时刻只有一个线程可以访问一个I/O流,以防止多个线程同时对一个I/O流进行操作所带来的意想不到的结果。类FilterInputStream和FilterOutputStream分别作为所有过滤输入流和输出流的父类。
 
几种常见的过滤流
    ◇ BufferedInputStream和BufferedOutputStream
    缓冲流,用于提高输入/输出处理的效率。
  ◇ DataInputStream 和 DataOutputStream
    不仅能读/写数据流,而且能读/写各种的java语言的基本类型。
  ◇ LineNumberInputStream
    除了提供对输入处理的支持外,LineNumberInputStream可以记录当前的行号。
  ◇ PushbackInputStream
    提供了一个方法可以把刚读过的字节退回到输入流中,以便重新再读一遍。
  ◇ PrintStream
    打印流的作用是把Java语言的内构类型以其字符表示形式送到相应的输出流。
 
字符流的处理
java中提供了处理以16位的Unicode码表示的字符流的类,即以Reader和Writer 为基类派生出的一系列类。
ⅠReader类是处理所有字符流输入类的父类。
    ⅡWriter类是处理所有字符流输出类的父类。
这两个类是抽象类,只是提供了一系列用于字符流处理的接口,不能生成这两个类的实例,只能通过使用由它们派生出来的子类对象来处理字符流。如InputStreamReader和OutputStreamWriter;BufferedReader和BufferedWriter等.
 
对象串行化
对象的寿命通常随着生成该对象的程序的终止而终止。有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复。我们把对象的这种能记录自己的状态以便将来再生的能力,叫做对象的持续性(persistence)。对象通过写出描述自己状态的数值来记录自己,这个过程叫对象的串行化(Serialization)。实现串行化需继承 Serializable接口。java.io包中,提供了ObjectInputStream和ObjectOutputStream将数据流功能扩展至可读写对象。
串行化能保存的元素
只能保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量,而且串行化保存的只是变量的值,对于变量的任何修饰符,都不能保存。
transient关键字
对于某些类型的对象,其状态是瞬时的,这样的对象是无法保存其状态的,例如一个Thread对象,或一个FileInputStream对象,对于这些字段,我们必须用transient关键字标明
定制串行化
缺省的串行化机制,对象串行化首先写入类数据和类字段的信息,然后按照名称的上升排列顺序写入其数值。如果想自己明确地控制这些数值的写入顺序和写入种类,必须定义自己的读取数据流的方式。就是在类的定义中重写writeObject()和readObject()方法。
注意:在使用完流(或文件)后必须记得讲流(或文件)关闭:in.close(); out.close(); f.close();
 
流类处理的几种常见情况(流间组合):
Ⅰ     BufferedInputStream bis = new BufferedInputStream(System.in); 
        BufferedOutputStream bos = new BufferedOutputStream(new File("filename"));     
 
Ⅱ   InputStreamReader in = new InputStreamReader(System.in);
       OutputStreamWriter out = new OutputStreamWriter(new
FileOutputStream("filename.txt"));
 
Ⅲ   BufferedReader in = new BufferedReader(new InputStreamReader(System.in));     
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new
FileOutputStream ("filename.txt"));
       PrintWriter out = new PrintWriter(new FileWriter("filename.txt"));
 
Ⅳ   FileInputStream fin = new FileInputStream(filename); /
       FileOutputStream fos = new FileOutputStream(new File("filename"));
 
Ⅴ   DataInputStream din = new DataInputStream(new FileInputStream("filename.dat")));
DataInputStream din = new DataInputStream(newBufferedInputStream (new
FileInputStream ("filename.dat")));
 
Ⅵ   ObjectInputStream s = new ObjectInputStream(new FileInputStream("filename.ser")); 
       ObjectOutputStream s = new ObjectOutputStream(new
        FileOutputStream("filename.ser"));
 
Ⅶ   RandomAccessFile inOut = new RandomAccessFile("filename.dat", "rw");      
 
 
 
基本网络技术
原理:
在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一地确定Internet上的一台主机。而TCP层则提供面向应用的可靠的或非可靠的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据的。目前较为流行的网络编程模型是客户机/服务器(C/S)结构。即通信双方一方作为服务器等待客户提出请求并予以响应。客户则在需要服务时向服务器提出申请。服务器一般作为守护进程始终运行,监听网络端口,一旦有客户请求,就会启动一个服务进程来响应该客户,同时自己继续监听服务端口,使后来的客户也能及时得到服务。
 
网络基本概念
IP地址:标识计算机等网络设备的网络地址,由四个8位的二进制数组成,中间以小数点分隔。
主机名(hostname):网络地址的助记名,按照域名进行分级管理。
端口号(port number):网络通信时同一机器上的不同进程的标识。
服务类型(service):网络的各种服务。
注意:通常一台主机上总是有很多个进程需要网络资源进行网络通讯。网络通讯的对象准确的讲不是主机,而应该是主机中运行的进程。这时候光有主机名或IP地址来标识这么多个进程显然是不够的。端口号就是为了在一台主机上提供更多的网络资源而采取得一种手段,也是TCP层提供的一种机制。只有通过主机名或IP地址和端口号的组合才能唯一的确定网络通讯中的对象:进程。
 
两类传输协议:TCP;UDP
TCP是Tranfer Control Protocol的简称,是一种面向连接的保证可靠传输的协议。通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。
 
UDP是User Datagram Protocol的简称,是一种无连接的协议,每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。
 
注意:既然有了保证可靠传输的TCP协议,为什么还要非可靠传输的UDP协议呢?主要的原因有两个。一是可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时间和网络的带宽,因此TCP传输的效率不如UDP高。二是在许多应用中并不需要保证严格的传输可靠性,比如视频会议系统,并不要求音频视频数据绝对的正确,只要保证连贯性就可以了,这种情况下显然使用UDP会更合理一些。
 
创建一个URL
类URL的构造方法都声明抛弃非运行时例外(MalformedURLException),因此生成URL对象时,我们必须要对这一例外进行处理,通常是用try-catch语句进行捕获。格式如下:
 
try {
        URL myURL = new URL(...);
}catch(MalformedURLException e) {
        ....
}
 
从URL读取WWW网络资源
当我们得到一个URL对象后,就可以通过它读取指定的WWW资源。这时我们将使用URL的方法openStream(),其定义为:
InputStream openStream();
方法openSteam()与指定的URL建立连接并返回InputStream类的对象以从这一连接中读取数据。
ex:    BufferedReader in = new BufferedReader(new InputStreamReader((new URL(...)).openStream()));
 
通过URLConnetction连接WWW
类URLConnection提供了很多方法来设置或获取连接参数,程序设计时最常使用的是getInputStream()和getOurputStream(),其定义为:
   InputSteram getInputSteram();
   OutputSteram getOutputStream();
 
通过返回的输入/输出流我们可以与远程对象进行通信。看下面的例子:
  URL url =new URL ("http://www.javasoft.com/cgi-bin/backwards");
  //创建一URL对象
  URLConnectin con=url.openConnection();
  //由URL对象获取URLConnection对象
  DataInputStream dis=new DataInputStream (con.getInputSteam());
  //由URLConnection获取输入流,并构造DataInputStream对象
  PrintStream ps=new PrintSteam(con.getOutupSteam());
  //由URLConnection获取输出流,并构造PrintStream对象
  String line=dis.readLine(); //从服务器读入一行
  ps.println("client…"); //向服务器写出字符串 "client…"
  
基于Socket(套接字)的低层次Java网络编程
网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket。Socket通常用来实现客户方和服务方的连接。Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定。
Socket通讯的一般过程:
使用Socket进行Client/Server程序设计的一般连接过程是这样的:Server端Listen(监听)某个端口是否有连接请求,Client端向Server端发出Connect(连接)请求,Server端向Client端发回Accept(接受)消息。一个连接就建立起来了。Server端和Client端都可以通过Send,Write等方法与对方通信。
对于一个功能齐全的Socket,都要包含以下基本结构,其工作过程包含以下四个基本的步骤:
  (1)创建Socket;
  (2)打开连接到Socket的输入/出流;
  (3)按照一定的协议对Socket进行读/写操作;
  (4)关闭Socket.
注意,在选择端口时,必须小心。每一个端口提供一种特定的服务,只有给出正确的端口,才能获得相应的服务。0~1023的端口号为系统所保留
 
客户端的Socket
try {
        Socket socket = new Socket("127.0.0.1",8080);
}catch(IOException e) {
        System.out.println("Error: " + e);
}
服务器端的ServerSocket
ServerSocket server = null;
try {
        server = new ServerSocket(8080);
}catch(IOException e) {
        System.out.println("can not listener to : " + e);
}
Socket socket = null;
try {
        //accept()是一个阻塞方法,一旦有客户请求,它就会返回一个Socket对象用于同客户进行交互
        socket = server.accept();
}catch(IOException e) {
        System.out.println("Error : " + e);
}
打开输入/出流类Socket提供了方法getInputStream ()和getOutStream()来得到对应的输入/输出流以进行读/写     操作,这两个方法分别返回InputStream和OutputSteam类对象。为了便于读/写数据,我们可以在返回的输入/输出流对象上建立过滤流,如DataInputStream、DataOutputStream或PrintStream类对象,对于文本方式流对象,可以采用InputStreamReader和OutputStreamWriter、PrintWirter等处理。
 
关闭Socket
每一个Socket存在时,都将占用一定的资源,在Socket对象使用完毕时,要其关闭。关闭Socket可以调用Socket的Close()方法。在关闭Socket之前,应将与Socket相关的所有的输入/输出流全部关闭,以释放所有的资源。而且要注意关闭的顺序,与Socket相关的所有的输入/输出该首先关闭,然后再关闭Socket。
数据报(Datagram)
所谓数据报(Datagram)就跟日常生活中的邮件系统一样,是不能保证可靠的寄到的,而面向链接的TCP就好比电话,双方能肯定对方接受到了信息。
Datagram通讯的表示方法:DatagramSocket;DatagramPacket
原理:
包java.net中提供了两个类DatagramSocket和DatagramPacket用来支持数据报通信,DatagramSocket用于在程序之间建立传送数据报的通信连接, DatagramPacket则用来表示一个数据报。用数据报方式编写client/server程序时,无论在客户方还是服务方,首先都要建立一个DatagramSocket对象,用来接收或发送数据报,然后使用DatagramPacket类对象作为传输数据的载体。在接收数据前,应该采用上面的第一种方法生成一个DatagramPacket对象,给出接收数据的缓冲区及其长度。然后调用DatagramSocket 的方法receive()等待数据报的到来,receive()将一直等待,直到收到一个数据报为止。
  DatagramPacket packet=new DatagramPacket(buf, 256);
  Socket.receive (packet);
发送数据前,也要先生成一个新的DatagramPacket对象,这时要使用上面的第二种构造方法,在给出存放发送数据的缓冲区的同时,还要给出完整的目的地址,包括IP地址和端口号。发送数据是通过DatagramSocket的方法send()实现的,send()根据数据报的目的地址来寻径,以传递数据报。
  DatagramPacket packet=new DatagramPacket(buf, length, address, port);
Socket.send(packet);
 
 
 
原创粉丝点击