Data, Classes, Inheritance

/* This is wrapper class...
 Objective would be to push more functionality into this Class to enforce consistent definition
 */
public abstract class Generics {
	public final String masterType = "Generic";
	private String type;	// extender should define their data type

	// generic enumerated interface
	public interface KeyTypes {
		String name();
	}
	protected abstract KeyTypes getKey();  	// this method helps force usage of KeyTypes

	// getter
	public String getMasterType() {
		return masterType;
	}

	// getter
	public String getType() {
		return type;
	}

	// setter
	public void setType(String type) {
		this.type = type;
	}
	
	// this method is used to establish key order
	public abstract String toString();

	// static print method used by extended classes
	public static void print(Generics[] objs) {
		// print 'Object' properties
		System.out.println(objs.getClass() + " " + objs.length);

		// print 'Generics' properties
		if (objs.length > 0) {
			Generics obj = objs[0];	// Look at properties of 1st element
			System.out.println(
					obj.getMasterType() + ": " + 
					obj.getType() +
					" listed by " +
					obj.getKey());
		}

		// print "Generics: Objects'
		for(Object o : objs)	// observe that type is Opaque
			System.out.println(o);

		System.out.println();
	}
}

public class Alphabet extends Generics {
	// Class data
	public static KeyTypes key = KeyType.title;  // static initializer
	public static void setOrder(KeyTypes key) {Alphabet.key = key;}
	public enum KeyType implements KeyTypes {title, letter}
	private static final int size = 26;  // constant used in data initialization

	// Instance data
	private final char letter;
	
	/*
	 * single letter object
	 */
	public Alphabet(char letter)
	{
		this.setType("Alphabet");
		this.letter = letter;
	}

	/* 'Generics' requires getKey to help enforce KeyTypes usage */
	@Override
	protected KeyTypes getKey() { return Alphabet.key; }

	/* 'Generics' requires toString override
	 * toString provides data based off of Static Key setting
	 */
	@Override
	public String toString()
	{
		String output="";
		if (KeyType.letter.equals(this.getKey())) {
			output += this.letter;
		} else {
			output += super.getType() + ": " + this.letter;
		}
		return output;
	}

	// Test data initializer for upper case Alphabet
	public static Alphabet[] alphabetData()
	{
		Alphabet[] alphabet = new Alphabet[Alphabet.size];
		for (int i = 0; i < Alphabet.size; i++)
		{
			alphabet[i] = new Alphabet( (char)('A' + i) );
		} 	
		return alphabet;
	}
	
