Hi, me again. People say bad things about the French nationalised industries, but France Telecom just replaced 1/2 mile of cable through trees to my house within 24 hours of localising a fault to that area. For free. Vive la France!
Anyway -

I'm back online, so start asking!
J

WOW! I wish we still had Telefonica in Spain as nationalized industry. We don't! and they are now sub-contracting other enterprises to do the job, with not much of control.

Anyway, in relation to the project, I hope you have had time to see what I sent previously. I finished tha part of the job that jas to do with building the structure. It works and looks nice. Disregard the lack of exception controls. I know it is a bad practice, but it has been so much to me to try to understand Java and start this not easy homework, for which I only have until th eend of this month. I also have to study the matter. This homework is only to be allowed to do the exams, so I have decided to focus on the functionalities and, if I have time, to learn about exceptions and try to put more controls. Thanks for reading this long Paragraph() with XXX Phrases() and XXXXX Words() ;-)

So, you can see my solution and tell me whatever comes to your mind that you find useful.

I would like to know your opinion about, on one hand, declaring elementoCompuesto as an abstract class or even an interface and, on the other hand, insert a generic ArrayList<T> in this super-class. I still have to code some extra methods for showing, finding, replacing... contents of each class's ArrayList, that I would have to write time after time, adapting the almost identical code to each.

As for declaring an interface... would I lose the inheritances? I need to put some inheritance in my work, as they want me to use as much OOP concepts I could.
As for Abstract, would this help me in any way apart from "using abstract code" as an OOP concept itself?
Thankyou, guys, for your time.

Declaring an interface makes you lose inheritance. It forces you to implement a consistent set of methods in each class (which is good), but each has to be implemented in each class (bad). If Java allowed a class to inherit from multiple superclasses (you can't, it's not part of ther language for good reasons) you would probably never see an interface.
I can't spend hours studying this, but at first sight it looks to me like elementoCompuesto is a perfect superclass, You can say Phrase, Paragraph etc "is a kind of elementoCompuesto" - that says "superclass" to me.
Similarly , when you say "code some extra methods ... that I would have to write time after time, adapting the almost identical code to each." that also says to me: put those methods (and the ArrayList they need) in the superclass and inherit them, just code the differences in each class.
If you are lucky you can identify the places where you need the different parts - which is where you use abstract - eg in the superclass

public void doSomething() {
   // loads of common code
   doTheSpecialBits();
   // loads more common code
}
abstract void doTheSpecialBits(); // implement this in each subclass

Hmm, that sounds interesting, though, I think I would need to make myself explain better:
The Phrase constructor:

/**
     * Constructor for objects of class frase
     */
    public Frase(String inputTxt) {
        // Split the input string into words with the delimiter " "
        String [] protoPalabrasArray = inputTxt.split("\\s");
        for (String protopalabra :protoPalabrasArray){
            Palabra unaPalabra = new Palabra(protopalabra);
         // if unaPalabra's DNI = -1 it is empty and will not be added
            if (unaPalabra.getDNI() != -1) { 
                PalabrasArrayList.add(unaPalabra);
                this.estadisticas.incr(statIndex.PALABRAS);
                statsArray stv = unaPalabra.getStatsVect();
                this.estadisticas.addStats(stv);
            }
            this.estadisticas.incr(statIndex.CARACTERES);
            this.estadisticas.incr(statIndex.SIMBOLOS); // añadimos el carácter " " a la estadística
        }
       //Si no está vacío, pido un DNI. If !self.isempty ask for a ID number
       // si la palabra está vacía se marca con DNI=-1 para que Parrafo lo sepa
      if (this.estadisticas.getStat(statIndex.PALABRAS)!=0) {this.DNI = servidor_DNI.dameDNI();} 
      else {this.DNI = -1;}
    }
}

The pragraph constructor

/**
     * Constructor for objects of class parrafo
     */
    public Parrafo(String inputTxt)    {
        // Split the input string into phrases with the delimiter "."
        String [] protoFrasesArray = inputTxt.split("\\.\\s"); 
        for (String protofrase :protoFrasesArray){
            Frase unaFrase = new Frase(protofrase);
         // if unaFrase's DNI = -1 it is empty and will not be added
            if (unaFrase.getDNI() != -1) {
               FrasesArrayList.add(unaFrase);
               this.estadisticas.incr(statIndex.FRASES);
               statsArray stv = unaFrase.getStatsVect();
               this.estadisticas.addStats(stv);
            }
            this.estadisticas.incr(statIndex.CARACTERES);
            // añadimos el carácter "." a la estadística
            this.estadisticas.incr(statIndex.SIMBOLOS); 
        }
       // if the Parrafo object has phrases,  ask for a ID number
       // if there are no phrases, DNI=-1 and Pagina will know that
      if (this.estadisticas.getStat(statIndex.FRASES)!=0) {this.DNI = servidor_DNI.dameDNI();} 
      else {this.DNI = -1;}
    }
