October 30, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Understanding Properties in Java and C#

  • March 18, 2003
  • By Richard G. Baldwin
  • Send Email »
  • More Articles »

Java Programming Notes # 2100


Preface

Six parts to this tutorial

This is a long and technically complex tutorial lesson.  Therefore, I have broken it into six parts.  You should be able to finish reading each part in one sitting.

Part 1 explains properties in general, based on a real-world scenario with which we are all familiar.

Part 2 provides a detailed explanation of Java properties including:

  • Simple and indexed properties.
  • Bound and constrained properties.
  • Introspection based on design patterns and low-level reflection.
  • Introspection based on explicit BeanInfo information.

Part 3 explains C# properties from the viewpoint of the general user, and compares C# properties at that level with Java properties.

Part 4 explains C# properties from the viewpoint of the sophisticated user (based on reflection) and compares C# properties at that level with Java properties.

Part 5 provides a summary of the entire tutorial lesson.

Part 6 contains complete program listings for several Java and C# programs used for illustration elsewhere in the lesson.

Viewing tip

You may find it useful to open another copy of this lesson in a separate browser window.  That will make it easier for you to scroll back and forth among the different listings and figures while you are reading about them.

Supplementary material

I recommend that you also study the other lessons in my extensive collection of online Java tutorials.  You will find those lessons published at Gamelan.com.  However, as of the date of this writing, Gamelan doesn't maintain a consolidated index of my Java tutorial lessons, and sometimes they are difficult to locate there.  You will find a consolidated index at www.DickBaldwin.com.

Part 1, Properties in General

What is a traffic light?

This question may appear to be trivial at first glance.  However, this is not a trivial question.  How would you explain a traffic light to an alien from outer space who has never seen a transportation system like we have on Earth?

Assume that the alien has never seen an automobile, a street, an intersection, a traffic jam, or any of the other things that we commonly associate with the flow of traffic.  Providing an explanation of a traffic light to our alien friend would not be easy. 

What is a property?

Explaining what a property is can be equally difficult.  Before you can explain how you implement a property, you need to be able to explain what it is that you are implementing.

Two blocks past the red light ...

In the small town where I grew up, the traffic lights were commonly referred to as "red lights."  Someone might make a statement similar to "My house is on the corner of the third street past the red light."

Obviously describing a traffic light as a red light is inadequate.  A traffic light is red only part of the time.  It is also green part of the time and amber part of the time.  So, we need a better explanation that that.

Light sources and colors

Let's assume that our alien friend does understand the concepts of light sources and colors.  For brevity, we will refer to light sources simply as lights.

We might describe a traffic light as a group of lights, always including red, green, and amber, which are used for a specific purpose.  However, that would also be an inadequate description.  In every town, there are many groups of lights that may include red, green, and amber, which are not traffic lights.  Rather, those groups of lights may be used for a variety of purposes, such as advertising or simple illumination.

Must be uniquely identifiable

Therefore, our explanation of a traffic light would need to be much more specific that that.  When you drive, it is very important that you are able to identify the traffic lights.  Therefore, very important to our explanation would be the information that makes it possible to always identify traffic lights as such, and to separate them from the many other groups of colored lights that we see when we look around.

An array of lights

For example, we might say that a traffic light is always an array of three or more lights arranged in a horizontal or vertical line.  We might explain that in the case of the horizontal arrangement, the red light is always on the left, and the green light is always on the right.  (At least that appears to be the case based on observation.)

We might explain that traffic lights are always located in specific positions relative to the geometry of the intersection.  We would probably need to describe other unique characteristics of traffic lights before our alien friend could learn to always recognize them as such.  Hopefully, by describing enough of the characteristics of traffic lights, we could teach our alien friend to always recognize one when she sees one.  As you can see, however, explaining a traffic light to our alien friend would not be an easy task.

When is a traffic light really a traffic light?

The bottom line to this discussion, however, is that a traffic light is really a traffic light only when drivers recognize it as such.  If everyone in town were to suddenly forget how to recognize traffic lights, they would change from being traffic lights to being big ugly boxes with lights blinking in them.  Chaos would reign, and there would be lots of collisions at the intersections.

Similarly, I'm going to tell you later that a property is really a property only when other programs recognize it as such.  If other properly-written programs can't recognize a property, then it is not a property after all.  It is simply another value among many values contained in a program.

What is a property?

Explaining a property is just about as difficult as explaining a traffic light.

As in the case of a traffic light, we could begin by saying that it should always be possible for a programmer or another program to recognize a property as being a property.  Therefore, a property must have some attribute that makes it instantly recognizable as such and distinguishable from other values that are not properties.

The purpose of a property

Beyond this, we might say that a property is a value that is used for specific purposes, although the purpose of using a property in one program may be different from the purpose of using a property in another program.

(In this sense, a property is more complex than a traffic light, which usually has only one overall purpose (to control the flow of traffic) regardless of the observer.)

Objects may have properties

We could explain that objects may have properties, and in most cases, a property is a value that is stored in, or accessible by way of, a member variable belonging to the object.  However, this is not true in all cases.  It is perfectly legal for a property value to be generated on-the-fly when it is requested.  It is not absolutely necessary for the property value to be stored in a member variable of the object.

Limit properties to member variables

Even if we were to impose the (artificial) limitation that properties must be stored in member variables, we would still have problems with our explanation.  Just as a city can have many red, green, and amber lights that are not traffic lights (particularly when the Christmas decorations are up), an object can encapsulate many member variables that are not properties.  Therefore, under this limitation, we might say that the value of a property is stored in a member variable, but a value stored in a member variable is not necessarily a property.

Can you recognize a property?

In the case of traffic lights, we can say that because of the convergence of many visual patterns, most people who see a traffic light will have learned to recognize it as a traffic light.  Similarly, we can say that most programmers and programs that have learned the rules for recognizing properties will recognize a property when they see one.  However, the recognition methodology is different in Java and C#, (and such recognition is somewhat easier in Java than in C#.)

When is a property really a property?

A property is really a property only when other programs recognize it as such.  If a program can't recognize a property, then it is simply a value among many values contained in a program.

Why should I care?

It is my belief that most people who plan to make a living as computer programmers during the next ten years will need to be proficient in both Java and C#, particularly if they ever plan to change jobs.

The platform independent marketplace

Java is already well established as the de facto standard programming language for computer programs that need a wide degree of platform independence.  I don't see that changing in the foreseeable future.

The Windows programming marketplace

Although C# hasn't really taken off as of the Spring of 2003, this new language, along with VB.NET, in conjunction with MS.NET, appears to be the programming vehicle that Microsoft will promote heavily for programs that run on Windows platforms.  I believe that to some extent the slowdown in the economy has slowed down the acceptance of MS.NET, C#, and VB.NET.

Will MS.NET be successful?

Will MS.NET be successful in the marketplace?  Let me simply say that Bill Gates has had few (if any) failures in the marketplace since I first heard his name back around 1981 when I was using a VisiCalc spreadsheet on a TRS-80 computer that I purchased from Radio Shack.  I bought my first IBM personal computer running Gate's operating system around that time and the rest is history.  I don't believe that MS.NET, C#, and VB.NET will fail in the marketplace.  I believe that they will succeed and really take off as soon as the high-tech economy recovers from its current slump.

And you need to be ready when that happens.

The good news

The good news is that Java and C# are very similar.  If you understand Java, it is easy to learn and understand C#.  If you understand C#, it is very easy to learn and understand Java.

The bad news

The bad news is that Java and C# are not identical.  There are a few areas where they are significantly different, and the implementation of properties is one of those areas.  Therefore, in order to be proficient in both languages, you will need to understand the differences in the way that properties are implemented in each of the two languages.

In order to be proficient in both languages, you will also need to understand the implementation differences in some other areas as well, such as event handling and arrays.  I hope to be able to find the time to publish additional lessons that explain the other significant differences between Java and C# in the future.

Why do we need properties?

Different authors will provide different reasons for the need for properties to exist.  For example, some authors will tell you that properties are needed to support a concept known as information hiding.  I personally disagree with that assessment.  While information hiding is a very important design goal, there are much easier ways to accomplish information hiding than through the mechanism of properties.

Some programs need to identify properties

My explanation is that some programs need to be able to positively identify and possibly modify a specific set of values associated with an object.  One way to make that happen is to cause those values to become properties of the object, and to cause the program to recognize them as properties.

Property editors

The most familiar example of the use of properties is the case of high-level IDEs, such as Microsoft's Visual Studio.net.  (For brevity, I will refer to Visual Studio.net simply as MSVS during the remainder of this lesson.)  For example, when you drag a Button object onto a Form object in MSVS, (while in C# designer mode), and select the button with your mouse, a Properties Window, similar to that shown in Figure 1 opens. 

Figure 1 MSVS Property Window

The property window lists more than forty different properties associated with the Button object, along with their default values.

The list includes properties with names like Location, Size, BackColor, and ForeColor, and each of the properties has a default value.

Purpose of a property editor

The values for each of the properties will either be stored in member variables of the Button object at runtime, or generated on-the-fly based on values stored in other member variables.  The purpose of the property editor is to allow the programmer to modify the default property values at design time so that the Button object will look and behave more to the programmer's liking when the program starts running than would otherwise be the case.

The ability to recognize properties is a critical feature of MSVS and other similar software development environments.

Member values that are not properties

Although I have never looked at the source code for the Button class, my guess is that there are numerous other values stored in member variables of the Button class that are not recognized by MSVS as properties.  For example, this might include values that control those aspects of the three-dimensional appearance of the button that cannot be modified by the programmer at design time.

The FlatStyle property

The FlatStyle property of a C# button, as created by MSVS, can have any of the following four values:

  • Flat
  • Popup
  • Standard
  • System

The appearance and behavior of the button is somewhat different, depending on the value of the FlatStyle property.

A Standard button

For example, the default appearance of a Standard button is to protrude from the screen.  The behavior of the button is to appear to be pressed into the screen when you point to it with the mouse pointer and press the left button on the mouse.

An optical illusion

This appearance is the result of an optical illusion produced by highlighting the left and top of the button and placing a shadow on the right and bottom of the button when it is in the default position (see Figure 2).  The highlighted portion appears to be a lighter color than the background color of the button, and the shaded portion appears to be a darker color than the background color.

Figure 2 A C# form with buttons of different colors

I may be wrong, but I don't believe that the programmer has independent control over the difference in colors between the highlighted portion and the background color.  The programmer has control only over the background color through a property named BackColor.  Different buttons on a form can have different background and highlight colors as shown in Figure 2.

The main point

The background color is a property named BackColor.  However, the information that makes it possible to create the corresponding highlight color is not recognized as a property.  This information may be generated on the fly when needed, or may be stored in a member variable of the button that is not recognized as a property.  As I mentioned earlier, there are probably many other values stored in member variables of a Button that also are not recognized as properties.

An automatic code generator

MSVS is a program whose primary purpose is to generate code automatically.  The use of a code generator like MSVS can greatly reduce the programming effort required of the programmer.

When operated in designer mode, the MSVS has the ability to write the code required to instantiate the buttons and to place them on the form at runtime.  While in designer mode, the program must have the ability to recognize those values that are to be treated as properties and to expose them to the programmer for editing.  Therefore, the program must have, and does have the ability to tell the difference between member values of the class that are to be treated as properties and member values of the class that are not to be treated as properties.

A more subtle use of properties

A somewhat more subtle use of properties is illustrated by the code in the lessons entitled JavaServer Pages and JavaBeans Components, Parts I, II, and III.  You will find these lessons published as lessons number 762, 764, and 766 on my Web Site.

For example, lesson 766 explains the use of the jsp:getProperty tag when creating Java Server Pages.  The JSP engine knows how recognize the properties belonging to a JavaBeans component when it encounters this tag in the JSP code.  Thus, this tag, in conjunction with the JSP engine, makes it possible to get and use a property value of a JavaBeans component when creating Java Server Pages for whatever purpose that property value may be needed.

Different approaches

While both Java and C# make use of properties for similar reasons, the approach to the creation and recognition of properties is handled much differently in Java and C#.  You will need to understand those differences to be proficient in both languages.  This lesson will explain those differences.

Part 2, Properties in Java, Detailed Explanation

What is a JavaBeans component?

According to Sun,

"The goal of the JavaBeans APIs is to define a software component model for Java, so that third party ISVs can create and ship Java components that can be composed together into applications by end users."

In other words, the JavaBeans component model is the standard software component model for Java.

Serialization or Externalization

Without getting into the details as to why, I will tell you that all beans must support either Serialization or Externalization.  To qualify as a JavaBeans component, a class must implement either the Serializable interface or the Externalizable interface.  Thus, the JavaBeans component classes that I will present in this lesson will implement the Serializable interface.

(If you are familiar with the Serializable interface, you already know that nothing is required to implement the interface other than to declare that it is implemented by the class.  There are no declared methods in the interface that must be defined in your class.)

The Java Introspector

In order for a Java property to be a property, it must be recognized as such by the Java Introspector.  According to Sun,

"The Introspector class provides a standard way for tools to learn about the properties, events, and methods supported by a target Java Bean."

In this part of the lesson, I will show you how to use the Introspector class to discover and display information about the properties, events, and methods for three simple bean classes.

Continuing with Sun's explanation,

"For each of those three kinds of information, the Introspector will separately analyze the bean's class and superclasses looking for either explicit or implicit information and use that information to build a BeanInfo object that comprehensively describes the target bean."

What is a BeanInfo object?

BeanInfo is an interface.  An object of a class that implements the BeanInfo interface is a BeanInfo object.  Such an object encapsulates information about the properties, events, and methods of the Java Bean that it describes.  Sun goes on to say,

"For each class "Foo", explicit information may be available if there exists a corresponding "FooBeanInfo" class that provides a non-null value when queried for the information."

Will provide BeanInfo for one bean class

I will provide a class that implements the BeanInfo interface for one of the three bean classes that I will discuss in this lesson.

Continuing with Sun's description,

"If we don't find explicit BeanInfo on a class, we use low-level reflection to study the methods of the class and apply standard design patterns to identify property accessors, event sources, or public methods."

Two ways to make a bean's properties recognizable

Thus, the author of a Java Bean class can make the properties recognizable in either of two ways:

  • Provide an auxiliary class that implements the BeanInfo interface to identify and provide information about the properties.
  • Rely on low-level reflection based on standard Java design patterns.

Two of the bean classes that I will discuss in this lesson will depend on low-level reflection for introspection.  I will define a class that implements the BeanInfo interface for the third bean class.

Simple and indexed properties

Java properties come in two varieties, simple and indexed.  A simple property is a single-valued property.  An indexed property is a property that may consist of more than one value where the individual values are accessed via a numeric index.

I will illustrate both simple and indexed properties in this lesson.

Bound properties

Whether simple or indexed, a property may also be a bound property.  According to Sun,

"A component can choose to provide a change notification service for some or all of its properties.  Such properties are commonly known as bound properties, as they allow other components to bind special behavior to property changes."

The enabled property

One of the best examples of bound properties that I can think of is the relationship that exists between menu items and corresponding buttons on a button bar.  Many graphical user interfaces provide several buttons, each of which is tied specifically to an item on a menu.  Pressing the button or selecting the corresponding menu item always produces the same result.

(For example, the Back button on the Internet Explorer browser corresponds to a selection on the View menu.)

Synchronization is critical

It is critical that a button on the button bar and the corresponding menu item track one another in terms of being enabled or disabled.

In Java, menu items and buttons on a button bar have an enabled property, which is either true or false.  When you create a button bar and associate the buttons with menu items, you can set things up so that a change in the value of the enabled property on one will cause the other to be notified of the change.  This mechanism can be used to assure that the button and the corresponding menu item track one another in terms of being enabled or disabled.  I discuss this scenario in detail in the lesson entitled Understanding Action Objects in Java.

One of the bean classes that I will discuss in this lesson has a bound property.  I will use that example to explain how to create and service bound properties.

Constrained properties

Whether simple or indexed, a property may also be a constrained property.  According to Sun,

"Sometimes when a property change occurs some other bean may wish to validate the change and reject it if it is inappropriate.  We refer to properties that undergo this kind of checking as constrained properties."

The control logic required to support constrained properties is somewhat more complex than that required to support bound properties.  This lesson does not provide sample code to support constrained properties.

Enough talk, let's see some code

I will begin by discussing the program named PropertyDisplay01, which is used in this part of the lesson to display information about the properties, events, and methods belonging to a JavaBeans component.

