Class.forName().newInstance() vs new

A

Abu Yahya

I have a class that instantiates a private member based on a value in a
configuration file.

The value is used to determine the class name.

I initially decided to use code similar to the following:


// class name comes from property file
String dbMgrClassName = props.getProperty("db.manager");
Class<?> k = Class.forName(dbMgrClassName);
db = (DB) k.newInstance();
db.init(props);

However, a colleague pointed out that using "new" is faster than using
"Class.forName().newInstance()". So, I changed the code to the following:

String dbMgrClassName = props.getProperty("db.manager");
if (dbMgrClassName.equals("DB2"))
db = new DB2();
else if (dbMgrClassName.equals("Oracle"))
db = new Oracle();
else if (dbMgrClassName.equals("SQLServer"))
db = new SQLServer();
else { // handle unrecognized
Class<?> k = Class.forName(dbMgrClassName);
db = (DB) k.newInstance();
}
db.init(props);

My question is: Does using if-else statements like the above really
improve performance? What is the best approach to instantiate classes
whose type you don't know at compile time?
 
D

David Lamb

My question is: Does using if-else statements like the above really
improve performance? What is the best approach to instantiate classes
whose type you don't know at compile time?

That code is unlikely to be in some critical inner loop, so any
efficiency gains would be marginal. Your original solution requires no
change if the possible classes change and is simpler to understand, each
of which on its own wins out over marginal gains in efficiency.
 
R

Robert Klemme

I have a class that instantiates a private member based on a value in a
configuration file.

The value is used to determine the class name.

I initially decided to use code similar to the following:


// class name comes from property file
String dbMgrClassName = props.getProperty("db.manager");
Class<?> k = Class.forName(dbMgrClassName);
db = (DB) k.newInstance();
db.init(props);

However, a colleague pointed out that using "new" is faster than using
"Class.forName().newInstance()". So, I changed the code to the following:

String dbMgrClassName = props.getProperty("db.manager");
if (dbMgrClassName.equals("DB2"))
db = new DB2();
else if (dbMgrClassName.equals("Oracle"))
db = new Oracle();
else if (dbMgrClassName.equals("SQLServer"))
db = new SQLServer();
else { // handle unrecognized
Class<?> k = Class.forName(dbMgrClassName);
db = (DB) k.newInstance();
}
db.init(props);

My question is: Does using if-else statements like the above really
improve performance? What is the best approach to instantiate classes
whose type you don't know at compile time?

I would stick with the forName() approach. If performance is critical
then I would define an interface for the factory method and configure
the name of a class which much implement this interface. Then you need
forName() only once (for instantiating the factory instance) and can use
new in factory methods (or do even more fancy things like caching etc.).

Doing if else cascades is certainly the worst thing - not so much
because of the performance but because of the deficiency that you need
to touch the code every time you want to add a new class. With the
other two approaches you do not have to do that.

Kind regards

robert
 
A

Abu Yahya

...

As coded, the forName code was left in as a fall-through handler, so it
new classes can be handled without touching the code.

That's right.
Of course, that
also means it has all the complications of both the if-else approach and
the forName approach.

The intent was to get the best of both worlds, but I agree it's made it
less easy to understand.
 
A

Abu Yahya

I would stick with the forName() approach. If performance is critical
then I would define an interface for the factory method and configure
the name of a class which much implement this interface. Then you need
forName() only once (for instantiating the factory instance) and can use
new in factory methods (or do even more fancy things like caching etc.).

Thanks for your reply, Robert.

Could you give an example of how the factory method might look like?

Thanks in advance!
 
R

Robert Klemme

...

As coded, the forName code was left in as a fall-through handler, so it
new classes can be handled without touching the code. Of course, that
also means it has all the complications of both the if-else approach and
the forName approach.

Thanks for hinting at this detail, Patricia! Performance of this piece
of code can vary dramatically with configured class / handler name.
That adds a level of complication which might make tracking issues
harder ("It was so fast in our lab, now on production it's awfully slow.").

Also I find the inconsistency about what needs to be configured
irritating: the string can either be a logical name of a handler *or* a
class name - and you cannot even distinguish them easily (handler names
presented so far are also valid class names). IMHO for this it would be
better to have two different properties with clear defined precedence
for logical handler name property. That would also make it explicit
that there are two mechanisms involved. Even though, I still prefer one
of the two uniform approaches (class name, factory class name).

Kind regards

robert
 
R

Robert Klemme

There's some good examples here:

<http://en.wikipedia.org/wiki/Factory_method_pattern>

And in the linked article, "Item 1: Consider static factory methods
instead of constructors."

<http://drdobbs.com/java/208403883?pgno=1>

If Class.forName() is the bottleneck then a static factory method does
not help in this particular case. You would have to configure the
method name or a class name anyway and use reflection to get at the
instance or method.

Abu, to answer your question (pseudo code):

interface com.your.company.db.DbManager {
// methods
}

interface com.your.company.db.DbManagerFactory {
DbManager create(/* args if needed */) throws WhateverException
}

class com.your.company.db.ora.OraDbManager implements DbManager {
// ...
}

class com.your.company.db.ora.OracleDbManagerFactory implements
DbManagerFactory {
public DbManager create() {
return new OraDbManager();
}
}


Kind regards

robert
 
M

Martin Gregorie

Is there really any program that instantiates so many database managers
that the difference between newInstance and constructor, and the
pipeline reloads related to conditional branches, become measurable?
Is there actually that much difference? It strikes me that both 'new' and
Class.forName() are doing essentially the same, namely searching the
class path for the required class, loading it into the JVM and
instantiating an object from it. I also wonder if 'new' might not be
implemented as a wrapper for Class.forName(). It certainly could be done
that way: both return a class object if they are successful and throw an
exception if the class can't be found.
 
R

Robert Klemme

On 6/12/2011 5:05 AM, Robert Klemme wrote:
...
...

Is there really any program that instantiates so many database managers
that the difference between newInstance and constructor, and the
pipeline reloads related to conditional branches, become measurable?

Only OP knows. That's why I also suggested to go with Class.forName()
and only pick a different solution if there really was a performance issue.
I was concerned about the testing issues. Suppose some future changes
introduce a bug in the fall through path. In order to catch that bug,
there would have to be at least one test that instantiates a database
manager other than the ones that are being handled specifically.

Another bad effect from complexity in the implementation...

Cheers

robert
 
R

Robert Klemme

Is there actually that much difference? It strikes me that both 'new' and
Class.forName() are doing essentially the same, namely searching the
class path for the required class, loading it into the JVM and
instantiating an object from it.

Actually, the code will execute a Class.forName() under the hoods for
the version with direct instantiation. There is still a fundamental
difference though: the solution explicitly using Class.forName() will
provide the name at runtime while the version with the explicit
constructor call will have it compiled into the code. Consequently when
providing the name at runtime reflection has to be used (which is
usually a tad slower).

The conceptual difference between providing a type at compile time and
run time is reflected by the necessity to use reflection (in the dynamic
case) which defers particular type checks to runtime - which is usually
significantly slower when done frequently because it has to be done for
_every_ call.
I also wonder if 'new' might not be
implemented as a wrapper for Class.forName(). It certainly could be done
that way: both return a class object if they are successful and throw an
exception if the class can't be found.

Class.forName() only yields a class (if successful) while new SomeClass
yields an instance - so new is more like a wrapper around
Class.forName().newInstance(). But as I said, there is a fundamental
conceptual difference between the two.

Kind regards

robert
 
J

Joshua Cranmer

The conceptual difference between providing a type at compile time and
run time is reflected by the necessity to use reflection (in the dynamic
case) which defers particular type checks to runtime - which is usually
significantly slower when done frequently because it has to be done for
_every_ call.

One particular difference is that, as new uses a class already in the
constant pool, the lookup only needs to be done at most once per file,
since it is otherwise indexed by an integer into a cache. Class.forName
will have a slightly more expensive lookup, since it needs to index a
hashtable by a String.
 
R

Roedy Green

I have a class that instantiates a private member based on a value in a
configuration file.

When you use new, it must be followed by hard coded the name of the
class.

When you use newInstance, you can create the Class object with
Class.forName so all you need is a string containing the class name.
This is more general, but more convoluted than using new.

When you use Class.forName, GENJAR or the like has no idea that the
class need be included in the jar. All it sees is the string, not the
class name. The class name does not exist until run time. This can be
a good or bad thing.
--
Roedy Green Canadian Mind Products
http://mindprod.com
One of the great annoyances in programming derives from the irregularity
of English spelling especially when you have international teams.
I want to find a method or variable, but I don't know precisely
how its is spelled or worded. English is only approximately phonetic.
Letters are randomly doubled. The dictionary often lists variant spellings.
British, Canadian and American spellings differ.I would like to see an
experiment where variable names were spelled in a simplified English, where
there were no double letters.I also think you could add a number of rules
about composing variable names so that a variable name for something would
be highly predictable. You would also need automated enforcement of the
rules as well as possible.
 
I

Ian Shef

I have a class that instantiates a private member based on a value in a
configuration file.

The value is used to determine the class name.

I initially decided to use code similar to the following:


// class name comes from property file
String dbMgrClassName = props.getProperty("db.manager");
Class<?> k = Class.forName(dbMgrClassName);
db = (DB) k.newInstance();
db.init(props);

However, a colleague pointed out that using "new" is faster than using
"Class.forName().newInstance()". So, I changed the code to the following:

String dbMgrClassName = props.getProperty("db.manager");
if (dbMgrClassName.equals("DB2"))
db = new DB2();
else if (dbMgrClassName.equals("Oracle"))
db = new Oracle();
else if (dbMgrClassName.equals("SQLServer"))
db = new SQLServer();
else { // handle unrecognized
Class<?> k = Class.forName(dbMgrClassName);
db = (DB) k.newInstance();
}
db.init(props);

My question is: Does using if-else statements like the above really
improve performance?

Maybe yes, maybe no. If you don't have a benchmark that shows it to be an
issue, don't worry about it. Initializing the databas manager is probably
going to be a lot more preformance-consuming than anything else that you
are doing here.
What is the best approach to instantiate classes
whose type you don't know at compile time?

Well, actually you _do_ know the type for db, you just didn't show us
directly; apparently it is DB. What you don't know at compile time is the
implementation.
I prefer to use java.util.ServiceLoader myself. It means that you have to
have "a provider-configuration file in the resource directory META-
INF/services" instead of a property or a value in a separate configuration
file. This could be a good thing or a bad thing, depending upon your
application.
 
L

lewbloch

Is there actually that much difference? It strikes me that both 'new' and
Class.forName() are doing essentially the same, namely searching the
class path for the required class, loading it into the JVM and
instantiating an object from it. I also wonder if 'new' might not be
implemented as a wrapper for Class.forName(). It certainly could be done
that way: both return a class object if they are successful and throw an
exception if the class can't be found.

'new' is not a wrapper for 'Class.forName()' because while 'forName()'
does return a class object, 'new' does not unless the class
instantiated actually is 'Class'. Since the constructors for 'Class'
are not exposed, that's unlikely.

'newInstance()' is different from 'new' also. It's invoked
reflectively, i.e., via runtime mechanisms, not via a compiled
constructor invocation as via 'new', and throws different exceptions
from the corresponding constructor. It's also semantically limited to
no-arg constructors.

'newInstance()' appears in a reflective context which is perforce
going to be slower than compiled-in decisions. Such a context will
properly appear only when performance is not the overarching concern,
nor readability.
 
N

Nigel Wade

'newInstance()' is different from 'new' also. It's invoked
reflectively, i.e., via runtime mechanisms, not via a compiled
constructor invocation as via 'new', and throws different exceptions
from the corresponding constructor. It's also semantically limited to
no-arg constructors.

There is an alternative to the "simple" Class.newInstance() which allows
constructors with arguments to be used. The
Class.getConstructor(Class...) or Class.getDeclaredConstructor(Class...)
method can be used to obtain other constructors for the class. The
newInstance(Object) method of the returned Constructor can then be used
to get an instance of the class (where obj is actually an Object[]
containing the constructor arguments).
 
M

Michael Wojcik

lewbloch said:
There are some

"There's some [plural] ..." is quite common in idiomatic American.

True, which is an argument for avoiding it (or correcting it, as John
did in his edit).

Though it's not quite as grating as, say, the use of "would" to
indicate the subjunctive mood. ("If I would have knowed there's some
cupcakes, I would have totally ate them all.")

I've pretty much given up on nominative/objective case of pronouns as
a shibboleth ("between you and I") - I suspect more people in the US
now ignore traditional pronoun case than attempt to apply it - but
attentive writers do still try to watch agreement in number, I think.
 
L

lewbloch

lewbloch said:
"There's some [plural] ..." is quite common in idiomatic American.

True, which is an argument for avoiding it (or correcting it, as John
did in his edit).

Though it's not quite as grating as, say, the use of "would" to
indicate the subjunctive mood. ("If I would have knowed there's some
cupcakes, I would have totally ate them all.")

I've pretty much given up on nominative/objective case of pronouns as
a shibboleth ("between you and I") - I suspect more people in the US
now ignore traditional pronoun case than attempt to apply it - but
attentive writers do still try to watch agreement in number, I think.

Your comments are appropriate for formal writing. Usenet is
conversational, ergo one should accept idiomatic expressions.
Otherwise we'd insist that no one use "doubt" to mean a mere question
without suspicion.

I do aver that one should spell nouns, particularly proper nouns,
correctly in technical speech, which this is for all its informality,
and it only makes sense to spell the first-person singular nominative
pronoun in English correctly as it's short enough to remember.

There's some folks even more pedantic than I, apparently. Welcome to
the club, Michael.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top