Algumas considerações que fazendo testes eu cheguei:
(pode ser óbvio mas não sabia disso)
Considerando a estrutura:
/home/
secreto/
java/
testes/ //---> testes é raiz para app e util
app/
SomeApp.java
util/
BitUtils.java
A) Comando-> javac:
* Não leva em consideração se tem ou não package declarado na classe;
* se tiver a opção "-d" junto ao classpath, o package poderá ser usado;
* O classpath não serve para localizar a classe a ser COMPILADA;
* O classpath na linha de comando/ambiente serve para informar onde estão as classes que SomeApp vai precisar;
* o pacote declarado na instrução import é usado pelo classpath para encontrar classes que a Classe a ser compilada irá precisar;
Situação 1: SomeApp não depende de outra classe:
package app; //para javac package não tem relevância
public class SomeApp
{
public static void main(String [] args){}
}
Neste caso é possível fazer algo como:
javac SomeApp.java; //executado em app
javac /home/secreto/java/testes/app/SomeApp.java //de qualquer diretório pois o caminho é absoluto
Situação 2: SomeApp depende de util.BitUtils:
* o classpath tem que conter o caminho até o diretório raiz do pacote util, que neste caso é testes para que possa localizar util e depois a classe BitUtis
package app; //para javac package não tem relevância
public class SomeApp
{
public static void main(String [] args){
byte[] bytes = new byte[256];
util.BitUtils.process(bytes); //javac precisa encontrar (via classpath) a classe util.BitUtils
}
}
Neste caso o classpath de linha de comando/ambiente deverá conter o caminho até a classe
util.BitUtils
javac /home/secreto/java/testes/app/SomeApp.java //erro, javac não encontra util.BitUtils
javac -cp . /home/secreto/java/testes/app/SomeApp.java //erro se executar dentro de util, dentro de teste funciona (. é o diretório atual)
Mas informando ao classPath onde util.BitUtils se encontra o código funcionará:
javac -cp ../. /home/secreto/java/testes/app/SomeApp.java // executando dentro de util ou app
javac -cp . /home/secreto/java/testes/app/SomeApp.java // executando dentro de testes
B) Comando-> java:
* Leva em consideração se tem package declarado na classe, e deve usar nomeDoPacote.NomeDaClasse
* O classpath na linha de comando/ambiente serve para informar onde estão a raiz dos pacotes que SomeApp vai precisar
Situação 1: classe a ser executada não tiver a instrução package e não usar nenhuma outra classe:
pode-se executar a classe diretamente no diretório que a classe.class se encontra:
Situação 2: classe a ser executada tiver a instrução package
package app; //para java package tem relevância
public class SomeApp
{
public static void main(String [] args){
byte[] bytes = new byte[256];
util.BitUtils.process(bytes); //java precisa encontrar (via classpath) a classe util.BitUtils
}
}
- Tentar executar essa classe no diretório
app dessa forma:
Dá exeção
SomeApp java.lang.NoClassDefFoundError: SomeApp (wrong name: app/SomeApp)
Então como executar?
Para executar a classe em app é obrigatório:
1º) incluir o classpath até o diretório raiz do pacote (testes)
2º) incluir o nome da classe: Atenção o nome da classe não é SomeApp. Deve incluir o package assim: app.SomeApp
retorna ao diretório anterior (raiz do pacote) e inclui o nome da classe
java -cp .. app.SomeApp //executando em app (.. volta para testes)
caminho absoluto até a raiz do pacote e nome da classe
java -cp /home/secreto/java/testes/ app.SomeApp //executando de qualquer local pois o caminho é absoluto até a raiz do pacote
Incluir o caminho absoluto até
app não funciona:
java -cp /home/secreto/java/testes/app SomeApp //app não é raiz do pacote app
ou
java -cp /home/secreto/java/testes/app app.SomeApp //app não é raiz do pacote app
* o classpath tem que ser até o diretório raiz do pacote, que neste caso é testes e incluir o nome da classe app.SomeApp
E se SomeApp dependesse de outra classe?
/home/
secreto/
java/ // ---> java é raiz para testes
testes/ //---> testes é raiz para app e util
OtherTestes.java
app/
SomeApp.java
util/
BitUtils.java
package app; //para java package tem relevância
public class SomeApp
{
public static void main(String [] args){
byte[] bytes = new byte[256];
util.BitUtils.process(bytes); //java precisa encontrar (via classpath) a classe util.BitUtils
testes.OtherTestes.other(); //java precisa encontrar (via classpath) a classe testes.OtherTestes
}
}
Para javac:
*Agora javac terá que encontrar através do classpath tanto util.BitUtils quanto testes.OtherTestes
javac -cp ../.:../../. /home/secreto/java/testes/app/SomeApp.java // funciona
Para java
java -cp ../;../../ app.SomeApp //executando em app
../ : localiza a raiz de
util.BitUtils que é
testes
../../ : localiza a raiz de
testes.OtherTestes que é
java
java -cp ../;. app.SomeApp //executando em testes
../ : localiza a raiz de
testes.OtherTestes que é
java
. : localiza a raiz de
util.BitUtils que é
testes (já estamos em
testes então
. informa que é o diretório atual)
Bom foi assim que eu entendi.
Pode haver algum erro de conceito mas pra mim ficou claro dessa forma.
Abraços.