回顾Java Beans

我们现在已理解了同步,接着可换从另一个角度来考察Java Beans。无论什么时候创建了一个Bean,就必须假定它要在一个多线程的环境中运行。这意味着:
(1) 只要可行,Bean的所有公共方法都应同步。当然,这也带来了“同步”在运行期间的开销。若特别在意这个问题,在关键区域中不会造成问题的方法就可保留为“不同步”,但注意这通常都不是十分容易判断。有资格的方法倾向于规模很小(如下例的getCircleSize())以及/或者“微小”。也就是说,这个方法调用在如此少的代码片里执行,以至于在执行期间对象不能改变。如果将这种方法设为“不同步”,可能对程序的执行速度不会有明显的影响。可能也将一个Bean的所有public方法都设为synchronized,并只有在保证特别必要、而且会造成一个差异的情况下,才将synchronized关键字删去。
(2) 如果将一个多造型事件送给一系列对那个事件感兴趣的“听众”,必须假在列表中移动的时候可以添加或者删除。

第一点很容易处理,但第二点需要考虑更多的东西。让我们以前一章提供的BangBean.java为例。在那个例子中,我们忽略了synchronized关键字(那时还没有引入呢),并将造型设为单造型,从而回避了多线程的问题。在下面这个修改过的版本中,我们使其能在多线程环境中工作,并为事件采用了多造型技术:
 

//: BangBean2.java
// You should write your Beans this way so they
// can run in a multithreaded environment.
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;

public class BangBean2 extends Canvas
    implements Serializable {
  private int xm, ym;
  private int cSize = 20; // Circle size
  private String text = "Bang!";
  private int fontSize = 48;
  private Color tColor = Color.red;
  private Vector actionListeners = new Vector();
  public BangBean2() {
    addMouseListener(new ML());
    addMouseMotionListener(new MM());
  }
  public synchronized int getCircleSize() {
    return cSize;
  }
  public synchronized void
  setCircleSize(int newSize) {
    cSize = newSize;
  }
  public synchronized String getBangText() {
    return text;
  }
  public synchronized void
  setBangText(String newText) {
    text = newText;
  }
  public synchronized int getFontSize() {
    return fontSize;
  }
  public synchronized void
  setFontSize(int newSize) {
    fontSize = newSize;
  }
  public synchronized Color getTextColor() {
    return tColor;
  }
  public synchronized void
  setTextColor(Color newColor) {
    tColor = newColor;
  }
  public void paint(Graphics g) {
    g.setColor(Color.black);
    g.drawOval(xm - cSize/2, ym - cSize/2,
      cSize, cSize);
  }
  // This is a multicast listener, which is
  // more typically used than the unicast
  // approach taken in BangBean.java:
  public synchronized void addActionListener (
      ActionListener l) {
    actionListeners.addElement(l);
  }
  public synchronized void removeActionListener(
      ActionListener l) {
    actionListeners.removeElement(l);
  }
  // Notice this isn't synchronized:
  public void notifyListeners() {
    ActionEvent a =
      new ActionEvent(BangBean2.this,
        ActionEvent.ACTION_PERFORMED, null);
    Vector lv = null;
    // Make a copy of the vector in case someone
    // adds a listener while we're
    // calling listeners:
    synchronized(this) {
      lv = (Vector)actionListeners.clone();
    }
    // Call all the listener methods:
    for(int i = 0; i < lv.size(); i++) {
      ActionListener al =
        (ActionListener)lv.elementAt(i);
      al.actionPerformed(a);
    }
  }
  class ML extends MouseAdapter {
    public void mousePressed(MouseEvent e) {
      Graphics g = getGraphics();
      g.setColor(tColor);
      g.setFont(
        new Font(
          "TimesRoman", Font.BOLD, fontSize));
      int width =
        g.getFontMetrics().stringWidth(text);
      g.drawString(text,
        (getSize().width - width) /2,
        getSize().height/2);
      g.dispose();
      notifyListeners();
    }
  }
  class MM extends MouseMotionAdapter {
    public void mouseMoved(MouseEvent e) {
      xm = e.getX();
      ym = e.getY();
      repaint();
    }
  }
  // Testing the BangBean2:
  public static void main(String[] args) {
    BangBean2 bb = new BangBean2();
    bb.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e){
        System.out.println("ActionEvent" + e);
      }
    });
    bb.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e){
        System.out.println("BangBean2 action");
      }
    });
    bb.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e){
        System.out.println("More action");
      }
    });
    Frame aFrame = new Frame("BangBean2 Test");
    aFrame.addWindowListener(new WindowAdapter(){
      public void windowClosing(WindowEvent e) {
        System.exit(0);
      }
    });
    aFrame.add(bb, BorderLayout.CENTER);
    aFrame.setSize(300,300);
    aFrame.setVisible(true);
  }
} ///:~

