package lectures.inheritance;
import util.annotations.WebDocuments;
/**
 * Again first study and run the program and try to understand what 
 * it does on your own.
 * 
 * It declares and defines a method that is already inherited from its superclass's
 * superclass: addElement(). The @Override annotation indicates this fact.
 * 
 * As the name indicates, this method overrides (replaces) the inherited method 
 * for its instances. 
 * 
 * However, the overridden method can still be accessed using the "super" prefix.
 * 
 */
@WebDocuments({"Lectures/Inheritance.pptx", "Lectures/Inheritance.pdf", "Videos/Inheritance.avi"})
public class AnImprovedInheritingStringSet extends AnInheritingStringDatabase // extending an extended class
    implements InheritingStringDatabase { // same interface as implemented by the superclass

    public AnImprovedInheritingStringSet() {
        super(); 
//      super.super();
        uselessVariable = 1;
//      System.out.println("AnInheritingStringSet constructor called");
//      super();
    }
    
    /*
     * Redeclaration of inherited addElement()
     */
    @Override
    public void addElement(String element) {
        /*
         * Set break point below and step over until you reach super.addElement()
         */
        
        if (!member(element)) { // add only if the element is not a member
            /*
             * click on addElement below and hit F3 to see where the call
             * on super is defined.          * 
             *
             * 
             */
            super.addElement(element);
            /*
             * what if we called addElement without super?           * 
             */
//          addElement(element); 
        }
    }
    
    /*
     * Useless re-declaration, does nothing useful besides show
     * another form of overriding
     */
//  @Override
//  protected boolean isFull() {
//      /*
//       * Click on the name isFull() and hit CTRL-SHIFT_G (or right click
//       * menu, select References->Project) to see which method calls it. 
//       * 
//       * Set breakpoint below and debug-run.
//       * 
//       * When the program breaks look at the stack to see which method calls it and
//       * where the method is declared
//       */
//      System.out.println ("isFull called in Set");
//      return super.isFull();
//  }
    public int size() {
        
        System.out.println ("Set size() called");
        return super.size();
    }
     public static void main (String[] args) {       
        InheritingStringDatabase aStringSet = new AnImprovedInheritingStringSet();
        System.out.println (aStringSet.size()); // size() is implemented in ABaseStringHistory
   
//      StringDatabase aStringSet = new AStringDatabase(); 
        /*
         * click on manipulateDatabase and hit F3 to see where the call is defined
         */
        manipulateDatabase(aStringSet); 
        /*
         * What if we called the static manipulateDatabase with "super"? 
         * Is that legal in Java? Try uncommenting this to see.
         */
//      super.manipulateDatabase(aStringSet);
      }
     
}
/*
.
 */
/*
 * 
 * Set a break point at the start of addElement and Step Over (F6) the 
 * statements to see which path is taken when main is called for each added
 * element. 
 * 
 * 
 * COLLECTIONS
 * 
 * Adding an item a second time to an instance of AnInheritingStringSet
 * results in:  
 *  (a) an exception.
 *  (b) the addition being ignored.
 *  (c) a duplicate item.
 * 
 * INHERITING ANCESTOR METHODS
 *  
 * Look at the call to size() in main.
 * 
 * If object a is an instance of class C, and C is a subclass of E, and E
 * is a subclass of F, then it is  possible to invoke on a:
 *  (a) only the methods implemented in C.
 *  (b) only the methods implemented in  C and E.
 *  (c) only the methods implemented in E. 
 *  (d) methods implemented in C, E and F.
 *
 * REDECLARING ANCESTOR METHODS
 * 
 * 
 * In the following 8 questions, assume c is an instance of C, 
 * e is an instance of E, C is a subclass of E,
 * and both C and E define a method header m.
 * 
 * (T/F) It is illegal to call m on c.
 * 
 * (T/F) It is illegal to call m on e.
 *  
 * (T/F) Calling m on c results in call of the implementation of m in C.
 * 
 * (T/F) Calling m on c results in call of the implementation of m in E.
 * 
 * (T/F) Calling m on e results in call of the implementation of m in C.
 * 
 * (T/F) Calling m on e results in call of the implementation of m in E.
 * 
 * (T/F) Class C can call the implementation of m in E.
 * 
 * (T/F) Class E can call the implementation of m in C.
 * 
 * Uncomment the re-declaration of the isFull() method and follow the 
 * instructions in it. 
 * 
 * (T/F) A method in superclass can call an overriding method in the subclass.
 * 
 * Can the addElement() method in ABaseStringHistory call the member() method
 * in AnInheritingStringSet? Try it if you cannot answer the question.
 *  
 * (T/F) A method in a superclass can call a non-overriding method in the subclass.
 */
