Why does `javac -cp` not need `.`, while `java -cp` does?
Asked Answered
B

2

7

I have two questions:

Why does javac -cp not need .?

$ javac -cp /home/t/programs/java/test/junit-4.11.jar TestCase.java

Why does java -cp need .?

$ java -cp /home/t/programs/java/test/junit-4.11.jar:/home/t/programs/java/test/hamcrest-core-1.3.jar org.junit.runner.JUnitCore TestCase
JUnit version 4.11
Could not find class: TestCase

Time: 0.002

OK (0 tests)

$ java -cp .:/home/t/programs/java/test/junit-4.11.jar:/home/t/programs/java/test/hamcrest-core-1.3.jar org.junit.runner.JUnitCore TestCase
JUnit version 4.11
.running TestCase test1
.running TestCase test2

Time: 0.023

OK (2 tests)

TestCase.java:

import static org.junit.Assert.*;
import org.junit.Test;

// define a test case class, whose instances represent test cases
public class TestCase {

  @Test
  public void test1() {
      System.out.println("running TestCase test1");
      assertTrue(true);
  }

  @Test
  public void test2() {
      System.out.println("running TestCase test2");
      assertTrue(true);      
  }

}
Boynton answered 11/4, 2019 at 12:44 Comment(2)
This is zero percent of a real answer, but: Java 1 was a rush job, and they got some stuff wrong. It wouldn't surprise me if this inconsistency was just a thing they either didn't notice, or wasn't a high priority fix. And then once it's out, they didn't want to change it.Socorrosocotra
@Socorrosocotra No, it is perfectly consistent, it's just that the reasons aren't very well explained. Or indeed at all.Mightily
M
7

Because javac handles files, java handles fully qualified class names.

EDIT

To expand a bit, when you're compiling, you're passing the files you want to compile directly to javac, so the classpath is only meant to contain the packages you need to compile the files you're passing in as argument. That is, the file you're compiling doesn't need to be in the classpath.

On the other hand, when you're executing with java, you're telling the JVM "run this class from the classpath". Granted, the default classpath is .. But then you decided to specify a custom classpath with -cp, which does not add to the classpath, but ovverides it. So you have to add it back explicitly.

See the last section of the official tutorial for confirmation.

Mascle answered 11/4, 2019 at 12:48 Comment(1)
it's not correct to say handles packages and classes, a more correct way would be handles fully qualified class namesUnship
L
1

. being part of the compiler's classpath is the result of a couple of things happening implicitly. In order to be able to compile, generated classes referenced in other classes need to be accessible via classpath. So the compiler adds the class-file-destination path to the classpath. If you don't provide anything in particular, that directory is the source-directory. If you don't provide that specifically the process' working directory is used which is by default ..

Calling javac -help shows you the different possible settings:

"c:\Program Files\Java\jdk1.8.0_181\bin\javac.exe" -help
Usage: javac <options> <source files>
where possible options include:
  -g                         Generate all debugging info
  -g:none                    Generate no debugging info
  -g:{lines,vars,source}     Generate only some debugging info
  -nowarn                    Generate no warnings
  -verbose                   Output messages about what the compiler is doing
  -deprecation               Output source locations where deprecated APIs are used
  -classpath <path>          Specify where to find user class files and annotation processors
  -cp <path>                 Specify where to find user class files and annotation processors
  -sourcepath <path>         Specify where to find input source files
  -bootclasspath <path>      Override location of bootstrap class files
  -extdirs <dirs>            Override location of installed extensions
  -endorseddirs <dirs>       Override location of endorsed standards path
  -proc:{none,only}          Control whether annotation processing and/or compilation is done.
  -processor <class1>[,<class2>,<class3>...] Names of the annotation processors to run; bypasses default discovery process
  -processorpath <path>      Specify where to find annotation processors
  -parameters                Generate metadata for reflection on method parameters
  -d <directory>             Specify where to place generated class files
  -s <directory>             Specify where to place generated source files
  -h <directory>             Specify where to place generated native header files
  -implicit:{none,class}     Specify whether or not to generate class files for implicitly referenced files
  -encoding <encoding>       Specify character encoding used by source files
  -source <release>          Provide source compatibility with specified release
  -target <release>          Generate class files for specific VM version
  -profile <profile>         Check that API used is available in the specified profile
  -version                   Version information
  -help                      Print a synopsis of standard options
  -Akey[=value]              Options to pass to annotation processors
  -X                         Print a synopsis of nonstandard options
  -J<flag>                   Pass <flag> directly to the runtime system
  -Werror                    Terminate compilation if warnings occur
  @<filename>                Read options and filenames from file

The options I referred to are -s and -sourcepath. -cp is used to define additional locations (directories and library files) where the compiler can look for already compiled classes. That's also the meaning of -cp when calling java, so there is no contradiction between these two executables.

Lieu answered 11/4, 2019 at 13:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.