什么是JavaBean?


1793

我认为,“ Bean”是具有属性和getter / setter的Java类。据我了解,它等效于C结构。真的吗?

另外,有没有真正的句法 bean和常规类之间差异?有没有特殊的定义或接口?

基本上,为什么会有一个术语呢?

还什么的Serializable接口是什么意思?


14
看到使用Java Bean的地方?。这是遵循某些约定的类。
马修·弗拉申

5
为了完整起见,这里是指向JavaBeans Specification的链接。
informatik01

2
请注意。如果您曾经听到有人绕过POJO这个词,那么他们实际上通常是Bean。当您看到POJO时,它们几乎总是具有setter和getter,它们是可序列化的,…实际上,POJO不需要setter和getter,可序列化的接口或其他任何东西-它只是一个没有特定要求的普通Java对象。
比尔K

Answers:


2011

JavaBean只是一个标准

  1. 所有私有属性(使用getters / setters
  2. 一个公开的无参数构造函数
  3. 实施Serializable

而已。这只是一个约定。尽管很多图书馆都依赖它。

关于Serializable,来自API文档

通过实现java.io.Serializable接口的类,可以启用类的可序列化性。未实现此接口的类将不会对其状态进行序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。

换句话说,可序列化的对象可以写入流,因此可以写入文件,对象数据库,甚至任何东西。

而且,JavaBean和另一个类之间在语法上没有区别-如果一个类遵循标准,则该类就是JavaBean。

之所以有一个术语,是因为该标准允许库以编程方式对您以预定义方式定义的类实例进行操作。例如,如果一个库想流式传输您传递给它的任何对象,它就知道它可以,因为您的对象是可序列化的(假设lib要求您的对象是正确的JavaBeans)。


197
对了,在我看来,几乎所有围绕bean的文档都无法像您一样简洁地描述该术语。+1
AndaP 2012年

10
一个bean的成员也必须是bean吗?似乎是一个合理的要求
。.– worldsayshi

14
@worldsayshi-不,不是必需的。例如,一个bean可以包含一个String;而且String不是bean。(字符串是不可变的,因此您不能通过调用空的构造函数和设置器来创建它。)除非可以从外部对它们进行序列化,否则Serializable对象应该具有Seri​​alizable成员似乎是合理的。因此,不,Java Bean成员不需要具有Java Bean的任何方面。尽管如果它们是豆类也更简单
ViliamBúr13年

12
“所有私有属性”不正确。从getter和setter推断属性(如果有方法X getFoo()-> Bean具有可读的属性称为“ foo”;如果有方法setFoo(X foo)-> Bean具有可写属性,称为“ foo” “ foo”)。属性可以由成员字段(但不一定是)支持,后者通常是私有的。
2015年

2
我希望成为Java Bean,“一个类必须是Public”。真的需要实现串行化接口吗?
Satyabrata sahoo

286

有一个术语使其听起来特别。现实远没有那么神秘。

基本上是一个“ Bean”:

  • 是一个可序列化的对象(即,它实现java.io.Serializable并正确执行了该操作),
  • 具有“属性”,其“获取器”和“设置器”只是具有某些名称的方法(例如,getFoo()是“ Foo”属性的“获取器”),并且
  • 有一个公共的0-arg构造函数(因此可以随意创建并通过设置其属性进行配置)。

更新:

至于Serializable:那不过是一个“标记接口”(一个没有声明任何函数的接口),它告诉Java实现类同意(并暗示它有能力)“序列化”-一个转换的过程。一个实例转换成字节流。这些字节可以存储在文件中,通过网络连接发送等,并具有足够的信息以允许JVM(至少是一个了解对象类型的人)稍后重新构造对象-可能是在另一个实例中应用程序,甚至在其他机器上!

当然,为了做到这一点,班级必须遵守某些限制。其中最主要的是所有实例字段都必须是原始类型(int,bool等),也可以序列化的某个类的实例或标记为,transient以便Java不会尝试包含它们。(这当然意味着transient字段将不能在流中幸存。具有transient字段的类应准备在必要时重新初始化它们。)

不能由那些遵守限制类不应该实现Serializable(和,IIRC,Java编译器甚至不会它这样做。)


这可能是一个愚蠢的问题,但是除了原始类型或类的实例之外,实例字段还能是什么?
kingfrito_5005 '16

8
@ kingfrito_5005:将会是另一个。但是,如果它是一个类的实例,那么该类是否可序列化就很重要。为了使一个类可序列化,其非transient部分必须是某种可序列化的类型。
cHao

可能忘记提到构造器应该没有参数。具有公共默认构造函数(因此可以随意创建它,并可以通过设置其属性进行配置)。
阿莫斯·科斯基

@AmosKosgei:没忘记;这只是多余的。根据定义,默认构造函数可以不带参数调用。
cHao

@Amos:但是,据我看来,“默认构造函数”在Java中的含义与在C ++中有所不同。:P用“ 0-arg”替换“默认”。
cHao

94

JavaBean是遵守极其简单的编码约定的Java类。您要做的就是

  1. 实现java.io.Serializable接口-保存对象的状态
  2. 使用公共的空参数构造函数-实例化对象
  3. 提供公共的getter / setter方法-获取和设置私有变量(属性)的值。

这种简单的解释正是我所要的。谢谢!
Modo

62

JavaBeans的属性

JavaBean是满足某些编程约定的Java对象:

  1. JavaBean类必须实现SerializableExternalizable

  2. JavaBean类必须具有no-arg构造函数

  3. 所有JavaBean属性必须具有公共setter和getter方法

  4. 所有JavaBean实例变量都应该是私有的

JavaBeans的例子

@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;
   }
}