/*
 * 
 * CLASS OBJECT
 * 
 * Go to the definition of toString() in ABaseStringHistory.
 * 
 * Comment out the current return statement and uncomment the one below it,
 * which uses super.toString().
 * 
 * ABaseStringHistory does not explicitly extend any class.
 *  
 * To which class is super referring?
 * 
 * Set a breakpoint at the new return statement.
 * 
 * Debug-Run the program again. When you stop at the break point,
 * and step into (F5) the super call in the return statement.
 * 
 * In which class do you land? (You may not be able to see the source code of 
 * the class if you do not have a jdk installed, but you should be able
 * to see the name of the class in Eclipse.) 
 * 
 * Which is true:
 *  (a) The predefined class, Object, is the immediate superclass of any class
 *          that does not explicitly extend a class.
 *  (b) The predefined class, Class, is  the immediate superclass of any class
 *          that does not explicitly extend a class.
 * 
 * (T/F) The method toString() is implemented in the class Object.
 * 
 * Look at the stack of calls in the Debug window. 
 * 
 * You can keep doing step-return (F7) until you hit the main class.
 * 
 * Which statement in the main class led to the call of toString()? (If you were doing
 * step-return the whole way, you will land at the line following that statement)
 * 
 * (T/F) System.out.println(o) calls the toString() method on o.  
 * 
 * Comment out the super.toString() call and uncomment the original 
 * when you are done.
 * 
 */
/*
 * 
 * REDECLARING VARIABLES
 * 
 * Uncomment the declarations of the "size" variable in AnInheritingStringDatabase.
 * 
 * Now we have two declarations of this variable,
 * 
 * Run that program again and look at the output - the member() and removeElement() no
 * longer work properly. 
 * 
 * Can you explain why?
 * 
 * Set a break point at the start of the addElement() method in ABaseStringHistory.
 * 
 * Set a breakpoint also on at the start of the indexOf method in AnInheritingStringDatabase.

 * When the program stops at the addElement() method, hover over the 
 * value of the size variable referenced in the method.
 * 
 * What value does it have when the method finishes? 
 * 
 * Press F8 to resume the program, until you hit the breakpoint in indexOf().
 * 
 * When the program stops in the indexOf() method, hover over the size
 * variable in the method declaration. 
 * 
 * What value is it at the start of  the method? 
 * 
 * Can you explain why it is different? Look at the variables window in the debugger
 * at the variables of the instance of AnInheritingStringDatabase (under "this").
 * 
 * How many size variables does it have and what are their values?
 * 
 * Comment out the duplicate size variable declaration and
 * debug-run the program again.
 *  
 * When the program stops at indexOf, hover over the size 
 * variable declaration again in the method
 * and look at its value again.

 * Will you ever re-declare a variable again in a subclass?
 * 
 * In the following 6 questions, assume c is an instance of C, 
 * e is an instance of E, C is a subclass of E,
 * and both declare a variable v. 
 * 
 * (T/F) It is illegal for C to declare v.
 * 
 * (T/F) c has a single variable named v.
 * 
 * (T/F) c has multiple variables named v.
 * 
 * (T/F) Methods declared in class C refer to the variable defined in C.
 * 
 * (T/F) Methods declared in class C refer to the variable defined in E. 
 *  
 * (T/F) Methods declared in class E refer to the variable defined in E. 
 * 
 */
