What is the difference between Class.forName and ClassLoader.defineClass

Discussion in 'Java' started by Ulrich Scholz, Dec 6, 2005.

  1. Dear all,

    I have three ways of reading in a class in a dynamic way: Instantiating
    the class works with two of them, with the third this results in an
    exception:

    Exception in thread "main" java.lang.IllegalAccessError: tried to
    access class JSHOP2_Method0 from class domainpresentationplanner

    >From the class description, I cannot find out why defineClass does not

    work. The three ways are:

    // (1) does not work
    File file = new File(full_path_to_file,
    "domainpresentationplanner.class");
    classCode = getBytesFromFile(file);
    domainClass = defineClass("domainpresentationplanner", classCode, 0,
    classCode.length);
    domain = (Domain) domainClass.newInstance(); // the same in all three
    cases

    // (2) works
    domainClass = loadClass("domainpresentationplanner");
    domain = (Domain) domainClass.newInstance();

    // (3) works
    domainClass = Class.forName("domainpresentationplanner");
    domain = (Domain) domainClass.newInstance();


    getBytesFromFile is taken from
    http://javaalmanac.com/egs/java.io/File2ByteArray.html

    I should mention that domainpresentationplanner.java, the java file
    whose compilation produced domainpresentation.class, is comprised of
    several classes, one of them being JSHOP2_Method0. All resulting class
    files are in the same directory as domainpresentation.class.

    Why does version (1) not work but (2) and (3) do?

    Thank you, Uli
    Ulrich Scholz, Dec 6, 2005
    #1
    1. Advertising

  2. Ulrich Scholz

    oulan bator Guest

    Hi,

    defineClass is protected, then that means that your are overriding a
    ClassLoader.
    check then for the findClass() method (log calls)

    I don't known if this is a "simplified" version of your code, but
    that's not the usual way to dynamically load classes using define class

    BR
    oulan bator, Dec 6, 2005
    #2
    1. Advertising

  3. Ulrich Scholz schrieb:
    > I have three ways of reading in a class in a dynamic way: Instantiating
    > the class works with two of them, with the third this results in an
    > exception:
    >
    > Exception in thread "main" java.lang.IllegalAccessError: tried to
    > access class JSHOP2_Method0 from class domainpresentationplanner
    >
    >>From the class description, I cannot find out why defineClass does not

    > work. The three ways are:
    >
    > // (1) does not work
    > File file = new File(full_path_to_file,
    > "domainpresentationplanner.class");
    > classCode = getBytesFromFile(file);
    > domainClass = defineClass("domainpresentationplanner", classCode, 0,
    > classCode.length);
    > domain = (Domain) domainClass.newInstance(); // the same in all three
    > cases

    As described in
    <http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html> all
    the defineClass(...) methods are all declared protected. As such they
    can only be called from *within* ClassLoader and its subclasses.
    You would need to fiddle with defineClass(...) *only* if you write your
    own subclass of ClassLoader. You never call defineClass(...) from
    outside, but instead let it be called from inside the ClassLoader base
    class.
    >
    > // (2) works
    > domainClass = loadClass("domainpresentationplanner");
    > domain = (Domain) domainClass.newInstance();

    As described in
    <http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html#loadClass(java.lang.String)>
    ClassLoader's method loadClass(String) is called by the JVM to load
    classes. Therefore I think it is not meant to be used by applications
    (at least not by "normal" applications). Don't ask me why it is public,
    though. private would have been enough, because the JVM is able to call
    even private methods.
    >
    > // (3) works
    > domainClass = Class.forName("domainpresentationplanner");
    > domain = (Domain) domainClass.newInstance();

    Class.forName(String) and Class.forName(String,boolean,ClassLoader) is
    the most high-level method of your 3 ways, and therefore the most usual
    way to load classes. I would recommend to restrict your application to
    use only Class.forName, and try to avoid explicit calls to ClassLoader
    methods as much as you can.
    BTW: Class.forName(...) and newInstance() only work if the class is
    public and has a public no-argument constructor.
    >
    >
    > getBytesFromFile is taken from
    > http://javaalmanac.com/egs/java.io/File2ByteArray.html
    >
    > I should mention that domainpresentationplanner.java, the java file
    > whose compilation produced domainpresentation.class, is comprised of
    > several classes, one of them being JSHOP2_Method0. All resulting class
    > files are in the same directory as domainpresentation.class.
    >
    > Why does version (1) not work but (2) and (3) do?


    --
    "Thomas:Fritsch$ops:de".replace(':','.').replace('$','@')
    Thomas Fritsch, Dec 6, 2005
    #3
  4. > As described in
    > <http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html#lo...)>
    > ClassLoader's method loadClass(String) is called by the JVM to load
    > classes.


    I should have mentioned that I did try the three ways in a subclass of
    ClassLoader.
    Ulrich Scholz, Dec 6, 2005
    #4
  5. Ulrich Scholz

    Roedy Green Guest

    On 6 Dec 2005 08:30:56 -0800, "Ulrich Scholz" <> wrote,
    quoted or indirectly quoted someone who said :

    > domainClass = defineClass("domainpresentationplanner", classCode, 0,
    >classCode.length);

    I gather this code is hidden inside your own classloader? But you
    hard coded a name? I think we need to see more of your program to
    figure out what you did.
    --
    Canadian Mind Products, Roedy Green.
    http://mindprod.com Java custom programming, consulting and coaching.
    Roedy Green, Dec 6, 2005
    #5
  6. Ulrich Scholz

    Chris Smith Guest

    Ulrich Scholz <> wrote:
    > > As described in
    > > <http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ClassLoader.html#lo...)>
    > > ClassLoader's method loadClass(String) is called by the JVM to load
    > > classes.

    >
    > I should have mentioned that I did try the three ways in a subclass of
    > ClassLoader.


    Okay. The difference, then, is that Class.forName and
    ClassLoader.loadClass both use the normal class loading scheme.
    ClassLoader.defineClass skips that normal scheme and defines the class
    directly in this class loader.

    The normal scheme is to do the following:

    1. First, ask the parent class loader for the class.
    2. If the parent doesn't have it, load it in this class loader.
    3. If this class loader can't find it, throw an exception.

    So if you're seeing the behavior you describe, it must be because
    Class.forName and ClassLoader.loadClass are actually finding the class
    in the parent. However, defineClass doesn't look in the parent first,
    so it loads the class in the current class loader.

    So why does this cause IllegalAccessError? You're attempting to access
    a package-access class from its package. However, when your class
    domainpresentationplanner uses that other class, the other class *is*
    loaded by the default scheme described above, and ends up loaded from
    the parent class loader. So you end up with domainpresentationplanner
    loaded from one class loader, and JSHOP2_Method0 loaded from a different
    class loader. Even though their packages have the same name, a package
    can belong to one and only one class loader... so they are actually
    different packages. The package-access level doesn't permit this, and
    the error is thrown.

    Confused? You should be. Basically, you should never call defineClass
    in a class loader except in the following circumstances:

    A. You may call defineClass from findClass, if you are writing a class
    loader that respects the delegation model.

    B. You may call defineClass from loadClass(String,boolean) if you are
    writing a class loader that does *not* respect the delegation model.

    However, you *must* use delegation consistently throughout your class
    loader. Pick A or B, not both (and implement B consistently, if that's
    your choice).

    --
    www.designacourse.com
    The Easiest Way To Train Anyone... Anywhere.

    Chris Smith - Lead Software Developer/Technical Trainer
    MindIQ Corporation
    Chris Smith, Dec 7, 2005
    #6
  7. Roedy Green schreef:
    > On 6 Dec 2005 08:30:56 -0800, "Ulrich Scholz" <> wrote,
    > quoted or indirectly quoted someone who said :
    >
    >
    >>domainClass = defineClass("domainpresentationplanner", classCode, 0,
    >>classCode.length);

    >
    > I gather this code is hidden inside your own classloader? But you
    > hard coded a name? I think we need to see more of your program to
    > figure out what you did.


    And how about starting class names with an uppercase letter?

    H.

    --
    Hendrik Maryns

    ==================
    www.lieverleven.be
    http://aouw.org
    Hendrik Maryns, Dec 7, 2005
    #7
  8. Ulrich Scholz

    Chris Uppal Guest

    Ulrich Scholz wrote:

    > // (1) does not work
    > File file = new File(full_path_to_file,
    > "domainpresentationplanner.class");
    > classCode = getBytesFromFile(file);
    > domainClass = defineClass("domainpresentationplanner", classCode, 0,
    > classCode.length);
    > domain = (Domain) domainClass.newInstance(); // the same in all three
    > cases


    [This is only emphasing a point made in the other replies]

    You should not use defineClass() to create class objects /except/ as one
    private step in the overall process of loading a class (as controlled by the
    JVM). Application code should never create a class object that way, it should
    always use one of the forms of Class.forName().

    -- chris
    Chris Uppal, Dec 7, 2005
    #8
  9. > Application code should never create a class object [with defineClass()],

    OK, I agree

    > it should always use one of the forms of Class.forName().


    Here, I have my doubts. From my current (in the last two day constantly
    growing) knowledge about the class loading mechanism of Java (or, at
    least what I believe to know about it), it follows that I have to
    create new subclasses of ClassLoader because I dynamically create and
    use a class file of the same name. For each new version I need a
    different ClassLoader.

    As I need to write a sublcass of MyClassLoader ClassLoader anyway,
    where's the difference of using Class.forName/3 with an instance of
    MyClassLoader and of using MyClassLoader.loadClass/2 directly?

    Uli
    Ulrich Scholz, Dec 7, 2005
    #9
  10. Ulrich Scholz

    Chris Uppal Guest

    Ulrich Scholz wrote:

    > As I need to write a sublcass of MyClassLoader ClassLoader anyway,
    > where's the difference of using Class.forName/3 with an instance of
    > MyClassLoader and of using MyClassLoader.loadClass/2 directly?


    Calling loadClass() directly side-steps some of the stuff that the JVM does
    with the new class after it has been loaded and before it is returned by
    Class.forName(). E.g. try getting the class object for MyClass[];
    Class.forName("[LMyClass;", true, aClassloader)
    works (or whatever the exact String should be -- I can't remember off-hand) but
    trying the same thing via a classloader does not, since it is the JVM that
    "manages" array classes. There /may/ be other processing that it side-steps
    too, I don't know for sure, and the specs are not clear.

    -- chris
    Chris Uppal, Dec 7, 2005
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. jakk
    Replies:
    4
    Views:
    12,049
  2. learningjava
    Replies:
    1
    Views:
    528
    Anton Spaans
    Oct 27, 2003
  3. H.MuthuKumaraRajan

    .class and Class.forName

    H.MuthuKumaraRajan, Nov 6, 2003, in forum: Java
    Replies:
    11
    Views:
    1,713
    H.MuthuKumaraRajan
    Nov 7, 2003
  4. j pike
    Replies:
    4
    Views:
    767
    Chris Uppal
    Mar 3, 2004
  5. cyril
    Replies:
    2
    Views:
    3,836
    cyril
    Aug 25, 2004
Loading...

Share This Page