Java SE 学习笔记 第八记

2012-07-27

1、AWT:Java第一代的GUI,是重量级的,将实际生成界面组件的操作委托给具体的操作系统GUI相关的API去完成,所以不同的操作系统生成的界面外观和感官是不同的。

2、Swing:Sun推出的GUI组件,属于轻量级,可以屏蔽掉操作系统实现的细节。

3、AWT中所有的容器类都继承与java.awt.Container,主要包含Window和Panel两个子类。Window主要包含Frame和Dialog框架类,是顶级窗口容器,相当于图形界面程序的最外层。Panel主要是包含各种组件面板容器(所有组件必须包含到一个容器中),并且Panel无法单独显示,必须添加到一个容器中。每个Panel都有自己的布局管理器,即使是添加到其他Panel中的Panel。

4、布局管理器:能够根据相应布局管理器的规则自动管理容器中组件的大小和位置,通过setLayout()设置容器的布局管理器。使用布局管理器后,容器中组件的setLocation()、setSize()、setBounds()方法的设置都会被屏蔽。

5、Frame必须设置setVisible(Boolean bool)方法为true,窗口程序才可见。Frame的pack()方法调用后会以正常显示Frame内所有组件最佳的比例显示窗口。

6、BorderLayout布局管理器:将组件分为东南西北中五个区域,是Frame默认的布局管理器。其中每个区域只能加入一个组件,如果加入过个组件,则后加入的组件会覆盖之前的组件。当容器发生大小变换的时候,南北区域只能在水平方向上缩放,东西区域只能在垂直方向上缩放,中间区域可再垂直方向和水平方向上一起缩放。当一个区域没有填充组件的时候,其他区域会自动延伸。

7、FlowLayout布局管理器:流布局管理器,Panel默认的布局管理器,将组件按顺序排列,默认是按行排列,不会改变组件大小,但是当一行容不下所有组件时,会自动换行。

8、GridLayout布局管理器:网格布局管理器,组件按行从左到右添加,行满换行继续添加。一个组件可以跨越多个网格。

9、CardLayout布局管理器:将界面看做一系列卡片的布局,并且在一个时刻只能显示一个卡片的内容,使用show()方法切换卡片。

10、事件模型包括:事件(事件也是一个对象,集成了相关事件的信息,通过传递事件将事件信息给处理方法)、事件源、事件处理器(接收事件、解释事件并处理用户交互的方法)。

11、JDK1.0的事件模型是层次模型,事件产生后会在产生事件的组件类处理,如果处理不了则会由包含组件的容器处理器,知道到Frame也无法处理的话,则不处理。这种模型的弊端是会造成事件处理方法的混乱,很难辨清事件到底会在哪里被处理,故从JDK1.1开始不再使用这种事件模型,而是委托模型,将事件处理委托给指定的监听器处理,一个组件的某个事件对应一个监听器,如果没有对应的监听器则不会由上层容器的监听器处理,即不会处理这个事件。

12、典型的事件类型:MouseEvent(鼠标事件,包含了关于鼠标位置等鼠标操作信息)、WindowEvent(窗口事件,包含窗口关闭等窗口操作信息)、ActionEvent(动作事件,包含相应组件基本操作的信息)。

13、委托模型的处理过程:当一个组件产生一个事件后,该组件对应这个事件所注册的监听器addXxxListener(XxxListener l),即参数XxxListener e(一般XxxListener是一个接口,使用的时候需要使用该接口的实现类)的事件处理器方法处理事件。以Button为例,单击Button后产生一个ActionEvent事件,ActionEvent事件会传递给被其注册的所有ActionListener(Button的addActionEListener()所注册)的actionPerformed(ActionEvent e)方法接收,并执行这个方法。

14、ActionEvent类的getActionCommand()方法可放回与动作相关联的命令名称,比如Button返回的Button的标签名。另外,该类中还有方法getWhen()返回发生该事件的事件。

15、委托模型使用步骤:
    1)编写监听器XxxListener中相关事件处理方法:一般AWT提供相应监听器XxxListener接口,事件的处理方法需要自定义监听器类实现这个接口,并重写这个接口中所有方法(可通过JDK帮助文档获得接口中所有的方法),把事件的处理代码放置到重写的方法中。特别的,JDK提供了适配器Adapter,Adapter适配器是实现了一个或多个接口的类,但是实现的接口方法体为空,什么事情也不做。JDK中提供了大量事件监听器接口的适配器XxxAdapter,因此,只要继承相应监听器适配器,就可以只重写监听器接口中需要用到的几个方法,以提升开发效率(如果自定义的监听器已经继承了其他类,那么只能实现接口这种方法)。
    2)为组件注册相应的监听器:可通过查询JDK文档得知该组件能够注册的监听器类型的方法。一般注册方法的格式为addXxxListener(XxxListener l),只要将自定义的监听器实例引用作为该方法参数即可向该组件注册监听器。同一个组件可以注册多个XxxListener类型的监听器。
    3)当组件接收到相应操作产生相应事件后,会根据该组件注册的监听器匹配处理该事件的监听器,并将事件对象发送给注册的处理这个事件类型的所有监听器,存在次事件的多个监听器时,它们都会接收到事件和执行处理。
    4)特别的,经常将步骤1和2合并,使用内部类监听器作为addXxxListener()的参数。

16、Input is evil!

17、观察者模式(Observer):该模式定义了一种一对多的依赖关系,使多个观察者对象同时监听某一个主题对象。只要主题对象在状态上发生了变化,主题对象就会通知所有的观察者对象,让它们更新自己的状态。

18、观察者模式的组成:
    1)抽象主题角色:主题角色之所以能被观察者角色监听,原因在于主题角色中存在一个保存了该主题角色对所有观察者对象的应用的集合。抽象主题角色一般是一个抽象类或者接口,并且至少要提供增加或删除观察者角色对象应用的方法,以及通知观察者对象主题角色状态发生改变的方法。
    2)具体主题角色:是抽象主题角色的子类或者实现对象,具体包含了一个或多个观察者类型的集合,并且实现了抽象主题角色中的方法,同时也具有具体自我特征的成员变量和方法。
    3)抽象观察者角色:一般也是一个接口,定义了更新自己的方法以供主题角色的通知观察者方法调用。
    4)具体观察者角色:实现抽象观察者角色接口的类,实现了具体供主题角色通知方法调用的更新自己状态的方法,以便与主题角色状态相协调。在需要的情况下,还可以保存一个指向具体主题角色的引用。

19、观察者模式的基本使用步骤:
    1)定义抽象主题角色和抽象观察者角色:一般都是接口。抽象主题角色添加或删除观察者角色方法的参数类型是观察者接口类型;它的通知观察者方法参数一般是一个对象(在事件处理机制中,一般是一个事件对象),并且会调用观察者接口中更改观察者状态的方法。抽象观察者角色更改自己状态方法的参数一般是抽象主题角色通知方法的参数类型。
    2)定义具体主题角色和具体观察者角色:都是实现了抽象主题或观察者的类。具体主题角色类中要定义抽象观察者类型的集合,增加或删除观察者方法负责把参数观察者添加或删除到集合中;通知观察者的方法中要遍历每一个集合,调用每个集合中元素及观察者类的更改自己状态的方法。观察者类中要具体实现更改自己状态的方法。
    3)new具体主题角色类和具体观察者类,使用主题角色的添加观察者方法添加观察者对象(也就是常说的注册观察者)。

20、观察者模式运行过程:当部署好主题角色和观察者角色后,一旦主题角色触发通知观察者的方法(可以是主题角色对象显示调用,或者是主题角色上定义了某些操作可以调用这个方法),观察者的更改自己的状态方法就会被调用。由此,实现了多个观察者对主题角色对象的依赖关系。

21、GUI程序的事件机制实质上就是观察者模式的运用,其中每个组件是一个具体主题对象,每个监听器是一个具体观察者对象。一旦某些操作触发了组件,底层实质是调用了通知观察者方法通知注册到组件上的每一个监听器,让它们调用更改自己状态的方法,而实现了事件处理。

————————————————————————————————————————————————————

2012-07-28

1、Swing组件主要存放于Javax.swing和Javax.swing.event两个包中。

2、Swing的三个顶层容器:JFrame、JDialog、JApplet。每一个顶层容器都默认包含一个content pane,用于包含顶层容器中所有的组件,但是不包括菜单。也就是说,顶层容器主要包括两个元素:content pane和菜单。

3、菜单的三级元素:MenuBar、Menu、MenuItem。

4、Swing提供的便捷关闭方法:Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)。

5、JDK对观察者模式提供了内置的支持:JDK提供了java.util.Observable主题类和Observer抽象观察者接口。

6、Observable主题类:该类提供了主题类应该具有的所有方法,类中存在保存Observer接口类型的观察者Vector集合。定义的主要方法有:addObserver(Observer o),当o与已有的观察者对象不同时,向集合中添加;deleteObserver(Observer o),向集合中删除观察者o;setChanged(),当主题类状态发生改变时,通过该方法记录已经发生了改变;notifyObservers(Object arg),通知所有观察者主题对象状态发生改变,会调用每个观察者对象中的update方法,并将参数arg传递过去。前提是Observable状态发生了改变,因为notifyObservers方法体中存在if语句判断状态改变常量changed是否为true,true的时候才会调用观察者中的update(如果changed为true,那么if的else最后会调用clearChange方法将changed改回false)。因此,在调用notifyObservers之前必须调用setchanged才会执行观察者中的update。

7、Observer观察者接口:接口中只定义了一个方法update(Observable o,Object arg),具体的观察者需要实现这个接口。当主题类Observable的notifyObservers方法被调用时,会调用观察者这个update方法,其中o是观察者观察的主题对象,arg是被观察主题对象notifyObservers方法传递过来的参数。update实现对观察者自身状态的修改,以协调主题对象状态的改变。

8、内部类:一般的类都是定义在package下,属于package级别类;而内部类是定义在类或方法内部的类。内部类分四种类型:静态内部类、成员内部类、局部内部类、匿名内部类。

9、静态内部类:定义在类内部,并且被static修饰,可以访问外部类的静态成员变量和静态方法。
    1)静态内部类相当于外部类的一个静态成员变量,属于类的静态成员,只是这个成员是外部类内部自己定义的一个类。在外部类的内部使用静态内部类,可以直接像使用普通类的方法使用静态内部类即可。在外部类外部,由于静态内部类类似于外部类的静态成员,所以外部类外部使用静态内部类与使用外部类静态成员方法相同,格式为“外部类名.静态内部类名”,也可以看做静态内部类的实际类名为“外部类名.静态内部类名”。因此,在外部类外部构造静态内部类实例,使用“new 外部类名.静态内部类名()”格式构造(括号内参数由静态内部类的构造方法决定)。
    2)对于静态内部类使用外部类静态成员变量和方法,只要外部类存在该静态成员和方法,在静态内部类中就可以直接调用。但如果静态内部类内部存在和外部类相同名字的静态成员变量和方法,则根据java的就近原则,静态内部类使用的是静态内部类的静态成员变量和方法。要是非得使用外部类的静态成员变量和方法,则需要在变量名和方法名前加“外部类名.”前缀来强制使用外部类的静态成员变量和方法。
    3)含有静态内部类的类编译后,除了生成外部类的class文件之外,同样会生成静态内部类的class文件,文件名为“外部类名$静态内部类名.class”。

10、成员内部类:定义在类内部,与静态内部类的区别在于少了static修饰,可以访问外部类的任何成员变量和方法。
    1)成员内部类,相当于外部类的一个成员,只是这个成员是由外部类中自己定义的类。在外部类内部,可以像使用普通类的方法直接使用成员内部类(构造的时候,new 内部类名的new前默认存在“this.”)。在外部类外部,由于成员内部类相当于外部类的一个成员,而访问类的成员必须通过类对象访问。所以要先构造一个外部类对象才可以构造一个成员内部类的对象。成员内部类的类名依然可以看做是“外部类名.成员内部类类名”,构造成员内部类的方法本质是:外部类名.成员内部类类名 成员内部类引用变量名 = 外部类对象.new 内部类名()。通常的做法是:外部类名.成员内部类类名 成员内部类引用变量名 = new 外部类名().new 内部类名()。
    2)对于成员内部类使用外部类成员变量和方法,只要外部类存在该成员变量和方法,成员内部类就可以直接使用。如果成员内部类定义了和外部类成员变量和方法相同名称的变量和方法,那么根据java就近原则,成员内部类将使用自己的变量和方法。但要是非得使用外部类的变量和方法,则需要在变量名和方法名之前加前缀“外部类名.this.”以表示使用的是外部类变量和方法。
    3)含有成员内部类的类编译后,同样除了生成外部类的class文件之外,也会以“外部类名$内部类名.class”的形式生成成员内部类的class文件。

11、局部内部类:定义在方法内部的类,只能访问方法中final修饰的变量,外部类外部无法访问到局部内部类,局部内部类是给方法是用的,一般很少是用局部内部类。
    1)局部内部类,相当于类的局部成员,存在于方法中,只能被方法使用。在方法中可以像普通类使用方法一样使用。
    2)对于局部内部类使用方法中局部变量的方法,只要是方法中存在的final修饰的局部变量,局部内部类就可以直接使用。如果方法中存在final修饰的局部变量与局部内部类中的成员变量同名,则根据就近原则,局部内部类将访问到局部内部类自己的变量,并且此时没有方法访问方法的局部变量。如果局部内部类要访问外部类的成员变量和方法,同样可以使用“外部类名.this.”前缀加外部类成员变量或者方法访问到。
    3)包含局部内部类的类编译后,除了生成外部类的class文件之外,同样也生成“外部类名$1局部内部类名.class”的局部内部类class文件(相比前两种内部类class文件,文件名$之后多了“1”)。

12、匿名内部类:定义在方法内部,没有类名,没有构造方法,不需要class关键字定义,只能访问方法中final修饰的局部变量,可以说是局部类的变形,是一种比较常用的内部类,比如事件机制中的监听器常用匿名内部类定义。
    1)匿名内部类的使用:匿名内部类默认要继承一个类或者实现一个接口,使用“new + 默认要继承的类名或者接口名(参数由继承的类或实现的接口构造方法决定){匿名内部类代码}”的方式定义并构造一个匿名内部类对象。
    2)同局部内部类一致,只能访问方法中final修饰的局部变量,如果局部变量名与匿名内部类变量名相同,根据就近原则使用匿名内部类变量。如果要使用外部类变量,同样加前缀“外部类名.this.”。
    3)包含匿名内部类的类编译后,除了生成外部类的class文件之外,也同时也生成内部类“外部类名$+阿拉伯数字.class”的class文件,$后的阿拉伯数字由1向上递增。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值