3

Javac was successfully re-compiling all my classes, except one, a class I had called "Box.java". Javac would compile it if specifically asked: javac Box.java, but not as part of a re-compile of the whole project.

  1. Am I right in thinking that this is because there is, it turns out, a class called "Box" (part of Swing I believe, and I am using Swing generally elsewhere)? The problem seems to have gone away by renaming my class (and associated methods etc.) "DecisionBox.java".

  2. If that's right, what's the best way of avoiding in future. I can find a list of Java reserved words fairly easily, but reserved classes....? Just search the JavaDocs? Or would an IDE spot this error?

I only ask because with no error messages it took ages to track down that a class wasn't being recompiled...

4
  • One of the reasons you would get a name duplication like this is if the package name space AND the class name are the same with something else that already exists... Commented Nov 19, 2013 at 23:12
  • 1
    what happens if you do a clean build, i.e. delete all class files then recompile? Commented Nov 19, 2013 at 23:14
  • what is the package of the class, and is the java file in the correct directory corresponding to the package? Commented Nov 19, 2013 at 23:15
  • 1
    Your scenario is exactly why "Packages" were invented. Commented Nov 19, 2013 at 23:30

1 Answer 1

2

It depends a bit on how you are compiling your whole project, and how your other source files use Box.

The Java compiler will automatically compile dependencies. It's not a problem that you have a class named Box that is the same name as javax.swing.Box, because the package names are used to differentiate.

However, it's possible, for example, that none of the other classes you are compiling are referring to your Box. For example, if you import javax.swing.* everywhere, and then just use Box, the class could very well be using javax.swing.Box. If the compiler can always resolve Box to javax.swing.Box, it has no reason to compile your Box, because as far as its concerned, you never use it.

If you are using the default package (i.e. no package) for your source files this can encourage potential confusion even more. You want to stay organized and be as explicit as possible about packages. Using the default package means you can't explicitly qualify your own class's names.

To be sure, make sure you are importing specific classes from packages instead of javax.swing.*, and if you need to use both your Box and javax.swing.Box in the same source file, explicitly specify the package names.

In other words, it sounds like the compiler is, at some point, not seeing that your Box is the one your classes are using -- and explicit imports and use of fully qualified package names can eliminate that confusion.

One experiment you can try is to delete all your compiled .class files, then recompile your project. If Box.java is never compiled, that is a hint that you may not actually be using it even though you think you are.

Fundamentally, if anything, this is a good case for not using wildcard package imports. By always explicitly importing the classes you are using, you significantly reduce the chance of the compiler making incorrect assumptions about your intentions. This (and, to a lesser extent, not using the default package) is the best way to avoid this situation in the future.

Update, based on new info in comments: The OP has a relation graph like:

 FirstClass
     Topic
         Boat
         DecisionBox

The reason Boat/DecisionBox don't get recompiled when they are modified is that Topic hasn't changed. So when you recompile FirstClass, it checks Topic. Topic doesn't need recompiled, and so Topic's dependencies aren't checked. If FirstClass referred directly to Boat (even e.g. Topic.getBoat()) then Boat would be recompiled. It's a shortcoming of javac's very basic dependency walking. Either delete all .class before recompiling, or you could use some other build system like ant (where you can specify dependencies) or your IDE's internal system (e.g. most IDE's will magically take care of this for you, although it is certainly nice to learn the command line interface, in practice you rarely use it without a supplementary build system).


Another possibility, by the way, although this is far less likely, is some incorrect timestamp on your Box.java or compiled Box.class that causes the compiler to think it didn't change, and thus doesn't need recompiled. It will only recompile the file if the timestamp on the .java file is newer than the .class file, or the .class doesn't exist.

Sign up to request clarification or add additional context in comments.

6 Comments

hmm... javac should compile a java file even if the class is not referenced from other java files.
@zhong.j.yu Only if you explicitly specify that file, i.e. actually do javac Box.java. That's why I said it depends on how the project is being compiled -- the assumption is that the OP is only directly compiling certain interesting classes (e.g. perhaps ones with main in them or something) and letting the compiler compile dependencies on its own. This is the right thing to do. javac does not arbitrarily search for and compile .java files. It only compiles a file if either a) you explicitly tell it to, or b) it is referenced from another source file.
Thanks for this full answer - my main class imported swing, so that makes sense. And also why I got no error message. I'm going to confess that I hadn't got to packages in the book yet! And of course, now I know where to look I see "Packages prevent name class conflicts"... well that's embarrassing :O Still, an error message might have helped me. Thanks again.
@DavidG-user3010867 Well, unfortunately, unless your Box isn't source-compatible with javax.swing.Box (e.g. you declare some custom methods and call them, or other things), which could cause the compiler to say, e.g. "javax.swing.Box has no method named x", the compiler can't really know that you meant something else, because a javax.swing.Box looks perfectly fine to it. Check out docs.oracle.com/javase/tutorial/java/package -- the concepts are very straightforward.
DecisionBox didn't fix it after all. I have a class with a main method (call it FirstClass). FirstClass creates new object Topic.java. Topic.java creates new objects from DecisionBox.java and Boat.java. All files are in the same dir, and each class will compile if specifically requested e.g. "Javac DecisionBox.java". But neither DecisionBox or Boat will recompile if I make a change to them AND just compile referencing FirstClass. But the JVM will happily run the obsolete classes ok. DecisionBox and Boat will recompile if I delete the classes OR make any change to Topic.java. Thoughts?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.