PDA

View Full Version : [JAVA] Sto impazzendo con i packages...


InsomNia_Italy
12-06-2009, 13:36
Ciao a tutti,
raga ho bisogno del vostro aiuto, sto impazzendo dietro i package.

Allora, devo creare una rubrica telefonica in java.
Ho creato una cartella su c:\ chiamata esercizio e sto lavorando li dentro.
Ho creato un file chiamato rubrica.java:

import java.io.*;

public class rubrica{
public static void main(String args[]) throws IOException{
BufferedReader in = new BufferedReader( new InputStreamReader( System.in ) );
int Scelta = 0;

System.out.println("Rubrica elettronica in Java");
System.out.println();
System.out.println("1) Visualizzare contatti");
System.out.println("0) Chiudere rubrica");
System.out.println();
ciclo: for(;;){
System.out.print("Inserire il numero della tua scelta: ");
Scelta = Integer.parseInt(in.readLine());
switch(Scelta){
case 1:
//VISUALIZZARE CONTATTI
System.out.println("VISUALIZZANDO I CONTATTI");
break ciclo;
case 0:
//CHIUDERE RUBRICA
System.out.println("Chiusura agenda...");
break ciclo;
default:
//SCELTA NON VALIDA
System.out.println("Scelta non valida");
break;
}
}}
}


Ok, un menu totalmente inutile, ma funziona.

Il problema viene ora che devo creare un'altra classe nella quale creare il mio costruttore in modo che poi dalla classe main possa fare ad esempio:
RubricaTelefonica [] lamiarubrica = new RubricaTelefonica[5];

Visto che nello stesso file non posso scrivere più di una classe e questa deve avere il nome del file, come faccio ?

Ho pensato di creare un'altro file appunto e poi di unire il tutto con i package, ma non sono stato capace di farlo. Mi aiutate? Ne ho bisogno :/ :mc:

renaulto
12-06-2009, 13:54
Visto che nello stesso file non posso scrivere più di una classe e questa deve avere il nome del fileQuesto vale solo per la classe con modificatore 'public'.

Quindi:

public class Rubrica{
}

class A {
}

class B {
}

ecc..

PGI-Bis
12-06-2009, 14:33
Puoi tranquillamente creare un secondo file, chiamiamolo Pippo.java, nel quale è dichiarata la tua classe Pippo il cui costruttore... può fare quello che gli pare. A questo puoi aggiungere un terzo file, Main.java, in cui dichiari una classe Main che contiene un metodo "main" che...fa quel che deve.

Se tutti i file sorgente sono nella stessa cartella, compilerai con un bel:

javac -d . *.java

e il compilatore farà il resto.

morskott
12-06-2009, 14:33
i packages devono esser dichiarati sopra la dichiarazione delle classipackages miopackage;ed il file và messo sotto%MIA_CARTELLA%\miopackage, quindi nel tuo caso avrai due file Rubrica.java e Altro.java

file: %MIA_CARTELLA%\rubrica\Rubrica.java

package rubrica;

public class Rubrica{

//blah blah blah

}

file: %MIA_CARTELLA%\rubrica\Altro.java

package rubrica;

public class Altro{

//blah blah blah

}

per compilare dalla cartella %MIA_CARTELLA% faraijavac rubrica\*.javamentre per eseguire sempre dalla cartella %MIA_CARTELLA% ipotizzando che il mai si trovi nella classe Rubrica faraijava rubrica.Rubrica

PGI-Bis
12-06-2009, 14:41
ed il file và messo sotto%MIA_CARTELLA%\miopackage, quindi nel tuo caso avrai due file Rubrica.java e Altro.java

file: %MIA_CARTELLA%\rubrica\Rubrica.java

No. I file sorgente possono stare ovunque.

InsomNia_Italy
12-06-2009, 14:48
Ecco, lo sapevo che c'era qualcosa di troppo strano =)

Comunque, vorrei approfittarne per chiedervi un'altra cosa. Per organizzare meglio il lavoro vorrei utilizzare quelle che in altri linguaggi sono le classiche funzioni/procedure, qui sono tutti metodi no?

Vi incollo un pezzetto di codice:
import java.io.*;

public class rubrica{

public static void main(String args[]) throws IOException{
SOGGETTO [] miosoggetto = new SOGGETTO[1];
rubrica.Riempi();
rubrica.Visualizza();
}

public static void Riempi(){
miosoggetto[0] = new SOGGETTO("PAPERINO","PLUTO");
}

public static void Visualizza(){
miosoggetto[0].getCognome();
miosoggetto[0].getNome();
}

} //FINE CLASSE RUBRICA



//COSTRUTTORE
class SOGGETTO{
private String cognome;
private String nome;

public SOGGETTO(String cogn,String nom) {
cognome = cogn;
nome = nom;
}

public String getCognome(){
return cognome;
}
public String getNome(){
return nome;
}
} //FINE CLASSE SOGGETTO

Mi segnala problemi nel metodo per il riempimento ed in quello per la visualizzazione dicendo che non riesce a trovare miosoggetto....
Come faccio per indicargli che è stato dichiarato nel main? Devo renderlo tipo globale? Come?

Grazie mille per il vostro aiuto!! :muro:

morskott
12-06-2009, 14:53
No. I file sorgente possono stare ovunque.

che io sappia la disposizione dei file sorgente in caso di uso dei packages è obbligata, mo provo, magari mi sbaglio

EDIT: hai ragione tu, è solo in fase di esecuzione che sei obbligato, comunque penso sia buona pratica pure coi files sorgenti rispettare le cartelle che avrai in fase di esecuzione

PGI-Bis
12-06-2009, 14:57
Puoi spostare la dichiarazione della variabile soggetto dal corpo del metodo main al corpo della classe rubrica. Poichè accedi alla variabile da contesti statici la variabile stessa deve essere statica.

import java.io.*;

