On Mon, Sep 30, 2002 at 12:22:25PM -0700, Craig R. McClanahan wrote:

> Comments intermixed.

Same. 

> On Mon, 30 Sep 2002, John Bindel wrote:
> 
> > Date: Mon, 30 Sep 2002 13:49:22 -0500
> > From: John Bindel <[EMAIL PROTECTED]>
> > Reply-To: Struts Users Mailing List <[EMAIL PROTECTED]>
> > To: Struts Users Mailing List <[EMAIL PROTECTED]>
> > Subject: Re: [OT - Java] How can I do this in Java?
> >
> > On Mon, Sep 30, 2002 at 12:02:41PM -0500, Jerry Jalenak wrote:
> >
> > > Yeah, already ran across the exceptions. Right now I'm trying
> > > to decide how to handle them since all of this code is actually
> > > in a custom Validator routine.....
> >
> > Good Lord, people, why is reflection anything but the option of
> > last resort here?
> >
> 
> While I agree with you that using reflection was a poor design choice for
> the problem stated here (the patterns should really be loaded from a data
> file instead of introspecting from the class), your condemnation of
> reflection in general is based on an incorrect definition of the term, and
> also outdated behavior related to performance.  See below for more.

Let me know how jdk 1.4 does on the test below.  It seems like it would
have been simple for a class loader to do the same caching of classes,
but such was not the case when I have looked at it.

> > You really do not want to be calling Class.forname(String) unless
> > there is some class that cannot be loaded by the compiler. First,
> > calling Class.forname is slow, and second, it perversely gets
> > rid of the compile-time type-safety that you would have is you
> > simply used MyClass.class.
> >
> 
> The Class.forName() method is not really reflection -- it is dynamic class
> loading.

IMO, the Class class itself is a part of reflection as stated below.

> Struts itself uses this to good effect, because it's not
> possible to know (at the time ActionServlet is compiled) the names of all
> the Action and ActionForm subclasses that *your* application will be
> using.

Agreed, but it wouldn't load class for name every time the action
is called.  It is needed only the first time the action is instantiated.
This is exactly the type of case in which I stated reflection is useful.

> Further, there is no loss of type safety when using dynamic class loading
> in the usual fashion, because you normally cast to the base class you are
> looking for.  For example, module error checking, this is how Struts
> actually loads an Action class instance:
> 
>   ClassLoader loader =
>     Thread.currentThread().getContextClassLoader();
>   if (classLoader == null) {
>     loader = this.getClass().getClassLoader();
>   }
>   Action action = (Action) loader.loadClass(actionClassName);
> 
> Note the cast to an Action, which protects you from type safety problems.

Which in general may lead to a runtime ClassCastException, which is
not desirable when you can avoid it.  Using reflection in cases that
do not require dynamic behavior is generally not the right approach.

> Of course, using dynamic class loading in the use case being discussed in
> this mail thread was totally unnecesary.  But please stop casting
> aspersions on a very useful feature of the Java language that makes
> dynamically extensible applications like Struts possible in the first
> place.

Did I?  My next statement shows exactly when I think reflection is
a useful tool, specifically when you are loading classes that cannot
be known until runtime as in Struts and other useful places.

> > Reflection is a tool that's useful when you do not know at build
> > time the classes with which you will be dealing. It's useful for
> > discovery of APIs. Using reflection instead of a lookup table
> > is needlessly obtuse and will cause your VM to do all sorts of
> > work on which any programmer should not want to be wasting CPU
> > cycles.
> >
> >
> > 1. Using reflection here is fragile, especially if it's not wrapped
> > within the class that defines your constants. Java is a strongly
> > typed language so letting the compiler help you is encouraged.
> 
> Since the problem at hand was to access *data*, the best approach would be
> to store the patterns externally in a properties file.  Then, the data
> could be used by multiple classes when it is needed (including the class
> in which the format strings are currently embedded).
> 
> > 2. Using reflection is slow. If you still think it's the way you
> > want to go, I would strongly recommend limiting the times you
> > call Class.forname, etc., such that you do not call it every time
> > you validate the zip code.
> 
> Firstly, as above, Class.forName() is not reflection.

Sure it is. These are the first two sentences of Sun's javadoc for
java.lang.Class:

  "Instances of the class Class represent classes and interfaces
  in a running Java application. Every array also belongs to a class
  that is reflected as a Class object that is shared by all arrays
  with the same element type and number of dimensions."

They say "reflected as a Class object", which you can take to mean
what you will.  Maybe it's only a true "reflection" API when it's
used to represent the types of arrays, but that's not they way I
understand the sentence. It is true that it is not in the java.lang.reflect
package.  

Here's a test for you to try:

long t1 = System.currentTimeMillis();
for (int i=0; i < 10000; ++i) {
   Class c = Class.forName("com.foo.MyClass");
}
long t2 = System.currentTimeMillis();
System.out.println("time: " + (t2 - t1) + "ms"); 


long t1 = System.currentTimeMillis();
HashMap m = new HashMap();

for (int i=0; i < 10000; ++i) {
   Class c = (Class)m.get("com.foo.MyClass");
   if (c == null) {
     Class c = Class.forName("com.foo.MyClass");
     m.put("com.foo.MyClass", c);
   }
}
long t2 = System.currentTimeMillis();
System.out.println("time: " + (t2 - t1) + "ms");


In Struts, we only need to call the forName() method once per
class since we can store the class or the single instance of the
Action in a Map, thus avoiding the delay of class.forName()
every time.

Let me know if VMs have gotten better at this since I did it
last year.

> Secondly, a subsequent call to Class.forName() for the same class name is
> *not* going to load the class bytecodes again; the class loader will
> remember that the requested class name has already been loaded, and just
> returns you the same instance.
> 
> Thirdly, there is *zero* performance difference (at runtime) between
> loading a class via Class.forName() and loading one (for the first time)
> with a "new" operator.  Why?  Because they both end up calling the exact
> same loadClass() method -- it's just a question of whether the developer
> calls the method explicitly or the bytecodes generated by the compiler
> call it for you.
> 
> As for the performance of real life uses of reflection, have you ever
> noticed how Struts actually implements the population of your form bean
> properties from the request parameters?  Yep ... that's right ... every
> single call to a property setter is done via reflection.  Seems fast
> enough to me, especially on a 1.4 JDK where the performance difference
> between direct calls and reflected calls is very very small.

Yeah, that always seemed like it could be faster to me.  Again, it's
a case in which we don't know the API when the Struts library is
compiled.

> > 3. Using reflection makes you check all sorts of exceptions for
> > things that you as the programmer know should not occur, but only
> > can be you are circumventing the type checking provided by the
> > language.  This is a clue that what should be a simple task is
> > being made more complex than it needs to be.
> >
> 
> In the particular use case at hand, reflection is the wrong technology to
> use.  However, it makes possible some things that would otherwise be
> impossible, or insanely complicated (to do form bean population without
> using reflection, Struts would have to examine all your form beans, then
> generate a custom Java class to do the auto-population and make sure these
> classes were all compiled and included in your webapp -- not something
> that can be guaranteed in a portable fashion).
> 
> > 4. I'm not sure what your application is, but using regexp strings
> > to validate ZIP codes per state seems like a bad idea. The US
> > post office makes new ZIP codes all the time, and unless you are
> > getting a list from them every week, the most you may want your
> > application to do is warn the user that the application doesn't
> > recognize the ZIP code.
> >
> 
> It doesn't look like he wanted to check the exact codes, just that the
> code is in the correct range for that state.  This is a perfectly
> reasonable compromise if you cannot afford the time to do the database
> lookup, or you don't have the mechanisms to maintain a current list of all
> the individual codes in your database.
> 
> > 5. Tell your product managers that validating ZIP codes is not
> > something you can do reliably without an often-updated list of
> > ZIP codes that you would need to download from the Post Office
> > on a regular schedule since your list of regexp string will
> > become outdated.
> >
> > 6. Lookup tables implemented by arrays or HashMaps are orders
> > of magnitude faster than the sequence of function calls and system
> > calls that you have to do with reflection.
> >
> >
> > I'm sorry I had to write this, but I am befuddled by the lack
> > of outcry over using reflection instead of a simple lookup table.
> 
> I'm saddened by the fact that you take a case of misuese of a particular
> feature and turn it into a diatribe against ever using it.

I don't think I did.  See my note with numeral 1.  I got carried away
because someone asked about a lookup table and got a response that
reflection was the way to go.

Cheers,
John
--
end of line


--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>


Reply via email to