很容易就可以为方法添加synchronized。但注意在addActionListener()和removeActionListener()中,现在添加了ActionListener,并从一个Vector中移去,所以能够根据自己愿望使用任意多个。
我们注意到,notifyListeners()方法并未设为“同步”。可从多个线程中发出对这个方法的调用。另外,在对notifyListeners()调用的中途,也可能发出对addActionListener()和removeActionListener()的调用。这显然会造成问题,因为它否定了Vector actionListeners。为缓解这个问题,我们在一个synchronized从句中“克隆”了Vector,并对克隆进行了否定。这样便可在不影响notifyListeners()的前提下,对Vector进行操纵。
paint()方法也没有设为“同步”。与单纯地添加自己的方法相比,决定是否对过载的方法进行同步要困难得多。在这个例子中,无论paint()是否“同步”,它似乎都能正常地工作。但必须考虑的问题包括:
(1) 方法会在对象内部修改“关键”变量的状态吗?为判断一个变量是否“关键”,必须知道它是否会被程序中的其他线程读取或设置(就目前的情况看,读取或设置几乎肯定是通过“同步”方法进行的,所以可以只对它们进行检查)。对paint()的情况来说,不会发生任何修改。
(2) 方法要以这些“关键”变量的状态为基础吗?如果一个“同步”方法修改了一个变量,而我们的方法要用到这个变量,那么一般都愿意把自己的方法也设为“同步”。基于这一前提,大家可观察到cSize由“同步”方法进行了修改,所以paint()应当是“同步”的。但在这里,我们可以问:“假如cSize在paint()执行期间发生了变化,会发生的最糟糕的事情是什么呢?”如果发现情况不算太坏,而且仅仅是暂时的效果,那么最好保持paint()的“不同步”状态,以避免同步方法调用带来的额外开销。
(3) 要留意的第三条线索是paint()基础类版本是否“同步”,在这里它不是同步的。这并不是一个非常严格的参数,仅仅是一条“线索”。比如在目前的情况下,通过同步方法(好cSize)改变的一个字段已合成到paint()公式里,而且可能已改变了情况。但请注意,synchronized不能继承——也就是说,假如一个方法在基础类中是“同步”的,那么在衍生类过载版本中,它不会自动进入“同步”状态。
TestBangBean2中的测试代码已在前一章的基础上进行了修改,已在其中加入了额外的“听众”,从而演示了BangBean2的多造型能力。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索方法
, synchronized
, addactionlistener
, actionlistener
, 同步
, public
, vector graphics
, 一个
|XM|ML|L简|简介|介|
java beans、java.beans包、java.beans jar包下载、java.beans包下载、java.beans jar包,以便于您获取更多的相关知识。

时间: 2024-12-13 06:34:19

回顾Java Beans的相关文章

利用Java Beans在应用程序中创建组件

JavaBeans模块使开发人员能够创建称之为组件的软件单元(也就是我们熟知的beans).你可以把beans加载在更复杂的组件.Java小型应用程序(applets)或应用程序上.JavaBeans广泛应用于IDE应用程序,使你能够很容易地可视化组合组件并动态修改它的属性. Beans是动态的,允许你改变和定制它.在JavaBean Builder Tool里的设计模块中,你能利用 Bean的属性窗口来可视化定制和保存(持久)bean.你也可以从toolbox中选择一个bean,把它拖拽到窗体

数据库中数据项变化不定时如何设计Java Beans

