Exercício: A classpath Java Introdução: O objetivo deste laboratório é demonstrar o conceito da classpath Java e de como ela afeta a compilação e execução dos programas Java. A classpath é provavelmente o conceito mais básico que você terá de entender. O conceito é, no entanto, essencial. Basicamente, a classpath é o local onde residem os arquivos *.class. Se a variável de ambiente classpath não for preenchida corretamente, você obterá o famoso erro “java.lang.NoClassDefFoundError: <nome do arquivo *.class>. Exercício 1: Experimentos com a classpath usando o programa Alo em linha de comando Faça este exercício em linha de comando (uma janela em modo console). Neste exercício você experimentará a classpath com um programa simples contendo uma única classe. (1.0) Compile e rode o programa Alo usando “javac” e “java” em linha de comando 1. Crie um diretório onde você salvará seus programas Java (fizemos algo semelhante em um laboratório anterior) C:\> mkdir c:\meusprogramasjava C:\> cd \meusprogramasjava 2. Usando o notepad escreva o programa Alo.java a seguir e salve-o no diretório C:\meusprogramasjava 3. Compile o arquivo Alo.java usando o compilador javac. O compilador javac vem com o J2SE SDK que você baixou. Ele fica no diretório %JAVA_HOME%\bin. O resultado da compilação será a criação do arquivo Alo.class. 4. Assegure-se de que o arquivo Alo.class tenha sido criado. O arquivo Alo.class contém a representação em bytecodes da classe Alo. 5. Execute o programa Alo usando o comando java (1.1) Exercício: rodando um programa com a opção “-classpath” ou “-cp” As opções –classpath ou –cp especificam a localização onde os arquivos *.class (neste exemplo temos somente um único arquivo chamado Alo.class) estão localizados. Quando você não usa a opção -classpath, o interpretador Java tenta encontrar os arquivos *.class nos diretórios especificados na variável de ambiente CLASSPATH ou no diretório corrente. Na realidade, o interpretador Java tenta encontrar os arquivos *.class na seguinte ordem: Nos diretórios que você especificou com a opção -classpath ou -cp Nos diretórios especificados na variável de ambiente CLASSPATH (se você não usou as opções -classpath ou -cp) No diretório corrente (se você não usou as opções -classpath ou -cp e a variável de ambiente CLASSPATH não foi criada) 1. Rode o programa Alo usando o comando java com a opção -cp . (existe um ponto depois do -cp) ou com a opção -classpath . (existe um ponto depois do -classpath). 2. Execute o programa com o comando java -classpath .. Alo para ver se ele ainda funciona (ao invés de um único ponto, usamos dois pontos entre o -classpath e o Alo. Os dois pontos .. indicam o diretório pai do diretório corrente, C: neste exemplo, enquanto que um único ponto . indica o diretório corrente, C:\meusprogramasjava neste exemplo). A tentativa de executar o programa deve resultar no erro mostrado a seguir. Isto aconteceu porque você configurou a classpath para apontar para o diretório raiz, C:\, o qual não contém o arquivo Alo.class 3. Mova agora o arquivo Alo.class para o diretório raiz e tente novamente o comando anterior. Você deverá obter o resultado a seguir. Tente entender os resultados obtidos. 4. Você pode especificar múltiplos diretórios com as opções -cp ou -classpath (funcionará se o arquivo Alo.class for encontrado em um desses três diretórios) (1.2) Usando a variável de ambiente CLASSPATH Você pode configurar a classpath através da variável de ambiente CLASSPATH. Dessa forma, a classpath adquire um escopo global, isto é, ela é aplicada a todos os programas Java rodando nesta plataforma. Você pode sobrescrever a classpath global com as opções -classpath or -cp quando você roda um programa específico. 1. Configure a variável de ambiente CLASSPATH para apontar para o diretório contendo o arquivo Alo.class e então rode o programa. C:\meusprogramasjava>set CLASSPATH=c:\meusprogramasjava (configura a variável de ambiente CLASSPATH) C:\meusprogramasjava>java Alo Exception in thread "main" java.lang.NoClassDefFoundError: Alo (Erro: o arquivo Alo.class não está mais neste diretório uma vez que você o moveu para a raiz no passo anterior) C:\meusprogramasjava>move ..\Alo.class . (move novamente o arquivo Alo.class para o diretório corrente) C:\meusprogramasjava>java Alo Alo mundo 2. Configure a variável de ambiente CLASSPATH para apontar para um diretório qualquer e rode novamente o programa. C:\meusprogramasjava>set CLASSPATH=c:\tmp (configura a variável de ambiente CLASSPATH para apontar para um diretório qualquer, c:\tmp) C:\meusprogramasjava>java Alo Exception in thread "main" java.lang.NoClassDefFoundError: Alo (erro porque o diretório c:\tmp não contém o arquivo Alo.class) C:\meusprogramasjava>java -cp . Alo Alo mundo (sobrescreve a variável de ambiente com sua própria classpath) 3. Configure a variável de ambiente CLASSPATH para apontar para uma lista de diretórios e rode novamente o programa. C:\meusprogramasjava>set CLASSPATH=c:\tmp;c:\meusprogramasjava (procura em cada diretório na seqüência especificada) C:\meusprogramasjava>java Alo Alo mundo (funciona, uma vez que o arquivo Alo.class está no diretório c:\meusprogramasjava) Resumo Neste exercício você aprendeu como usar as opções -classpath e -cp e como configurar e usar a variável de ambiente CLASSPATH Exercício 2: Experimentos com a classpath usando as classes Estudante e Cliente em linha de comando Faça este exercício em linha de comando (uma janela em modo console). Neste exercício você experimentará a classpath com as classes Estudante e Cliente primeiro sem uma declaração de pacote e depois usando pacotes. Observe que um dos benefícios de usar uma IDE é que a IDE toma conta de todas as questões referentes à classpath de modo que você não tem de se preocupar com isso. (2.1) Escreva as classes Estudante.java e Cliente.java sem usar o comando package 1. Escreva o arquivo Estudante.java usando o Notepad. Salve-o no diretório C:\meusprogramasjava 2. Escreva o arquivo Cliente.java usando o Notepad. Salve-o também no diretório C:\meusprogramasjava 3. Apague os arquivos *.class criados anteriormente de modo que possamos começar do zero. C:\meusprogramasjava>del *.class (apaga todos os arquivos com a extensão class) 4. Compila os dois arquivos com javac C:\meusprogramasjava>javac Estudante.java Cliente.java C:\meusprogramasjava>dir *.class Volume in drive C is ACER Volume Serial Number is 4424-9D24 Directory of C:\meusprogramasjava 05/04/2007 05/04/2007 18:57 934 Cliente.class 18:57 796 Estudante.class 2 File(s) 1.730 bytes 0 Dir(s) 11.655.606.272 bytes free 5. Rode o programa C:\meusprogramasjava>java -cp . Cliente Nome = Ana Numero de Estudantes = 3 (2.2) Adicione um comando package às classes Estudante.java e Cliente.java 1. Modifique o arquivo Estudante.java como mostrado a seguir. A modificação consiste em adicionar o comando package no início do arquivo. 2. Modifique o arquivo Cliente.java como mostrado a seguir. A modificação consiste em adicionar o comando package no início do arquivo. 3. Apague os arquivos *.class criados anteriormente de modo que possamos começar do zero. C:\meusprogramasjava>del *.class (apaga todos os arquivos com a extensão class) 4. Compila os dois arquivos com javac C:\meusprogramasjava>javac Estudante.java Cliente.java C:\meusprogramasjava>dir *.class Volume in drive C is ACER Volume Serial Number is 4424-9D24 Directory of C:\meusprogramasjava 05/04/2007 05/04/2007 18:57 934 Cliente.class 18:57 796 Estudante.class 2 File(s) 1.730 bytes 0 Dir(s) 11.655.606.272 bytes free 5. Rode o programa. Você deve obter o erro java.lang.NoClassDefFoundError: Cliente C:\meusprogramasjava>java -cp . Cliente Exception in thread "main" java.lang.NoClassDefFoundError: Cliente (wrong name: pacoteEstudante/Cliente) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:620) at java.security.SecureClassLoader.defineClass (SecureClassLoader.java:124) at java.net.URLClassLoader.defineClass (URLClassLoader.java:260) at java.net.URLClassLoader.access$100(URLClassLoader.java:56) at java.net.URLClassLoader$1.run(URLClassLoader.java:195) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass (Launcher.java:268) at java.lang.ClassLoader.loadClass(ClassLoader.java:251) at java.lang.ClassLoader.loadClassInternal (ClassLoader.java:319) A exceção ocorreu porque a máquina virtual Java tenta encontrar o arquivo Cliente.class no diretório pacoteEstudante (começando da classpath atual, a qual foi configurada como sendo o diretório corrente) uma vez que o arquivo Cliente.java agora tem um comando package, o qual indica que o arquivo Cliente.class reside no diretório pacoteEstudante. 6. Crie um novo diretório chamado pacoteEstudante e mova os arquivos Estudante.java e Cliente.java para este novo diretório. C:\meusprogramasjava>mkdir pacoteEstudante C:\meusprogramasjava>move Estudante.java pacoteEstudante C:\meusprogramasjava>move Cliente.java pacoteEstudante Os arquivos *.java que tem o comando package têm de estar localizados em uma estrutura de diretórios que reflita o caminho especificado no comando package. 7. Compile o código. Você obtém este erro de compilação porque você está tentando compilar os dois arquivos Java que não residem mais no diretório corrente. C:\meusprogramasjava>del *.class C:\meusprogramasjava>javac Estudante.java Cliente.java error: cannot read: Estudante.java 1 error 8. Compile o código usando o caminho completo dos arquivos *.java. A compilação deve ser bem sucedida. Observe que os arquivos *.class são criados sob a pasta pacoteEstudante e não no diretório corrente. C:\meusprogramasjava>javac pacoteEstudante\Estudante.java pacoteEstudante\Cliente.java C:\meusprogramasjava>dir pacoteEstudante Volume in drive C is ACER Volume Serial Number is 4424-9D24 Directory of C:\meusprogramasjava\pacoteEstudante 05/04/2007 05/04/2007 05/04/2007 05/04/2007 05/04/2007 05/04/2007 19:38 <DIR> . 19:38 <DIR> .. 19:38 966 Cliente.class 19:12 1.159 Cliente.java 19:38 812 Estudante.class 19:12 753 Estudante.java 4 File(s) 3.690 bytes 2 Dir(s) 11.655.143.424 bytes free 9. Rode o programa usando a opção –classpath C:\meusprogramasjava>java -classpath . Cliente Exception in thread "main" java.lang.NoClassDefFoundError: Cliente Observe que você obteve o erro java.lang.NoClassDefFoundError: Cliente. Isso ocorreu porque a máquina virtual Java tenta encontrar o arquivo Cliente.class no diretório (ou diretórios) especificado na opção -classpath. Como o único diretório especificado na opção -classpath é o diretório corrente, e o diretório corrente não contém o arquivo Cliente.class, obtivemos o erro mostrado. 10. Rode o programa usando a opção -classpath pacoteEstudante C:\meusprogramasjava>java -classpath pacoteEstudante Cliente Exception in thread "main" java.lang.NoClassDefFoundError: Cliente (wrong name:pacoteEstudante/Cliente) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:620) at java.security.SecureClassLoader.defineClass (SecureClassLoader.java:124) at java.net.URLClassLoader.defineClass (URLClassLoader.java:260) at java.net.URLClassLoader.access$100(URLClassLoader.java:56) at java.net.URLClassLoader$1.run(URLClassLoader.java:195) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass (ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass (Launcher.java:268) at java.lang.ClassLoader.loadClass(ClassLoader.java:251) at java.lang.ClassLoader.loadClassInternal (ClassLoader.java:319) Observe que você ainda obteve o erro java.lang.NoClassDefFoundError: Cliente. Mas dessa vez, a exceção também diz (wrong name: pacoteEstudante/Cliente) na segunda linha. Tipicamente, isto indica que a máquina virtual Java encontrou a classe, mas, de alguma forma, a estrutura de diretórios do pacote especificada no arquivo *.class não corresponde à estrutura de diretórios real. Neste exemplo em particular, a máquina virtual Java tentou primeiramente encontrar o arquivo Cliente.class na classpath (a classpath foi configurada para apontar para o diretório pacoteEstudante) e o encontrou. Esse é o motivo pelo qual você não obteve uma exceção de uma única linha, como nos casos anteriores. Uma vez que a classe foi encontrada, a máquina virtual Java verifica a hierarquia do pacote especificado no arquivo *.class, que é pacoteEstudante. Lembre-se, na plataforma Java, a estrutura do pacote deve refletir a estrutura real de pastas. Em outras palavras, a máquina virtual Java tenta encontrar o arquivo ./pacoteEstudante/Cliente.class a partir da classpath. Uma vez que a classpath foi configurada para apontar para o diretório pacoteEstudante, a máquina virtual está procurando pelo arquivo .\pacoteEstudante\pacoteEstudante\Cliente.class, o qual não existe. 11. Rode o programa com a opção “-classpath .” mas com o caminho apropriado para o arquivo *.class C:\meusprogramasjava>java -cp . pacoteEstudante.Cliente Nome = Ana Numero de Estudantes = 3 Funcionou porque a máquina virtual Java encontrou o arquivo Cliente.class dentro do diretório pacoteEstudante começando a busca a partir da classpath 12. Rode o programa com as opções a seguir. Tente entender porque não funcionou. C:\meusprogramasjava>java -classpath pacoteEstudante pacoteEstudante.Cliente Exception in thread "main" java.lang.NoClassDefFoundError: pacoteEstudante/Cliente 13. Rode o programa com as opções a seguir. Tente entender porque não funcionou. C:\meusprogramasjava>cd pacoteEstudante C:\meusprogramasjava\pacoteEstudante>java -classpath . Cliente Exception in thread "main" java.lang.NoClassDefFoundError: Cliente (wrong name: pacoteEstudante/Cliente) at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:620) at java.security.SecureClassLoader.defineClass (SecureClassLoader.java:124) at java.net.URLClassLoader.defineClass (URLClassLoader.java:260) at java.net.URLClassLoader.access$100(URLClassLoader.java:56) at java.net.URLClassLoader$1.run(URLClassLoader.java:195) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:188) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass (Launcher.java:268) at java.lang.ClassLoader.loadClass (ClassLoader.java:251) at java.lang.ClassLoader.loadClassInternal (ClassLoader.java:319) 14. Rode o programa com as opções a seguir. Tente entender porque funcionou. C:\meusprogramasjava\pacoteEstudante>java -classpath .. pacoteEstudante.Cliente Nome = Ana Numero de Estudantes = 3 15. Rode o programa com as opções a seguir. Tente entender porque funcionou. C:\meusprogramasjava\pacoteEstudante>cd \ C:\>java -cp meusprogramasjava pacoteEstudante.Cliente Nome = Ana Numero de Estudantes = 3 (2.3) Acrescente uma outra classe em um pacote diferente 1. Crie um outro diretório chamado outropacote onde você irá criar um outro programa Java C:\meusprogramasjava>mkdir outropacote 2. Crie a classe ClasseBoba.java a seguir no diretório outroPacote 3. Modifique a classe Estudante.java para usar a classe ClasseBoba, como mostrado a seguir: 4. Compile o código e verifique que os arquivos *.class foram gerados C:\meusprogramasjava>javac pacoteEstudante\*.java C:\meusprogramasjava>dir pacoteEstudante Volume in drive C is ACER Volume Serial Number is 4424-9D24 Directory of C:\meusprogramasjava\pacoteEstudante 06/04/2007 06/04/2007 06/04/2007 05/04/2007 06/04/2007 06/04/2007 15:13 <DIR> . 15:13 <DIR> .. 15:13 966 Cliente.class 19:12 1.159 Cliente.java 15:13 1.043 Estudante.class 15:07 931 Estudante.java 4 File(s) 4.099 bytes 2 Dir(s) 11.647.528.960 bytes free C:\meusprogramasjava>dir outropacote Volume in drive C is ACER Volume Serial Number is 4424-9D24 Directory of C:\meusprogramasjava\outropacote 06/04/2007 15:13 <DIR> . 06/04/2007 06/04/2007 06/04/2007 15:13 <DIR> .. 15:13 497 ClasseBoba.class 15:04 165 ClasseBoba.java 2 File(s) 662 bytes 2 Dir(s) 11.647.528.960 bytes free 5. Rode o programa C:\meusprogramasjava>java -classpath . pacoteEstudante.Cliente Alo, eu sou boba. Seu nome eh Ana Nome = Ana Numero de Estudantes = 3 Trabalho adicional 1. O trabalho consiste em codificar e executar um programa Java em linha de comando usando os aplicativos “javac” e “java” (não use uma IDE para este exercício) Escreva uma classe chamada Comida no pacote pacotecomida.pacotefruta o O arquivo Comida.java deve ter na primeira linha a declaração: package pacotecomida.pacotefruta o Adicione alguns métodos de sua própria escolha à classe Comida.java Escreva uma classe chamada ComidaMain pertencente ao pacote pacotecomida.pacotefruta o A classe ComidaMain deve criar um objeto Comida o A classe ComidaMain deve então invocar um método do objeto Comida