Consider the following two classes, defined in two source files:
Foo.java
public class Foo {
}
Bar.java
public class Bar {
Foo foo;
}
When we invoke javac Bar.java, the current directory now contains Foo.class and Bar.class.
I'd like to understand the exact steps that javac uses to determine that it needs to compile Foo.java when I ask it to compile Bar.java.
Could I get a pointer to the set of classes in the source code which implement the steps to infer the source files that a given source file depends on?
I've looked through the Java compiler API, as well as perused the source myself, but have so far been unsuccessful at finding what I seek, probably due to lack of familiarity.
I am continuing to read the source, but asking this question in case someone happens to be much more familiar with the javac source code and knows this already.
Related
Trying to compile a multi file package. Needing to compile via: javac mainfile.java while also compiling all the other (about 4 other .java files) at the same time through the one file? I have tried using statements like extend and import package.* Any help would be appreciated.
I have used different compiling methods and arguments but trying to do it just by only inserting javac mainfile.java and java mainfile
Summary: Trying to compile multiple java files at once, through java compiling a single file.
My current code for the main file:
package mypackage;
import mypackage.*;
public class mainfile{
public static void main(String[] args) {
Myfile.main(args) //run main from other file
}
}
Edit: Sorry for the lack of information, when compiling, the compiler returns:
MainFile.java:15: error: cannot find symbol
Myfile.main(args);
^
symbol: variable Myfile
location: class mainfile
1 error
javac as a tool does not do what you want. But, that's why other tools exist.
What you're asking for boils down to 'I want a build system'. The vast majority of java projects use maven or gradle.
It would seem like this works fine:
javac -sourcepath src src/mainfile.java
but you'd be deceived. That will merely compile all source files that are directly referenced by the code in mainfile.java, but there are many other ways to refer to code, such as SPI, reflection, XML config files. The vast majority of java projects will end up using some construct that ends up 'breaking' the -sourcepath "trick" sooner rather than later, which is presumably why all java projects use a build system instead of relying on -sourcepath.
Note that all source files act as if they have:
import java.lang.*;
import yourownpackage.*;
at the top, whether you write this out or not. And, import is java-ese for 'alias'. import foo.bar.Baz; means: Whenever 'Baz' appears in this file as a type, assume I meant to write 'foo.bar.Baz', and that is all: import foo.bar.Baz does not run any code that is in the Baz class whatsoever. If you don't use Baz, then the class file produced doesn't mention Baz at all. This will also not cause javac to then compile your entire directory.
File name: B.java
public class B
{
public static void main(String[] args){}
}
public class A{}
java B.java runs without error
javac B.java gives a compile error: class A needs to be declared in a file A.java
I understand that a java file can not have more than one public class, but why can a java file run without error using the java command when you get compile errors for the code using javac?
Java-11+ allows launching Single-File Source-Code programs without compiling. You can learn more about it from this article. As per the specification, if the first class in the file has main, it executes the same without caring for other public classes in the file. Thus, if you change the order of classes in the file and try java B.java, it will fail.
My guess, and it is only a guess since I haven't used Java 11 extensively, is that:
The "javac" command produces class files that can be combined into a large program, and thus there could be multiple references to class A "elsewhere" in the program. It is this generality that produces the restriction on one public class per source file (though frankly I don't see why compiling B.java cannot result in A.class and B.class)
The "java" command processes a single source file. From that point of view it is irrelevant whether A is public or not; A can be used from within the single file (same package!) in any case.
I know I can include a class or collection of classes in my Java project using the import statement.
For example, import java.io.utils.* imports (i.e. makes available for use in my Java program) all the classes in the java.io.utils package.
My question is, do the classes in an imported package need to be compiled? Or can packages also include uncompiled Java files? If it can be either, when can we use class files and when can we use Java files?
Import just means "make the imported classes available by their simple names" - you can remove imports entirely if you use fully-qualified names everywhere. It's definitely not like #include in C for example.
When you compile, if you try to refer to uncompiled code it will be compiled at that point, assuming the compiler can guess where to find the source code. The result never refers to uncompiled code, because the compiler needs to know what each type exposes.
As a complete example, construct the following file structure:
// src/foo/A.java
package foo;
import bar.*;
public class A {
public static void main(String[] args) {
B.sayHello();
}
}
// src/bar/B.java
package bar;
public class B {
public static void sayHello() {
System.out.println("Hello");
}
}
Then in the src directory, run:
javac foo/A.java
That will automatically compile bar/B.java - but wouldn't compile any other code that isn't referenced (potentially transitively).
I would strongly recommend against using this "compile on demand" behaviour anyway though - if you compile class A that depends on class B, it will compile B the first time, but after that if you change B and recompile A, the compiler won't recompile B. I would organize your code into appropriate projects, and always recompile a complete project at a time, adding a project's output directory to the classpath for a project that depends on it, rather than allowing compiling one project to recompile bits of another on demand.
(Note that this isn't talking about the incremental compilation that many IDEs support... that's a rather different matter, and is fine assuming it's been implemented properly.)
Unlike C, import in Java does not "copy" stuff. Packages in Java is simply a way of avoiding ambiguity. javax.swing.Timer and java.utils.Timer are different Timers. When you say import javax.swing.Timer, you are telling the compiler that you mean javax.swing.Timer, not any other Timer.
All these things that you can import comes from the JDK or some other libraries you're using, or they are created by you. The classes that fall into the former category is already compiled (.class). The classes you created are compiled as well, when you do javac. You can't refer to any uncompiled classes. Since they are uncompiled, the computer does not know they exist.
The reason why your IDE knows your packages and classes before you compile your code is because IDEs are smart. They compile your code before you even notice it.
As Java documentation reports.
You might have to set your CLASSPATH so that the compiler and the JVM can find the .class files for your types.
link: https://docs.oracle.com/javase/tutorial/java/package/summary-package.html
I am taking a java programming class right now and it is my first real programming experience (although i have done some programming before). for the class i have to use jEdit to write programs, and terminal to compile and run them (i have a mac, and programs that automatically compile, run, and debug programs are banned for educational purposes). things were going very well for me at first, but a few days ago, terminal stopped overwriting the .class files on my QuickSort program when i try to compile it. i change the code so that it will look completely different when it runs, but after i compile and run it, there is no change. however, if i delete the .class files before i recompile, the changes are implemented next time i run it. neither me nor my teacher have been able to find any info on this problem or how to fix it (the exact same thing did happen to a classmate of mine three days before it happened to me, and we are the only mac users in the class). if anyone knows what the problem is, how to fix it, or where i can find someone who does know how to fix it, i would really appreciate it. deleting five .class files every time i compile my program is a huge pain and has already led to some serious problems for me. thank you so much for all of your help!
*edit: i am running mac os x 10.8.5
The compiler isn't smart enough about detecting which class files are out of date, so either manually tell it to recompile everything using javac *.java or use a build tool such as Ant.
The reason the compiler doesn't recompile all of the classes is that it tries to be 'smart' and avoid unnecessary work by only recompiling files that changed. If a .class file is newer than the matching .java file, the source code hasn't changed since the previous compilation so the class isn't recompiled.
This can cause problems when there are multiple files with a chain of dependencies. Consider this simple example:
// file: A.java
public class A { public static void main(String[] args) { new B().run(); } }
// file: B.java
public class B { void run() { new C().run(); } }
// file: C.java
public class C { void run() { System.out.println("hello world"); } }
When A is compiled for the first time, the compiler sees that it references B, which in turn references C. All three are compiled and all is well.
If B.java is modified and A is recompiled, the compiler sees that A references B and since B.java is newer than B.class it is recompiled. It doesn't recompile C because C.java hasn't changed. All is still well.
But if C.java is modified and A is recompiled the compiler sees that A depends on B, but since B.java hasn't changed it is not recompiled. So the compiler never gets to C and doesn't recompile it even though C.java has changed.
I'm not sure what is going wrong here. I have to write a Tetris program based off of a Skeleton given by my teacher for school. The current class that I am implmenting is called "TetrisPiece" and the abstract class being extended is called "Piece." For some reason I cannot compile my code because it cannot located the Piece class.
I have Piece.java and TetrisPiece.java in the same folder. The structure is:
/src
/TetrisPiece.java
/Piece.java
/Piece.class
I type
javac Piece.java
and it compiles correctly, then I type
javac -cp . TetrisPiece.java
and it results in a compiler error (I have to type -cp . because I messed up my classpath somehow and Java can't find the current directory). I looked through a couple similar StackOverflow Questions and they did not have an answer to this. If the information I provide is not detailed enough (which I assume it isn't) please tell me what else I should provide to give an adequate answer.
You need to compile the files at the same time:
javac Piece.java TetrisPiece.java
Then, assuming TetrisPiece has a main() method, you can run the program with:
java TetrisPiece