/*
 * PRIVATE VS PROTECTED VS DEFAULT ACCESS
 *
 * For this part, you need to know to look for compile errors in classes
 * in this package and the package lectures.inheritance.extra.  
 * 
 * You will play with the access of the variable "uselessVariable" declared in
 * class ABaseStringHistory by commenting and uncommenting appropriate
 * alternate declarations.
 * 
 * In reaction to changes to this access, you will determine in which classes
 * (in these two packages) compile errors arise, indicating that the variable
 * is no longer visible.
 * 
 * You can go to the declaration of uselessVariable and press CTRL SHIFT G
 * to see all of its references, or place your cursor in it, right-click and
 * select References->Workspace.
 * 
 * The variable is accessed in the several places. It is accessed in the three
 * classes we have seen so far, all of which are in this package. 
 * 
 * It is also accessed in AnIndependentClassInSamePackage, declared in this
 * package, which is not a subclass of ABaseStringHistory.
 * 
 * In addition, it is accessed in 
 * lectures.inheritance.extra.AnObservableStringHistory and
 * lectures.inheritace.extra.AnIndependentClassInAnotherPackage. The former is 
 * a subclass of AABaseStringHistory while the latter is not.
 * 
 * Currently the access is public, which makes the variable visible in all
 * classes in which it is accessed. 
 * 
 * Change the access to private, protected, and default, and observe the errors.
 * After each change, save the file so that Java rebuilds the project and you see
 * the errors.
 * 
 * A class C can access private variables of class D only if: 
 *  (a) C and D are the same.
 *  (b) C is a subclass of D (directly or indirectly).
 *  (c) C is in the same package as D.
 *  (d) none of the above
 *  
 * A class C can access protected variables of class D only if:  
 *  (a) C is a subclass of D (directly or indirectly).
 *  (b) C is in the same package as D.
 *  (c) C is a subclass of D (directly or indirectly) or C is in
 *      the same package as D
 *  (d) C and D are the same
 *  
 * A class C can access variables declared in class D with default access only if:  
 *  (a) C and D are the same.
 *  (b) C is a subclass of D (directly or indirectly).
 *  (c) C is in the same package as D.
 *  (d) C is a subclass of D (directly or indirectly) or C is in
 *      the same package as D.
 *  
 * Return the variable to public access once you're done.
 *
 * CONSTRUCTORS AND SUBCLASSING
 * 
 * Uncomment the println() calls in the parameterless constructor in 
 * ABaseStringHistory, AnInheritingStringDatabase, and AnInheritingStringSet
 * and run this program and observe the output.
 * 
 * If C is a subclass of E, and an object c of type C is instantiated, then:
 *  (a) a constructor of only C is called.
 *  (b) a constructor of only E is called.
 *  (c) a constructor of C and E are called. 
 * 
 * Comment out the first call to super() and uncomment the first call to
 * super(2) in the constructor of AnInheritingStringDatabase.
 * 
 * Run the program or use F3 to go to the definition of super(2).
 * 
 * (T/F) A constructor in a class can  determine which overloaded
 *  constructor of its superclass is called by providing appropriate parameters to
 *  a super call that does not specify a method name.
 *  
 *  Comment out the first call to super(2) and uncomment the second one. 
 *  What happens?
 *  
 *  Comment out the super(2) call.
 *  
 * (T/F) A super() call can be invoked anywhere in a constructor.
 * 
 * Uncomment the super(2) call in the clear() method. What happens? 
 * 
 * (T/F) A superclass constructor can be called from any method of a subclass.
 * 
 * Comment out this super(2) call.
 * 
 * Now you have no super calls in AnInheritingStringDatabase.
 * 
 * Run the program.
 * 
 * Is the constructor of ABaseStringHistory called? If so, which one?
 * 
 * Comment out the parameterless constructor in ABaseStringHistory and go to
 * AnInheritingStringDatabase. What happened?
 * 
 * If no super() call is made in a constructor:
 *  (a) an exception is thrown.
 *  (b) no superclass constructor is called.
 *      (c) a call to the parameterless super constructor is automatically added as
 *  the first statement in the constructor. 
 *  
 *  Uncomment the parameterless constructor in ABaseStringHistory.
 *  
 * Comment out the entire constructor in AnInheritingStringDatabase so
 * we have no constructor in this class.
 * 
 * Run the program. Is the superclass constructor called?
 * 
 * (T/F) If a class has no constructor, then Java inserts into its object code
 * a constructor with no parameters that makes a call to a constructor with
 * no parameters in its superclass.
 * 
 * 
 * ORDER OF INITIALIZATION
 * 
 * To really understand what is going on, put a break point on the first statement of 
 * the constructor in AStringSet and use f5 (Step into) to trace the path to the constructor
 * in ABaseStringHistory noting the order in which the variables and constructors are called.
 * Step over (F6) any println calls so that you do not get pulled into that code (if you
 * accidentally step into a println call, just step return- F8).
 * 
 * What is the order of initialization in this process?
 * 
 */