Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / June 2006

Tip: Looking for answers? Try searching our database.

Repercussions of changing single class in large project?

Thread view: 
Andy Dingley <dingbat@codesmiths.com> - 28 Jun 2006 10:26 GMT
I have a large project - several hundreds of classes.  If a single
.java file is changed, then obviously the compiled class is changed
too. However I'm not sure how many other classes would be affected by
this and would also change when recompiled.

By "will change", I'm thinking of a pragmatic meaning here, somewhere
between "the bytecode will be different" and "the program will be in
error if you mix the compiled classes by deploying too few class
files". I'm not interested in changes that merely cause recompilation,
only the end result.

What changes to source would cause dependent classes to change?  Is it
as simple as "anything in a signature, nothing outside a signature" ?

Does the way in which a class is imported affect that dependent class'
sensitivity to changes ?

Are these changes transitive?  If A depends on B which depends on C,
will changing C "significantly" also cause A to change ?

I appreciate this is a potentially complex question. If there are any
simple rules that can be applied, I'd love to hear them.

Thanks
Chris Uppal - 28 Jun 2006 12:35 GMT
dingbat@codesmiths.com wrote:

> What changes to source would cause dependent classes to change?

As far as I know, the contents of one classfile -- as produced by the
compiler -- are independent of the source (or classfile) for any other class,
with the following exceptions:

Obviously the faked-up relationship between inner and outer classes is tighter,
but that shouldn't be an issue here.

Numeric, boolean, and String fields (including non-static fields) which are
declared to be final, and initialised to a compile-time constant, are inlined
whereever they are referred to in any [other] class.  Hence, if you change the
values, then you must recompile the classes which use them.

There is only one circumstance where changes can propogate transitively --
that's when one class uses another class's constants to define its own.  E.g:
   public class A {  public static int X = 1; }
   public class B {  public static int Y = A.Y * 10; }
   public class C {  public static int Z = B.X * 10; }
In the above case, changing A.X means that classes B /and/ C have be
recompiled.

The Java compiler does a great deal of early binding -- it checks that methods
and fields exist in other classes (and that they are accessible, etc) before it
will let you use them.  So, clearly, removing a member could cause another
class to become uncompilable.  (Come to that, so can removing a class ;-)
Changing the class tree in a way that changes a class's total set of methods
and fields (including inherited ones) counts as adding or removing for these
purposes.

A more subtle, but related, point is that if you add or remove overloaded
methods, then the compiler might change it's mind about how to resolve an
overloaded method call.  E.g. if you have in V1 of your class:
   public class XYZ
   {
       public void aMethod(int i) { .... }
   }
and a caller in another class:
   xyz.aMethod('a');
then the compiler will statically resolve that call to invoke the (possibly
overriden) aMethod(int).  If you now add an overload to XYZ
   public class XYZ
   {
       public void aMethod(int i) { .... }
       public void aMethod(char c) { .... }
   }
and recompile /without/ recompiling the caller, then it will still call
aMethod(int).  If you now recompile the caller, then the static part of method
resolution will now see the new method as a better match for the parameter, so
it will generate code to invoke aMethod(char) instead.

============

Some examples of changes which do not propogate to other classfiles:

Changes to the bodies of methods in one class do not result in changes to any
other classfile.  Adding or removing members (fields, methods, nested classes)
does not result in changes to any other classfile unless it refers to those
specific members.  Re-ordering members does not result in changes to any other
classfile even if it /does/ use those members.

An example of where a fairly drastic change to one class doesn't cause changes
to another class's compiled form.  If we start with XYZ in its first form
above, and compile
   xyz.aMethod(0);
against it, then we'll get a certain compiled form for the caller.  If we now
refactor XYZ into
   class ABC
   {
       public void aMethod(int i) { .... }
   }
   public class XYZ
   extends ABC
   {
   }
and recompile the caller, then we'll get exactly the same compiled form as
before.

   -- chris
ddimitrov - 28 Jun 2006 13:20 GMT
> Numeric, boolean, and String fields (including non-static fields) which are
> declared to be final, and initialised to a compile-time constant, are inlined
> whereever they are referred to in any [other] class.  Hence, if you change the
> values, then you must recompile the classes which use them.

Just to add that since Java 1.5, the classfile format supports
java.lang.Class literals as well.

This means that if you have the following code:

interface ReflectionConfiguration {
Class<FooService> fooImplementation = FooServiceImpl.class;
}

class Client {
public static void main(String[] args) {
  FooService foo =
ReflectionConfiguration.fooImplementation.newInstance();
  foo.doSomething();
}
}

And then swap the fooImplementation to point to different class, the
change will be picked by the Client class if you use Java 1.4, but
won't be picked by 1.5 (unless you compile with -target 1.4).

This example is stupid, but in practice it happens.
Chris Uppal - 29 Jun 2006 13:41 GMT
> interface ReflectionConfiguration {
> Class<FooService> fooImplementation = FooServiceImpl.class;
[quoted text clipped - 11 lines]
> change will be picked by the Client class if you use Java 1.4, but
> won't be picked by 1.5 (unless you compile with -target 1.4).

I'm sorry but I don't understand what you mean.

I /thought/ you meant that class literals were treated like final compile-time
constants an inlined at the point of reference, which is plausible -- but very
nasty if true ;-)  But (I'm happy to say) that doesn't seem to be the case.
E.g:

========================
public class Constants
{
static final int A = 22;
static final Class C = String.class;
}
========================
public class Test
{
public static void
main(String[] args)
{
 System.out.println(Constants.A);
 System.out.println(Constants.C);
}
}
========================

In the first call to println(), the constant A is replaced by its value in the
generated bytecode:

   getstatic java/lang/System/out Ljava/io/PrintStream;
   bipush 22
   invokevirtual java/io/PrintStream/println (I)V

but the reference to the "constant" C is not:

getstatic java/lang/System/out Ljava/io/PrintStream;
getstatic Constants/C Ljava/lang/Class;
invokevirtual java/io/PrintStream/println (Ljava/lang/Object;)V

So if Constants.java is recompiled with a different vaue for C, Test.java does
not have to be recompiled to pick that up.  (That's using javac from Sun's
1.5.0_06-b05.)

   -- chris
ddimitrov - 29 Jun 2006 15:04 GMT
It seems that I was wrong about my assumptions for the class literals.

The actual problem that I've seen is that a class does not get
initilized on it's first reference under java 1.5

This is illustrated by the following snippet:

public class Test {
   public static void main(String[] args) {
       System.out.println("showing " + SomeClass.class);
   }
}

class SomeClass {
   static { System.out.print("loading and "); }
}

If we use JDK 5, the following commands produce the respective output:

>> javac *.java
>> java Test
showing class SomeClass

>> javac -source 1.4 *.java
>> java Test
loading and showing class SomeClass
Chris Uppal - 30 Jun 2006 10:42 GMT
> The actual problem that I've seen is that a class does not get
> initilized on it's first reference under java 1.5

Or even -- to judge from your example -- when its java.lang.Class object is
used (its toString() is invoked).

Personally, I find that distasteful...

   -- chris


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.