	/* 
	 * main to test Animal class
	 */
	public static void main(String[] args)
	{
		// Inheritance Hierarchy
		Alphabet[] objs = alphabetData();

		// print with title
		Alphabet.setOrder(KeyType.title);
		Alphabet.print(objs);

		// print letter only
		Alphabet.setOrder(KeyType.letter);
		Alphabet.print(objs);
	}
	
}
Alphabet.main(null);
class [LREPL.$JShell$13$Alphabet; 26
Generic: Alphabet listed by title
Alphabet: A
Alphabet: B
Alphabet: C
Alphabet: D
Alphabet: E
Alphabet: F
Alphabet: G
Alphabet: H
Alphabet: I
Alphabet: J
Alphabet: K
Alphabet: L
Alphabet: M
Alphabet: N
Alphabet: O
Alphabet: P
Alphabet: Q
Alphabet: R
Alphabet: S
Alphabet: T
Alphabet: U
Alphabet: V
Alphabet: W
Alphabet: X
Alphabet: Y
Alphabet: Z

class [LREPL.$JShell$13$Alphabet; 26
Generic: Alphabet listed by letter
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z

Modified Class for our Lesson

/*
 * Types class extends Generics and defines abstract methods
 */
public class Types extends Generics {
	// Class data
	public static KeyTypes key = KeyType.title;  // static initializer
	public static void setOrder(KeyTypes key) { Types.key = key; }
	public enum KeyType implements KeyTypes {title, name, isPrimitive, isObject}

	// Instance data
	private final String name;
	private final boolean isPrimitive;
	private final boolean isObject;

	/* constructor
	 *
	 */
	public Types(String name, boolean isPrimitive, boolean isObject)
	{
		super.setType("Types");
		this.name = name;
		this.isPrimitive = isPrimitive;
		this.isObject = isObject;
	}

	/* 'Generics' requires getKey to help enforce KeyTypes usage */
	@Override
	protected KeyTypes getKey() { return Types.key; }
	
	/* 'Generics' requires toString override
	 * toString provides data based off of Static Key setting
	 */
	@Override
	public String toString()
	{
		String output="";
		if (KeyType.name.equals(this.getKey())) {
			output += this.name;
		} else if (KeyType.isPrimitive.equals(this.getKey())) {
			output += this.isPrimitive;
		} else if (KeyType.isObject.equals(this.getKey())) {
			output += this.isObject;
		} else {
			output += super.getType() + ": " + this.name + ", is a primitive data type: " + this.isPrimitive + ", is an object: " + this.isObject;
		}
		return output;
		
	}

	// Test data initializer
	public static Types[] typess() {
		return new Types[]{
				new Types("ArrayList", false, true),
				new Types("Array", false, true),
				new Types("2D Array", false, true),
				new Types("Int", true, false),
				new Types("Boolean", true, false),
				new Types("Float", true, false)
		};
	}
	
	/* main to test Types class
	 * 
	 */
	public static void main(String[] args)
	{
		// Inheritance Hierarchy
		Types[] objs = typess();

		// print with title
		Types.setOrder(KeyType.title);
		Types.print(objs);

		// print name only
		Types.setOrder(KeyType.name);
		Types.print(objs);

		// print object status only
		Types.setOrder(KeyType.isObject);
		Types.print(objs);
	}

}
Types.main(null);
class [LREPL.$JShell$15F$Types; 6
Generic: Types listed by title
Types: ArrayList, is a primitive data type: false, is an object: true
Types: Array, is a primitive data type: false, is an object: true
Types: 2D Array, is a primitive data type: false, is an object: true
Types: Int, is a primitive data type: true, is an object: false
Types: Boolean, is a primitive data type: true, is an object: false
Types: Float, is a primitive data type: true, is an object: false

class [LREPL.$JShell$15F$Types; 6
Generic: Types listed by name
ArrayList
Array
2D Array
Int
Boolean
Float

class [LREPL.$JShell$15F$Types; 6
Generic: Types listed by isObject
true
true
true
false
false
false

Quick CB Notes

  • using static methods means that you can use the methods without creating an object, example being the Math class where you can say class.method instead of object.method
  • string class object where you can set it equal to a word like "theater" word.length
  • constructor is used to create the instance of the class
  • constructing an object using a class, and using an object uses object.method because it is an accessor method that returns a variable that returns the method ex: String location = teacher.getLocation(); or teacher.changeLocation("Florida");
  • modifiers are used to change the access to a method, like public, private, etc
  • setters/getters are used to protect the data in a class, getters return the value while setters sets or updates a value

Linked Lists, Queue, Stack, generic <T>

public class Node{
    Node next;
    int data;
    public ListLists(int data){
        this.data = data;
    }

}
// Linked lists are all connected. So, you can do methods like current.next or head.next. 



public class LinkedList{
    Node head;

    /*
     * We have to go to the head, then keep going to the next, untill you add the elemtn you want.
     */
    public void append(int data){

        if (head == null){
            head = new Node(data);
            return
        }

        Node current = head;
        while(current.next !=null){
            current = current.next;
        }

        current.next = new Node(data);
    }

    /*
     * If we want to prepend to a linked list, then we have to set the old head to the head.next, and set the new head as head.
     */
    public void prepend(int data){
        Node newHead = new Node(data);
        newHead.next = head;
        head = newHead;

    }

     /*
     in linked lists, we do not actually delete any of the values. For example, if we want to "delete" the second element of the list
    we simply stop at the first, ignore the second element, and then go to the third. 

      */ 
    public void deteleteWithValue(int data){ 
        if (head==null){
            return
        }
        if(head.data == data){
            head = head.next;
            return;
        }

        Node current = head;
        while(current.next != null){
            if(current.next.data == data){
                current.next = current.next.next;
                return;
            }
            current = current.next;
        }
       
    }

}
import java.util.Iterator;

/**
 * Queue Iterator
 *
 * 1. "has a" current reference in Queue
 * 2. supports iterable required methods for next that returns a generic T Object
 */
class QueueIterator<T> implements Iterator<T> {
    LinkedList<T> current;  // current element in iteration

    // QueueIterator is pointed to the head of the list for iteration
    public QueueIterator(LinkedList<T> head) {
        current = head;
    }

    // hasNext informs if next element exists
    public boolean hasNext() {
        return current != null;
    }

    // next returns data object and advances to next position in queue
    public T next() {
        T data = current.getData();
        current = current.getNext();
        return data;
    }
}

/**
 * Queue: custom implementation
 * @author     John Mortensen
 *
 * 1. Uses custom LinkedList of Generic type T
 * 2. Implements Iterable
 * 3. "has a" LinkedList for head and tail
 */
public class Queue<T> implements Iterable<T> {
    LinkedList<T> head = null, tail = null;

    /**
     *  Add a new object at the end of the Queue,
     *
     * @param  data,  is the data to be inserted in the Queue.
     */
    public void add(T data) {
        // add new object to end of Queue
        LinkedList<T> tail = new LinkedList<>(data, null);

        if (this.head == null)  // initial condition
            this.head = this.tail = tail;
        else {  // nodes in queue
            this.tail.setNextNode(tail); // current tail points to new tail
            this.tail = tail;  // update tail
        }
    }

    /**
     *  Returns the data of head.
     *
     * @return  data, the dequeued data
     */
    public T delete() {
        T data = this.peek();
        if (this.tail != null) { // initial condition
            this.head = this.head.getNext(); // current tail points to new tail
            if (this.head != null) {
                this.head.setPrevNode(tail);
            }
        }
        return data;
    }

    /**
     *  Returns the data of head.
     *
     * @return  this.head.getData(), the head data in Queue.
     */
    public T peek() {
        return this.head.getData();
    }

    /**
     *  Returns the head object.
     *
     * @return  this.head, the head object in Queue.
     */
    public LinkedList<T> getHead() {
        return this.head;
    }

    /**
     *  Returns the tail object.
     *
     * @return  this.tail, the last object in Queue
     */
    public LinkedList<T> getTail() {
        return this.tail;
    }

    /**
     *  Returns the iterator object.
     *
     * @return  this, instance of object
     */
    public Iterator<T> iterator() {
        return new QueueIterator<>(this.head);
    }
}
|           T data = current.getData();
cannot find symbol
  symbol:   method getData()

|           current = current.getNext();
cannot find symbol
  symbol:   method getNext()
/**
 * Queue Manager
 * 1. "has a" Queue
 * 2. support management of Queue tasks (aka: titling, adding a list, printing)
 */
class QueueManager<T> {
    // queue data
    private final String name; // name of queue
    private int count = 0; // number of objects in queue
    public final Queue<T> queue = new Queue<>(); // queue object

    /**
     *  Queue constructor
     *  Title with empty queue
     */
    public QueueManager(String name) {
        this.name = name;
    }

    /**
     *  Queue constructor
     *  Title with series of Arrays of Objects
     */
    public QueueManager(String name, T[]... seriesOfObjects) {
        this.name = name;
        this.addList(seriesOfObjects);
    }

    /**
     * Add a list of objects to queue
     */
    public void addList(T[]... seriesOfObjects) {  //accepts multiple generic T lists
        for (T[] objects: seriesOfObjects)
            for (T data : objects) {
                this.queue.add(data);
                this.count++;
            }
    }

    /**
     * Print any array objects from queue
     */
    public void printQueue() {
        System.out.println(this.name + " count: " + count);
        System.out.print(this.name + " data: ");
        for (T data : queue)
            System.out.print(data + " ");
        System.out.println();
    }
}

/**
 * Driver Class
 * Tests queue with string, integers, and mixes of Classes and types
 */
class QueueTester {
    public static void main(String[] args)
    {
        // Create iterable Queue of Words
        Object[] words = new String[] { "seven", "slimy", "snakes", "sallying", "slowly", "slithered", "southward"};
        QueueManager qWords = new QueueManager("Words", words );
        qWords.printQueue();

        // Create iterable Queue of Integers
        Object[] numbers = new Integer[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        QueueManager qNums = new QueueManager("Integers", numbers );
        qNums.printQueue();

        // Create iterable Queue of NCS Generics
        Animal.setOrder(Animal.KeyType.name);
        Alphabet.setOrder(Alphabet.KeyType.letter);
        Cupcake.setOrder(Cupcake.KeyType.flavor);
        // Illustrates use of a series of repeating arguments
        QueueManager qGenerics = new QueueManager("My Generics",
                Alphabet.alphabetData(),
                Animal.animals(),
                Cupcake.cupcakes()
        );
        qGenerics.printQueue();

        // Create iterable Queue of Mixed types of data
        QueueManager qMix = new QueueManager("Mixed");
        qMix.queue.add("Start");
        qMix.addList(
                words,
                numbers,
                Alphabet.alphabetData(),
                Animal.animals(),
                Cupcake.cupcakes()
        );
        qMix.queue.add("End");
        qMix.printQueue();
    }
}
QueueTester.main(null);
|       public final Queue<T> queue = new Queue<>(); // queue object
java.util.Queue is abstract; cannot be instantiated

|       public QueueManager(String name, T[]... seriesOfObjects) {
Possible heap pollution from parameterized vararg type T[]

|       public void addList(T[]... seriesOfObjects) {  //accepts multiple generic T lists
Possible heap pollution from parameterized vararg type T[]

Hack 1

public static class Queue{

    private static class Node{
        private int data;
        private Node next;
        private Node(int data){
            this.data = data;
        }
    }

    private Node head;
    private Node tail;
    
    public boolean isEmpty(){
        return head == true;
    }

    public int peek(){
        return head.data;
    }

    public void add(int data){
        //add to the tail
        Node node = new Note(data);
        if (tail != null){
            tail.next = node;
        }
        tail = node;
        if (head ==null){
            head = node;
        }        
    }

    public int remove(){
        int data = head.data;
        head = head.next;
        if (head ==null){
            tail = null;
        }
        return data;
    }


}

public class QueueExample {
    public static void main(String[] args) {
        Queue<String> queue = new LinkedList<String>();

        // Adding elements to the queue
        queue.add("seven");
        System.out.println("Enqueued data: " + "seven");
        printQueue(queue);

        queue.add("slimy");
        System.out.println("Enqueued data: " + "slimy");
        printQueue(queue);

        queue.add("snakes");
        System.out.println("Enqueued data: " + "snakes");
        printQueue(queue);

        queue.add("sallying");
        System.out.println("Enqueued data: " + "sallying");
        printQueue(queue);

        queue.add("slowly");
        System.out.println("Enqueued data: " + "slowly");
        printQueue(queue);

        queue.add("slithered");
        System.out.println("Enqueued data: " + "slithered");
        printQueue(queue);

        queue.add("southward");
        System.out.println("Enqueued data: " + "southward");
        printQueue(queue);

        // Removing elements from the queue
        String data =queue.remove();

        System.out.println("Dequeued data: " + data);
        printQueue(queue);

        data = queue.remove();
        System.out.println("Dequeued data: " + data);
        printQueue(queue);

        data = queue.remove();
        System.out.println("Dequeued data: " + data);
        printQueue(queue);

        data = queue.remove();
        System.out.println("Dequeued data: " + data);
        printQueue(queue);

        data = queue.remove();
        System.out.println("Dequeued data: " + data);
        printQueue(queue);

        data = queue.remove();
        System.out.println("Dequeued data: " + data);
        printQueue(queue);

        data = queue.remove();
        System.out.println("Dequeued data: " + data);
        printQueue(queue);
    }

    // Helper method to print the contents of the queue
    public static void printQueue(Queue<String> queue) {
        System.out.println("Words count: " + queue.size() + ", data: " + String.join(" ", queue));
        System.out.println();
    }
}

QueueExample.main(null);
|           return head == true;
bad operand types for binary operator '=='
  first type:  Queue.Node
  second type: boolean

|           Node node = new Note(data);
cannot find symbol
  symbol:   class Note

|   public static class Queue{
Modifier 'static' not permitted in top-level declarations, ignored

Hack 2

public class Combine{
    public ListNode main(listNode l1, listNode l2){
        ListNode current_node = new ListNode(0);
        while (l1!=null && l2!=null){
            if (l1.val<l2.val){
                current_node.next = l1;
                l1 = l1.next;
            }
            else{
                current_node.next = l2;
                l2 = l2.next;
            }

            current_node = current_node.next;
        }

        if((l1==null && l2!=null)){
            current_node.next = l2;
            l2 = l2.next;
        }
        if((l1!=null && l2==null)){
            current_node.next = l1;
            l1 = l1.next;
        }

        return current_node.next;
    }
}
Combine.main(null);
|   public class Combine{
|       public ListNode main(listNode l1, listNode l2){
|           ListNode current_node = new ListNode(0);
|           while (l1!=null && l2!=null){
|               if (l1.val<l2.val){
|                   current_node.next = l1;
|                   l1 = l1.next;
|               }
|               else{
|                   current_node.next = l2;
|                   l2 = l2.next;
|               }
|   
|               current_node = current_node.next;
|           }
|   
|           if((l1==null && l2!=null)){
|               current_node.next = l2;
|               l2 = l2.next;
|           }
|           if((l1!=null && l2==null)){
|               current_node.next = l1;
|               l1 = l1.next;
|           }
|   
|           return current_node.next;
|       }
|   }
Unresolved dependencies:
   - class listNode
   - class ListNode

Hack 3

public static class Random{

    private static class Node{
        private int data;
        private Node next;
        private Node(int data){
            this.data = data;
        }
    }
    private Node current;
    
    public static void main(String[] args) {
    while (node.current!= null){
        node.current = Math.random() *10;
    }
    }
}
Random.main(null);
|   public static class Random{
|   
|       private static class Node{
|           private int data;
|           private Node next;
|           private Node(int data){
|               this.data = data;
|           }
|       }
|       private Node current;
|       
|       public static void main(String[] args) {
|       while (node.current!= null){
|           node.current = Math.random() *10;
|       }
|       }
|   }
Unresolved dependencies:
   - variable node

Hack 4

public class Reverse{
    public static void main(String[] args){  
    Queue <Integer> queue = new ArrayDeque<>();
    queue.add(10);
    queue.add(20);
    queue.add(30);
    System.out.println(queue);

    Stack<Integer> stack = new Stack<>();
    while(!queue.isEmpty()){
        stack.push(queue.remove());
    }

    while(!stack.isEmpty()){
        queue.add(stack.pop());
    }
    System.out.print(queue);
}
}

Reverse.main(null);
[10, 20, 30]
[30, 20, 10]