/**
     * Constructor for objects of class pagina
     */
    public Pagina(String inputTxt) {
        // Split the input string into paragraphs with the delimiter "CRLF"
        String [] protoParrafosArray = inputTxt.split("(\r\n)");  
        for (String protoparrafo :protoParrafosArray){
            Parrafo unParrafo = new Parrafo(protoparrafo);
            // if unParrafo's DNI = -1 it is empty and will not be added
            if (unParrafo.getDNI() != -1) {   
                ParrafosArrayList.add(unParrafo);
               this.estadisticas.incr(statIndex.PARRAFOS);
               statsArray stv = unParrafo.getStatsVect();
               this.estadisticas.addStats(stv);
            }
            this.estadisticas.incr(statIndex.CARACTERES);
           // añadimos el carácter "CRLF" a la estadística 
            this.estadisticas.incr(statIndex.SIMBOLOS); 
        }
       // if the Pagina object has paragraphs,  ask for a ID number
       // if there are no paragraphs, DNI=-1 and Documento will know that
      if (this.estadisticas.getStat(statIndex.PARRAFOS)!=0) {this.DNI = servidor_DNI.dameDNI();} 
      else {this.DNI = -1;}
    }

First thing is to move as much code as possible out of the constructor, because you cannot inherit constructors. Put it in a method that the constructor calls, that way the method can be inherited. I think you should be able to use generics to make that method apply to each level in the document hierarchy. Here's a very quick sketch of what I mean (not compiled or tested - just pseudo-code)

class Superclass {
  ArrayList<Superclass> myList;
  <T> void load(String source, String delimiter, ArrayList<T> destination ) {
      // parse source by delimiters into arraylist
  }
}
class Subclass1 {
  Subclass1(String source) {
    myList = new ArrayList<Subclass2>();
    load(source, "\n", myList);
  }
)

Oh, James,

you cannot imagine how helpful you're being to me.
I'll be back to you after trying this. It Looks pretty.

ps: There's a small snag in that you need to parametise the kind of object that will be created & added to the arraylist, and you can't say new T();
This is a nasty limitation in the way Java does generics.
You may need to create a small factory class to create new objects of the right kind - there's lots of code via Google ("instantiate java generic type"), or have an abstract method in the superclass to return a new instance of the approropriate subclass and override that in each subclass with the correct type, eg

class Superclass {
  abstract Superclass newMember();
...
class Phrase {
  Superclass newMember() { 
    return new Word();
  }

Then in the superclass load method you can call newMwember() to get a new instance of the right type to add to the ArrayList

how do you see this?
THIS is the SUPER CLASS elementoCompuesto:

public class elementoCompuesto {
    public  int    DNI;
    ArrayList <elementoCompuesto> ComponentesArrayList;
    public statsArray estadisticas; // Array de enteros para los recuentos 
    // aquí iría perfecto un generic de arraylist public Generic Arraylist <> misElementos;
    
    /**
     * constructor
     */
    public elementoCompuesto(){
        estadisticas = new statsArray();
    }

    /**
     * Loader of subElementos. Cargador de subelementos en el ArrayList
     * IT's generic implementation, where <T> is the elemento class and <U> the subelemento class
     * delimiter is the string used to split the inputTxt. SubsArrayList is the arraylist of subelements that eac element
     * is composed of. SubIndex is the subelement class statistical index, that, in the caller can be written as statIndex.PARRAFO, for example
     * 
     */
    <T> void cargaComponentes (String inputTxt, String delimiter, ArrayList<U> SubsArrayList, int SubIndex, int [] specialStats) {
       String [] ProtoSubArray=inputTxt.split(delimiter);//string splitting in protos
        for (String protosub : ProtoSubArray) {
            <U> SubElemento = new <U> (protosub);
            if (SubElemento.getDNI() != -1) {    //getDNI=-1 ==> subelement is empty
                SubsArrayList.add(SubElemento);
                this.UpdateStatistics(SubIndex); ////<<--- still not implemented!!!
            }
        }
        if (this.estadisticas[SubIndex] != 0) {this.DNI = servidor_DNI.dameDNI();}
        else {this.DNI = -1;}
     }

...
}

THIS is one example of subclass (phrase):

import practica_2010.*;
import java.util.ArrayList;
public class Frase extends elementoCompuesto
{
  //instance variables

