我认为,我理解“Bean”是具有属性和 getter/setter 的 Java 类。
据我所知,它相当于 C struct
。真的吗?
此外,JavaBean
和常规 class
之间是否存在真正的句法差异?
是否有任何特殊定义或Interface
?
基本上,为什么有这个术语?
另外 Serializable
接口是什么意思?
JavaBean 只是一个 standard。它是一个常规的 Java class
,但它遵循某些约定:
所有属性都是私有的(使用 getter/setter) 一个公共的无参数构造函数实现 Serializable。
而已。这只是一个约定。很多图书馆都依赖它。
关于 Serializable
,来自 API documentation:
类的可序列化性由实现 java.io.Serializable 接口的类启用。未实现此接口的类将不会对其任何状态进行序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于识别可序列化的语义。
换句话说,可序列化对象可以写入流,因此可以写入文件、对象数据库等等。
此外,JavaBean 和另一个类之间在语法上没有区别——如果一个类遵循标准,那么它就是一个 JavaBean。
它有一个术语,因为该标准允许库以编程方式处理您以预定义方式定义的类实例。例如,如果一个库想要流式传输您传递给它的任何对象,它知道它可以,因为您的对象是可序列化的(假设该库要求您的对象是正确的 JavaBeans)。
有一个术语让它听起来很特别。现实远没有那么神秘。
基本上,一个“豆子”:
是一个可序列化的对象(也就是说,它实现了 java.io.Serializable,并且这样做是正确的),即
具有“属性”,其 getter 和 setter 只是具有特定名称的方法(例如,getFoo() 是“Foo”属性的 getter),并且
有一个公共的零参数构造函数(因此可以随意创建并通过设置其属性进行配置)。
至于 Serializable
:那不过是一个“标记接口”(一个不声明任何函数的接口),它告诉 Java 实现类同意(并暗示它能够)“序列化”——a将实例转换为字节流的过程。这些字节可以存储在文件中,通过网络连接发送等,并且有足够的信息允许 JVM(至少,知道对象类型的)稍后重建对象——可能在不同的实例中应用程序,甚至在另一台机器上!
当然,为了做到这一点,类必须遵守某些限制。其中最主要的是所有实例字段必须是原始类型(int、bool 等)、某些类的实例也可序列化,或者标记为 transient
,以便 Java 不会尝试包含它们。 (这当然意味着 transient
字段将无法在流中运行。具有 transient
字段的类应准备好在必要时重新初始化它们。)
不能遵守这些限制的类不应该实现 Serializable
(而且,IIRC,Java 编译器甚至不会让它这样做。)
transient
部分必须是某种可序列化的类型。
JavaBeans 是遵循极其简单的编码约定的 Java 类。你所要做的就是
实现 java.io.Serializable 接口 - 保存对象的状态 使用公共空参数构造函数 - 实例化对象 提供公共 getter/setter 方法 - 获取和设置私有变量(属性)的值。
JavaBean 的属性
JavaBean 是满足某些编程约定的 Java 对象:
JavaBean 类必须实现 Serializable 或 Externalizable JavaBean 类必须具有无参数构造函数 所有 JavaBean 属性必须具有公共 setter 和 getter 方法 所有 JavaBean 实例变量都应该是私有的
JavaBean 示例
@Entity
public class Employee implements Serializable{
@Id
private int id;
private String name;
private int salary;
public Employee() {}
public Employee(String name, int salary) {
this.name = name;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getName() {
return name;
}
public void setName( String name ) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}
}
举例说明。
1.导入java.io.Serializable
至于序列化,参见documentation。
2.私有字段
字段应该是私有的,以防止外部类轻松修改这些字段。不是直接访问这些字段,而是使用通常的 getter/setter 方法。
3.构造函数
没有任何参数的公共构造函数。
4. 获取器/设置器
用于访问和修改私有字段的 getter 和 setter 方法。
/** 1. import java.io.Serializable */
public class User implements java.io.Serializable {
/** 2. private fields */
private int id;
private String name;
/** 3. Constructor */
public User() {
}
public User(int id, String name) {
this.id = id;
this.name = name;
}
/** 4. getter/setter */
// getter
public int getId() {
return id;
}
public String getName() {
return name;
}
// setter
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
setId(int id)
正文,您想说的是 this.id = id;
而不是 this.id = is;
Java Beans 用于更少的代码和更多的工作方法......
Java Bean 在整个 Java EE 中用作运行时发现和访问的通用契约。例如,JavaServer Pages (JSP) 使用 Java Bean 作为页面之间或 servlet 和 JSP 之间的数据传输对象。 Java EE 的 JavaBeans 激活框架使用 Java Beans 将 MIME 数据类型的支持集成到 Java EE 中。 Java EE 管理 API 使用 JavaBeans 作为在 Java EE 环境中管理资源的基础。
关于序列化:
在对象序列化中,对象可以表示为一个字节序列,其中包括对象的数据以及有关对象类型和存储在对象中的数据类型的信息。
序列化的对象写入文件后,可以从文件中读取并反序列化,即表示对象及其数据的类型信息和字节可用于在内存中重新创建对象。
在跨多个服务器部署项目时,您会发现序列化很有用,因为 bean 将被持久化并在它们之间传输。
只是关于 bean 概念的一点背景/更新。许多其他答案实际上有什么但没有那么多为什么。
它们是早期在 Java 中作为构建 GUI 的一部分而发明的。他们遵循易于工具拆分的模式,让他们创建一个属性面板,以便您可以编辑 Bean 的属性。一般来说,Bean 属性代表屏幕上的一个控件(想想 x,y,width,height,text,..)
您也可以将其视为强类型数据结构。
随着时间的推移,这些对于使用相同类型访问的许多工具变得有用(例如,Hibernate 将数据结构持久化到数据库)
随着工具的发展,它们更多地转向注释,而不是将 setter/getter 名称分开。现在大多数系统都不需要 bean,它们可以使用任何带有注释属性的普通 Java 对象来告诉它们如何操作它们。
现在我将 bean 视为带注释的属性球——它们实际上只对它们携带的注释有用。
豆类本身并不是一种健康的模式。它们本质上破坏了封装,因为它们将所有属性暴露给外部操作,并且在使用它们时,有一种趋势(绝不是要求)创建代码以在外部操作 bean,而不是在 bean 内部创建代码(违反“don '不要向一个对象询问它的价值,而是要求一个对象为你做某事”)。使用带有最少 getter 且没有 setter 的带注释的 POJO 更能恢复封装并具有不变性的可能性。
顺便说一句,随着所有这些事情的发生,有人将这个概念扩展到了一种叫做 Enterprise Java Beans 的东西。这些是……不同的。而且它们足够复杂,以至于许多人觉得他们不了解整个 Bean 概念并停止使用该术语。我认为这就是为什么您通常会听到将 bean 称为 POJO 的原因(因为每个 Java 对象都是 POJO,这在技术上是可以的,但是当您听到有人说 POJO 时,他们通常会考虑遵循 bean 模式的东西)
JavaBeans 是一个标准,其他答案已经清楚地解释了它的基本语法要求。
然而,IMO,它不仅仅是一个简单的语法标准。 JavaBeans的真正意义或预期用途是,与围绕标准的各种工具支持一起,促进代码重用和基于组件的软件工程,即使开发人员能够通过组装现有组件(类)来构建应用程序,而无需编写任何代码(或者只需要写一点胶水代码)。不幸的是,这项技术被业界低估和利用不足,这可以从这个线程的答案中看出。
如果您阅读 Oracle 的tutorial on JavaBeans,您可以对此有更好的理解。
to facilitate code reuse and component-based software engineering, i.e. enable developers to build applications by assembling existing components (classes) and without having to write any code (or only have to write a little glue code).
这样的垃圾词,您可以举一个例子来说明“促进代码重用”的意思
根据维基百科:
该类必须有一个公共默认构造函数(不带参数)。这允许在编辑和激活框架内轻松实例化。类属性必须可以根据标准命名约定使用 get、set、is(可用于布尔属性而不是 get)和其他方法(所谓的访问器方法和修改器方法)进行访问。这允许在框架内轻松自动检查和更新 bean 状态,其中许多框架包括用于各种类型属性的自定义编辑器。 Setter 可以有一个或多个参数。该类应该是可序列化的。 (这允许应用程序和框架以独立于 VM 和平台的方式可靠地保存、存储和恢复 bean 的状态。)
有关更多信息,请遵循此 link。
关于问题的第二部分,序列化是一种持久性机制,用于将对象存储为一系列有符号字节。不太正式地说,它存储对象的状态,以便您以后可以通过反序列化检索它。
bean is 一个 Java 类,其方法名称遵循 properties、methods 和 events 的 JavaBean 准则(也称为设计模式)。因此,任何不属于属性定义的 bean 类的公共方法都是 bean 方法。最低限度,一个 Java 类,即使有一个属性作为唯一成员(当然,需要公共 getter 和 setter),一个公共方法作为唯一成员,或者只有一个公共事件侦听器注册方法,也是一个 Java bean。此外,该属性可以是只读属性(具有 getter 方法但没有 setter)或只写属性(仅具有 setter 方法)。 Java bean 需要是一个公共类才能对任何 beanbox 工具或容器可见。容器必须能够实例化它;因此,它也应该有一个公共构造函数。 JavaBeans specification 不要求 bean 具有公共零参数构造函数(显式或默认),以便容器实例化它。如果您可以提供包含序列化实例的文件(扩展名为 .ser),那么 beanbox 工具可以使用该文件来实例化原型 bean。否则,bean 将需要一个公共的零参数构造函数,无论是显式的还是默认的。
一旦 bean 被实例化,JavaBean API (java.beans.*) 就可以自省它并调用它的方法。如果没有实现接口 BeanInfo 或扩展 BeanInfo 实现的类 SimpleBeanInfo 类可用,则自省涉及使用反射(隐式自省)来研究目标 bean 支持的方法,然后应用简单的设计模式(指南)从这些方法支持哪些属性、事件和公共方法。如果实现接口 BeanInfo 的类(对于 bean Foo,它必须命名为 FooBeanInfo)可用,API 绕过隐式自省并使用该类的公共方法(getPropertyDescriptor()、getMethodDescriptors()、getEventSetDescriptors())来获取信息。如果扩展 SimpleBeanInfo 的类可用,取决于 SimpleBeanInfo 公共方法(getPropertyDescriptor()、getMethodDescriptors()、getEventSetDescriptors())中的哪一个被覆盖,它将使用这些被覆盖的方法来获取信息;对于未被覆盖的方法,它将默认为相应的隐式内省。一个 bean 无论如何都需要被实例化,即使它没有进行隐式自省。因此,公共零参数构造函数的要求。但是,当然,Serializable 或 Externalizable 接口并不是识别它所必需的。然而,Java Bean 规范说,“我们也希望它对于一个简单的小 Bean 的常见情况是“微不足道的”,它只是想保存其内部状态并且不想考虑它。因此,所有 bean 都必须实现 Serializable 或 Externalizable 接口。
总的来说,JavaBeans 规范对于 bean 的构成并不严格。 “编写 JavaBeans 组件非常简单。您不需要特殊工具,也不必实现任何接口。编写 bean 只需遵循某些编码约定。您所要做的就是让您的类看起来像一个 bean——使用 bean 的工具将能够识别和使用你的 bean。”简单地说,即使是下面的类也是一个 Java bean,
public class Trivial implements java.io.Serializable {}
如下所述,bean 是上述 Java SE 版本 (JavaBeans) 的 Java EE 版本。这些描述进一步说明了如上所述的基本思想。
春豆
比如说,一个 bean 构造函数有一些参数。假设有些是简单类型。容器可能不知道要为它们分配什么值;即使是这样,生成的实例也可能无法重用。只有当用户可以像在 Spring bean 中那样通过注解或 xml 配置文件进行配置(指定值)时,它才有意义。并假设某些参数是类或接口类型。同样,容器可能不知道要为其分配什么值。只有当用户可以通过注解或 xml 配置文件进行配置(指定特定对象)时,它才有意义。然而,即使在 Spring(通过 xml 配置文件)中,将特定对象(带有字符串名称)分配给构造函数参数(构造函数参数的属性或元素)也不是类型安全的;它基本上类似于资源注入。引用其他 Spring bean(称为协作者;通过构造函数参数元素中的元素)基本上是依赖注入,因此是类型安全的。显然,一个依赖项(collaborator bean)可能有一个带有注入参数的构造函数;那些注入的依赖项可能有一个带参数的构造函数等等。在这种情况下,最终,您将需要一些 bean 类(例如,MyBean.class),容器可以通过简单地调用 new MyBean() 来实例化它们,然后它才能通过构造函数上的依赖注入构造其他协作 bean——因此,需要bean 具有公共的零参数构造函数。假设,如果容器不支持依赖注入和/或不允许像 Spring 中那样通过一些注释或 xml 配置文件将简单类型的值分配给构造函数,则 bean 构造函数不应该有参数。即使是 Spring bean 应用程序也需要一些 bean 来具有公共的零参数构造函数(例如,在 Spring 应用程序没有仅具有简单类型作为构造函数参数的 bean 的场景中)。
JSF 托管 Bean
JSF 托管 bean 在 Web 容器中运行。它们可以使用@ManagedBean 注解或应用程序配置资源文件 managed-bean.xml 进行配置。但是,它仅支持通过资源注入(非类型安全)进行注入;不适合在构造函数上注入。 JSF spec 要求托管 bean 必须具有公共零参数构造函数。此外,它还说,“从本规范的 2.3 版开始,强烈建议不要使用本节中指定的托管 bean 设施。解决相同问题的更好、更紧密集成的解决方案是使用 JSR-365 中指定的上下文和依赖注入 (CDI)。”换句话说,要使用的 CDI 托管 bean,它为类似的构造函数提供类型安全的依赖注入对于Spring bean,CDI规范采用Managed Beans规范,适用于JEE平台的所有容器,而不仅仅是web层,所以web容器需要实现CDI规范。
托管 Bean
以下是 Managed Bean specification 的摘录,“托管 Bean 是具有最低要求的容器管理对象,也称为首字母缩略词“POJO”(普通旧 Java 对象)……它们可以被视为 Java EE 平台增强版本的在 Java SE 平台上找到的 JavaBeans 组件模型……。读者不会错过 Managed Beans 在 JavaServer Faces (JSF) 技术中发现的同名设施中的前身……本规范中定义的 Managed Beans 代表了 JSF 中的泛化;特别是,托管 Bean 可以在 Java EE 应用程序的任何地方使用,而不仅仅是在 Web 模块中。例如,在基本组件模型中,Managed Beans 必须提供无参数的构造函数,但建立在 Managed Beans 上的规范,例如 CDI (JSR-299),可以放宽该要求,并允许 Managed Beans 为构造函数提供更多复杂的签名,只要它们遵循一些明确定义的规则……托管 Bean 不能是:最终类、抽象类、非静态内部类。与常规 JavaBean 组件不同,托管 Bean 可能无法序列化。”因此,托管 Bean(也称为 POJO 或 POJO bean)的规范允许在 CDI 中进行扩展。
CDI 豆
The CDI specification 将托管 bean 重新定义为:在 Java EE 中运行时,如果顶级 Java 类满足要求,则它是托管 bean:
• 它不是内部类。 • 它是一个非抽象类,或者被注释为@Decorator。 • 它没有实现javax.enterprise.inject.spi.Extension。 • 它没有注解@Vetoed 或在一个包中没有注解@Vetoed。 • 它有一个适当的构造函数,或者:类有一个没有参数的构造函数,或者类声明了一个带有@Inject 注释的构造函数。
满足这些条件的所有 Java 类都是托管 bean,因此不需要特殊声明来定义托管 bean。或者
如果它被任何其他 Java EE 规范定义为托管 bean,并且如果
• 它没有使用定义 EJB 组件的注释进行注释,也没有在 ejb-jar.xml 中声明为 EJB bean 类。
与 Spring bean 不同,它不支持具有简单类型的构造函数,如果它支持使用 Spring 中的 xml 配置文件或任何注释进行配置,这可能是可能的。
EJB
EJB 在 EJB 容器中运行。它的 specification 说:“会话 bean 组件是一个托管 Bean。”“该类必须有一个不带参数的公共构造函数,”它对会话 bean 和消息驱动 bean 都说。此外,它说,“会话 bean 类不需要实现 SessionBean 接口或 Serializable 接口。”与 JSF bean 一样,EJB3 依赖注入基本上是资源注入,JSF bean 不支持带参数的构造函数,即通过依赖注入。但是,如果 EJB 容器实现 CDI,“可选:该类可能有一个使用 Inject 注释注释的附加构造函数,“它对会话 bean 和消息驱动 bean 都说,因为,”打包到 CDI bean 存档中且未使用 javax.enterprise.inject.Vetoed 注释注释的 EJB 被认为是启用 CDI豆。”
Java Bean 是应遵循以下约定的 Java 类(概念性):
它应该有一个无参数的构造函数。它应该是可序列化的。它应该提供设置和获取属性值的方法,称为 getter 和 setter 方法。
它是一个可重用的软件组件。它可以将许多对象封装到一个对象中,以便可以从多个位置访问同一个对象,并且是朝着易于维护代码迈出的一步。
它们是可序列化的,具有零参数构造函数,并允许使用 getter 和 setter 方法访问属性。 “Bean”这个名称是为了包含这个标准,它旨在为 Java 创建可重用的软件组件。 根据 Wikipedia。
构成应用程序主干并由 Spring IoC 容器管理的对象称为 bean。 bean 是由 Spring IoC 容器实例化、组装和管理的对象。否则,bean 只是应用程序中的众多对象之一。 根据 Spring IoC。
Java Bean 是满足以下三个条件的任何 Java 类:
它应该实现可序列化的接口(一个标记接口)。构造函数应该是公共的并且没有参数(其他人称之为“无参数构造函数”)。它应该有 getter 和 setter。
需要注意的是 serialVersionUID 字段对于维护对象状态很重要。
以下代码符合 bean 的条件:
public class DataDog implements java.io.Serializable {
private static final long serialVersionUID = -3774654564564563L;
private int id;
private String nameOfDog;
// The constructor should NOT have arguments
public DataDog () {}
/** 4. getter/setter */
// Getter(s)
public int getId() {
return id;
}
public String getNameOfDog() {
return nameOfDog;
}
// Setter(s)
public void setId(int id) {
this.id = id;
}
public void setNameOfDog(String nameOfDog) {
this.nameOfDog = nameOfDog;
}}
如果你熟悉 C/Golang,你从来没有听说过 C bean 或 Go bean,因为它们有 struct
关键字,开发人员可以轻松定义结构类型,而无需编写复杂的 OOP 关键字。
type User struct {
Name string
Age int
}
var user User
user.Name = "name"
user.Age = 18
var bytes, err = json.Marshal(user)
缺少 struct
类型是 Java 的错误,开发人员发现了这种严重的不足。
然后,Java Bean 被发明为另一个无聊的规则,让 class
伪装成 struct
,让您的编辑器或编译器不会因为您对类成员的不安全访问而哭泣或大喊大叫。
上面重复了 6 或 7 次,JavaBean 没有参数构造函数要求。
这是错误的,没有这样的要求,尤其是在 Java Spring 的上下文中。
在描述 JavaBeanns API (https://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/) 的规范版本 (1.01) 中也没有提及该要求。更重要的是——本规范在以下上下文中只提到了 2 次“空构造函数”:“每个定制器都应该有一个空构造函数。” “每个 PropertyEditor 都应该有一个 null 构造函数。”
因此,规范的作者似乎并不知道或不愿意使用术语“空构造函数”,对于 JavaBeans 本身仍然没有提及它。
@java.beans.ConstructorProperties
保持不变。原来的规范已经过时了,它甚至没有从那时起。唯一真正的“标准”是 java.beans.Introspector
中定义的。类真正做的唯一逻辑是检查是否存在具有 is/get/set 的方法。
要了解 JavaBean,您需要注意以下几点:
JavaBean 是概念性的东西,不能代表一类特定的东西
JavaBean 是一个开发工具,可以在可重用的软件组件中进行可视化操作
JavaBean 基于 Sun JavaBeans 规范,是可重用的组件。它最大的特点是可重用性。
POJO(普通的旧 Java 对象):POJO 是普通的 Java 对象,除了 Java 语言强制的限制之外没有其他限制。
序列化:用于保存对象的状态并通过网络发送。它将对象的状态转换为字节流。我们可以通过称为反序列化的过程从字节流中重新创建 Java 对象。
让你的类实现 java.io.Serializable 接口。并使用 ObjectOutputStream 类的 writeObject() 方法实现序列化。
JavaBean 类:它是一个特殊的 POJO,有一些限制(或约定)。
实现序列化 拥有公共无参数构造函数 所有属性都是私有的,具有公共 getter 和 setter 方法。
许多框架(如 Spring)使用 JavaBean 对象。
Bean 构成应用程序主干并由 Spring IoC 容器管理的对象称为 bean。 bean 是由 Spring IoC 容器实例化、组装和管理的对象。这些 bean 是使用您提供给容器的配置元数据创建的。
如果您想了解 Java-Beans,您首先必须了解软件组件。
软件组件
软件组件是运行特定操作的应用程序的一部分。软件组件也可以是服务的一部分。
一个组件是:
耦合(具有依赖关系)
Statefull(它保存实例变量的状态)
未标准化,它是为特定用例设计的(Java-EE Bean 之间的主要区别)
在客户端机器上运行
Java Beans(企业 Beans)
在 Java EE 服务器中运行的标准化组件
包括不同的业务逻辑来完成特定的服务
简化复杂多层分布式系统的开发
Java Beans 更像是一个管理大型系统的概念。这就是为什么他们需要标准化。
https://i.stack.imgur.com/8sCeX.gif
实际上,Bean 只是使用方便的对象。序列化它们意味着能够轻松地持久化它们(以易于恢复的形式存储)。
Beans 在现实世界中的典型用途:
简单的可重用对象 POJO(Plain Old Java Objects)
视觉对象
Spring 使用 Beans 来处理对象(例如,需要在 session 中序列化的 User 对象)
EJB (Enterprise Java Beans),更复杂的对象,比如 JSF Beans(JSF 是老的相当过时的技术)或 JSP Beans
所以事实上,Beans 只是一个约定/标准,它期望 Java 对象的某些行为(序列化)并提供一些方法来以某种方式更改它(属性的设置器)。
如何使用它们只是您的发明,但我在上面列出了最常见的情况。
Java Bean 是 JavaBeans 体系结构中的一个组件或基本构建块。 JavaBeans 体系结构是一种组件体系结构,它受益于基于组件的方法的可重用性和互操作性。
一个有效的组件架构应该允许程序从可能由不同供应商提供的软件构建块(在这种情况下为 Bean)组装而成,并且还使架构师/开发人员可以选择一个组件(Bean),了解它的功能并合并将其放入应用程序中。
由于类/对象是像 Java 这样的 OOP 语言的基本构建块,因此它们是 JavaBeans 架构中 Bean 的天然竞争者。
将普通 Java 类转换为 Java bean 的过程实际上只不过是使其成为可重用和可互操作的组件。这将转化为具有以下能力的 Java 类:
控制向另一个应用程序公开的类的属性、事件和方法。 (你可以有一个 BeanInfo 类,它只报告外部应用程序需要的那些属性、事件和方法。)持久性(可序列化或可外部化——这也意味着有无参数的构造函数,对字段使用瞬态)注册事件的能力以及生成事件(例如,利用绑定和约束属性)定制器(通过 GUI 或通过提供文档来定制 Bean)
为了将 Java 类称为 Java bean,它们不必具备上述所有能力。相反,它意味着实现上述与上下文相关的子集(例如,某个框架中的 bean 可能不需要定制器,其他一些 bean 可能不需要绑定和约束属性等)
Java 中几乎所有领先的框架和库都隐含地遵循 JavaBeans 架构,以便获得上述好处。
Spring @Bean 注解表示一个方法生成一个由 Spring 容器管理的 bean。
更多参考:https://www.concretepage.com/spring-5/spring-bean-annotation