As usual, I will discuss the program in fragments.  A complete listing of the program is provided in Listing J33 near the end of the lesson.

The display method

This program consists of a single static method named display.  To display information about a bean, invoke the display method passing the name of the JavaBeans component class as a String parameter.

The beginning of the class definition and the beginning of the method named display is shown in Listing J1.

public class PropertyDisplay01{

  public static void display(String beanClass)
                                throws Exception{

    Class myBeanClassObject = Class.forName(
                                      beanClass);

Listing J1

Get a Class object that describes the bean class

The code in Listing J1 shows the incoming String parameter known locally by the parameter name beanClass.

A little later, we will invoke the static method of the Introspector class named getBeanInfo.  At that time, we will need a Class object that describes the target bean class.  The code in Listing J1 creates such a Class object.  The static forName method of the class named Class returns a reference to such a Class object, given the name of the target bean class as a String parameter.

Get a BeanInfo object that describes the bean class

Given the Class object that describes the bean's class, the code in Listing J2 uses the static getBeanInfo method of the Introspector class to obtain a BeanInfo object containing information about the class of the bean.  The BeanInfo object's reference is saved in the reference variable named beanInfo.

    BeanInfo beanInfo = Introspector.getBeanInfo(
              myBeanClassObject,
              myBeanClassObject.getSuperclass());

Listing J2

According to Sun, the getBeanInfo method

"will separately analyze the bean's class and superclasses looking for either explicit or implicit information and use that information to build a BeanInfo object that comprehensively describes the target bean."

Behavior of the getBeanInfo method

There are several overloaded versions of the getBeanInfo method.  The version used in Listing J2 takes two parameters.  The first parameter is a reference to a Class object describing the bean class.  The second parameter is a Class object describing a stopClass.  Paraphrasing Sun, the stopClass is the superclass at which to stop the analysis.  Any methods, properties, or events in the stopClass or its superclasses will be ignored in the analysis.

In Listing J2, the stopClass is the immediate superclass of the target bean class.  Therefore, the BeanInfo object produced by the code in Listing J2 will contain information about the bean class, but will not contain information about any of its superclasses.

Get a BeanDescriptor object

From this point forward, all information about the bean and its properties will be obtained by performing various manipulations on the BeanInfo object.  We begin by invoking the getBeanDescriptor method on the BeanInfo object to get and process a BeanDescriptor object, as shown in Listing J3.

    BeanDescriptor beanDescriptor =
                    beanInfo.getBeanDescriptor();
    System.out.println("Name of bean:  " +
                       beanDescriptor.getName());
    System.out.println("Class of bean: " +
                  beanDescriptor.getBeanClass());

Listing J3

What is a BeanDescriptor object?

According to Sun,

"A BeanDescriptor provides global information about a "bean", including its Java class, its displayName, etc.  This is one of the kinds of descriptors returned by a BeanInfo object, which also returns descriptors for properties, methods, and events."

Having obtained the BeanDescriptor object, the code in Listing J3 invokes appropriate methods on the object to get and display the name and the class of the target bean.  As an example, the code in Listing J3 produced the following screen output for one of the beans that will be discussed later in this lesson.

Name of bean:  Prop02BeanX
Class of bean: class Prop02BeanX

Get and display exposed methods

A bean is said to expose all of its public methods.  According to Sun,

"A MethodDescriptor describes a particular method that a Java Bean supports for external access from other components."

Thus, each of the methods exposed by a bean is described by an object of the type MethodDescriptor.  The code in Listing J4 invokes the getMethodDescriptors method on the BeanInfo object to get an array of MethodDescriptor objects, where each object in the array describes one of the exposed methods.

    MethodDescriptor[] methodDescriptor =
                 beanInfo.getMethodDescriptors();

    for (int i=0;i < methodDescriptor.length;
                                            i++){
        System.out.println(
                  methodDescriptor[i].getName());
    }//end for-loop

Listing J4

The names of the exposed methods

Several kinds of information about an exposed method are contained in the corresponding MethodDescriptor object.  The code in Listing J4 iterates on the array to get and display the name of each method exposed by the bean.  For example, the code in Listing J4 produced the following list of exposed method names for one of the beans that will be discussed later in this lesson.

fetchSize
getColor
getData
putSize
setColor
setData

A PropertyDescriptor object

According to Sun,

"A PropertyDescriptor describes one property that a Java Bean exports via a pair of accessor methods."

The code in Listing J5 invokes the getPropertyDescriptors method on the BeanInfo object to get an array of PropertyDescriptor objects, where each object in the array describes one of the properties of the target bean.

    PropertyDescriptor[] propertyDescriptor =
               beanInfo.getPropertyDescriptors();

    for (int i=0; i < propertyDescriptor.length;
                                           i++) {
      System.out.println("Name: " +
                propertyDescriptor[i].getName());
      System.out.println(" Type:       " +
        propertyDescriptor[i].getPropertyType());

      System.out.println(" Get method: " +
          propertyDescriptor[i].getReadMethod());
      System.out.println(" Set method: " +
         propertyDescriptor[i].getWriteMethod());

      System.out.println(" Bound: " +
                propertyDescriptor[i].isBound());
      System.out.println(" Constrained: " +
          propertyDescriptor[i].isConstrained());
    }//end for-loop

Listing J5

Property name and type

Then the code in Listing J5 iterates on the array to get and display various attributes of each property.

Every Java property has a name and a type.  These attributes are obtained and displayed by invoking the appropriate methods on each PropertyDescriptor object in Listing J5.

Property accessor methods

Every Java property may have a read method, a write method, or both.  (Java jargon often refers to these methods as setter and getter methods, or accessor methods.)

The code in Listing J5 invokes the appropriate methods to get and display information about the accessor methods.

Bound and constrained properties

Earlier in this lesson, I discussed bound and constrained properties.  The final two statements in Listing J5 get and display whether or not each property is bound or constrained (I will have more to say about this later).

The screen output for a bean

The code in Listing J5 produced the following screen output for one of the beans that will be discussed later in this lesson.  This particular bean had two properties, one named color and the other named data.

Name: color
 Type:       class java.awt.Color
 Get method: public java.awt.Color Prop02BeanX.
             getColor()
 Set method: public void Prop02BeanX.
             setColor(java.awt.Color)
 Bound: false
 Constrained: false
Name: data
 Type:       class [Ljava.lang.Integer;
 Get method: public java.lang.Integer[]
             Prop02BeanX.getData()
 Set method: public void Prop02BeanX.
             setData(java.lang.Integer[])
 Bound: false
 Constrained: false

An EventSetDescriptor

According to Sun,

"An EventSetDescriptor describes a group of events that a given Java bean fires.  The given group of events are all delivered as method calls on a single event listener interface, and an event listener object can be registered via a call on a registration method supplied by the event source."

Event-driven programming in Java

One of the beans that I will discuss later has a bound property.  An understanding of bound properties depends on an understanding of event-driven programming in Java.  The overall topic of event-driven programming is far too complex to cover in this lesson.  I have published numerous tutorial lessons on event-driven programming on my web site.

Because of the relationship between bound properties and event-driven programming, I included the code in Listing J6 in this program for the purpose of getting and displaying information about the events that a bean can fire.

    EventSetDescriptor[] eventSetDescriptor =
               beanInfo.getEventSetDescriptors();

    for (int i=0; i < eventSetDescriptor.length;
                                            i++){
      System.out.println("Event Name: " +
                eventSetDescriptor[i].getName());
      System.out.println(" Add Method:    " +
                         eventSetDescriptor[i].
                         getAddListenerMethod());
      System.out.println(" Remove Method: " +
                      eventSetDescriptor[i].
                      getRemoveListenerMethod());

      methodDescriptor = eventSetDescriptor[i].
                  getListenerMethodDescriptors();

      for (int j=0; j < methodDescriptor.length;
                                            j++){
          System.out.println(" Event Type: " +
                  methodDescriptor[j].getName());
      }//end for-loop
    }//end for-loop

Listing J6

Additional complexity in the code

The pattern for the code in Listing J6 is pretty-much the same as before, but a little more complicated.  The additional complexity derives from the fact that each type of event can have multiple listener methods.  For example, an event of type WindowEvent has the following listener methods:

  • windowOpened
  • windowClosing
  • windowClosed
  • windowActivated
  • windowDeactivated
  • windowIconified
  • windowDeiconified

The getEventSetDescriptors method is invoked on the BeanInfo object to get an array of EventSetDescriptor objects in Listing J6.  Then nested for loops are used to iterate and display information about each event that the bean can fire.  I will defer further discussion of this topic until the discussion of the bean with a bound property later in the lesson.

Analyze bean properties

Now that you understand how the introspection program that we will use to analyze our beans works, we will begin analyzing the properties of several beans.  We will analyze three separate beans.  Each of the beans will illustrate some important characteristics of properties in Java.

The bean class named Prop02BeanX

The class definition for the first bean class named Prop02BeanX begins in Listing J7.

class Prop02BeanX implements Serializable{
  private String size = "Medium";
  private Color color = Color.RED;
  private Integer data[];

  public void setColor(Color color){
    this.color = color;
  }//end setColor

  public Color getColor(){
    return color;
  }//end getColor

Listing J7

Introspection was performed on this bean by invoking the following statement in the main method of a test class named Prop02Test.

PropertyDisplay01.display("Prop02BeanX");

(Note that complete listings of all the programs used in this lesson are shown near the end of the lesson.)

Exposed methods

Before getting into the details of the code in this bean class, let's take a look at the introspection output for the exposed methods of this bean:

fetchSize
getColor
getData
putSize
setColor
setData

This bean exposes six different public methods.  As you will see later, the four methods shown in boldface in the above list match the JavaBeans design patterns for properties, and are thus recognized as properties by the introspection process.  The other two methods do not match design patterns, and therefore are not recognized as properties by the introspection process.

Instance variables

Listing J7 begins by declaring three instance variables, two of which are used to store the values of the two properties.

(Note that the names that I gave the instance variables match the names of the properties.  However, that is not a requirement.  I did so solely for convenience.  There is no connection between the name of a property and the name of an instance variable used to store the property's value.)

Setter and getter methods for a simple property

The two methods shown in Listing J7 match the design patterns for a simple property named color.

(To learn a lot more about the rules for property design patterns, see the lessons on JavaBeans components, beginning with lesson number 500, on my web site.)

An indexed property

The two methods shown in Listing J8 match the design patterns for an indexed property named data.

  public void setData(Integer[] data){
    this.data = data;
  }//end setData

  public Integer[] getData(){
    return this.data;
  }//end getData

Listing J8

Ordinary accessor methods

The two methods shown in Listing J9 are accessor methods, which support the design objective of information hiding.  Note, however, that they do not match the design pattern for properties.

  public void putSize(String size){
    this.size = size;
  }//end putSize()

  public String fetchSize(){
    return size;
  }//end fetchSize()

Listing J9

Properties based on design patterns

I did not provide explicit BeanInfo information regarding the properties for this bean.  (I will provide explicit information for the third bean that I will discuss later.

Here is a repeat of a quotation from Sun that I provided earlier:

"If we don't find explicit BeanInfo on a class, we use low-level reflection to study the methods of the class and apply standard design patterns to identify property accessors, event sources, or public methods."

Since I did not provide explicit BeanInfo information for this bean, the introspection process identified two properties for this bean based on low-level reflection and design patterns.  Here is the screen output for one of the properties.  This output was produced when the introspection process was applied to this bean. (Note that I manually inserted some line breaks to force the material to fit in this narrow publication format.)

Name: color
 Type:       class java.awt.Color
 Get method: public java.awt.Color Prop02BeanX.
             getColor()
 Set method: public void Prop02BeanX.
             setColor(java.awt.Color)
 Bound: false
 Constrained: false

The name of the property

The reported name of the property is color.  Using low-level reflection and design patterns, the name is derived from the names of the setter and getter methods shown in Listing J7.

(There are some special rules regarding the case of the first character in the property name, which you will find in the JavaBeans component lessons on my web site.)

The type of the property

The type of the property, Color, is the same as the parameter and return types of the setter and getter methods in Listing J7.

Get and Set methods

The description of the Get method and Set method in the output matches the signatures of the getter and setter methods in Listing J7.

Neither bound nor constrained

I did not provide the code to establish this property as a bound property or a constrained property.  (I will provide a bound property for the second bean, which I will discuss later in this lesson.)  Thus, the introspection process reported this property to be neither bound nor constrained.

A simple property

A careful examination of the type of the property, as well as the parameter type for the setter method and the return type for the getter method indicates that this is a simple (single-valued) property.

An indexed property

As I indicated earlier, this bean also has an indexed property (shown in Listing J8).  The introspection output for the indexed property is shown below.

Name: data
 Type:       class [Ljava.lang.Integer;
 Get method: public java.lang.Integer[]
             Prop02BeanX.getData()
 Set method: public void Prop02BeanX.
             setData(java.lang.Integer[])
 Bound: false
 Constrained: false

The property type

Although you may not be familiar with this nomenclature, the square bracket shown in the description of the type indicates that the type of this property is an array of type Integer.  This indicates that this is an indexed property.

The fact that this is an indexed property is also indicated by the return type of the Get method and the parameter type of the Set method in the introspector output.  The introspector output indicates that the return type of the Get method is a reference to an array object of type Integer.  The output also indicates that the parameter type of the Set method is a reference to an array object of type Integer.

Another indexed property design pattern

Although I didn't illustrate it in this program, there is another design pattern for indexed properties that supports setting and/or getting a single value belonging to the property based on a numeric index.  Again, you can read about that in the JavaBeans component lessons on my web site.

A simple bound property

Now let's take a look at the class definition for a bean that has one simple bound property.  As before, we will analyze this bean using the introspection program discussed earlier.

Before getting into the details of the class definition, lets examine a list of exposed methods for this class, as identified by the introspection process.

The ordinary accessor methods

As before, I did not provide explicit BeanInfo information for this bean.  Therefore, the introspector based its output on low-level reflection and design patterns.

As with the previous bean, the following two exposed methods did not match the design patterns, and therefore, were not identified as properties.

fetchSize
putSize

The setter and getter methods

The introspection process based on low-level reflection and design patterns identified the following two methods as the accessor methods for a simple property named color.

setColor
getColor

Event registration methods

As discussed earlier in this lesson, a bound property has the ability to register interested listeners, and to notify them whenever the value of the property changes.  The simple property in this bean is a bound property.  Therefore, the bean has the ability to fire events of type PropertyChangeEvent.

As a result, the bean exposes the following two event registration methods, which were included in the list of exposed methods identified by the introspection process.

addPropertyChangeListener
removePropertyChangeListener

The Prop02BeanY bean class definition

Now that you have seen the list of exposed methods, lets examine the class definition for the bean class in fragments.  (A complete listing is provided near the end of the lesson.)

The class definition for the class named Prop02BeanY begins in Listing J10.

class Prop02BeanY implements Serializable{
  private String size = "Medium";
  private Color color = Color.RED;

  private PropertyChangeSupport changes =
                 new PropertyChangeSupport(this);

Listing J10

The class definition begins with the declaration of two rather uninteresting instance variables named size and color.  However, this is followed by a very interesting declaration of an instance variable of type PropertyChangeSupport named changes.

Registration and notification

A bound property must have the ability to register interested listeners and to notify them when the value of the property changes.  Obviously it is possible to start from scratch and to write your own code to accomplish those tasks.  However, the code required to accomplish those tasks is far from trivial.

Fortunately, Sun has provided a helper class named PropertyChangeSupport, to relieve us of the requirement to write that code

The PropertyChangeSupport class

Here is part of what Sun has to say about the PropertyChangeSupport class.

"This is a utility class that can be used by beans that support bound properties. You can use an instance of this class as a member field of your bean and delegate various work to it."

Basically, an object of this class can be used to create and maintain a registration list of interested listeners, and to notify those listeners of a change in a property value when instructed to do so.  This can save you a large amount of programming and testing effort.

Constructing the PropertyChangeSupport object

As of the Java SDK, v1.4.1, this class has only one constructor.  The constructor requires one parameter of type Object, which, according to Sun, is "The bean to be given as the source for any events."

As you can see in Listing J10, a new object of the PropertyChangeSupport class is instantiated, passing a reference to the bean object as a parameter to the constructor.  A reference to the PropertyChangeSupport object is saved in the instance variable named changes.

PropertyChangeSupport methods

The PropertyChangeSupport class has about a dozen methods, of which there are about six different overloaded method names.  We will be interested in the three methods discussed below.

addPropertyChangeListener(
              PropertyChangeListener listener)

This method adds a PropertyChangeListener to the registration list. The listener is registered for all properties.  (A more selective overloaded version of this method can be used to register a listener for a specific individual property.)

removePropertyChangeListener(
              PropertyChangeListener listener)

This method removes a PropertyChangeListener from the registration list. This removes a PropertyChangeListener that was registered for all properties.  Again, a different overloaded version is available to remove a listener that was registered for a specific individual property.

firePropertyChange(String propertyName,
                   Object oldValue,
                   Object newValue)

According to Sun, this method reports a bound property update to any registered listeners. In other words, this is the method that can be used to notify all registered listeners of a change in a property value.  No event is fired if old value and the new value are equal and non-null.

Method wrappers

The PropertyChangeSupport object's reference, shown in Listing J10, is held as a private instance variable of the bean class.  Therefore, the registration methods of the PropertyChangeSupport object are not directly accessible to listener objects that need to register.

The code in Listing J11 exposes a pair of public registration methods for the bean class, and wraps those methods around calls to the registration methods of the PropertyChangeSupport object.

(The registration methods exposed by the bean class have identical signatures to the registration methods of the PropertyChangeSupport object.)

  public void addPropertyChangeListener(
                   PropertyChangeListener lstnr){
    changes.addPropertyChangeListener(lstnr);
  }//end addPropertyChangeListener

  public void removePropertyChangeListener(
                   PropertyChangeListener lstnr){
    changes.removePropertyChangeListener(lstnr);
  }//end removePropertyChangeListener

Listing J11

When a listener object invokes one of the registration methods on an object of the bean class, the action required to handle that registration is delegated to the PropertyChangeSupport object.

The setter method for the color property

Listing J12 shows the setter method for the property named color.

(The syntax of this setter method is a design pattern for a simple property named color.)

  public void setColor(Color color){
    Color oldColor = this.color;
    this.color = color;
    changes.firePropertyChange(
                        "color",oldColor, color);
  }//end setColor

Listing J12

The code in Listing J12 begins by saving the current value of the color property in a local variable named oldColor.  Then it stores the new value of the property in the instance variable named color.

Firing a PropertyChangeEvent

Then the code in Listing J12 invokes the firePropertyChange method on the PropertyChangeSupport object.  This causes all listener objects registered on the PropertyChangeSupport object to be notified of the change in the property value.  The PropertyChangeSupport object assumes responsibility for notifying the registered listeners.  This relieves the bean programmer of having to write the code to accomplish that task.

Several overloaded versions of the firePropertyChange method are defined in the PropertyChangeSupport class.  Here is some of what Sun has to say about the version that I elected to use in this program.

"Report a bound property update to any registered listeners. No event is fired if old and new are equal and non-null."

The propertyChange method

All listeners registered on the PropertyChangeSupport object must implement the PropertyChangeListener interface and must define the propertyChange method declared in that interface. 

Each registered listener is notified of the change in property value by invoking its propertyChange method and passing a PropertyChangeEvent object's reference as a parameter.  As we will see later, methods of the PropertyChangeEvent object can be used to extract the name of the property, the old property value, and the new property value.

Remaining code in the bean class

The remaining code in the bean class named Prop02BeanY is shown in Listing J13.

  public Color getColor(){
    //This is a property based on design
    // patterns
    return color;
  }//end getColor

  public void putSize(String size){
    //This is not a property based on
    // design patterns
    this.size = size;
  }//end putSize()

  public String fetchSize(){
    //This would not be a property based on
    // design patterns
    return size;
  }//end fetchSize()

}//end class Prop02BeanY

Listing J13

This is essentially the same as the code that you saw before.  The first method in Listing J13, named getColor, is the design-pattern getter method for the property named color.

The remaining two methods do not meet the syntax requirements for design patterns.  Therefore, an analysis of the properties of the bean using introspection based on low-level reflection would identify only one property for this bean class.  That property would be named color.

Performing introspection

Introspection was performed on this bean by invoking the following statement in the main method of a test class named Prop02Test.

PropertyDisplay01.display("Prop02BeanY");

Exposed methods

The exposed methods identified by the introspection process were:

setColor
getColor
fetchSize
putSize
addPropertyChangeListener
removePropertyChangeListener

As discussed earlier, the first two methods in the above list are the setter and getter methods for the property named color.  The last two methods in the list are the registration methods for property-change listeners.  The two methods in the middle are simply public methods.

Properties

The introspection process produced the following information for properties:

Name: color
 Type:       class java.awt.Color
 Get method: public java.awt.Color Prop02BeanY.
             getColor()
 Set method: public void Prop02BeanY.
             setColor(java.awt.Color)
 Bound: true
 Constrained: false

This bean class did not provide explicit information for properties, events, and methods.  Hence, the introspection process identified one simple bound property named color.  That property was not constrained.  The getter and setter methods match the design-pattern syntax for a simple property.

Events

Here is something that we haven't seen previously in this lesson.  Because the property is bound, the bean has the ability to register and notify a collection of interested listeners of changes in the value of the property named color.  The output produced by the introspection process follows:

Event Name: propertyChange
 Add Method:   public void Prop02BeanY.
               addPropertyChangeListener(
               java.beans.PropertyChangeListener)
 Remove Method:public void Prop02BeanY.
               removePropertyChangeListener(
               java.beans.PropertyChangeListener)
 Event Type: propertyChange

The above information regarding events should be self-explanatory based on the earlier discussion.

Exercise the bean

In addition to analyzing the bean using introspection, the code in the main method of a test class named Prop02Test also exercises the behavior of the bean insofar as the bound property is concerned.  The following code is executed in the main method:

Prop02BeanY aProp02BeanY = new Prop02BeanY();
aProp02BeanY.addPropertyChangeListener(
                           new PropListener());
aProp02BeanY.setColor(Color.BLUE);
aProp02BeanY.setColor(Color.GREEN);

As you can see, the above code instantiates a new object of the bean class and registers a listener object on the bean object.  (The listener object is instantiated anonymously from the class named PropListener.)

Then the above code invokes the setter method to change the property value from its default value (RED) to BLUE.  Following that, it invokes the setter method again to change the property value from BLUE to GREEN.  As we will see shortly, each of these changes produces a PropertyChange event.

The PropListener class

Before examining the output produced by the above code, let's examine the class definition for the class named PropListener, from which the listener object was instantiated.

The entire class definition is shown in Listing J14.

class PropListener implements
                          PropertyChangeListener{
  public void propertyChange(
                        PropertyChangeEvent evt){
    System.out.println("PropertyChangeEvent");
    System.out.println(" Property Name: "
                        + evt.getPropertyName());
    System.out.println(" Old Value: "
                            + evt.getOldValue());
    System.out.println(" New Value: "
                            + evt.getNewValue());
  }//end propertyChange
}//end PropListener

Listing J14

If you are familiar with event-driven programming in Java, this class definition should look pretty much like what you would expect.

The PropertyChangeListener interface

To begin with, the class implements the PropertyChangeListener interface.  Thus, objects instantiated from the class can be treated as type PropertyChangeListener.  This makes them eligible for being registered on a PropertyChangeSupport object.

(The addPropertyChangeListener registration method of the PropertyChangeSupport class will only accept incoming parameters of type PropertyChangeListener.)

The propertyChange method

The PropertyChangeListener interface declares a single method named propertyChange, which receives an incoming parameter of type PropertyChangeEvent.

The PropertyChangeEvent class

As of SDK version 1.4.1, the PropertyChangeEvent class defines five methods that can be invoked on the incoming parameter to the propertyChange method.

The code in Listing J14 invokes three of those methods to get the name of the property, the old property value, and the new property value each time the method is invoked.

The output

The remaining output produced by executing statements in the main method to change the property values is shown below (note that I manually inserted a line break to separate the output produced from the first event from the output produced by the second event).

PropertyChangeEvent
 Property Name: color
 Old Value: java.awt.Color[r=255,g=0,b=0]
 New Value: java.awt.Color[r=0,g=0,b=255]

PropertyChangeEvent
 Property Name: color
 Old Value: java.awt.Color[r=0,g=0,b=255]
 New Value: java.awt.Color[r=0,g=255,b=0]

The RGB syntax

In case you are unfamiliar with the RGB color syntax, the letters and the associated values in the square brackets above indicate the color in terms of red, green, and blue components.  A value of zero means no contribution from that color.  A value of 255 means a maximum contribution from that color.

As you can see, the first event was accompanied by a change in the value of the color property from all red to all blue.  The second event was accompanied by a change from all blue to all green.  Of course, this matches what we knew to be the case based on the parameters passed to the setter method in the main method.

Now for a change of pace

Neither of the bean classes examined so far provides explicit information regarding properties, methods, and events.  Rather, introspection on each of those bean classes relies upon design patterns and low-level reflection.

The next bean that we examine, Prop02BeanZ, will provide explicit information regarding properties, but will rely upon design patterns and low-level reflection for methods and events.

The Prop02BeanZ bean class

The beginning of the class definition for this bean is shown in Listing J15.

class Prop02BeanZ implements Serializable{
  private String size = "Medium";
  private Color color = Color.RED;

  public void setColor(Color color){
    this.color = color;
  }//end setColor

  public Color getColor(){
    return color;
  }//end getColor

Listing J15

As you can see, the two methods defined in Listing J15 match the design-pattern syntax for the setter and getter methods of a simple property.  However, we will explicitly instruct the introspection process to ignore design patterns.  Therefore, unlike in the previous case, the introspection process will not identify color as a simple property of the bean.

The size property

The remainder of the bean class definition is shown in Listing J16.

  public void putSize(String size){
    this.size = size;
  }//end putSize()

  public String fetchSize(){
    return size;
  }//end fetchSize()

}//end class Prop02BeanZ

Listing J16

As you can see, the two accessor methods in Listing J16 do not match the design-pattern syntax for setter and getter properties of a bean.  However, we will explicitly instruct the introspection process to treat these two methods as the setter and getter methods of a simple bean.  Therefore, the introspection process will identify size as a simple property of the bean.

Explicit information for properties, events, and methods

To explain the process of providing explicit information for the properties, events, and methods of a bean, I'm going to repeat some of the information from Sun that I provided earlier, and show how it applies in this case.

"The Introspector class provides a standard way for tools to learn about the properties, events, and methods supported by a target Java Bean.

For each of those three kinds of information, the Introspector will separately analyze the bean's class and superclasses looking for either explicit or implicit information and use that information to build a BeanInfo object that comprehensively describes the target bean."

Explicit information for properties only

For this bean class, I will provide explicit information only for properties.  I will not provide explicit information for events or methods.  Continuing with the material from Sun,

"For each class "Foo", explicit information may be available if there exists a corresponding "FooBeanInfo" class that provides a non-null value when queried for the information."

In this case, I will provide a corresponding class named Prop02BeanZBeanInfo.  Various methods can be invoked on an object instantiated from that class to provide explicit information regarding properties.

"If a class provides explicit BeanInfo about itself ... we regard the explicit information as being definitive...  If we don't find explicit BeanInfo on a class, we use low-level reflection to study the methods of the class and apply standard design patterns to identify property accessors, event sources, or public methods."

Low-level reflection and design patterns not used

I interpret this to mean that low-level reflection is used only in those cases where the class doesn't provide explicit BeanInfo about itself.  In the case of this bean class, I will provide explicit BeanInfo regarding properties.  Thus, the introspection process will ignore the fact that the class contains methods that satisfy the design-pattern syntax for properties.  As a result, the accessor methods named setColor and getColor will not result in the introspection process identifying color as a property.

Implementing the BeanInfo interface

Here is part of what Sun has to say about implementing the BeanInfo interface.

"A bean implementor who wishes to provide explicit information about their bean may provide a BeanInfo class that implements this BeanInfo interface and provides explicit information about the methods, properties, events, etc, of their bean.

A bean implementor doesn't need to provide a complete set of explicit information. You can pick and choose which information you want to provide and the rest will be obtained by automatic analysis using low-level reflection of the bean classes' methods and applying standard design patterns."

In particular, you can provide lots of information by defining methods such as getEventSetDescriptors to return explicit information.  However, if you elect not to provide explicit information of a particular type (such as events), you can simply define the method so that it will return null.  This will cause the introspection process to obtain BeanInfo of that type on the basis of design patterns and low-level reflection.

The SimpleBeanInfo class

This is a convenience class that makes it easier to provide classes that implement the BeanInfo interface.  According to sun, the methods in this class default to

"...providing "noop" information, and can be selectively overridden to provide more explicit information on chosen topics. When the introspector sees the "noop" values, it will apply low level introspection and design patterns to automatically analyze the target bean."

Presumably, the reference to "noop" information in the above quotation means that the default versions of the methods return null.

The class named Prop02BeanZBeanInfo

Explicit information about this bean class was provided by defining a public class named Prop02BeanZBeanInfo that extends SimpleBeanInfo and overrides the method named getPropertyDescriptors(None of the other methods were overridden.)

The entire class definition is shown in Listing J17.

public class Prop02BeanZBeanInfo
                          extends SimpleBeanInfo{

  public PropertyDescriptor[]
                        getPropertyDescriptors(){
    try{
      PropertyDescriptor pd =
                          new PropertyDescriptor(
                               "size",
                               Prop02BeanZ.class,
                               "fetchSize",
                               "putSize");
      PropertyDescriptor[] pda = {pd};
      return pda;
    }catch(IntrospectionException e){
      return null;
    }//end catch
  }//end getPropertyDescriptors()

}//end class Prop02BeanZBeanInfo

Listing J17

The getPropertyDescriptors method

The getPropertyDescriptors method must return a reference to an array object of type PropertyDescriptor.  Each element in the array describes one property belonging to the bean being described.

In this case, a one-element array object was created and a reference to that object was returned.

The PropertyDescriptor class

According to Sun,

"A PropertyDescriptor describes one property that a Java Bean exports via a pair of accessor methods."

As of SDK version 1.4.1, the class defines three overloaded constructors.  I elected to use the version of the constructor that requires the following four parameters:

  • The programmatic name of the property as type String(For this case, the name is size.)
  • The Class object for the target bean as type Class.
  • The name of the method used for reading the property value as type String. May be null if the property is write-only.  (For this case, the method is named fetchSize.)
  • The name of the method used for writing the property value as type String. May be null if the property is read-only. (For this case, the method is named putSize.)

Using the BeanInfo object

When the introspection process instantiates an object of the class and invokes the getPropertyDescriptors method on it, the process will conclude that there is one simple property named size, with the setter and getter methods named putSize and fetchSize.

(Note that I did not define the methods named setColor and getColor as setter and getter methods for a property.  Therefore, in spite of the fact that these methods satisfy design patterns, the introspection process will not identify a property named color.)

Analyze the bean

Introspection was performed on this bean by invoking the following statement in the main method of the test class named Prop02Test.

PropertyDisplay01.display("Prop02BeanZ");

Methods

This produced the following list of exposed methods belonging to the bean:

fetchSize
getColor
putSize
setColor

You will recognize two of these methods as the setter and getter methods defined in Listing J17.

Properties

The introspection process produced the following information regarding properties:

Name: size
 Type:       class java.lang.String
 Get method: public java.lang.String Prop02BeanZ.
             fetchSize()
 Set method: public void Prop02BeanZ.putSize(
             java.lang.String)
 Bound: false
 Constrained: false

As you might expect, the information regarding the name of the property and the names of the setter and getter methods corresponds exactly to the information regarding properties defined in Listing J17.

Since the bean class definition didn't provide registration methods for either bound or constrained properties, the introspection process reported that the property named size is neither bound nor constrained.

Events

The introspection process reported that this bean is not the source of any events.

Hopefully by now you have a pretty good idea how properties work in Java.  That brings us to the third major part of this lesson, having to do with properties in C#.

Part 3, Comparison with C# Properties for the General User

This part of the lesson concentrates on properties in C# and a comparison of C# properties with Java properties.  A sample C# program is provided to illustrate C# properties.  A sample Java program is also provided to illustrate the similarity of properties between C# and Java.

This part of the lesson explains and compares Java and C# properties up to, but not including the use of reflection and introspection.  Reflection and introspection are covered in Part 4.

Methods and fields

You will see that C# properties act like methods to the creator of the class but look like public fields to clients of the class.  As a result, public fields and properties are indistinguishable to readers of the C# code who don't have ready access to documentation on the class.

As you saw in Part 2, Java properties look like methods to clients of the class, and it is impossible to confuse properties with public fields in Java.

Properties are used for essentially the same purpose in both languages.

Properties support data hiding

Both C# properties and Java properties provide the data hiding generally required by good object-oriented design.  However, properties are not a prerequisite for data hiding.  Data hiding can be easily accomplished in either C# or Java in the absence of properties.

Reflection and introspection

Perhaps the most important characteristic of properties has to do with reflection and introspection.  This is a process whereby one object can discover and manipulate the properties belonging to another object, instantiated from a class that may not have existed when the class of the first object was defined.  Reflection and introspection will be discussed in detail in Part 4.

Bound properties and constrained properties

Another important characteristic of properties has to do with bound properties and constrained properties.  This is a process by which an object can be automatically notified when the value of a bound or constrained property belonging to another object changes.  Bound properties were discussed in detail in Part 2.  A brief discussion of bound and constrained properties will also be provided in Part 4.

C# and Java properties are very similar

Properties are so similar between C# and Java that if you understand properties in either language, you should have no difficulty understanding properties in both languages.

Once again, what is a property?

In C#, unlike Java, a property is created by including a special block of code having a unique syntax in a class definition.  The syntax of this special block of code is unlike anything else in C#, and is unlike anything in Java.

As you learned in Part 2, a property is created in Java by including one or both of a pair of set and get methods meeting a certain (design pattern) format specification in a class definition.  Alternatively, a property is created in Java by providing a class that implements the BeanInfo interface.  The methods belonging to the BeanInfo object provide explicit information about the properties, events, and methods of a corresponding bean object.

By the time you finish studying this lesson in its entirety, you should know what properties are, and you should know how to create and use them in both C# and Java.

What others have to say about C# properties

Let's begin with what others have to say about properties in C#.  Here is what Microsoft has to say in the documentation for the PropertyInfo class:

"Properties are logically the same as fields. A property is a named aspect of an object's state whose value is typically accessible through get and set accessors. Properties may be read-only, in which case a set routine is not supported."

Programming C# by Jesse Liberty

Here's what Jesse Liberty has to say about properties in his O'Reilly book entitled Programming C#.

"... properties ... act like methods to the creator of the class but look like fields to clients of the class.

Properties allow clients to access class state as if they were accessing member fields directly, while actually implementing that access through a class method.

Properties provide a simple interface to the client, appearing to be a member variable.  They are implemented as methods, however, providing the data hiding required by good object-oriented design."

As you learned in Part 2, this description is true for C# properties, but is not true for properties in general.

C# In A Nutshell

Here is what the authors of C# In A Nutshell from O'Reilly have to say on the matter:

"Properties can be characterized as object-oriented fields.  Properties promote encapsulation by allowing a class or struct to control access to its data, and by hiding the internal representation of the data."

This is true, of course, but there seems to be something missing.  The same data-hiding benefits can be, and have been, achieved by C++ and Java programmers for years, using simple accessor methods.  Data hiding is made possible by the availability of access modifiers for class members.  Typically data hiding is achieved by providing public methods for accessing private instance variables.  While properties generally use this same scheme, properties are not a prerequisite for data hiding.

C# Primer, A Practical Approach

Here is what Stanley Lippman has to say in C# Primer, A Practical Approach from Addison-Wesley.

"A property typically is a public class member providing read and possibly write access to a private data member of the class.  We define a property by specifying an access level, type, and property name."

What does Dick Baldwin have to say on the matter?

In my opinion, the above descriptions have missed the mark in terms of what properties are really all about.  If the benefits of properties were limited to the above descriptions, it would not have been worth the effort for Microsoft to develop a new and unique syntax for properties.  It would not have been worth the effort for Sun to develop design patterns for properties.  It would not have been worth the effort for both Microsoft and Sun to develop the reflection and introspection capability for properties discussed in Part 2 and Part 4 of this lesson.

The real importance of properties is not based on making methods look like fields.  Also, the importance is not based on data hiding.  Rather, the real importance of properties has to do with reflection and introspection, which I discussed in Part 2 (for Java) and will discuss further in Part 4 (for both C# and Java).

(Another important aspect of Java properties has to do with bound properties and constrained properties.  I discussed this aspect in Part 2, and will discuss it further in Part 4.)

Fields or methods?

Liberty's statement that "properties, ... act like methods to the creator of the class but look like fields to clients of the class" is true for C#, but is not true in Java.  In my opinion, whether properties look like fields or look like methods is immaterial to the experienced programmer.  I can't imagine that an experienced OOP programmer would care one way or the other.

Java has provided the benefits of properties in its JavaBeans Component technology for several years, and Java properties do not look like fields to clients of the class.  Rather, they look like simple method invocations to clients of the class.  In the six or more years that I have been involved in Java, I have yet to hear anyone complain that Java properties don't look like fields.

However, programmers are entitled to their own preferences, and some programmers may prefer for properties to look like fields instead of methods.

Not a prerequisite for data hiding

As mentioned earlier, the availability of properties is not a prerequisite for the "data hiding required by good object-oriented design."  Data hiding has been easily accomplished for many years in C++ using private instance variables and public accessor methods with no concept of properties being involved.

My description of a property

As I indicated at the beginning of this lesson, it can sometimes be difficult to describe a property.  The following paragraphs contain another of my descriptions of a property.  This description is based on practical considerations.  For the most part, I will describe the things that must be true for a property to exist, and more importantly, to be really useful.

Name, type, and value

First, a property must have a name, a type, and a value, and possibly some other attributes as well, (such as being read only or read/write).

(I discussed indexed properties that have more than one value in Part 2.)

Same name and type, but different value

A property belongs to an object.  Every object instantiated from the same class will have the same set of properties.  The properties belonging to all the objects instantiated from the same class will have the same names and types, but won't necessarily have the same values from one object to the next.

Where is the value stored?

The value of a property is probably most commonly stored in an instance variable belonging to the object, but that is not a requirement.  The value could be stored in a database, or a disk file, or elsewhere, or could be computed on-the-fly when requested.

The state of the object

The value of a property generally contributes to the state of the object to which it belongs, and when the value of the property changes, the state of the object changes accordingly.

(When the state of an object changes due to a change in a bound property value, other interested objects can be automatically notified of that change of state.)

Standardization is required

To be really useful, the access methodology for a property must be predefined and standardized within a given programming language.  However, the access methodology need not be the same from one language to the next.  As mentioned earlier, C# accesses properties as fields, while Java accesses properties as methods.

The real importance of properties

It must be possible for executing code to learn everything there is to know about the properties belonging to a (previously unknown) object at runtime, and to be able to access those properties for reading and writing at runtime.  This must be possible even though the author of the executing code had no knowledge of the unknown object's class when the code was originally written.

(In C#, this is referred to as reflection.  In Java, it is referred to as introspection based on low-level reflection.)

Because .NET is language-neutral, this capability must exist across all languages supported by .NET, even if the language used to define the class and its properties is different from the language used to instantiate objects from the class.

A real-world example

Let me describe a real-world example of what I mean.  Ever since the introduction of Visual Basic several years ago, software developers have been interested in using standard software components to develop software.  Using software components to develop software is similar to using electronic components to manufacture electronic devices.

The great promise of using standard software components to develop software is that it can reduce the cost of software development in the same way that the use of standard electronic components has reduced the manufacturing cost of electronic devices such as computers.

A toolkit full of software components

In this style of programming, the programmer has access to a toolkit full of software components, and a builder tool that can be used to wire those software components together to produce a software application.

A sophisticated computer program

The builder tool itself is a very sophisticated and complex computer program.  In order for the builder tool to wire software components together, according to the wishes of the programmer, the builder tool must be able to extract the following information (as a minimum) from each software component that is installed in the toolkit:

  • Properties
  • Events
  • Methods

Components need to communicate

For example, when two components are wired together, one component may need to access, and possibly modify, property values belonging to the other component.  This is only possible if the builder tool can discover everything that it needs to know about the properties of every component in the toolkit.  (The builder tool is unable to read the documentation for a software component the way you and I do.)

Property editors

Even before getting to the point where one component needs to access the properties belonging to another component, the builder tool itself usually needs to discover and access the properties of every component being used to develop an application.

Most builder tools provide a property editor as a graphical user interface (GUI). The property editor makes it possible for the programmer to set initial property values on every software component so that the program being developed will start running with all of its component objects in the correct state.  For example, the programmer will normally want to set the location, height, width, text, and color of each button in a GUI so that it will be in the correct location with the correct size, text, and color when the program starts running.  (A screen shot of the C# property editor for the MSVS builder tool is shown in Figure 1.)

As distinguished from data hiding

In my opinion, the ability to accomplish this under software control is what separates properties from the ordinary data hiding that we have been practicing for many years.

Should properties look like fields or methods?

The ability to accomplish the discovery of properties at runtime has nothing to do with whether the property looks like a field or looks like a method.  It has been done successfully both ways.  Some programmers may prefer one approach to the other, but in reality, the difference is trivial.  To an experienced programmer, the difference in programming effort between the two approaches is negligible.

Self-documenting code

In my opinion, however, the approach where the property looks like a method is the more self-documenting of the two.  This approach produces code that is easier to read and understand by interested third parties who don't have ready access to the class documentation.

We have been striving for years to develop better self-documenting programming styles.  Making properties look like fields instead of methods is a step backwards in my opinion.  However, from a technical viewpoint, it can obviously be done either way.

What really matters is ...

What really matters is that the mechanism for accessing properties be predefined and standardized so that code can discover and manipulate the properties at runtime.

Common at the MSIL level

It is also a requirement that regardless of the programming syntax used by the different languages supported by .NET, they must all compile to the same result at the Microsoft Intermediate Language (MSIL) level.

(Interestingly, according to C# In A Nutshell, even though the property programming syntax at the source code level used by C# is radically different from that used by Java, the MSIL representation produced by C# looks like the Java source code representation.)

C# and Java approach standardization in different ways, and they both seem to work very well.  Even though the standardization approach is different between the two languages, the underlying concepts being implemented are very similar.

The C# approach to standardization

The C# approach uses a special source-code syntax to create a property.  You will see an example of this syntax in the sample program to be discussed later.  As far as I know, this special syntax must be used in all cases where you need to create a property in C#.

The Java approach to standardization

As you learned in Part 2, Java allows for two different approaches to standardization.  The simplest Java approach makes use of JavaBeans Design Patterns, which are nothing more than a set of well-defined naming conventions.  Using this approach, you can create a property in Java by causing the signatures of a pair of set and get methods to adhere to the design pattern format specifications.  This was illustrated in Part 2.  You will also see an example of this approach in the programs to be discussed later.

The other approach allowed by Java involves considerably more work.  With this approach, you must define a companion or helper class that implements a rather complex interface named BeanInfo.  An object instantiated from this helper class can be queried to discover the properties belonging to objects of the class that it is designed to represent.  This was also illustrated in Part 2.

It's time to look at some code

I'm going to show you a C# program named Props01.cs that illustrates properties from three different viewpoints:

  • The viewpoint of the developer of the class that defines properties.
  • The viewpoint of the user of the class to simply set and get property values.
  • The viewpoint of the sophisticated user of the class to discover and use properties at runtime.

The first two viewpoints are illustrated in this part of the lesson.  The third viewpoint contains some powerful material, and the discussion of the third viewpoint will be deferred until Part 4.

A comparable Java program

In addition, I'm going to show you a comparable Java program named Props01.java that accomplishes exactly the same thing.  I will compare the code between the two programs and discuss the similarities and the differences.  You will see that even at the complex level of the third viewpoint, the concepts involved are very similar to the Java program.  Even the syntax in the C# program is very similar to the Java program.

Explain in fragments

The complete C# program is shown in Listing C19, and the complete Java program is shown in Listing J36.  These two listings are near the end of the lesson in Part 6.

In order to help you to focus specifically on important sections of code, I will explain the behavior of these programs in fragments.

A target class

The C# program consists of two classes.  The first class that I will discuss is named TargetClass.  This class defines some properties (as well as some other members), which are accessed by code in the Main method of the other class named Props01.

Listing C1 shows the beginning of the code for the definition of the class named TargetClass.  Here we are seeing things from the viewpoint of the developer of the class named TargetClass.
 

public class TargetClass{

  public string text;

Listing C1

A public instance variable

The class named TargetClass declares a public instance variable of type string named text.  There's nothing exciting about a public instance variable.  I included it for demonstration purposes only.  I will show that there is no discernible difference between accessing a public instance variable and accessing a property in C#.

Implementing data hiding the "old" way

Listing C2 shows a pair of set and get methods that accomplish data hiding for this C# program.

(The signatures of these two methods also satisfy the JavaBeans Design Pattern for property accessor methods.  If this were a Java program, the existence of these two methods would indicate a simple property named color.)

  private int colorData = 0;

  public void setColor(int data){
    //Validating code goes here
    colorData = data;
  }//end setColor

  public int getColor(){
    return colorData;
  }//end getColor

Listing C2

Not a property in C#

However, this is not a Java program.  This is a C# program.  The signatures of these two methods do not indicate a property in C#.  A different syntax is required to create a property in C#.  The fact that this is not a property will be confirmed in Part 4 when we write code to discover the properties of an object of this class.

A C# property

C# uses the special syntax shown in boldface in Listing C3 to create a property named height.
 

  private int heightData;

  public int height{
    get{
      return heightData;
    }//end get

    set{
      //Validating code goes here
      heightData = value;
    }//end set
  }//end height property

Listing C3

(If the set code block is omitted, the property is a read-only property.)

Special syntax

There isn't much for me to explain about this syntax.  You will simply need to memorize it.

(Pay particular attention to the number and locations of the curly braces.  Also pay attention to the hidden parameter named value, which I will explain shortly.)

The property value

In this case, the property value is stored in the instance variable named heightData.  However, that is not a requirement.  The code could be written to store the property value in a database, in a disk file, or in any other location accessible by the code in the object.

The name and type of the property

The name and type of the property is established by the line of code that reads

public int height{

In this case, the property is named height and it is type int.

The get method

Although they don't look like methods, this code effectively contains two methods named get and set.

Whenever the using code references the property name in a fetching sense, the code in the get block is executed.  This block must contain a return statement to return a value of the specified type.  The get block could also contain any other code that you might want to have executed in conjunction with such a fetch operation.  An example of a fetch operation is highlighted in boldface below, where obj is a reference to an object instantiated from this class.

Console.WriteLine("height: " + obj.height);

The set method and the value parameter

Whenever the using code references the property name in a storage sense (as the left operand of an assignment operator, for example), the code in the set block is executed.

The value to be stored (the right operand of the assignment operator, for example) is passed to the set code as a hidden parameter named value.  The name of this hidden parameter never changes.  The code in the set block must save the value of the hidden parameter named value in an appropriate location if it is to be successfully returned later.

Additional code

You can place any code that you might want to have executed in conjunction with such a set operation in the set block.  Data validation code is particularly appropriate here.

An example of such a storage operation is shown below where obj is a reference to an object instantiated from this class.

obj.height = 20;

In this case, the hidden parameter named value will contain an int value of 20.

Another property named width

Listing C4 shows code that defines another property of type int named width.  This code uses the same syntax as that used for the property named height.
 

  private int widthData;

  public int width{
    get{
      return widthData;
    }//end get
    set{
      //Validating code goes here
      widthData = value;
    }//end set
  }//end width property

Listing C4

This is the end of the class definition for the class named TargetClass.

An object of type TargetClass

An object instantiated from the class named TargetClass contains:

  • One public instance variable of type string named text.  Data hiding is not accomplished with respect to this instance variable.
  • One private instance variable named colorData protected by accessor methods named setColor and getColor.  Data hiding is accomplished with respect to this instance variable without the use of properties.  (The use of properties is not necessary to accomplish data hiding.)
  • Two properties of type int named height and width.  Data hiding is accomplished here also.

Switching viewpoints

Now its time to switch to the viewpoint of the user of the class named TargetClass.  This user already knows the names and the types of the properties and has no interest in discovering properties at runtime.

The Main method

Listing C5 shows the beginning of the class named Props01 and the beginning of the Main method in that class.

This code begins by instantiating and saving a reference to a new object of the class named TargetClass discussed above.  The reference is saved in the reference variable named obj.  The reference to this object will be used to access the public instance variable, the hidden data, and the properties of this object.

(The reference will also be used in Part 4, along with reflection, to discover the properties belonging to the object at runtime.)

public class Props01{
  static TargetClass obj;
  
  public static void Main(){
    obj = new TargetClass();

Listing C5

Access the public instance variable

The code in Listing C6 uses the object's reference to directly store the string "Quit" in the public instance variable named text.  Following this, the code uses the object's reference to directly get and display the value in the public instance variable named text.
 

    obj.text = "Quit";
    Console.WriteLine(
                  "text: " + obj.text);

Listing C6

Will compare with property access methodology

There is nothing particularly interesting about the code in Listing C6.  This code is presented here for later comparison with code that accesses the properties.  The code in Listing C6 produces the following output on the screen.

text: Quit

Accessing the hidden data

The code in Listing C7 uses the two accessor methods to first set a value in the private instance variable, and then to get and display that value.  Note that data hiding is fully supported here without the use of properties.
 

    obj.setColor(15);

    Console.WriteLine(
           "color: " + obj.getColor());

Listing C7

Listing C7 is a straightforward application of simple data hiding using accessor methods.  No special support of any kind is required to use this technique.  The code in Listing C7 produces the following output on the screen:

color: 15

Accessing a property

Now we are going to access a C# property in a simple non-discovery way.  This is shown in Listing C8.
 

    obj.height = 20;

Listing C8

The code in Listing C8 sets the value 20 in the property named height.

Appears to access a public field

Note that the syntax of this statement looks exactly like the syntax of the first statement in Listing C6 (except that the data types and variable names are different).  The code in Listing C6 assigns a value directly to a public instance variable.  Without having access to the documentation for the class named TargetClass, it would not be possible for the reader of this code to know whether height is the name of a property or is the name of a public instance variable.

Not self-documenting code

This is what I meant earlier when I said that this approach to property access is not self-documenting.  For the experienced programmer, the first statement in Listing C7, which invokes a method, is no more challenging than the statement in Listing C8, which appears to access a public field.

As I mentioned earlier, I can't imagine why an experienced programmer would prefer for properties to look like public fields instead of methods, given the significant loss in self-documentation that results from that design.  Obviously, however, experienced programmers at Microsoft have this preference.  Other than the self-documentation aspect, it seems to me that this difference is a trivial syntax issue.

Display the property value.

Listing C9 gets and displays the value stored in the property named height.
 

    Console.WriteLine(
              "height: " + obj.height);

Listing C9

Again, this looks like the code is accessing a public field named height.  Without having access to the documentation for the class named TargetClass, the reader of the code would have no way of knowing any different.

The code in Listing C9 produces the following output on the computer screen:

height: 20

Accessing another property

Listing C10 first sets, and then gets and displays the value of the property named width.
 

    obj.width = 50;
    Console.WriteLine(
                "width: " + obj.width);

Listing C10

There's nothing new here.  The code in Listing C10 produces the following output on the computer screen:

width: 50

A comparable Java program

Now I'm going to show you a Java program named Props01.java that accomplishes exactly the same thing as the C# program discussed above.  As with the C# program, the Java program will illustrate properties from three significantly different viewpoints:

  • The viewpoint of the developer of the class that defines properties.
  • The viewpoint of the user of the class to simply set and get property values.
  • The viewpoint of the sophisticated user of the class to discover and use properties at runtime.

As was the case with the C# program, the third viewpoint contains some powerful material, and will be discussed in detail in Part 4.

The most significant aspect of the third viewpoint will be the remarkable similarity between the C# code and the Java code, even at this complex level.

Explain in fragments

The complete Java program is shown in Listing J36 near the end of the lesson.  As usual, in order to help you to focus on important sections of code, I will explain the behavior of this program in fragments.

A target class

As was the case with the C# program, the Java program consists of two classes.  The first class that I will discuss is named TargetClass.  This class defines some properties, which are accessed by code in the main method of the other class named Props01.

Listing J18 shows the beginning of the definition of a Java class that mimics the behavior of the C# class shown in Listings C1 through C4.  Here we are seeing things from the viewpoint of the developer of the class named TargetClass.
 

class TargetClass 
               implements Serializable{

  public String text;

Listing J18

Serializable interface

This Java class implements the Serializable interface.  Without getting into the details, let me just say that this is required to cause the class to satisfy the JavaBeans Component specification, making it suitable for introspection.  (Introspection was discussed in Part 2, and will be explained and illustrated again in Part 4.)

Class not declared public

Note that unlike the C# class in Listing C1, I didn't declare the Java class public.  Rather, by not declaring an access level, I caused this class to be package private by default.  This was done strictly for convenience.  In Java, every public class must be defined in a separate source code file.  I made this class package private to avoid the requirement to create and maintain separate source code files for each of the class definitions in the program. (Java access of package private is similar to internal access in C#.)

A public instance variable

As was the case with the C# class in Listing C1, this class definition begins with the declaration of a public instance variable.  This instance variable will be used later to illustrate that access to a property in Java has no resemblance to access to a public instance variable.  Therefore, it isn't possible to confuse the two.

A property named color

The Java code in Listing J19 is identical to the C# code in Listing C2.
 

  private int colorData = 0;

  public void setColor(int data){
    //Validating code goes here
    colorData = data;
  }//end setColor

  public int getColor(){
    return colorData;
  }//end getColor

Listing J19

As is the case in C#, the code in Listing J19 accomplishes data hiding by providing public accessor methods for a private instance variable.  Perhaps more important, by adhering to JavaBeans Design Patterns, the code in Listing J19 creates a Java property named color.

This is all that is required to create a property in Java.  No special and unusual source code syntax is required.  All that is required is to provide accessor methods that satisfy the JavaBeans Design Patterns for property accessor methods, and these two methods meet that requirement.

The name and type of the property

According to the JavaBeans Design Pattern for property accessor methods, the name of the Java property is the word following get or set in the name of the accessor methods, with the case of the first character flipped.  The type of the property is the same as the type of the single argument of the set method, which must match the return type of the get method.

The property value

For the code in Listing J19, the property value is stored in the instance variable named colorData.  However, as with C#, this is not a requirement.  The code could be written to store the property value in a database, in a disk file, or in any other location accessible by the code in the object.

Properties named height and width

The code in Listing J20 creates two more Java properties named height and width.
 

  private int heightData;

  public void setHeight(int data){
   //Validating code goes here
   heightData = data;
  }//end setHeight

  public int getHeight(){
    return heightData;
  }//end getHeight


  private int widthData;

  public void setWidth(int data){
   //Validating code goes here
   widthData = data;
  }//end setwidth

  public int getWidth(){
    return widthData;
  }//end getwidth
  
Listing J20

The code in Listing J20 is different from the C# code in Listings C3 and C4 used to create C# properties named height and width.  This is because Listings C3 and C4 use the special syntax required to create properties in C#.  In the end, however, the properties behave essentially the same way in both languages.

Listing J20 is also the end of the Java class definition for the class named TargetClass.

An object of type TargetClass

A Java object instantiated from the class named TargetClass contains:

  • One public instance variable of type string named text.  Data hiding is not accomplished with respect to this instance variable.
  • Three properties of type int named color, height, and width.  Because the property value is stored in a private instance variable, this code also accomplishes data hiding.

Switching viewpoints

Now its time to switch to the viewpoint of the user of the class named TargetClass.  This user knows the names and types of the properties and has no interest in discovering properties at runtime. (Discovery of properties will be explained in Part 4.)

The main method

Listing J21 shows the beginning of the class named Props01 and the beginning of the main method for that class.  Except for the difference in the signature of the main method, the Java code in Listing J21 is identical to the C# code in Listing C5.
 

public class Props01{
  static TargetClass obj;
  
  public static void main(String[] args){
    obj = new TargetClass();

Listing J21

The code in Listing J21 begins by instantiating and saving a reference to a new object of the class named TargetClass discussed above.  The reference is saved in the reference variable named obj.  The reference to this object will be used to access the public instance variable and the properties of this object.

(The reference will also be used in Part 4, along with introspection, to discover the properties belonging to the object at runtime.)

Access the public instance variable

As was the case in the C# program, the code in Listing J22 uses the object's reference to directly store the string "Quit" in the public instance variable named text.  Following this, the code uses the object's reference to directly get and display the value in the public instance variable named text.

(Except for the different syntax required for console output, this code is identical to the C# code in Listing C6.)

    obj.text = "Quit";
    System.out.println(
                  "text: " + obj.text);

Listing J22

Will compare with property access methodology

There is nothing particularly interesting about the code in Listing J22.  This code is presented here for later comparison with code that accesses the properties.  The code in Listing J22 produces the following output on the screen.

text: Quit

Accessing the property named color

The code in Listing J23 uses the two property accessor methods to first set a value in the property named color, and then to get and display that value.  Note that data hiding is fully supported here.
 

    obj.setColor(15);

    System.out.println(
           "color: " + obj.getColor());

Listing J23

Again, except for the different syntax used for console output, the Java code in Listing J23 is identical to the C# code in Listing C7. The difference, however, is that this Java code involves setting and getting a property value, while that is not the case with the C# code.

The code in Listing J23 produces the following output on the screen:

color: 15

Syntax comparison

It is also important to note that this property access syntax bears no resemblance to the code in Listing J22, which accesses a public instance variable.  There is no chance of confusing public instance variables with properties in Java.  Thus, the syntax used for accessing properties in Java is more self-documenting than the syntax used for accessing properties in C#.

Accessing the properties named height and width

The code in Listing J24 uses the property access methods to first set, and then get and display the values in the properties named height and width.
 

    obj.setHeight(20);
    System.out.println("height: " + 
                      obj.getHeight());

    obj.setWidth(50);
    System.out.println("width: " + 
                       obj.getWidth());

Listing J24

Compare the bottom half of the code in Listing J24 (width property access) with the C# code in Listing C10 to see a direct comparison of the difference in property access mechanisms in C# and Java.  There's nothing new here, so I won't discuss it further.

The code in Listing J24 produces the following output on the computer screen:

height: 20
width: 50

Review of Part 3

In Part 3, you have learned:

  • C# properties act like methods to the creator of the class but look like public fields to clients of the class.  As a result, public fields and properties are indistinguishable to readers of the C# code who don't have ready access to documentation on the class.
  • Java properties look like methods to clients of the class, and it is impossible to confuse properties with public fields in Java.
  • Properties are used for essentially the same purpose in both C# and Java.
  • Both C# properties and Java properties provide the data hiding generally required by good object-oriented design.
  • Properties are not a prerequisite for data hiding.  Data hiding can be easily accomplished in C#, Java, or C++ in the absence of properties.
  • The most important aspect of properties in both C# and Java is their involvement in the processes of reflection and introspection at runtime.
  • Properties are so similar between C# and Java that if you understand properties in either language, you should have no difficulty understanding properties in both languages.  While they differ in syntax between the two languages, they are very similar in concept.

Except for reflection and introspection, Part 3 also provided sample programs to illustrate the items in the above list.

Part 4, Comparison with C# Properties for the Sophisticated User

Reflection and introspection

As stated above, the most important aspect of properties has to do with reflection and introspection.  This is a process whereby one object can discover and manipulate the properties belonging to another unknown object even though the author of the executing program had no knowledge of the unknown object's class when the executing program was originally written.  Reflection and introspection are discussed in detail in this part of the lesson.

(Although introspection for Java properties was discussed in Part 2, the discussion of reflection and introspection is somewhat deeper in this section than was the case in Part 2.)

Bound properties and constrained properties

Another important characteristic of properties has to do with bound properties and constrained properties.  This is a process by which an object can be automatically notified when the value of a bound or constrained property belonging to another object changes.  A detailed discussion was provided in Part 2.  An additional brief discussion of bound and constrained properties will be provided in this part of the lesson.

The most important aspect of properties

It must be possible for executing code to learn everything there is to know about the properties belonging to an object at runtime, and to be able to access those properties for reading and writing at runtime.

(In C#, this is referred to as reflection.  In Java, it is referred to as introspection, possibly based on low-level reflection.)

For .NET, this capability must exist across several languages, even if the language used to define the class and its properties is different from the language used to instantiate objects from the class.

Let's see some code

In this part of the lesson, I will continue my discussion of a C# program that illustrates properties from three different viewpoints:

  • The viewpoint of the developer of the class that defines properties.
  • The viewpoint of the user of the class to simply set and get property values.
  • The viewpoint of the sophisticated user of the class to discover and use properties at runtime.

The first two viewpoints were covered in Part 3.  The third viewpoint is the primary topic of this part of the lesson.  While you might find it complex, I hope that you will stick with it until you understand the concepts involved.

A comparable Java program

In addition, I will continue my discussion of a comparable Java program that accomplishes exactly the same thing as the C# program.  I will compare the code between the two programs and discuss the similarities and the differences.  You will see that even at the complex level of the third viewpoint, the C# and Java programs are very similar both in terms of concepts and syntax.

Explain in fragments

The complete C# program is shown in Listing C19, and the complete Java program is shown in Listing J36.  These two listings are near the end of the lesson in Part 6.

In order to help you to focus on important sections of code, I will explain the behavior of these programs in fragments.

A target class

The C# program consists of two classes.  The first class, which I discussed in detail in Part 3, is named TargetClass.  This class defines some properties (as well as some other members), which are accessed by code in the Main method of the other class named Props01.

Listing C11 shows the entire definition of the class named TargetClass.  Of particular interest in this part of the lesson is the boldface material, which defines two properties, named height and width.
 

public class TargetClass{
  //A public instance variable
  public string text;
  
  //This would be a property named
  // color in Java, but not in C#
  private int colorData = 0;
  public void setColor(int data){
    //Validating code goes here
    colorData = data;
  }//end setColor
  public int getColor(){
    return colorData;
  }//end getColor
  
  //This is a property named height
  private int heightData;
  public int height{
    get{
      return heightData;
    }//end get
    set{
      //Validating code goes here
      heightData = value;
    }//end set
  }//end height property

  //This is a property named width
  private int widthData;
  public int width{
    get{
      return widthData;
    }//end get
    set{
      //Validating code goes here
      widthData = value;
    }//end set
  }//end width property
  
}//end TargetClass

Listing C11

An object of type TargetClass

An object instantiated from the class named TargetClass contains:

  • One public instance variable of type string named text.
  • One private instance variable named colorData protected by accessor methods named setColor and getColor.
  • Two properties of type int named height and width.

The Main method

Listing C12 shows the beginning of the class named Props01 and the beginning of the Main method in that class.

This code, (which you have seen before) begins by instantiating and saving a reference to a new object of the class named TargetClass discussed above.  The reference is saved in the reference variable named obj.

The reference to this object was used in Part 3 to access the public instance variable, the hidden data, and the properties of this object.  The reference will be used in this part of the lesson to discover the properties belonging to the object at runtime.
 

public class Props01{
  static TargetClass obj;
  
  public static void Main(){
    obj = new TargetClass();

Listing C12

The user viewpoint

In this part of the lesson, we will look at C# properties from the viewpoint of the sophisticated user who needs to first discover and then use properties at runtime.

Three steps

Basically, this process will consist of three steps:

  • Get a reference to an object of the type Type, which represents the type of an object instantiated from the class named TargetClass(This is similar to getting an object of the type Class in Java.)
  • Use the Type object to get an array of objects of type PropertyInfo.  This array will contain one object for each property belonging to the target object of type TargetClass. (From the previous discussion, you already know that the target object contains two properties, one named height and the other named width.  Therefore, the array will have two elements.)
  • Iterate on the array object, using each object in the array to determine the name, type, and current value of the corresponding property belonging to the TargetClass object.

C# and the Object class

Listing C13 shows the first step in this process.  (Note that I skipped the code in the Main method that was covered in Part 3.)
 

    //Some code skipped in Main method

    Type theType = obj.GetType();

Listing C13

All classes in C# (and Java as well) derive either directly or indirectly from the class named Object.  The class named Object defines several methods that are inherited into all other classes.  Some of those methods, (such as Equals and ToString), are meant to be overridden in new classes.  In C#, those methods are declared to be virtual

The GetType method is not virtual

Some of the methods of the Object class, (such as GetType), are meant to be used as is, without overriding them.  Those methods are not declared to be virtual, so they cannot be overridden.

(Note that the GetType method in C# has the same purpose as the getClass method in Java.  Note also that all methods in Java are virtual by default unless they are marked as final.  All non-final methods, including getClass, can be overridden in Java.)

A Type object

When the GetType method is invoked on an existing object, it returns a reference to an object of the type Type.  According to Microsoft,

"The Type object exposes the metadata associated with the class of the current Object."

Metadata vs. runtime type information

In Java jargon, it would be said that the Type object exposes the runtime type information (RTTI) of the object on which the method is invoked (except that in Java the method is named getClass, and the object that is returned by the method is type Class instead of type Type).

(Actually, the .NET documentation for the typeof operator contains the following statement, "To obtain the run-time type of an expression, you can use the .NET Framework method GetType."  It appears that Microsoft uses the terms metadata and run-time type interchangeably.)

Alternate ways to get a Type object

There are several other ways to get a Type object as well, including the typeof operator and the static GetType method of the Type class (the GetType method invoked in Listing C13 is an instance method, defined in the Object class, and inherited into the TargetClass class).

The static GetType method

The static GetType method of the Type class returns a Type object representing a type specified by the name of a class as a string.  (The corresponding method in Java is the method named forName, which is a static method of the class named Class.)

The typeof operator

The typeof operator returns a Type object representing a type specified by the name of its operand.

(This is similar to the instanceof operator in Java, which is used to determine the type of an object based on its reference.  However, the instanceof operator is used with a different syntax and returns type boolean.)

What is a Type object?

Here is what Microsoft has to say about a Type object:

"This class is the primary way to access metadata, and it acts as a gateway to the Reflection API. Use the members of Type to get information about a type declaration, such as the constructors, methods, fields, properties, and events of a class ..."

Step 1: Getting the Type object

The code in Listing C13 invokes the GetType method on the object instantiated earlier from the class named TargetClass.  The GetType method returns a reference to an object of the type Type.  This object represents the class from which the object was instantiated, TargetClass in this case.  The reference to the Type object is saved in the reference variable named theType.

Step 2:  Getting property information

In this step, we will get information about the properties defined in the class named TargetClass, which is represented by the object of the type Type.

The Type class provides several methods that can be invoked on an object of the Type class, to get information about the type represented by the Type object.  A few of those methods are shown in the following list to illustrate some of the information that is available.  (In general, the names of the methods indicate the type of information that they are designed to provide.)

  • GetProperties
  • GetEvents
  • GetFields
  • GetInterfaces
  • GetMembers
  • GetMethods
  • GetConstructors

Invoking the GetProperties method

The code in Listing C14 invokes the GetProperties method on the Type object.
 

    PropertyInfo[] propInfo = 
               theType.GetProperties();

Listing C14

According to Microsoft, the GetProperties method "Returns all the public properties of the current Type."  The information is returned as an array of objects where each object in the array is of type PropertyInfo.

One PropertyInfo object for each property

Each object of type PropertyInfo in the array represents one of the properties belonging to the target object under investigation.  In this case, the target object is the object instantiated from the class named TargetClass

Number of properties equals number of elements

The number of elements in the array indicates the number of properties belonging to the target object.

Using the Length property of the array

Every array object in C# has a property named Length, whose value is "The total number of elements in all the dimensions of the Array."  Since this is a one-dimensional array, the value of Length is the same as the number of properties belonging to the target object.  The code in Listing C15 gets and displays the value of the Length property.
 

    Console.WriteLine(
        "Number of Public Properties: "
                    + propInfo.Length);

Listing C15

The number of properties

The code in Listing C15 produces the following output on the screen, which matches what we already know about the number of properties defined in the class named TargetClass.

Number of Public Properties: 2

Getting information about each property

Each of the PropertyInfo objects contained in the array can be queried to obtain information about the specific property that it represents.  The code in Listing C16 displays some explanatory text on the screen and then calls the method named DisplayPropertyInfo, passing a reference to the array of PropertyInfo objects to the method.
 

    Console.WriteLine(
        "Descriptions of Properties:");

    DisplayPropertyInfo(propInfo);

Listing C16

The method named DisplayPropertyInfo is designed to get and display information from each element in the array.  As a result, this method gets and displays information about each property in the class named TargetClass.

PropertyInfo objects

An object of the PropertyInfo type contains properties and methods that can be accessed to obtain information about the property that the object represents.  For example, the name and the type of the property represented by the object are stored in the object's properties named Name and PropertyType(Here we have the properties of one object representing attributes of a property of another object.)

The DisplayPropertyInfo method

The method named DisplayPropertyInfo receives a reference to the array of PropertyInfo objects as an incoming parameter.  The entire method consists of a single for loop, and is shown in Listing C17.
 

  public static void 
            DisplayPropertyInfo(
              PropertyInfo[] propInfo){

    for(int i=0;i<propInfo.Length;i++){
      PropertyInfo myPropInfo = 
                           propInfo[i];

      Console.WriteLine("Name: " + 
                      myPropInfo.Name);

      Console.WriteLine("Type: " + 
              myPropInfo.PropertyType);

     //------------------------------//

      //Get and display the value
      MethodInfo readMethod = 
             myPropInfo.GetGetMethod();
      Console.WriteLine("Value: " +
          readMethod.Invoke(obj,null));

    }//end for loop
  }//end DisplayPropertyInfo

Listing C17

Step 3:  Iterate on the array

This method uses a for loop to iterate on the array, extracting name, type, and value information from each object stored in the array.

Getting the name and type information is straightforward.  Getting the value information is a little more complicated. (Listing C17 contains a comment separator to visually separate the code that gets the name and type from the code that gets the value.)

Different issues

From a conceptual viewpoint, there is a significant difference between name and type on one hand, and value on the other.  The name and type of a property is the same for every object instantiated from a given class.  However, the current value of the property will vary among different objects instantiated from the same class.  Therefore, value is specific to each object instantiated from the class, while name and type are the same for all objects instantiated from the class.

Getting the name and type

The code to get and display the name and the type of the property represented by the PropertyInfo object is shown above the visual separator in Listing C17.  As mentioned earlier, this code is straightforward.  All that is required is to access the properties named Name and PropertyType belonging to the PropertyInfo object.  The values of these properties are the name and the type of the property represented by the PropertyInfo object.

Getting the property value for a specific object

The code required to get and display the value of a particular property for a specific object is shown below the visual separator in Listing C17.  This code consists of the following steps (as you will see later, despite its complexity, this is essentially the same process used to accomplish the same task in Java):

  • Invoke the GetGetMethod on the PropertyInfo object to get a reference to an object of type MethodInfo that represents the get method for the particular property represented by the PropertyInfo object.
  • Invoke the Invoke method on the MethodInfo object, passing a reference to the target object as a parameter.  This causes the get method to be invoked on the target object, returning the current value of the property for that object.

The MethodInfo class

An object of the MethodInfo class represents a specific method.  It contains numerous properties and methods that allow you to manipulate the method represented by the object.  For example, there is a method named GetParameters that can be invoked to get a list that identifies the number and types of parameters required by the method.

The Invoke method of the MethodInfo class

In this case, we are interested in the Invoke method of the MethodInfo class.  This method makes it possible for us to invoke the get method represented by the MethodInfo object on a specific object of the TargetClass class.

The Invoke method requires two parameters.  The first parameter is a reference to the object on which we want the get method to be invoked.  In this case, this is the object of the class named TargetClass, which has been the target of the investigation from the beginning.

The second parameter is a reference to an array object, where each element in the array contains a reference to an object that is to be passed as a parameter to the method being invoked.  In this case, the get method requires no parameters, so the code in Listing C17 passes null as the second parameter to the Invoke method.

Invoking the get method on the target object

The result of invoking the Invoke method on the reference to the object of type MethodInfo, while passing the target object as a parameter, is to cause the get method to be invoked on the target object.  The int value returned by the get method is picked up and returned by the Invoke method.  This value is passed to the WriteLine method in Listing C17, which causes it to be displayed on the computer screen.

The screen output

The screen output for the first iteration of the for loop in Listing C17 is shown below:

Name: height
Type: System.Int32
Value: 20

This output indicates that the name of the first property found by our discovery process was height.  This agrees with what we already know to be true.

The property type information

The property type reported by this process looks a little strange.  What in the world is the type System.Int32?

According to the Microsoft documentation, the type System.Int32 represents a 32-bit signed integer.  However, when we defined the class named TargetClass, we defined the type of the height property as type int, not type System.Int32.  Here is what Microsoft has to say about the relationship between type int and type System.Int32, (with my parenthetical expression inserted):

"The corresponding .NET Framework data type (for type int) is System.Int32. The properties and methods of the int data type are the same as the System.Int32 properties and methods."

Here is what Stanley Lippman has to say in C# Primer, A Practical Approach:

"The keywords for the C# predefined types are aliases for types defined within the System namespace.  For example, int is represented under .NET by the System.Int32 type, and float by the System.single type."

Thus, when we specified type int, we were actually using an alias to specify type System.Int32.

The property value

Finally, the current value represented by the height property on the target object is reported to be 20, which we can verify by examining Listing C8, which shows the value of the height property being set to 20.

The second property named width

The screen output for the second and last iteration of the for loop in Listing C17 is shown below:

Name: width
Type: System.Int32
Value: 50

Because we defined the TargetClass, and wrote the program that defined the properties and set the values of the two properties, we know these to be the correct name, type, and current value.  However, prior knowledge of the answers is not a prerequisite for the correct operation of this discovery process.  It would work correctly if someone else had written the class named TargetClass and had provided us with only the compiled version of the class.

An alternative approach for getting the property value

The code in Listing C18 uses the GetValue method of the PropertyInfo class to get and display the current property value.  This single statement is, in effect, a shorthand replacement for the last two statements inside the for loop in Listing C17.
 

/***********
      Console.WriteLine("Value: " + 
        myPropInfo.GetValue(obj,null));
***********/

Listing C18

The importance of properties

So now you know the true importance of properties in C#.  In my opinion, the importance of properties has nothing to do with making properties look like fields instead of methods.  Similarly, it has nothing to do with information hiding, although those are two interesting by-products of properties.  Rather, the importance of properties is that properties support one aspect of the reflection process.

The reflection process makes it possible for one object to discover and manipulate the properties, events, methods, constructors, fields, etc., belonging to another unknown object, at runtime, with no prior knowledge of the class from which the other object was instantiated.  This, in turn, facilitates the development of very sophisticated software that makes heavy use of information about objects gained at runtime.

A comparable Java program

Now I will continue my discussion of a Java program that accomplishes exactly the same thing as the C# program discussed above.  As with the C# program, the Java program illustrates properties from three significantly different viewpoints:

  • The viewpoint of the developer of the class that defines properties.
  • The viewpoint of the user of the class to simply set and get property values.
  • The viewpoint of the sophisticated user of the class to discover and use properties at runtime.

Also, as was the case with the C# program, the first two viewpoints were covered in Part 3.

The third viewpoint is the primary topic of this part of the lesson.  I hope that you will stick with it until you understand the concepts involved.

The most significant aspect of the third viewpoint will be the remarkable similarity between the C# code and the Java code, even at this complex level.

Explain in fragments

The complete Java program is shown in Listing J36 in Part 6.  As usual, in order to help you to focus on important sections of code, I will explain the behavior of this program in fragments.

A target class

As was the case with the C# program, the Java program consists of two classes.  The first class, which was explained in detail in Part 3, is named TargetClass.  This Java class mimics the behavior of the C# class shown in Listing C11.

This class defines some properties, which are accessed by code in the main method of the other class named Props01.  Listing J25 shows the definition of the class named TargetClass in its entirety.  The boldface code in Listing J25 shows the definition of three properties named color, height, and width.
 

class TargetClass 
               implements Serializable{
  //A public instance variable
  public String text;
  
  //This is a property named color
  private int colorData = 0;
  public void setColor(int data){
    //Validating code goes here
    colorData = data;
  }//end setColor
  public int getColor(){
    return colorData;
  }//end getColor
  
  //This is a property named height
  private int heightData;
  public void setHeight(int data){
   //Validating code goes here
   heightData = data;
  }//end setHeight
  public int getHeight(){
    return heightData;
  }//end getHeight
  
  //This is a property named width
  private int widthData;
  public void setWidth(int data){
   //Validating code goes here
   widthData = data;
  }//end setwidth
  public int getWidth(){
    return widthData;
  }//end getwidth
  
}//end TargetClass

Listing J25

An object of type TargetClass

A Java object instantiated from the class named TargetClass contains:

  • One public instance variable of type string named text.
  • Three properties of type int named color, height, and width.

The main method

Listing J26 shows the beginning of the class named Props01 and the beginning of the main method for that class.  Except for the difference in the signature of the main method, the Java code in Listing J26 is identical to the C# code in Listing C12.
 

public class Props01{
  static TargetClass obj;
  
  public static void main(String[] args){
    obj = new TargetClass();

Listing J26

The code in Listing J26, which you have seen before, begins by instantiating and saving a reference to a new object of the class named TargetClass discussed above.  The reference is saved in the reference variable named obj.  The reference was used to access the public instance variable and the properties of this object in Part 3.   In this part of the lesson, the reference will be used in the introspection process to discover the properties belonging to the object at runtime.

The user viewpoint

As was the case with the C# program, we're getting ready to park the family station wagon and take a ride in a sports car.  We will examine Java properties from the viewpoint of the sophisticated user of the class who needs to first discover and then use properties at runtime.  You saw a preview of this in Part 2, but the code in this part of the lesson goes further than the code that you saw in Part 2.  In particular, the code in this part will not only identify the properties, but also will get and display their current values.

The bottom line at the beginning

I'm going to give you the bottom line at the beginning.  Our objective is to compare the process of discovering and manipulating properties in Java with the process of discovering and manipulating properties in C#.  We will see that even though the names of the classes and methods that we will use to accomplish this purpose are different, the concepts and mechanisms involved are remarkably similar.  Once you understand how to do this in one language, you should understand how to do it in both languages.

Four steps are required

This process will consist of four steps.  (Recall that only three steps were required in C#.  An extra step is required in Java.)  If you compare the description of these Java steps with the descriptions of the steps required to accomplish the same thing in C#, you will find them to be almost identical.

Step 1: A Class object

First I will get a reference to an object of the type Class, which represents the type of an object instantiated from the class named TargetClass.

(Recall that the corresponding object was of the type Type in C#.  Frankly, I prefer the C# name Type to the Java name Class, because an object of the type Class in Java can also represent primitive types.  Primitive types are not objects instantiated from classes in Java.  Also, when lecturing, it is easier to talk about the Type class than to talk about the Class class.)

Step 2: A BeanInfo object

Next I will use the Class object to get a reference to an object of type BeanInfo, which represents the class named TargetClass at a much deeper level than the object of the class named Class (this is the extra step that is required in Java).  The object of type BeanInfo provides considerably more information about TargetClass than does the object of type Class.

(Note that the BeanInfo object can be configured to represent not only the TargetClass object, but also the superclasses of TargetClass.  However, in this program, I constrained it to preclude information about the superclasses for simplicity.)

Step 3: An array of PropertyDescriptor objects

Then I will use the BeanInfo object to get an array of objects of type PropertyDescriptor.

(This corresponds to the second step in C#, which produces an array of objects of type PropertyInfo)

This array will contain one object for each property belonging to the target object of type TargetClass.

(From the previous discussion, you already know that the target object contains three properties, named color, height, and width.  Therefore, the array will have three elements.)

Step 4: Iterate on the array

Finally, I will iterate on the array object, using each object in the array to determine the name, type, and current value of the corresponding property belonging to the TargetClass object.

Java and the Object class

Listing J27 shows the first step in this process.
 

    //Some code skipped in main method

    Class theType = obj.getClass();

Listing J27

(This Java listing corresponds to the C# listing in Listing C13.  Note that I skipped the code in the main method that was covered in Part 3.)

Object defines eleven methods

All classes in Java (and C# as well) derive either directly or indirectly from the class named Object.  The class named Object in Java defines eleven methods that are inherited into all other classes. 

Some methods may be overridden

Some of those methods, (such as equals and toString), are intended to be overridden in new classes.  In Java, they are virtual by default, so they may be freely overridden. 

Some methods are final

Some of the methods, (such as getClass), are intended to be used as is, without overriding them.  Those methods are declared final so that they cannot be overridden.

Invoking the getClass method

When the getClass method is invoked on an existing object, it returns a reference to an object of the type Class.  According to Sun,

"Instances of the class Class represent classes and interfaces in a running Java application."

In Java jargon, it would be said that the Class object exposes the runtime type information (RTTI) of the object on which the method is invoked.

Alternate ways to get a Class object

I know of three ways to get a Class object in Java.  One way is to invoke the getClass method on an object, as illustrated in Listing J27.  (This is similar to invoking the GetType instance method in C#.)

The second way is to invoke the static forName method of the Class class, passing the name of the target class as a String parameter. (This is similar to invoking the static GetType method of the Type class in C#.)

The third way involves getting Class objects that represent primitive types.  I will defer an explanation of that process until a future lesson.

Step 1: Getting the Class object

The code in Listing J27 invokes the GetClass method on the object instantiated earlier from the class named TargetClass.  The GetClass method returns a reference to an object of the type Class.  This object represents the class from which the object was instantiated, TargetClass in this case.  The reference to the Class object is saved in the reference variable named theType.

The Introspector class

The discovery process in Java is described as introspection using low-level reflection.  The class named Introspector plays an important role in this process.  Here is what Sun has to say about the Introspector class:

"The Introspector class provides a standard way for tools to learn about the properties, events, and methods supported by a target Java Bean.

For each of those three kinds of information, the Introspector will separately analyze the bean's class and superclasses looking for either explicit or implicit information and use that information to build a BeanInfo object that comprehensively describes the target bean."

Note that a Java Bean is a standard software component used in the Java version of software component programming.  Note also that I did not provide an associated BeanInfo class in this program.  Therefore, introspection will be performed in this program using low-level reflection and design patterns.  (See Part 2 for a discussion of explicit BeanInfo information.)

Step 2: Getting the BeanInfo object

The Introspector class provides several static methods, including three overloaded versions of a method named getBeanInfo.

The code in Listing J28 uses one of the overloaded versions of the getBeanInfo method to get a BeanInfo object capable of providing information about the target object earlier instantiated from the class named TargetClass.
 

      BeanInfo beanInfo = 
        Introspector.getBeanInfo(
                    theType,theType.
                      getSuperclass());

Listing J28

(Since there is no requirement for this step in C#, there is no C# code listing corresponding to Listing J28.)

Two parameters required

This version of the getBeanInfo method requires two parameters.  The first parameter is a Class object representing the class from which the target object was instantiated, TargetClass in this case.

The second parameter is also a Class object.  This object represents a superclass of the target object.  The resulting BeanInfo object will contain information about the target class and all of its superclasses up to, but not including the class represented by the second parameter. 

Use the direct superclass

In this case, the second parameter is the direct superclass of the target class.  Therefore, the resulting BeanInfo object will contain information about the target class only (information about superclasses was precluded for simplicity).

Step 3:  Getting property information

This step corresponds to the second step in the C# reflection process.  We will get information about the properties defined in the class named TargetClass, which is now represented by the object of type BeanInfo.

Several methods available

The BeanInfo object provides several methods that can be invoked to get information about the class represented by the BeanInfo object.  A few of those methods are shown in the following list to illustrate some of the information that is available.  (In general, the names of the methods indicate the type of information they are designed to provide.)

  • getPropertyDescriptors
  • getMethodDescriptors
  • getEventSetDescriptors

Invoking the getPropertyDescriptors method

The code in Listing J29 invokes the getPropertyDescriptors method on the BeanInfo object.  (This is similar to invoking the GetProperties method on the Type object in the C# program shown in Listing C14.)
 

      PropertyDescriptor[] propInfo = 
              beanInfo.getPropertyDescriptors();

Listing J29

PropertyDescriptor objects

According to Sun, the getPropertyDescriptors method returns "An array of PropertyDescriptors describing the editable properties supported by this bean."

An array of PropertyDescriptor objects

The information is returned as an array of objects, where each object in the array is of type PropertyDescriptor.  Each object of type PropertyDescriptor represents one of the properties belonging to the target class under investigation. 

The number of properties

In this case, the target class is the class named TargetClass.  The number of elements in the array indicates the number of properties belonging to objects of the target class.

Using the length property of the array

As in C#, every array object in Java has a final public member variable (constant) named length, whose value is the number of elements in the array. 

In this case, the value of length is the same as the number of properties belonging to the target class.  The code in Listing J30 gets and displays the value of length. (This code corresponds to the code in the C# program shown in Listing C15.)
 

      System.out.println(
               "Number of Properties: "
                    + propInfo.length);

Listing J30

The number of properties

The code in Listing J30 produces the following output on the screen, which matches what we already know about the number of properties defined in the Java class named TargetClass(Recall that the Java class has three properties whereas the corresponding C# class has only two properties.)

Number of Public Properties: 3

Getting information about each property

Each of the PropertyDescriptor objects contained in the array can be queried to obtain information about the specific property that it represents.  The code in Listing J31 displays some explanatory text on the screen and then calls the method named DisplayPropertyInfo, passing a reference to the array of PropertyDescriptor objects to the method.  (The Java code in Listing J31 corresponds to the C# code in Listing C16.)
 

      System.out.println(
        "Descriptions of Properties:");

      displayPropertyInfo(propInfo);

Listing J31

The DisplayPropertyInfo method

As was the case with the C# program, the method named DisplayPropertyInfo is designed to get and display information from each element in the array.  As a result, this method gets and displays information about each property in the class named TargetClass.

The PropertyDescriptor objects

Each object of the PropertyDescriptor type contains several methods that can be invoked to obtain information about the property that the object represents.  For example, the name and the type of the property represented by the object can be obtained by invoking the methods named getName and getPropertyType on the PropertyDescriptor object.

(By now, you should suspect that these are properties of the PropertyDescriptor object, based on JavaBeans Design Patterns.)

Step 4: Iterate on the array of PropertyDescriptor objects

The method named DisplayPropertyInfo receives a reference to the array of PropertyDescriptor objects as an incoming parameter.  The entire method, consisting of a single for loop, is shown in Listing J32.

(This corresponds to Listing C17 in the C# program discussed earlier.  If you compare the two listings, you will find that they are very similar in both syntax and concept.)

  public static void 
      displayPropertyInfo(
        PropertyDescriptor[] propInfo){

    for(int i=0;i<propInfo.length;i++){
      PropertyDescriptor myPropInfo = 
                           propInfo[i];

      System.out.println("Name: " + 
                 myPropInfo.getName());

      System.out.println("Type: " +
         myPropInfo.getPropertyType());

     //------------------------------//

      //Get and display the value
      Method readMethod = 
            myPropInfo.getReadMethod();
      try{
        System.out.println("Value: " + 
          readMethod.invoke(obj,null));
      }catch(Exception e){
        e.printStackTrace();}
    }//end for loop
  }//end displayPropertyInfo

Listing J32

This method uses a for loop to iterate on the array, extracting name, type, and value information using each object stored in the array.

Getting the name and type information is straightforward.  As is the case in C#, getting the value information is a little more complicated.

(Listing J32 contains a comment separator to visually separate the code that gets the name and type from the code that gets the value.)

Different issues

As is the case in C#, there is a significant difference between name and type on one hand, and value on the other.  The name and type of a property is the same for every object instantiated from a given class.  However, the current value of the property will vary among different objects instantiated from the same class.  Therefore, value is specific to each object instantiated from the class, while name and type are the same for all objects instantiated from the class.

Getting the name and type

The code to get and display the name and the type of the property represented by the PropertyDescriptor object is shown above the visual separator in Listing J32.  As mentioned earlier, this code is straightforward.  All that is required is to invoke the methods named getName and getPropertyType belonging to the PropertyDescriptor object.  The values returned by these methods are the name and the type of the property represented by the PropertyDescriptor object.

Getting the property value for a specific object

The code required to get and display the value of a particular property for a specific object is shown below the visual separator in Listing J32.  This code consists of the following steps (note that this is essentially the same process used to accomplish the same task in C#, as shown in Listing C17):

  • Invoke getReadMethod on the PropertyDescriptor object to get a reference to an object of type Method that represents the get method for the particular property represented by the PropertyDescriptor object.
  • Invoke the invoke method on the Method object, passing a reference to the target object as a parameter.  This causes the get method to be invoked on the target object, returning the current value of the property for that object.

The Method class

An object of the Method class provides information about, and access to, a single method on a class or interface. The reflected method may be a class method or an instance method (including an abstract method).

(The Method class in Java is very similar to the MethodInfo class in C#.)

Numerous methods

The Method object contains numerous methods that allow you to manipulate the method that it represents.  For example, there is a method named getParameterTypes that you can use to get a list that identifies the number and types of parameters required by the method.

(Recall that the C# MethodInfo class has a method named GetParameters that serves essentially the same purpose as the getParameterTypes method in Java.)

The invoke method of the Method class

In this case, we are interested in the invoke method of the Method class.  This method makes it possible to execute the get method represented by the Method object on a specific object of the TargetClass class.

Two parameters required

As was the case in C#, the Java invoke method requires two parameters.  The first parameter is a reference to the object on which we want the get method to be invoked.  In this case, this is the object of the class TargetClass, which has been the target of the investigation from the beginning.

The second parameter is a reference to an array object, where each element in the array contains a reference to an object that is to be passed as a parameter to the method being invoked.  In this case, the get method requires no parameters, so the code in Listing J32 passes null as the second parameter to the invoke method.

(If you compare this portion of Listing J32 with the corresponding portion of Listing C17, you will see that the process involved is essentially the same for C# and Java.  Even the name of the invoke method is the same, except that in C#, the method is named Invoke instead of invoke.)

Invoking the get method on the target object

The result of invoking the invoke method on the reference to the object of type Method, while passing the target object as a parameter, is to cause the get method to be invoked on the target object.  The int value returned by the get method is picked up and returned by the invoke method.  This value is passed to the println method in Listing J32, which causes it to be displayed on the computer screen.

The screen output

The screen output for the first iteration of the for loop in Listing J32 is shown below:

Name: color
Type: int
Value: 15

This output indicates that the name of the first property found by the introspection process is color.  The property is of type int, and the current value is 15.  We know from our prior knowledge of the behavior of the program that this is a correct report.

The properties named height and width

The screen output for the remaining two iterations of the for loop in Listing J32 is shown below:

Name: height
Type: int
Value: 20
Name: width
Type: int
Value: 50

Because we defined the TargetClass, and wrote the program that set the values of the three properties, we know these to be the correct name, type, and current value.  However, prior knowledge of the answers is not a prerequisite for the correct operation of this introspection process.  As in C#, the introspection process would work correctly if someone else had written the class named TargetClass and had provided us with only the compiled version of the class.

Bound and constrained properties

Properties in Java have an extra capability that apparently doesn't exist for properties in C#.

(I strongly suspect that this general capability does exist somewhere in C# and I simply haven't discovered it yet.  I also expect that the day after this article is published, I will receive a flurry of email telling me that I am wrong and that the capability described below does exist for properties in C#.  That will be good because that is how I often learn new things.)

In Java, a bound property has the ability to register interested observer objects and to notify those observer objects each time the property value changes.  A constrained property has the ability to do the same thing with the added stipulation that any observer of a constrained property has the right to veto the change.

Toolbar buttons and menus

A good example of the use of bound properties involves the construction of toolbar buttons that correspond to items on a menu. 

The toolbar button and the corresponding menu item should track one another in terms of being enabled and disabled.  A toolbar button can register itself as an observer on the enabled property of a menu item.  Each time the value of the enabled property of the menu item changes, the toolbar button will be notified, and can change its own enabled property accordingly.  See Understanding Action Objects in Java for a further discussion of this capability.

Part 5, Summary

This lesson concentrates on properties in Java and C#, and a comparison of Java properties with C# properties.

C# and Java properties are very similar

Properties are so similar in C# and Java that if you understand properties in either language, you should have no difficulty understanding properties in both languages.

Summary of Part 1

It is a little difficult to explain properties in a way that makes sense.  This is particularly true in Java, which doesn't use a special syntax to create a property.  Therefore, Part 1 uses the analogy that trying to explain a property is sort of like trying to explain a traffic light to an alien from outer space.

The bottom line is that a traffic light is a traffic light only when drivers recognize it as such.  Otherwise, it is simply some blinking light bulbs in an ugly box in the proximity of an intersection. 

Similarly, a property is a property only when other programs recognize it as such.  Otherwise, it is simply a value, among potentially many values maintained within a program.

C# programs use reflection to recognize properties.  Java programs use introspection based on low-level reflection to recognize properties.

Part 1 also advances the notion that the major importance of properties has to do with the use of reflection and introspection.  These processes make it possible to write very sophisticated programs that recognize and manipulate the values of properties belonging to previously unknown objects.  Microsoft's Visual Studio.net is an example of such a program.

Part 1 also discusses the importance for programmers to become proficient in both Java and C# so that they will be able to meet the programming needs of the future.  Fortunately, Java and C# are very similar.

Summary of Part 2

Part 2 explains Java properties in detail.  This includes an explanation of the following concepts:

  • Simple properties
  • Indexed properties
  • Bound properties
  • Constrained properties
  • Introspection based on low-level reflection and design patterns
  • Introspection based on explicit BeanInfo information

A sample program is presented and discussed that illustrates all of the concepts in the above list except constrained properties.

The sample program in Part 2 also illustrates the use of introspection to get information about events and exposed methods.

Summary of Part 3

Part 3 discusses properties in C#, and compares C# properties with Java properties.

A sample C# program in Part 3 illustrates C# properties, and a sample Java program illustrates the similarity of properties in C# and Java.

Methods and fields

C# properties act like methods to the creator of the class but look like public fields to clients of the class.  As a result, public fields and properties are indistinguishable to readers of the code who don't have ready access to documentation on the class.

Java properties look like methods to clients of the class.  As a result, it is impossible to confuse properties with public fields in Java.  As a result, Java properties are more self-documenting than C# properties.  Beyond this, however, properties are used for essentially the same purposes in both languages.

Properties support data hiding

Both C# properties and Java properties provide the data hiding generally required by good object-oriented design.  However, properties are not a prerequisite for data hiding.  Data hiding can be easily accomplished in C#, Java, or C++ in the absence of properties.

Summary of Part 4

Part 4 continues the discussion of properties in C#, and the comparison of C# properties with Java properties.

Reflection and introspection

The most important aspect of properties has to do with reflection and introspection.  This is a process whereby one object can discover and manipulate the properties belonging to another unknown object even though the author of the executing program had no knowledge of the unknown object's class when the executing program was originally written.

Sample programs in Part 4 illustrate reflection and introspection for both C# and Java.

Part 6, Complete Program Listings

This part of the lesson contains complete program listings for all of the programs discussed in the body of the lesson.
 
/*File PropertyDisplay01.java
Copyright 2003, R.G.Baldwin

The purpose of this program is to display
information about the properties belonging to a
JavaBeans Component.

To display the information, invoke the static
method named display passing the bean class as a
String parameter.

Tested using SDK 1.4.1 under Win2000.
************************************************/

import java.beans.*;
import java.lang.reflect.*;

public class PropertyDisplay01{

  public static void display(String beanClass)
                                throws Exception{

    //Create an object of type Class that
    // describes the class of the bean. The
    // static method Introspector.getBeanInfo()
    // requires either one or two objects of
    // type Class as parameters.  The forName()
    // method of the Class class returns such an
    // object, given the name of a class as a
    // String parameter.
    Class myBeanClassObject = Class.forName(
                                      beanClass);

    //Given the Class object that describes the
    // bean's class, use the static getBeanInfo()
    // method of the Introspector class to obtain
    // information about the class of the bean.
    // Save this information in an object of type
    // BeanInfo.  The second parameter passed to
    // getBeanInfo() prevents introspection from
    // going further up the inheritance
    // hierarchy.
    BeanInfo beanInfo = Introspector.getBeanInfo(
              myBeanClassObject,
              myBeanClassObject.getSuperclass());

    //A BeanDescriptor object provides global
    // information about a bean, including its
    // Java class, its displayName, etc. Use the
    // getBeanDescriptor() method to extract
    // information of that type from the
    // beanInfo object and store it in a new
    // BeanDescriptor object. Display the
    // information using methods designed to
    // extract the name and class of the bean
    // from the beanDescriptor object.

    BeanDescriptor beanDescriptor =
                    beanInfo.getBeanDescriptor();
    System.out.println("Name of bean:  " +
                       beanDescriptor.getName());
    System.out.println("Class of bean: " +
                  beanDescriptor.getBeanClass());
    System.out.println("");


    //A MethodDescriptor describes a particular
    // method that a Java Bean supports for
    // external access from other components.
    // The getMethodDescriptors() method returns
    // an array of MethodDescriptor objects where
    // each object describes one of the methods.
    System.out.println("==== Methods: ====");
    MethodDescriptor[] methodDescriptor =
                 beanInfo.getMethodDescriptors();
    for (int i=0;i < methodDescriptor.length;
                                            i++){
        System.out.println(
                  methodDescriptor[i].getName());
    }//end for-loop
    System.out.println("");



    //A PropertyDescriptor object describes one
    // property that a Java Bean exports via a
    // pair of accessor methods. Use the
    // getPropertyDescriptors() method to create
    // an array of PropertyDescriptor objects,
    // one for each exported property.  Then
    // display that information using methods
    // designed to extract the name of the
    // property, the type of the property, the
    // name of the get method, and the name of
    // the set method.  Also determine and
    // display whether or not the property is
    // a bound property, and whether or not it
    // is a constrained property.
    System.out.println("==== Properties: ====");
    PropertyDescriptor[] propertyDescriptor =
               beanInfo.getPropertyDescriptors();
    for (int i=0; i < propertyDescriptor.length;
                                           i++) {
      System.out.println("Name: " +
                propertyDescriptor[i].getName());
      System.out.println(" Type:       " +
        propertyDescriptor[i].getPropertyType());
      System.out.println(" Get method: " +
          propertyDescriptor[i].getReadMethod());
      System.out.println(" Set method: " +
         propertyDescriptor[i].getWriteMethod());
      System.out.println(" Bound: " +
                propertyDescriptor[i].isBound());
      System.out.println(" Constrained: " +
          propertyDescriptor[i].isConstrained());
    }//end for-loop
    System.out.println("");


    //An EventSetDescriptor object describes a
    // group of events that a given Java bean
    // fires. Information can be extracted from
    // each object of the type.
    System.out.println("==== Events: ====");
    EventSetDescriptor[] eventSetDescriptor =
               beanInfo.getEventSetDescriptors();
    for (int i=0; i < eventSetDescriptor.length;
                                            i++){
      System.out.println("Event Name: " +
                eventSetDescriptor[i].getName());
      System.out.println(" Add Method:    " +
                         eventSetDescriptor[i].
                         getAddListenerMethod());
      System.out.println(" Remove Method: " +
                      eventSetDescriptor[i].
                      getRemoveListenerMethod());
      methodDescriptor = eventSetDescriptor[i].
                  getListenerMethodDescriptors();
      for (int j=0; j < methodDescriptor.length;
                                            j++){
          System.out.println(" Event Type: " +
                  methodDescriptor[j].getName());
      }//end for-loop
    }//end for-loop

  }//end display method
}//end class

Listing J33

 

/*File Prop02Test.java
Copyright 2003, R.G.Baldwin

Purpose:  This program, in conjunction with the
files named Prop02BeanZBeanInfo.java and
PropertyDisplay01.java, illustrates several
important aspects of properties including:

Simple properties
Indexed properties
Bound properties
Property design patterns
Explicit identification of properties using a
  class that implements the BeanInfo interface.

This program produces the following output on
the screen.  Note that in some cases, line
breaks were manually inserted in this listing to
force the material to fit in this narrow format.

Process Prop02BeanX
Name of bean:  Prop02BeanX
Class of bean: class Prop02BeanX

==== Methods: ====
fetchSize
getColor
getData
putSize
setColor
setData

==== Properties: ====
Name: color
 Type:       class java.awt.Color
 Get method: public java.awt.Color Prop02BeanX.
             getColor()
 Set method: public void Prop02BeanX.
             setColor(java.awt.Color)
 Bound: false
 Constrained: false
Name: data
 Type:       class [Ljava.lang.Integer;
 Get method: public java.lang.Integer[]
             Prop02BeanX.getData()
 Set method: public void Prop02BeanX.
             setData(java.lang.Integer[])
 Bound: false
 Constrained: false

==== Events: ====


Process Prop02BeanY
Name of bean:  Prop02BeanY
Class of bean: class Prop02BeanY

==== Methods: ====
addPropertyChangeListener
fetchSize
getColor
putSize
removePropertyChangeListener
setColor

==== Properties: ====
Name: color
 Type:       class java.awt.Color
 Get method: public java.awt.Color Prop02BeanY.
             getColor()
 Set method: public void Prop02BeanY.
             setColor(java.awt.Color)
 Bound: true
 Constrained: false

==== Events: ====
Event Name: propertyChange
 Add Method:   public void Prop02BeanY.
               addPropertyChangeListener(
               java.beans.PropertyChangeListener)
 Remove Method:public void Prop02BeanY.
               removePropertyChangeListener(
               java.beans.PropertyChangeListener)
 Event Type: propertyChange

Exercise PropertyChangeListener
PropertyChangeEvent
 Property Name: color
 Old Value: java.awt.Color[r=255,g=0,b=0]
 New Value: java.awt.Color[r=0,g=0,b=255]
PropertyChangeEvent
 Property Name: color
 Old Value: java.awt.Color[r=0,g=0,b=255]
 New Value: java.awt.Color[r=0,g=255,b=0]


Process Prop02BeanZ
Name of bean:  Prop02BeanZ
Class of bean: class Prop02BeanZ

==== Methods: ====
fetchSize
getColor
putSize
setColor

==== Properties: ====
Name: size
 Type:       class java.lang.String
 Get method: public java.lang.String Prop02BeanZ.
             fetchSize()
 Set method: public void Prop02BeanZ.putSize(
             java.lang.String)
 Bound: false
 Constrained: false

==== Events: ====
Press any key to continue...


Tested using SDK 1.4.1 under Win 2000.
************************************************/


import java.io.Serializable;
import java.awt.Color;
import java.beans.*;

class Prop02Test{
  public static void main(String[] args)
                                throws Exception{
    System.out.println("Process Prop02BeanX");
    PropertyDisplay01.display("Prop02BeanX");

    System.out.println("");
    System.out.println("\nProcess Prop02BeanY");
    PropertyDisplay01.display("Prop02BeanY");
    Prop02BeanY aProp02BeanY = new Prop02BeanY();
    aProp02BeanY.addPropertyChangeListener(
                             new PropListener());
    System.out.println(
            "\nExercise PropertyChangeListener");
    aProp02BeanY.setColor(Color.BLUE);
    aProp02BeanY.setColor(Color.GREEN);

    System.out.println("");
    System.out.println("\nProcess Prop02BeanZ");
    PropertyDisplay01.display("Prop02BeanZ");

  }//end main
}//end class Prop02Test
//=============================================//

class Prop02BeanX implements Serializable{
  private String size = "Medium";
  private Color color = Color.RED;
  private Integer data[];

  public void setColor(Color color){
    //This would be a property based on design
    // patterns
    this.color = color;
  }//end setColor

  public Color getColor(){
    //This would be a property based on design
    // patterns
    return color;
  }//end getColor


  public void setData(Integer[] data){
    //This would be a property based on design
    // patterns
    this.data = data;
  }//end setData

  public Integer[] getData(){
    //This would be a property based on design
    // patterns
    return this.data;
  }//end getData


  public void putSize(String size){
    //This would not be a property based on
    // design patterns
    this.size = size;
  }//end putSize()

  public String fetchSize(){
    //This would not be a property based on
    // design patterns
    return size;
  }//end fetchSize()

}//end class Prop02BeanX
//=============================================//


class Prop02BeanY implements Serializable{
  private String size = "Medium";
  private Color color = Color.RED;

  private PropertyChangeSupport changes =
                 new PropertyChangeSupport(this);

  public void addPropertyChangeListener(
                   PropertyChangeListener lstnr){
    changes.addPropertyChangeListener(lstnr);
  }//end addPropertyChangeListener

  public void removePropertyChangeListener(
                   PropertyChangeListener lstnr){
    changes.removePropertyChangeListener(lstnr);
  }//end removePropertyChangeListener

  public void setColor(Color color){
    //This would be a property based on design
    // patterns
    Color oldColor = this.color;
    this.color = color;
    changes.firePropertyChange(
                        "color",oldColor, color);
  }//end setColor

  public Color getColor(){
    //This would be a property based on design
    // patterns
    return color;
  }//end getColor

  public void putSize(String size){
    //This would not be a property based on
    // design patterns
    this.size = size;
  }//end putSize()

  public String fetchSize(){
    //This would not be a property based on
    // design patterns
    return size;
  }//end fetchSize()

}//end class Prop02BeanY
//=============================================//

class PropListener implements
                          PropertyChangeListener{
  public void propertyChange(
                        PropertyChangeEvent evt){
    System.out.println("PropertyChangeEvent");
    System.out.println(" Property Name: "
                        + evt.getPropertyName());
    System.out.println(" Old Value: "
                            + evt.getOldValue());
    System.out.println(" New Value: "
                            + evt.getNewValue());
  }//end propertyChange
}//end PropListener
//=============================================//

class Prop02BeanZ implements Serializable{
  private String size = "Medium";
  private Color color = Color.RED;

  public void setColor(Color color){
    //This would be a property based on design
    // patterns
    this.color = color;
  }//end setColor

  public Color getColor(){
    //This would be a property based on design
    // patterns
    return color;
  }//end getColor

  public void putSize(String size){
    //This would not be a property based on
    // design patterns
    this.size = size;
  }//end putSize()

  public String fetchSize(){
    //This would not be a property based on
    // design patterns
    return size;
  }//end fetchSize()

}//end class Prop02BeanZ
//=============================================//

Listing J34

 

/*File Prop02BeanZBeanInfo.java
Copyright 2003, R.G.Baldwin

Purpose:  See Prop02Test.java

Tested using SDK 1.4.1 under Win 2000.
************************************************/

import java.beans.*;

public class Prop02BeanZBeanInfo
                          extends SimpleBeanInfo{

  public PropertyDescriptor[]
                        getPropertyDescriptors(){
    try{
      PropertyDescriptor pd =
                          new PropertyDescriptor(
                               "size",
                               Prop02BeanZ.class,
                               "fetchSize",
                               "putSize");
      PropertyDescriptor[] pda = {pd};
      return pda;
    }catch(IntrospectionException e){
      return null;
    }//end catch
  }//end getPropertyDescriptors()

}//end class Prop02BeanZBeanInfo

Listing J35

 

/*File Props01.cs
Copyright 2002, R.G.Baldwin

This program is intended to explore and
explain the use of properties in C#.

Program tested using:
Microsoft (R) Visual C# .NET Compiler 
version 7.00.9466
for Microsoft (R) .NET Framework 
version 1.0.3705
Under Win2000 Version 5.0 SP 2

Program output is:
text: Quit
color: 15
height: 20
width: 50
Number of Public Properties: 2
Descriptions of Properties:
Name: height
Type: System.Int32
Value: 20
Name: width
Type: System.Int32
Value: 50
**************************************/
using System;
using System.Reflection;

public class TargetClass{
  //A public instance variable
  public string text;
  
  //This would be a property named
  // color in Java, but not in C#
  private int colorData = 0;
  public void setColor(int data){
    //Validating code goes here
    colorData = data;
  }//end setColor
  public int getColor(){
    return colorData;
  }//end getColor
  
  //This is a property named height
  private int heightData;
  public int height{
    get{
      return heightData;
    }//end get
    set{
      //Validating code goes here
      heightData = value;
    }//end set
  }//end height property

  //This is a property named width
  private int widthData;
  public int width{
    get{
      return widthData;
    }//end get
    set{
      //Validating code goes here
      widthData = value;
    }//end set
  }//end width property
  
}//end TargetClass
//===================================//

public class Props01{
  static TargetClass obj;
  
  public static void Main(){
    obj = new TargetClass();
    
    //Access a public instance 
    // variable
    obj.text = "Quit";
    Console.WriteLine(
                  "text: " + obj.text);
    
    //Invoke public accessor methods
    obj.setColor(15);
    Console.WriteLine(
           "color: " + obj.getColor());
    
    //Set and get a property
    obj.height = 20;
    Console.WriteLine(
              "height: " + obj.height);

    //Set and get another property
    obj.width = 50;
    Console.WriteLine(
                "width: " + obj.width);

    //Now do reflection to identify
    // properties of the object
    Type theType = obj.GetType();
    PropertyInfo[] propInfo = 
               theType.GetProperties();
    Console.WriteLine(
        "Number of Public Properties: "
                    + propInfo.Length);
    Console.WriteLine(
        "Descriptions of Properties:");
    // Display all the properties.
    DisplayPropertyInfo(propInfo);

  }//end Main
  
  public static void 
            DisplayPropertyInfo(
              PropertyInfo[] propInfo){
    for(int i=0;i<propInfo.Length;i++){
      PropertyInfo myPropInfo = 
                           propInfo[i];
      Console.WriteLine("Name: " + 
                      myPropInfo.Name);
      Console.WriteLine("Type: " + 
              myPropInfo.PropertyType);

      //Get and display the value
      MethodInfo readMethod = 
             myPropInfo.GetGetMethod();
      Console.WriteLine("Value: " +
          readMethod.Invoke(obj,null));

/*    Alternative approach for value
      Console.WriteLine("Value: " + 
        myPropInfo.GetValue(obj,null));
*/
      
    }//end for loop
  }//end DisplayPropertyInfo
  
}//end class Props01
//===================================//


Listing C19

 
 

/*File Props01.java
Copyright 2002, R.G.Baldwin

This program is intended to explore and
explain the use of properties in Java,
and is designed for comparison with a
similar C# program.

Program tested using:
SDK 1.4.0 under Win2000 V5.0 SP2

Program output is:
text: Quit
color: 15
height: 20
width: 50
Number of Properties: 3
Descriptions of Properties:
Name: color
Type: int
Value: 15
Name: height
Type: int
Value: 20
Name: width
Type: int
Value: 50
**************************************/
import java.beans.*;
import java.lang.reflect.*;
import java.io.*;

//This class is not declared public in
// order to avoid the rqmt for separate
// files
class TargetClass 
               implements Serializable{
  //A public instance variable
  public String text;
  
  //This is a property named color
  private int colorData = 0;
  public void setColor(int data){
    //Validating code goes here
    colorData = data;
  }//end setColor
  public int getColor(){
    return colorData;
  }//end getColor
  
  //This is a property named height
  private int heightData;
  public void setHeight(int data){
   //Validating code goes here
   heightData = data;
  }//end setHeight
  public int getHeight(){
    return heightData;
  }//end getHeight
  
  //This is a property named width
  private int widthData;
  public void setWidth(int data){
   //Validating code goes here
   widthData = data;
  }//end setwidth
  public int getWidth(){
    return widthData;
  }//end getwidth
  
}//end TargetClass
//===================================//

public class Props01{
  static TargetClass obj;
  
  public static void main(
                        String[] args){
    obj = new TargetClass();
    
    //Access a public instance 
    // variable
    obj.text = "Quit";
    System.out.println(
                  "text: " + obj.text);
    
    //Invoke property methods
    obj.setColor(15);
    System.out.println(
           "color: " + obj.getColor());
    
    obj.setHeight(20);
    System.out.println("height: " + 
                      obj.getHeight());

    obj.setWidth(50);
    System.out.println("width: " + 
                       obj.getWidth());

    //Now do reflection and 
    // introspection to identify
    // properties of the object
    Class theType = obj.getClass();

    try{
      BeanInfo beanInfo = 
      Introspector.getBeanInfo(
                    theType,theType.
                      getSuperclass());

    
      PropertyDescriptor[] propInfo = 
            beanInfo.
              getPropertyDescriptors();

      System.out.println(
               "Number of Properties: "
                    + propInfo.length);
      System.out.println(
        "Descriptions of Properties:");
      // Display all the properties.
      displayPropertyInfo(propInfo);
    }catch(IntrospectionException e){
                  e.printStackTrace();}

  }//end Main
  
  public static void 
      displayPropertyInfo(
        PropertyDescriptor[] propInfo){
    for(int i=0;i<propInfo.length;i++){
      PropertyDescriptor myPropInfo = 
                           propInfo[i];
      System.out.println("Name: " + 
                 myPropInfo.getName());

      System.out.println("Type: " +
         myPropInfo.getPropertyType());

      //Get and display the value
      Method readMethod = 
            myPropInfo.getReadMethod();
      try{
        System.out.println("Value: " + 
          readMethod.invoke(obj,null));
      }catch(Exception e){
        e.printStackTrace();}
    }//end for loop
  }//end displayPropertyInfo
  
}//end class Props01

Listing J36

Copyright 2003, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which has gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com

-end-




Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel