mi permetto di consigliarti qualche piccolo accorgimento per migliorare i programmi (soprattutto) dal punto della comprensione per le altre persone che guarderanno il codice (ed anche per te stesso), non prenderle come critiche ma come consigli amichevoli però:
1. classi totalmente differenti dal main conviene separarle "fisicamente" dal main, cioè scriverle direttamente in un'altro file .java così da avere il main (e metodi annessi) in un posto, ed il resto nell'altro (parlo della classe prodotti). Nel nostro esempio conviene avere il file
prodotti.java che contiene tutte le classi progettate nel diagramma UML, ed il file (ad esempio)
prova.java che contiene il main con annessi e connessi. Non è un obbligo ma è semplicemente un consiglio per mettere ordine che servirà a te e a chi legge il codice.
2. il
toString è un metodo che adotteranno tutti, quindi in questo caso è meglio scriverlo
abstract nella superclasse e poi fare l'overriding nelle sottoclassi così da fargli adempiere in pieno il suo compito: ritornare una stringa con tutte le informazioni dell'oggetto.
3. Per evitare di perdere tempo ad inventarsi nomi differenti per i parametri (col rischio di confondersi) è meglio usare la parola chiave
this nel modo spiegato dal tutorial che ti ho linkato (che vedo tu usi invece nel toString quando invece non ce n'è bisogno).
4. Le variabili di istanza delle classi conviene metterle con attributo
private in quanto ti servono solamente in quella classe. Per richiamarle si usano i metodi (pubblici ovviamente)
getAttributo() per evitare di influenzare in qualche modo la variabile (un modo per non correre rischi in poche parole

).
5. I nomi dei metodi e della classi è convenzione scriverli al plurale e con la sintassi
MetodoMio() e
MiaClasse. Ma questa è solo una convenzione poi sei libero di scrivere nomi a tuo piacimento. Per le variabili stesso discorso ma, a meno di situazioni che lo richiedano, solitamente vanno al singolare (peso, scadenza etc). Le costanti invece vengono scritte sempre in MAIUSCOLO per distinguerle dalle variabili semplici (anche questa è una convenzione ma seguirle non fa male e rende solo il codice meno confusionario).
6. Nel main la stampa dei prodotti potevi farla direttamente nel for che comprendeva la switch, così avresti risparmiato righe di codice ed un ciclo iterativo. Questa si chiama ottimizzazione del codice, non necessaria con programmini semplici e piccoli come questo, ma in caso di programmi grossi la differenza si nota

.
7. Il totale dove sta? nelle singole classi? e perchè? visto che è un
attributo comune a tutti, conviene metterlo come parametro della superclasse (così verrà ereditato da tutti). In codice significa:
abstract class Prodotti
{
private static int totale=0;
private float peso;
final float C=3;
public Prodotti(int peso)
{
this.peso=peso;
totale++;
}
public static int getTotale()
{
return totale;
}
//altri metodi come getPeso() etc...
}
se nel main dichiari un array di prodotti senza la sintassi sopra e poi fai
Prodotti.getTotale()
ti dà ovviamente errore perchè totale non è una variabile della classe Prodotti (quindi non la trova).
Spero di non essere stato confusionario ma che sia tutto abbastanza chiaro! ^^
Saluti!
EDIT: Corretto grazie alla segnalazione di crasher.