Java 中文官方教程 2022 版(三十三)(3)https://developer.aliyun.com/article/1488022
使用您的新 JavaBean
将BumperSticker
从调色板拖到您的表单中。
您可以像处理其他 bean 一样处理BumperSticker
实例。要看到这一点,将另一个按钮拖到表单中。这个按钮将启动BumperSticker
的动画。
将按钮连接到BumperSticker
bean,就像您已经将第一个按钮连接到文本字段一样。
- 首先,点击连接模式按钮。
- 点击第二个按钮。NetBeans 会给它一个红色轮廓。
- 点击
BumperSticker
组件。连接向导弹出。 - 点击**+旁边的action**,然后选择actionPerformed。点击下一步 >。
- 选择方法调用,然后从列表中选择go()。点击完成。
如果您对任何步骤感到不确定,请查看连接应用程序。这里的过程非常相似。
再次运行该应用程序。当你点击第二个按钮时,BumperSticker
组件会动画显示心形的颜色。
再次注意,你已经制作出一个功能完善的应用程序,而没有编写任何代码。
Lesson: 编写 JavaBeans 组件
原文:
docs.oracle.com/javase/tutorial/javabeans/writing/index.html
编写 JavaBeans 组件非常容易。你不需要特殊的工具,也不必实现任何接口。编写 bean 只是遵循某些编码约定的问题。你所需要做的就是让你的类看起来像一个 bean —— 使用 bean 的工具将能够识别和使用你的 bean。
然而,NetBeans 提供了一些功能,使编写 bean 更容易。此外,Java SE API 包括一些支持类来帮助实现常见任务。
本课程中的代码示例基于一个简单的图形组件称为FaceBean
。
FaceBean 源代码仅包括:
FaceBean.java
包括 FaceBean 源代码的整个 NetBeans 项目:
FaceBean.zip
一个 bean 是一个遵循 JavaBeans 指南的方法名的 Java 类。一个 bean 构建工具使用内省来检查 bean 类。基于这种检查,bean 构建工具可以找出 bean 的属性、方法和事件。
以下各节描述了 JavaBeans 指南中关于属性、方法和事件的内容。最后,一个关于BeanInfo
的部分展示了如何定制开发者与你的 bean 的体验。
属性
原文:
docs.oracle.com/javase/tutorial/javabeans/writing/properties.html
要在 bean 类中定义属性,请提供公共的 getter 和 setter 方法。例如,以下方法定义了一个名为mouthWidth
的int
属性:
public class FaceBean { private int mMouthWidth = 90; public int getMouthWidth() { return mMouthWidth; } public void setMouthWidth(int mw) { mMouthWidth = mw; } }
像 NetBeans 这样的构建工具识别方法名,并在其属性列表中显示mouthWidth
属性。它还识别类型int
,并提供一个适当的编辑器,以便在设计时操作属性。
此示例显示了一个可读写的属性。还有其他组合也是可能的。例如,只读属性具有 getter 方法但没有 setter。只写属性只有 setter 方法。
boolean
属性的特殊情况允许使用is
而不是get
来定义访问方法。例如,boolean
属性running
的访问器可以如下所示:
public boolean isRunning() { // ... }
可用并在以下部分描述基本属性的各种特殊化。
索引属性
索引属性是一个数组而不是单个值。在这种情况下,bean 类提供了一个用于获取和设置整个数组的方法。以下是一个名为testGrades
的int[]
属性的示例:
public int[] getTestGrades() { return mTestGrades; } public void setTestGrades(int[] tg) { mTestGrades = tg; }
对于索引属性,bean 类还提供了用于获取和设置数组特定元素的方法。
public int getTestGrades(int index) { return mTestGrades[index]; } public void setTestGrades(int index, int grade) { mTestGrades[index] = grade; }
绑定属性
绑定属性在其值更改时通知监听器。这有两个含义:
- bean 类包括用于管理 bean 监听器的
addPropertyChangeListener()
和removePropertyChangeListener()
方法。 - 当绑定属性更改时,bean 向其注册的监听器发送
PropertyChangeEvent
。
PropertyChangeEvent
和PropertyChangeListener
位于java.beans
包中。
java.beans
包还包括一个名为PropertyChangeSupport
的类,它负责大部分绑定属性的工作。这个方便的类跟踪属性监听器,并包含一个方便的方法,向所有注册的监听器触发属性更改事件。
以下示例显示了如何使用PropertyChangeSupport
使mouthWidth
属性成为绑定属性。绑定属性的必要添加部分用粗体显示。
import java.beans.*; public class FaceBean { private int mMouthWidth = 90; private PropertyChangeSupport mPcs = new PropertyChangeSupport(this); public int getMouthWidth() { return mMouthWidth; } public void setMouthWidth(int mw) { int oldMouthWidth = mMouthWidth; mMouthWidth = mw; mPcs.firePropertyChange("mouthWidth", oldMouthWidth, mw); } public void addPropertyChangeListener(PropertyChangeListener listener) { mPcs.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { mPcs.removePropertyChangeListener(listener); } }
绑定属性可以直接与其他 bean 属性绑定,使用像 NetBeans 这样的构建工具。例如,您可以将滑块组件的value
属性绑定到示例中显示的mouthWidth
属性。NetBeans 允许您在不编写任何代码的情况下执行此操作。
约束属性
约束属性是一种特殊类型的绑定属性。对于约束属性,bean 跟踪一组否决监听器。当约束属性即将更改时,监听器会就更改进行协商。任何一个监听器都有机会否决更改,此时属性保持不变。
否决监听器与属性更改监听器是分开的。幸运的是,java.beans
包中包含一个VetoableChangeSupport
类,大大简化了受限属性。
对mouthWidth
示例的更改显示为粗体:
import java.beans.*; public class FaceBean { private int mMouthWidth = 90; private PropertyChangeSupport mPcs = new PropertyChangeSupport(this); private VetoableChangeSupport mVcs = new VetoableChangeSupport(this); public int getMouthWidth() { return mMouthWidth; } public void setMouthWidth(int mw) throws PropertyVetoException { int oldMouthWidth = mMouthWidth; mVcs.fireVetoableChange("mouthWidth", oldMouthWidth, mw); mMouthWidth = mw; mPcs.firePropertyChange("mouthWidth", oldMouthWidth, mw); } public void addPropertyChangeListener(PropertyChangeListener listener) { mPcs.addPropertyChangeListener(listener); } public void removePropertyChangeListener(PropertyChangeListener listener) { mPcs.removePropertyChangeListener(listener); } public void addVetoableChangeListener(VetoableChangeListener listener) { mVcs.addVetoableChangeListener(listener); } public void removeVetoableChangeListener(VetoableChangeListener listener) { mVcs.removeVetoableChangeListener(listener); } }
NetBeans 中的开发支持
创建 bean 属性的编码模式很简单,但有时很难确定是否一切都正确。NetBeans 支持属性模式,因此您在编写代码时可以立即看到结果。
要利用此功能,请查看Navigator窗格,通常位于 NetBeans 窗口的左下角。通常,此窗格处于Members View模式,显示当前类中定义的所有方法和字段。
单击组合框切换到Bean Patterns视图。您将看到一个属性列表,其中列出了 NetBeans 可以从您的方法定义中推断出的属性。随着您的输入,NetBeans 会更新此列表,这是检查您工作的方便方式。
在下面的示例中,NetBeans 发现了可读写的mouthWidth
属性和可读写的索引testGrades
属性。此外,NetBeans 还意识到FaceBean
允许注册PropertyChangeListener
和VetoableChangeListener
。
方法
原文:
docs.oracle.com/javase/tutorial/javabeans/writing/methods.html
一个方法是豆子能做的事情。任何不是属性定义的公共方法都是一个豆子方法。当你在像 NetBeans 这样的构建工具的上下文中使用一个豆子时,你可以将豆子的方法作为应用程序的一部分。例如,你可以将按钮按下与调用你的豆子方法之一联系起来。
事件
原文:
docs.oracle.com/javase/tutorial/javabeans/writing/events.html
一个 bean 类可以触发任何类型的事件,包括自定义事件。与属性一样,事件通过特定模式的方法名称来识别。
public void add*<Event>*Listener(*<Event>*Listener a) public void remove*<Event>*Listener(*<Event>*Listener a)
监听器类型必须是java.util.EventListener
的子类。
例如,Swing 的JButton
是一个 bean,当用户点击它时会触发action
事件。JButton
包括以下方法(实际上是从AbstractButton
继承而来),这些方法是事件的 bean 模式:
public void addActionListener(ActionListener l); public void removeActionListener(ActionListener l);
Bean 事件被构建工具识别,并可用于将组件进行连线。例如,您可以将按钮的action
事件连接起来,以触发某些操作,比如调用另一个 bean 的方法。
使用 BeanInfo
原文:
docs.oracle.com/javase/tutorial/javabeans/writing/beaninfo.html
Bean,尤其是图形组件,可能有大量属性。如果你的类继承自 Component
、JComponent
或其他 Swing 类,它已经拥有一百多个属性。虽然像 NetBeans 这样的构建工具使编辑 bean 属性变得容易,但对于经验不足的程序员来说,很难找到要编辑的正确属性。
BeanInfo
概述
BeanInfo
是一个改变你的 bean 在构建工具中显示方式的类。构建工具可以查询 BeanInfo
以找出应该首先显示哪些属性以及哪些应该隐藏。
你的 bean 对应的 BeanInfo
类应该与 bean 类同名,只是在末尾加上 BeanInfo
。例如,FaceBean
类有一个对应的描述它的 FaceBeanBeanInfo
类。
虽然可以手动实现 BeanInfo
类,但使用像 NetBeans 这样的工具来编辑 BeanInfo
会更容易。
在 NetBeans 中创建 BeanInfo
在项目窗格中,按住 Control 键单击 bean 类的名称,然后从上下文菜单中选择BeanInfo Editor…。
NetBeans 注意到你没有 BeanInfo
并询问是否要创建一个。点击Yes。
NetBeans 会创建一个新的类并将你带到源代码编辑器。点击Designer切换到可视化编辑器。
点击查看完整图片
从可视化编辑器左侧的列表中选择属性,然后在右侧编辑其属性。如果你不希望某个特定属性出现在使用构建工具的开发人员面前,点击Hidden。要表示某个属性应该在其他属性之前显示,点击Preferred。你还可以指示属性是否绑定或受限。
你可以为 bean 的事件源和方法提供类似的信息。
当构建工具加载你的 bean 类以将其添加到工具栏时,它会自动找到相应的 BeanInfo
并用它来决定如何向开发人员展示你的 bean。
课程:高级 JavaBeans 主题
原文:
docs.oracle.com/javase/tutorial/javabeans/advanced/index.html
JavaBeans 开发入门很容易,但是 Bean 具有令人惊讶的深度。本课程涵盖了一些更高级的主题,包括 Bean 可以如何存储(持久化)以及如何为自定义数据类型提供自定义编辑器。
- Bean Persistence 描述了保存和重建 Bean 的机制。
- Long Term Persistence 涵盖了将 Bean 表示为 XML。
- Bean Customization 概述了为自定义数据类型创建编辑器组件。
Bean 持久性
原文:
docs.oracle.com/javase/tutorial/javabeans/advanced/persistence.html
当 bean 的属性、字段和状态信息被保存到存储中并从中检索时,bean 具有持久性的属性。组件模型提供了一种持久性机制,使组件的状态能够被存储在非易失性位置以供以后检索。
使持久性成为可能的机制称为 序列化。对象序列化意味着将对象转换为数据流并将其写入存储。任何使用该 bean 的小程序、应用程序或工具都可以通过反序列化来“重建”它。然后对象将恢复到其原始状态。
例如,Java 应用程序可以在 Microsoft Windows 机器上序列化一个 Frame 窗口,然后将序列化文件通过电子邮件发送到 Solaris 机器,然后 Java 应用程序可以将 Frame 窗口恢复到在 Microsoft Windows 机器上存在的确切状态。
任何使用该 bean 的小程序、应用程序或工具都可以通过 反序列化 来“重建”它。
所有的 bean 都必须持久化。为了持久化,您的 bean 必须通过实现 java.io.Serializable
(在 API 参考文档中)接口或 java.io.Externalizable
(在 API 参考文档中)接口来支持序列化。这些接口为您提供了自动序列化和定制序列化的选择。如果类的继承层次结构中的任何类实现了 Serializable
或 Externalizable
,那么该类就是可序列化的。
可序列化的类
只要该类或父类实现了 java.io.Serializable
接口,任何类都可以序列化。支持序列化的示例类包括 Component
、String
、Date
、Vector
和 Hashtable
。因此,Component
类的任何子类,包括 Applet
,都可以被序列化。不支持序列化的显著类包括 Image
、Thread
、Socket
和 InputStream
。尝试序列化这些类型的对象将导致 NotSerializableException
。
Java 对象序列化 API 自动将大多数 Serializable 对象的字段序列化到存储流中。这包括原始类型、数组和字符串。API 不会序列化或反序列化被标记为 transient 或 static 的字段。
控制序列化
您可以控制 bean 所经历的序列化级别。控制序列化的三种方式是:
- 通过
Serializable
接口实现的自动序列化。Java 序列化软件将整个对象序列化,除了 transient 和 static 字段。 - 定制序列化。通过使用
transient
(或static
)修饰符标记要排除的字段,可以选择性地排除不想序列化的字段。 - 自定义文件格式,由
Externalizable
接口及其两个方法实现。Beans 以特定文件格式编写。
默认序列化:Serializable 接口
Serializable
接口通过使用 Java 对象序列化工具提供自动序列化。Serializable
不声明任何方法;它充当标记,告诉对象序列化工具你的 bean 类是可序列化的。将你的类标记为Serializable
意味着你告诉 Java 虚拟机(JVM)你已经确保你的类将与默认序列化一起使用。以下是与Serializable
接口一起使用的一些重要点:
- 实现
Serializable
的类必须能够访问超类的无参数构造函数。当对象从.ser
文件中“重建”时,将调用此构造函数。 - 如果在超类中已经实现了
Serializable
,那么你不需要在你的类中实现它。 - 所有字段(除了静态和瞬态字段)都会被序列化。使用
transient
修饰符指定不想序列化的字段,并指定不可序列化的类。
使用transient
关键字进行选择性序列化
要在Serializable
对象中排除字段的序列化,请使用transient
修饰符标记字段。
transient int status;
默认序列化不会序列化transient
和static
字段。
选择性序列化:writeObject 和 readObject
如果你的可序列化类包含以下两种方法之一(签名必须完全相同),则默认序列化将不会发生。
private void writeObject(java.io.ObjectOutputStream out) throws IOException; private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
通过编写自己的writeObject
和readObject
方法的实现,可以控制更复杂对象的序列化。当需要对默认序列化无法处理的对象进行序列化,或者需要向序列化流添加不是对象数据成员的数据时,请实现writeObject
。实现readObject
以重建使用writeObject
写入的数据流。
Externalizable 接口
当需要完全控制 bean 的序列化时(例如,写入和读取特定文件格式时),请使用Externalizable
接口。要使用Externalizable
接口,你需要实现两个方法:readExternal
和writeExternal
。实现Externalizable
的类必须有一个无参数构造函数。