  //instance methods
  /**
   * Constructor for objects of class frase
   */
  public Frase(String inputTxt) {
    //Creates the arraylist using the generic from superclass
     PalabrasArrayList = new ComponentesArrayList<Palabra>(0);
    // cargaComponentes superclass method with parameters:
    // string to create subcomponente, delimiter for subcomponentes,
    // statistic index corresponding to subelemento and a int array, to count the
    // delimiters
     this.cargaComponentes (inputTxt, "\\s", PalabrasArrayList, statIndex.PALABRAS, {statIndex.CARACTERES,satIndex.SIMBOLOS});
       // If this is not empty ask ID server for an ID number
       // IF it is empty thhis.DNI=-1 so that the caller knows that condition
        if (this.estadisticas[statIndex.PALABRAS]!=0) {
              this.DNI = servidor_DNI.dameDNI();} 
        else {this.DNI = -1;}
    }
}

Hi, James,

I am trying to perfectionate the code, as I have seen many issues. This weekend I won't be able to work on it, so, don't think I have disapeared. See you on Monday!

Hi
You will have a problem with line 24 of the superclass - new <U>
1 I guess you mean new <T> or new T, but neither will work
You can do something like I suggested in my last post (I have some sample code if you get stuck), or there are other ways round it if you don't like that one.
Is ComponentesArrayList used anywhere - I think maybe its not needed becuase you craete arraylists of the exact correct type in each subclass.
Overall it's looking like a pretty good design to me.

As I see, if I'm creating, let's say, a paragraph, I have a string that I split into pieces. With each, I will try to create a phrase by passing it. Thus, I think I need to do something like
Phrase newPhrase = new Phrase(pieceOfString).
Phrases are the sub-elements of Paragraph. I create a sub-element and then, after updating stats and checking its emptyness, I add it to the arraylist of sub-elements (of phrases, in this case)
If I try to use generics and I assume <T> in this case means Paragraph and <U> phrase, I thought I would write, generically,

<U> newSubElement = new <U>(pieceOfString);

What I have seen after your comment is, I didn't use <T> anywhere in the text but in the method cargaComponentes. I wonder if I should say that the atribute "ArrayList <elementoCompuesto>" should be written as "ArrayList <T>"

I have a question, anyway, of the syntax. Should I put "<U> newSubElement = new <U>(pieceOfString)" or U newSubElement = new U(pieceOfString)? (the question is about using angled brackets inside the method or not).

As for if I use ComponentesArrayList, I see there's an error, as you suggested, but may be that I tried to make elementoCompuesto my <T> type, but I did nothing to accomplish this. I have imagined this code:

public class <T> {
    public  int    DNI;
    ArrayList <U> ComponentesArrayList;
    public statsArray estadisticas; // Array de enteros para los recuentos 


    public elementoCompuesto(){
        estadisticas = new statsArray();
        ComponentesArrayList = new ArrayList<U>(0);
    }