3
注释是必需的还是Java Bean的一部分?
giannis christofakis

7
@giannischristofakis不,注释不是必需的。注释是Spring框架的一部分,该框架广泛使用Java Bean。
熊天祥

1
为什么需要一个无参数的构造函数?
雷纳托

6
@Renato这很简单。考虑一下必须使用arg-constructor自动实例化bean的spring ...它将作为参数传递什么?;)
Alex75 '16

24

举例说明。

1.导入java.io.Serializable

至于序列化,请参阅文档

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;
    }
}

2
我猜setId(int id)是要说this.id = id;而不是要说的身体this.id = is;
steven7mwesigwa

18

Java Bean用于更少的代码和更多的工作方式... Java Bean在整个Java EE中都被用作运行时发现和访问的通用合同。例如,JavaServer Pages(JSP)使用Java Bean作为页面之间或Servlet和JSP之间的数据传输对象。Java EE的JavaBeans激活框架使用Java Bean将对MIME数据类型的支持集成到Java EE中。Java EE管理API使用JavaBeans作为Java EE环境中要管理的资源检测的基础。

关于序列化:

在对象序列化中,对象可以表示为字节序列,其中包括对象的数据以及有关对象类型和存储在对象中的数据类型的信息。

将序列化的对象写入文件后,可以从文件中读取并反序列化它,即表示对象及其数据的类型信息和字节可用于在内存中重新创建对象。


17

在跨多个服务器部署项目时,您会发现序列化很有用,因为Bean将被持久化并在它们之间进行传输。


1
您能否提供有关在多台服务器上部署项目的更多信息?谢谢
汉枫

4
假设有几个服务器的集群,对于Websphere,此链接stackoverflow.com/questions/3193345 / ...可能会有所帮助。
Truong Ha

10

Java Beans是一个标准,其他答案也清楚地说明了其基本语法要求。

但是,IMO不仅仅是一个简单的语法标准。Java Bean的真正含义或预期用途与围绕标准的各种工具支持一起,可促进代码重用和基于组件的软件工程,即使开发人员能够通过组装现有组件(类)来构建应用程序,而无需编写任何组件。代码(或者只需要写一点胶水代码)。不幸的是,该技术被业界低估和未充分利用,可以从该主题的答案中得知。