前言 我们不只一次抱怨信息系统中数据项变化不定,无法设计和实现Java Beans.我们也不只一次作过这样的事情:数据项增加或减少了,我需要修改信息系统以求适应.我们对付这种变化莫定的需求还有一招:天天催企业领导或业务人员决定数据项,而不开始下面的设计和开发,还美名其为一个需求的"需求里程碑"没到,至少这个需求相关的设计和开发绝对不能开始.本文为这种情况提供了一种解决办法,并美名其为"以动制动". JavaBean属性 Java Beans 作为一种组件技术,其结构

持久化代理-求解java.beans.PersistenceDelegate类怎么用?

问题描述 求解java.beans.PersistenceDelegate类怎么用? 定义一个持久化代理什么意思?这个持久化代理实现了一个类的什么?什么情况下可以使用这个类? 解决方案 你可以看下java.beans.PersistenceDelegate这个类的源码,ctrl+shift+T输入这个类就可以看到了.这类是个抽象类,主要功能是实现java的序列化操作的,完成序列化writeObject持久化到某个介质的目的.然后ctrl+T查看这个类的子类. 解决方案二: Java BeansJ

java的可视编程和Beans

迄今为止,我们已看到Java对创建可重复使用的代码片工作而言是多么的有价值."最大限度地可重复使用"的代码单元拥有类,因为它包含一个紧密结合在一起的单元特性(字段)和单元动作(方法),它们可以直接经过混合或通过继承被重复使用. 继承和多形态性是面向对象编程的精华,但在大多数情况下当我们创建一个应用程序时,我们真正最想要的恰恰是我们最需要的组件.我们希望在我们的设计中设置这些部件就像电子工程师在电路板上创造集成电路块一样(在使用Java的情况下,就是放到WEB页面上).这似乎会成为加快这

基于Java回顾之多线程详解_java

线程是操作系统运行的基本单位,它被封装在进程中,一个进程可以包含多个线程.即使我们不手动创造线程,进程也会有一个默认的线程在运行. 对于JVM来说,当我们编写一个单线程的程序去运行时,JVM中也是有至少两个线程在运行,一个是我们创建的程序,一个是垃圾回收. 线程基本信息 我们可以通过Thread.currentThread()方法获取当前线程的一些信息,并对其进行修改. 我们来看以下代码: 复制代码 代码如下: 查看并修改当前线程的属性 String name = Thread.currentT

基于Java回顾之I/O的使用详解_java

工作后,使用的技术随着项目的变化而变化,时而C#,时而Java,当然还有其他一些零碎的技术.总体而言,C#的使用时间要更长一些,其次是Java.我本身对语言没有什么倾向性,能干活的语言,就是好语言.而且从面向对象的角度来看,我觉得C#和Java对我来说,没什么区别. 这篇文章主要回顾Java中和I/O操作相关的内容,I/O也是编程语言的一个基础特性,Java中的I/O分为两种类型,一种是顺序读取,一种是随机读取. 我们先来看顺序读取,有两种方式可以进行顺序读取,一种是InputStream/Ou

存取程序状态的几种方法——Java I/O应用杂谈

程序 jungleford如是说     已经有一个多月没有搭理blog了,原因很多,譬如实验室的项目正在收工,巨忙:譬如找工作及其相关的事情:而且二月份大部分时间是陪老爹老妈,家里拨号的速度可想而知--但主要还是没有找到一个合适的topic,或者说这段时间懒了(临毕业前期综合症),净在看<汉武大帝>和历史方面的书,还有其它乱七八糟的闲书,就是没有认真地玩Java,哈哈!现在工作差不多落实了,好在不算太烂,小资青年jungleford的生活又开始步入正轨了!以上是新年里的一些废话.    今天

java Bean的封装

在我们可以安放一个Bean到一个可激活Bean的可视化构建工具中前,它必须被放入到标准的Bean容器里,也就是包含Bean类和一个表示"这是一个Bean"的清单文件的JAR(Java ARchive,Java文件)文件中.清单文件是一个简单的紧随事件结构的文本文件.对于BangBean而言,清单文件就像下面这样: Manifest-Version: 1.0 Name: bangbean/BangBean.class Java-Bean: True 其中,第一行指出清单文件结构的版本,这

.NET Framework For Java Programmers

.NET Framework For Java Programmers Author: Ashish Banerjee Objective After reading this article Java programmers should be able to decipher and de-jargonize the .NET architecture and relate it with the proposed ECMA standard.    Target Audience Java