    <T> void cargaComponentes (String inputTxt, String delimiter, ArrayList<U> SubsArrayList, int SubIndex, int [] specialStats) {
       String [] ProtoSubArray=inputTxt.split(delimiter);//string splitting in protos
        for (String protosub : ProtoSubArray) {
            <U> SubElemento = new <U> (protosub);
            if (SubElemento.getDNI() != -1) {    //getDNI=-1 ==> subelement is empty
                SubsArrayList.add(SubElemento);
                this.UpdateStatistics(SubIndex); ////<<--- still not implemented!!!
            }
        }
        if (this.estadisticas[SubIndex] != 0) {this.DNI = servidor_DNI.dameDNI();}
        else {this.DNI = -1;}
     }

though it seems to lead me to the point of your previous post... Let me work a bit more on this... Thanks, again

Hmm, seems very exciting and also complicated... What I've prior to the Generics aproach was working. I may waist too much time in going further with Generics. It may be advisable to let it go like this in order to finish the whole work. I still have to build up code for find/change, and consult the stats...

I will let you kow when I completely finish the code.

I also have another question that may need from me to open a new thread (so that other people who might find this one won't get confused). It's part of the whole project, but I think it also has importance by itself.

As I think have told you, phrases can consist of words or numbers. Numbers are complex elements that consist of basicElemento marked as DIGITOS. Whenever a word is made out of digits, has to be considered an object of class Number. The problem is that I am building each word char by char. I won't know if a series of digits will make a Number until I reach the end of the string. By that time, I have been constructing a Word instance, and I will end with a Word that should be a Number.
As they are almost the same, I decided to create a class that inherits from Word after seeing some advantages:
1: Number will be compatible to Word so I won't have to touch Phrase class.
2: I use a bit more of inheritance which is good for my teachers,
3: If I could have a way to, from the Word constructor, create a number, I won't even need to write almost any code for the Number class, as it is already done in Word class.

The need for this Number class is that I have to record every appearance of this elements apart from words. IT's part of the specifications.

I can always add an attribute in Word class with just a flag-like value, though it is not so nice to me as to use inheritance and treat numbers as a separate class that comes to my design naturally.

¿Do you think that I should open a new thread with something like "A super class that creates new instances of one (or more) of its subclasses" or it is ok to discuss this here?

I have decided to abandon the path of the generics, at least for this time. I will focus on the other functionalities the project has to complete. Now, the hot thread will be about how I can self.convert a Word in to a Number. What I forgot to mention in my last post is that I would like the oneWord to realize that it must return the Phrase a Number if it was the case, instead of making the phrase to detach the word and create a new Number from a string, which would need to re-create the arraylist of basicElemento, this time inside the Number.

I like the idea of number as a subclass of word. I don't think there's much point in a new thread, there is no way to "convert" an instance to an instance of a subclass (it's all about initialisation & constructors). You could handle the conversion in the number constructor, passing the word as a parameter and copying its values.

Don't give up on generics! They are important, and just need a little time.
Here's a demo prog that shows how easy the code can be for you...

import java.util.ArrayList;

public abstract class Superclass {

   // Supoerclass has 3 subclasses Sub1, Sub2, Sub3, which form a hierarchy.
   // Each contains a List of instances of the next lower class in the hierarchy
   // Eg: Superclass is a document element, subclasses are Page, Sentence, Word.
   // and Page has a List of Sentences, Sentence has a List of Words
   // Subclass constructors take a single String as parameter,
   // (which isn't used, it's just there to illustrate how params are handled).

   public static void main(String[] args) { // run this - it works
      new Sub1("some parameters");
   }

   // this generic method adds a couple of instances of the next
   // lower class to an appropriate array.
   // NB: The class of the object returned by newLowerClassInstance()
   // must correspond to the type of element in the list.
   @SuppressWarnings("unchecked")
   <T extends Superclass> void load(ArrayList<T> list, String params) {
      for (int i = 0; i < 2; i++) {
         T newElement = (T) newLowerClassInstance(params);
         // unchecked cast to (T)(see NB above)
         list.add(newElement);
         System.out.println("Added " + newElement + " to " + this);
      }
   }

   abstract Superclass newLowerClassInstance(String params);

   // Needed because you can't create an instance of a type in Java...
   // In load(...) we really want to say newInstance = new T(params));
   // but you can't.
   // This method returns a new instance of the appropriate next lower class
   // using the params (just for illustration here)
   // ****   Needs to be implemented for each class (trivial****)
   // (these implementations define the hierarchy - neat or what?)

   public String toString() { // just to make print a bit smarter
      return "a " + this.getClass().toString().split(" ")[1];
   }

}

/////////////////////////////////////////////////////////////////////////

class Sub1 extends Superclass { // first in hierarchy of subclasses
   ArrayList<Sub2> list = new ArrayList<Sub2>();

   Sub1(String params) {
      load(list, params);
   }

   Superclass newLowerClassInstance(String params) {
      return new Sub2(params);
   }
}

/////////////////////////////////////////////////////////////////////////

class Sub2 extends Superclass { // second in hierarchy of subclasses
   ArrayList<Sub3> list = new ArrayList<Sub3>();

   Sub2(String params) {
      load(list, params);
   }

   Superclass newLowerClassInstance(String params) {
      return new Sub3(params);
   }
}

/////////////////////////////////////////////////////////////////////////

class Sub3 extends Superclass { // bottom of hierarchy of subclasses
   Sub3(String params) {
      // has no list to load
   }

   Superclass newLowerClassInstance(String params) {
      return null; // there is no lower class in the hierarchy
   }
}

Have a look at that - it's more comments than code, but the code is complete - it illustrates jsu what you need (it's runnable too, you can check the output)

ps: here's a good example of how the right architecture can help you...
combining the word/number thing into the code I just posted is easy because of the way it's structured...
Inthe Phrase class you implement the abstract method like this

class Phrase {
  Superclass newLowerClassInstance(String params) {
    Word w = new Word(params);
    if (w.isAllNumeric()) return new NumericWord(w);
    // Word class needs a method to say it consists of all numerics
    return w;
  }
}

class NumericWord extends Word{
   NumericWord(Word w) {
     // copy the instance variables from w
   }
}
commented: JamesCherrill, thanks for your effort in getting into my shoes, and for putting your knowledge at my fingertips. You took your time to carefully understand my problema and got it seriously to help. +1

James, I am sorry that I didn't get back to you and to this thread. Now I have moved to Boston and finally couldn't finish all my study. I actually had a version that worked perfectly in all but the generics (I decided to stop, but they were so promising that I would definitely return to them in the future) and in Number as subclass of Word. But I carefully had copied all your suggestions and guides. I found them very smart and try-worth.

For now I don't have to go on with this project, sadly, because I really want to see it working and full of advanced design. The teachers did like it very much(and their congratulations should be extended to you), and hey accepted it as finished 'cause they saw it covered everything the asked for.

Anyway, now I "know where yoy e-live", so I will be back as soon as I have another project.

Thanks for everything and be sure that I will add more gold to your reputation.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.