如果您阅读有关Java Bean的 Oracle 教程,则可以更好地理解。


有用的帖子和链接。当我想到bean时,的确确实想到了“ Visual Builder”类型的东西,如Oracle文章中所述。我想知道是否还有许多其他框架可以大范围地使用它们……
mike rodent

9

根据维基百科:

  1. 该类必须具有公共默认构造函数(不带参数)。这样可以在编辑和激活框架内轻松实例化。

  2. 根据标准命名约定,必须使用get,set,is(可用于布尔属性而不是get)和其他方法(所谓的访问器方法和mutator方法)访问类属性。这样可以轻松自动地检查和更新框架中的Bean状态,其中许多框架都包含针对各种类型的属性的自定义编辑器。设置器可以有一个或多个参数。

  3. 该类应可序列化。[这允许应用程序和框架以独立于VM和平台的方式可靠地保存,存储和还原Bean的状态。]

有关更多信息,请遵循此 链接。


7

关于问题的第二部分,序列化是一种持久性机制,用于将对象存储为带符号的字节序列。简单地说,它存储对象的状态,以便您以后可以通过反序列化来检索它。


7

Java Bean是Java类[概念性],应遵循以下约定:

  1. 它应该有一个无参数的构造函数。
  2. 它应该是可序列化的。
  3. 它应该提供设置和获取属性值的方法,称为getter和setter方法。

它是可重用的软件组件。它可以将许多对象封装到一个对象中,以便可以从多个位置访问同一对象,这是朝着轻松维护代码迈出的一步。


1
在谈论Java Bean时,我喜欢短语“可重用软件组件”,因为Java Bean通常绝对不做任何事情。
Rodney P. Barbati

6

它们是可序列化的,具有零参数构造函数,并允许使用getter和setter方法访问属性。给出了名称“ Bean”以包含该标准,该标准旨在为Java创建可重用的软件组件。according to 维基

构成应用程序主干并由Spring IoC容器管理的对象称为bean。Bean是由Spring IoC容器实例化,组装和以其他方式管理的对象。否则,bean仅仅是应用程序中许多对象之一。 according to 春天io


4

只是关于bean概念的一些背景/更新。实际上,许多其他答案都具有其中的含义,但原因却不多。

它们是在Java中作为构建GUI的一部分而发明的。它们遵循易于工具分解的模式,从而使它们可以创建属性面板,以便您可以编辑Bean的属性。通常,Bean属性表示屏幕上的一个控件(认为x,y,width,height,text等)。

您也可以将其视为强类型数据结构。

随着时间的流逝,它们对于使用相同访问类型的许多工具变得很有用(例如,Hibernate将数据结构持久存储到数据库中)

随着工具的发展,它们更多地转向注释,而不是分开设置器/获取器的名称。现在,大多数系统不再需要bean,它们可以使用带有注释属性的任何简单的旧java对象来告诉他们如何操作它们。

现在,我将bean视为带注释的属性球-它们实际上仅对它们带有的注释有用。

豆类本身不是健康的模式。它们破坏了封装的性质,因为它们将所有属性暴露给外部操纵,并且在使用它们时,有一种趋势(绝非必要)来创建代码以在外部操纵Bean,而不是在Bean内部创建代码(违反了“ don不要问一个对象的值,而是要一个对象为您做些事情”。使用带有最小的吸气剂且没有塞子的带注释的pojos,更多的是恢复面向对象的封装并具有不变性的可能性。

顺便说一下,随着所有这些事情的发生,有人将这一概念扩展到了称为Enterprise Java Beans的东西。这些是...不同。而且它们非常复杂,以至于许多人认为他们不了解整个Bean概念,因此停止使用该术语。我想,这就是为什么您通常会听到称为POJO的bean(因为每个Java对象都是POJO,从技术上讲这是可以的,但是当您听到有人说POJO时,他们最常考虑的是遵循bean模式的事物)


就在右边-违反了“不要问一个对象的值,而是要一个对象为您做些事情”)
ARK

3

Java Bean是满足以下三个条件的任何Java类:

  1. 它应该实现可序列化的接口(一个Marker接口)。
  2. 构造函数应该是公共的并且没有参数(其他人称为“ no-arg构造函数”)。
  3. 它应该有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;
}}

2

要了解JavaBean,您需要注意以下几点:JavaBean是一个概念性的东西,不能代表一类特定的东西

JavaBean是一种开发工具,可以在可重用的软件组件中可视化操作

JavaBean基于Sun JavaBeans规范,可以是可重用的组件。它的最大特点是可重用性。


1

Bean Java类,其方法名称遵循Java Bean准则(也称为设计模式)的属性方法事件。。因此,不属于属性定义的Bean类的任何公共方法都是Bean方法。至少,一个Java类(即使具有作为其唯一成员的属性(当然,需要附带公共getter和setter),作为唯一成员的public方法或仅一个公共事件侦听器注册方法)也是Java bean。此外,该属性可以是只读属性(具有getter方法,但没有setter)或只写属性(仅具有setter方法)。Java bean必须是一个公共类,才能对任何beanbox工具或容器可见。容器必须能够实例化;因此,它也必须有一个公共构造函数。在JavaBeans规范不需要Bean具有公用的零参数构造函数(显式或默认),容器即可实例化它。如果您可以提供一个包含序列化实例的文件(扩展名为.ser),则beanbox工具可以使用该文件来实例化原型bean。否则,bean必须具有公共的零参数构造函数,无论是显式的还是默认的。

实例化该bean之后,Java Bean API(java.beans。*)可以对其进行内部检查并在其上调用方法。如果没有实现接口BeanInfo或扩展BeanInfo实现的类SimpleBeanInfo类,则自省涉及使用反射(隐式自省)研究目标Bean支持的方法,然后应用简单的设计模式(准则)从中推论出这些方法支持哪些属性,事件和公共方法。如果有一个实现接口BeanInfo的类(对于Foo,必须将其命名为FooBeanInfo)可用,则API绕过隐式自省,并使用此类的公共方法(getPropertyDescriptor(),getMethodDescriptors(),getEventSetDescriptors())来获取信息。如果扩展SimpleBeanInfo的类可用,根据哪个SimpleBeanInfo公共方法(getPropertyDescriptor(),getMethodDescriptors(),getEventSetDescriptors())被覆盖,它将使用那些被覆盖的方法来获取信息;对于未重写的方法,它将默认为相应的隐式自省。无论如何,即使没有进行隐式自省,也需要实例化Bean。因此,需要公共zeri-args构造函数。但是,当然,并不需要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构造函数具有一些参数。假设一些是简单类型。容器可能不知道要为它们分配什么值。即使这样做,结果实例也可能不可重用。仅当用户可以像在Spring bean中那样通过注释或xml配置文件配置(指定值)时,这才有意义。并假设某些参数是类或接口类型。同样,容器可能不知道要为其分配什么值。仅当用户可以通过注释或xml配置文件配置(指定特定对象)时,这才有意义。但是,即使在Spring中(通过xml配置文件),将特定对象(带有字符串名称)分配给构造函数参数(构造函数参数的属性或元素)也不是类型安全的;这基本上就像资源注入一样。引用其他Spring bean(称为合作者;通过构造函数参数元素中的元素)基本上是依赖注入,因此是类型安全的。显然,一个依赖项(协作者bean)可能具有一个带有注入参数的构造函数。那些注入的依赖项可能具有带有参数的构造函数,依此类推。在这种情况下,最终,您需要容器可以通过简单地调用new MyBean()实例化的一些bean类(例如,MyBean.class),然后才能通过对构造函数的依赖注入构造其他协作Bean,因此, bean具有公共的零参数构造函数。假设,如果某个容器不支持依赖项注入和/或不允许像Spring中那样通过某些注释或xml配置文件向构造函数分配简单类型的值,Bean构造函数不应具有参数。即使是Spring bean应用程序,也需要一些bean具有公共的零参数构造函数(例如,在您的Spring应用程序没有使用简单类型作为构造函数参数的bean的情况下)。

JSF管理的bean在Web容器中运行。可以使用@ManagedBean批注或应用程序配置资源文件managed-bean.xml来配置它们。但是,它仅支持通过资源注入(不是类型安全)进行注入;不适合在构造函数上注入。的 JSF规范要求托管bean必须具有公共零参数构造函数。进一步说,“从本规范的2.3版开始,强烈建议不要使用本节中指定的托管bean工具。解决同一问题的更好,更紧密集成的解决方案是使用JSR-365中指定的上下文和依赖注入(CDI)。“换句话说,将使用CDI管理的bean,它为构造函数提供了类型安全的依赖注入CDI规范采用了Managed Beans规范,该规范不仅适用于Web层,而且适用于JEE平台的所有容器,因此,Web容器需要实现CDI规范。

这是Managed Bean规范的摘录 “受管Bean是具有最低要求的容器管理对象,否则以缩写词“ POJO”(普通的旧Java对象)而闻名……它们可以看作是Java SE平台上JavaBeans组件模型的Java EE平台增强版本。 …。读者不会错过Managed Bean在JavaServer Faces(JSF)技术中发现的同名功能中的前身。本规范中定义的Managed Bean代表了JSF中所发现的那些的概括。特别是,受管Bean可以在Java EE应用程序中的任何地方使用,而不仅仅是在Web模块中使用。例如,在基本组件模型中,托管Bean必须提供无参数的构造函数,但是要建立在托管Bean之上的规范,例如CDI(JSR-299),可以放宽该要求,并允许Managed Bean为构造函数提供更复杂的签名,只要它们遵循一些明确定义的规则即可。Managed Bean不得为:最终类,抽象类,非静态内部类。与常规JavaBean组件不同,托管Bean可能无法序列化。” 因此,受管Bean的规范(也称为POJO或POJO Bean)允许像CDI中那样进行扩展。

CDI规范将托管Bean重新定义为:在Java EE中运行时,如果满足要求,则顶级Java类是托管Bean:

•它不是内部类。•这是一个非抽象类,或使用@Decorator进行了注释。•它没有实现javax.enterprise.inject.spi.Extension。•它没有注释@Vetoed或在带有注释@Vetoed的程序包中。•它具有适当的构造函数,或者:类具有没有参数的构造函数,或者该类声明带有@Inject注释的构造函数。

满足这些条件的所有Java类都是托管Bean,因此不需要特殊声明即可定义托管Bean。要么

是否通过其他任何Java EE规范将其定义为托管Bean,以及

•在ejb-jar.xml中,未使用EJB组件定义的注释对其进行注释或将其声明为EJB bean类。

与Spring Bean不同,它不支持简单类型的构造函数,如果它支持使用xml配置文件(例如Spring或任何注释)进行配置,则可能是可行的。

EJB在EJB容器中运行。它的规格表示:“会话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的豆。”


0

实际上,Bean只是易于使用的对象。序列化它们意味着能够轻松持久化它们(以易于恢复的形式存储)。

Bean在现实世界中的典型用法:

  • 简单的可重用对象POJO(普通的旧Java对象)
  • 视觉对象
  • Spring使用Beans处理对象(例如,需要在会话中序列化的User对象)
  • EJB(企业Java Bean),更复杂的对象,例如JSF Bean(JSF是过时的技术)或JSP Bean

所以事实上,Beans 只是一个约定/标准,它期望Java对象执行某些操作(序列化),并提供以某种方式更改它的方法(属性设置者)。

如何使用它们只是您的发明,但我在上面列出了最常见的情况。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.