public class rubrica{
private static SOGGETTO [] miosoggetto = new SOGGETTO[1];

public static void main(String args[]) throws IOException{
rubrica.Riempi();
...eccetera

Tecnicamente vai a creare un'intersezione tra l'ambito del nome "miosoggetto" e l'ambito del corpo dei metodi statici in cui lo vuoi usare. Prima non ti funzionava perchè gli stessi ambiti erano disgiunti. Ma è dettagliume.

morskott
12-06-2009, 14:57
Ecco, lo sapevo che c'era qualcosa di troppo strano =)

Comunque, vorrei approfittarne per chiedervi un'altra cosa. Per organizzare meglio il lavoro vorrei utilizzare quelle che in altri linguaggi sono le classiche funzioni/procedure, qui sono tutti metodi no?

Vi incollo un pezzetto di codice:
import java.io.*;

public class rubrica{

public static void main(String args[]) throws IOException{
SOGGETTO [] miosoggetto = new SOGGETTO[1];
rubrica.Riempi();
rubrica.Visualizza();
}

public static void Riempi(){
miosoggetto[0] = new SOGGETTO("PAPERINO","PLUTO");
}

public static void Visualizza(){
miosoggetto[0].getCognome();
miosoggetto[0].getNome();
}

} //FINE CLASSE RUBRICA



//COSTRUTTORE
class SOGGETTO{
private String cognome;
private String nome;

public SOGGETTO(String cogn,String nom) {
cognome = cogn;
nome = nom;
}

public String getCognome(){
return cognome;
}
public String getNome(){
return nome;
}
} //FINE CLASSE SOGGETTO

Mi segnala problemi nel metodo per il riempimento ed in quello per la visualizzazione dicendo che non riesce a trovare miosoggetto....
Come faccio per indicargli che è stato dichiarato nel main? Devo renderlo tipo globale? Come?

Grazie mille per il vostro aiuto!! :muro:

Hai mai visto java prima d'ora?

PGI-Bis
12-06-2009, 15:01
è solo in fase di esecuzione che sei obbligato, comunque penso sia buona pratica pure coi files sorgenti rispettare le cartelle che avrai in fase di esecuzione

Sì, è un'ottima pratica.

Per l'esecuzione in verità la questione della collocazione dei file class in cartelle appartenenti a rami aventi la stessa struttura del nome del package è un dettaglio della specifica versione di Java proposta da Sun. La piattaforma intesa come "standard" è indipendente da questa particolarità - e in effetti è possibile e a volte utile caricare le classi da un database attraverso le librerie standard.

InsomNia_Italy
12-06-2009, 15:03
Puoi spostare la dichiarazione della variabile soggetto dal corpo del metodo main al corpo della classe rubrica. Poichè accedi alla variabile da contesti statici la variabile stessa deve essere statica.

import java.io.*;

public class rubrica{
private static SOGGETTO [] miosoggetto = new SOGGETTO[1];

public static void main(String args[]) throws IOException{
rubrica.Riempi();
...eccetera

Tecnicamente vai a creare un'intersezione tra l'ambito del nome "miosoggetto" e l'ambito del corpo dei metodi statici in cui lo vuoi usare. Prima non ti funzionava perchè gli stessi ambiti erano disgiunti. Ma è dettagliume.

Ti ringrazio, gentilissimo e preciso!

InsomNia_Italy
12-06-2009, 15:04
Hai mai visto java prima d'ora?

Spiritoso!

Usavo Visual Basic parecchio tempo fa, ora sto cercando di avvicinarmi al Java, non lapidatemi per questo eh...

PGI-Bis
12-06-2009, 15:12
Spiritoso!

Usavo Visual Basic parecchio tempo fa, ora sto cercando di avvicinarmi al Java, non lapidatemi per questo eh...

Pian piano si impara tutto. Forse è anche meglio iniziare a usare una lingua secondo un metodo appreso in una lingua diversa. A un certo punto scoprirai quasi per caso che alcune cose possono essere fatte diversamente. Impararlo tutto d'un botto sarebbe bello ma lo darei per ostico: negli anni ha accumulato parecchie caratteristiche.

Hai tutta la mia solidarietà: io parto da Java e sto cercando di addentrarmi in Scala. Ogni tre righe tiro due parolacce e un lamento. E con tutta probabilità se uno "scaliano" vedesse i miei sorgenti perderebbe due o tre diottrie. L'importante è perseverare.

morskott
12-06-2009, 15:15
Spiritoso!

Usavo Visual Basic parecchio tempo fa, ora sto cercando di avvicinarmi al Java, non lapidatemi per questo eh...

non volevo essere nè ironico nè offensivo, volevo solo sapere a che livello stavi, se ti son sembrato uno delle due scusami.

In java puoi accedere a qualsiasi variabile che sia nello scope corrente, dentro ad un metodo puoi accedere a: variabili locali al metodo, variabili argomenti del metodo, variabili di classe (se il metodo è statico a variabili statiche, se il metodo non è statico a variabili sia statiche che non), puoi anche accedere a variabili non della tua classe se e solo se rientri nel modificatore applicato alla variabile che vuoi vedere: se la variabile ha modificatore "public" puoi accederci da dovunque, modificatore di default (se non ci scrivi nulla) solo dall'interno del suo package, "protected" dall'interno del suo package a da tutte le classi che ereditano e "private" solo dalla classe di dichiarazione.

Sì, è un'ottima pratica.

Per l'esecuzione in verità la questione della collocazione dei file class in cartelle appartenenti a rami aventi la stessa struttura del nome del package è un dettaglio della specifica versione di Java proposta da Sun. La piattaforma intesa come "standard" è indipendente da questa particolarità - e in effetti è possibile e a volte utile caricare le classi da un database attraverso le librerie standard.

Si, dipende dal classloader che hai a runtime, una volta dovetti far un classloader moddato che se non trovava il .class in locale se lo andava a cercare ad uno specifico indirizzo di rete, la forza di java penso sia pure questa, puoi "giocarci" a piacere :D

InsomNia_Italy
12-06-2009, 18:12
nessun problema morskott :)

Allora, aggiornamenti. Funziona tutto quello che deve funzionare, ripetizione menu, inserimento informationi (cognome, nome, età) previa richiesta di quanti inserirne, visualizzazione del tutto etc..

Mi chiedevo ora una cosa. Ogni volta che aggiungo nominativi, questi vengono salvati dopo quelli già presenti. Esiste un modo per ordinare automaticamente la classe creata ad hoc? Esiste un modo sbrigativo, avendo una classe già ordinata, per inserire il nuovo record nella posizione esatta in base all'ordinamento basato sul cognome?

Ho provato con Arrays.sort e Collections.sort ma non credo facciano al caso mio. Oppure sbaglio ad usarle :)

Grazie come sempre!! :help:

PGI-Bis
12-06-2009, 20:16
Hai tante opzioni per l'ordinamento. Collections.sort ordina liste (java.util.List). Arrays.sort ordina array (pippo[]). In entrambi i casi hai la possibilità di ordinare per criteri interni o esterni al tipo di oggetti contenuti nella lista o nell'array.

Per ordinare rispetto ad un criterio interno devi prendere la classe che dichiara il tipo di dato contenuto nella lista (diciamo la classe Pippo) e renderla implementazione dell'interfaccia Comparable<Pippo>.

Per ordinare rispetto ad un criterio esterno devi creare un'istanza di Comparator<Pippo>. Ad esempio:

Comparator<Pippo> ordinamentoPerCognome = new Comparator<Pippo>() {
public int compare(Pippo a, Pippo b) {
return Collator.getInstance().compare(a.getCognome(), b.getCognome());
}
};

A questo punto puoi usare "ordinamentoPerCognome" come secondo argomento del metodo Arrays.sort o del metodo Collections.sort. Il risultato è che l'array o la lista passata come primo argomento dei predetti metodi saranno ordinati in base al valore dei rispettivi campi "cognome".

InsomNia_Italy
15-06-2009, 14:38
Ciao, grazie per la risposta.

Ho provato a fare come dici tu, ma probabilmente sbaglio qualche cosa e ritorno un errore quando provo a visualizzare la lista ordinata:

La classe SOGGETTO è questa:
class SOGGETTO{
private String cognome;
private String nome;

Comparator<SOGGETTO> ordinamentoPerCognome = new Comparator<SOGGETTO>(){
public int compare(SOGGETTO A,SOGGETTO B) {
return Collator.getInstance().compare(A.cognome, B.cognome);
}
};

public SOGGETTO(String cogn,String nom) {
cognome = cogn;
nome = nom;
}
public String getCognome(){
return cognome;
}
public String getNome(){
return nome;
}
} //FINE CLASSE SOGGETTO

nella classe principale Rubrica utilizzo:

private static SOGGETTO [] nominativo = new SOGGETTO[50];

e prima di visualizzare tutti i nominativi inseriti questo:

Arrays.sort(nominativo);

L'errore che ricevo è questo:

Exception in thread "main" java.lang.ClassCastException: SOGGETTO cannot be cast to java.lang.Comparable
at java.util.Arrays.mergeSort(Unknown Source)
at java.util.Arrays.mergeSort(Unknown Source)
at java.util.Arrays.mergeSort(Unknown Source)
at java.util.Arrays.mergeSort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at rubrica.Visualizza(rubrica.java:73)
at rubrica.main(rubrica.java:30)

Cosa sbaglio? :muro:

PGI-Bis
15-06-2009, 14:47
Togli il comparator da soggetto:

class SOGGETTO{
private String cognome;
private String nome;

public SOGGETTO(String cogn,String nom) {
cognome = cogn;
nome = nom;
}
public String getCognome(){
return cognome;
}
public String getNome(){
return nome;
}
} //FINE CLASSE SOGGETTO

dichiaralo prima di ordinare e usa il metodo sort che prende un comparator:


Comparator<SOGGETTO> ordinamentoPerCognome = new Comparator<SOGGETTO>(){
public int compare(SOGGETTO A,SOGGETTO B) {
return Collator.getInstance().compare(A.cognome, B.cognome);
}
};
Arrays.sort(nominativo, ordinamentoPerCognome);

Usando il metodo sort con un solo argomento Arrays si aspetta che SOGGETTO sia un Comparable cioè che tu abbia una cosa tipo:

public class SOGGETTO implements Comparable<SOGGETTO> {
...eccetera

Tieni conto che per usare il sort di Arrays non devono esserci elementi "null" nell'array da ordinare.

InsomNia_Italy
15-06-2009, 17:24
Ok funziona alla grande nel caso in cui imposti un numero di oggetti da creare e li riempia tutti, proprio come avevi detto tu.

Non esiste un modo per ordinare anche avendo oggetti null?
Altrimenti mi tocca riallocare il numero di oggetti ad ogni operazione che ne modifica il numero, come ad esempio aggiunta/rimozione.

PGI-Bis
15-06-2009, 17:34
Usa una lista al posto dell'array.

private static ArrayList<SOGGETTO> nominativi = new ArrayList<SOGGETTO>();

per aggiungere elementi scrivi:

nominativo.add(un soggetto)

anzichè:

nominativo[x] = qualcosa

per togliergli

nominativo.remove(un indice);

L'ordinamento lo fai con Collections:

Collections.sort(nominativi, comparatore);