Generics Types and Collections
Generics Types and Collections
Hacks
College Board Classes and Objects
As a part of OOP, classes and objects are fundamentals to the OOP paradigm serving as the building blocks. Essentially, classes are like blueprints and objects are just instances or constructions of that blue print. Classes have a lot of properties and in particular their most useful quality is gathering data and methods into a single place. Methods and data types can either only be called through an instantiation of the class or statically called from the class
Access Modifiers
Access modifiers indicate the level of access different classes/objects have over other classes and objects. Of the four most common types, there are:
- private: only the object/class at hand can modify the object/class itself and cannot be called by sub classes or any other class.
- protected: subclasses can modify/use methods and data from its super classes
- default: default is the setting which enables the entire package (usually sub-classes) to access methods or data.
- public: any thing can call the methods or access the data of public variables/functions
Constructor
Constructors are the most important part of classes/objects since they dictate what happens to the object on the instantiation of the class. They usually ether take in parameters and set them data fields using those parameters, or run internal logic to set those parameters.
Modifiers
Modifiers are special attachments to functions that dictate the use of that function. For instance static only enables the class to call upon functions/data. Finals prevents any other change from occurring at all.
Getters/Setters
Getters and setters are usually reserved for private fields and help access references of certain classes to both as implied get information and set information.
Inheritance, Polymorphism, Abstraction, and Encapsulation
Probably the most important part about classes and objects are the 4 pillars of OOP. Inheritance is the passing down of methods and data from a super class to sub classes. This helps organize objects as "like" each other. We see this particular in this weeks hacks with GenericType and Object classes. Polymorphism is the ability for multiple classes to have the same name implying same output for the same reason but perhaps a different implementation. Abstraction is the broader overview of classes where we want to limit the scope of certain classes as much as possible so that only the most important of their implementation is visible and usable. Finally, encapsulation is the "wrapping" of classes into single objects/classes.
/* 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 Owner extends Generics {
public static KeyTypes key = KeyType.title;
public static void setOrder(KeyTypes key) { Owner.key = key; }
public enum KeyType implements KeyTypes {title, name, age, year, trusted}
private final String name;
private final int age;
private final int year;
// True if used, false if new
private final boolean trusted;
public Owner(String name, int year, int age, boolean trusted)
{
super.setType("Owner");
this.name = name;
this.age = age;
this.year = year;
this.trusted = trusted;
}
@Override
protected KeyTypes getKey() { return Owner.key; }
@Override
public String toString()
{
String output="";
if (KeyType.name.equals(this.getKey())) {
output += this.name;
} else if (KeyType.age.equals(this.getKey())) {
output += "00" + this.age;
output = output.substring(output.length() - 2);
} else if (KeyType.year.equals(this.getKey())) {
output += this.year;
} else if (KeyType.trusted.equals(this.getKey())) {
output += this.trusted;
} else {
output += super.getType() + ": " + this.name + ", " + this.year + ", " + this.age + ", " + this.trusted;
}
return output;
}
// Test data initializer
public static Owner[] owners() {
return new Owner[]{
new Owner("Don Trannn", 17, 2023, false),
new Owner("Bailey Say", 17, 2023, true),
new Owner("Evan Sanches", 17, 2023, true)
};
}
public static void main(String[] args)
{
// Inheritance Hierarchy
Owner[] objs = owners();
// print with title
Owner.setOrder(KeyType.title);
Owner.print(objs);
// print name only
Owner.setOrder(KeyType.name);
Owner.print(objs);
}
}
Owner.main(null);
/**
* Implementation of a Double Linked List; forward and backward links point to adjacent Nodes.
*
*/
public class LinkedList<T>
{
private T data;
private LinkedList<T> prevNode, nextNode;
/**
* Constructs a new element
*
* @param data, data of object
* @param node, previous node
*/
public LinkedList(T data, LinkedList<T> node)
{
this.setData(data);
this.setPrevNode(node);
this.setNextNode(null);
}
/**
* Clone an object,
*
* @param node object to clone
*/
public LinkedList(LinkedList<T> node)
{
this.setData(node.data);
this.setPrevNode(node.prevNode);
this.setNextNode(node.nextNode);
}
/**
* Setter for T data in DoubleLinkedNode object
*
* @param data, update data of object
*/
public void setData(T data)
{
this.data = data;
}
/**
* Returns T data for this element
*
* @return data associated with object
*/
public T getData()
{
return this.data;
}
/**
* Setter for prevNode in DoubleLinkedNode object
*
* @param node, prevNode to current Object
*/
public void setPrevNode(LinkedList<T> node)
{
this.prevNode = node;
}
/**
* Setter for nextNode in DoubleLinkedNode object
*
* @param node, nextNode to current Object
*/
public void setNextNode(LinkedList<T> node)
{
this.nextNode = node;
}
/**
* Returns reference to previous object in list
*
* @return the previous object in the list
*/
public LinkedList<T> getPrevious()
{
return this.prevNode;
}
/**
* Returns reference to next object in list
*
* @return the next object in the list
*/
public LinkedList<T> getNext()
{
return this.nextNode;
}
}
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);
}
}
/**
* 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 NCS Generics
Owner.setOrder(Owner.KeyType.name);
// Illustrates use of a series of repeating arguments
QueueManager qGenerics = new QueueManager("My Generics", Owner.owners());
qGenerics.printQueue();
qGenerics.queue.add(new Owner("Nathan Shih", 18, 2023, false));
qGenerics.printQueue();
qGenerics.queue.delete();
qGenerics.printQueue();
}
}
QueueTester.main(null);
import java.util.Iterator;
public class LinkedList<T> {
private T data;
private LinkedList<T> prevNode, nextNode;
// Create new node with T data and reference to previous LinkedList<T> node
public LinkedList(T data, LinkedList<T> node) {
setData(data);
setPrevNode(node);
setNextNode(null);
}
// Create new node using copy
public LinkedList(LinkedList<T> node) {
setData(node.data);
setPrevNode(node.prevNode);
setNextNode(node.nextNode);
}
// Getters
public T getData() {
return this.data;
}
public LinkedList<T> getPrev() {
return this.prevNode;
}
public LinkedList<T> getNext() {
return this.nextNode;
}
// Setters
public void setData(T data) {
this.data = data;
}
public void setPrevNode(LinkedList<T> node) {
this.prevNode = node;
}
public void setNextNode(LinkedList<T> node) {
this.nextNode = node;
}
}
/**
* 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() {
try {
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;
} catch (Exception E) {
return null;
}
}
/**
* Returns the data of head.
*
* @return this.head.getData(), the head data in Queue.
*/
public T peek() {
try {
return this.head.getData();
} catch (Exception E) {
return null;
}
}
/**
* 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);
}
}
/**
* 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++;
}
}
// Challenge 1
public T delete() {
count--;
return this.queue.delete();
}
/**
* 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();
while (qWords.delete() != null) {
qWords.printQueue();
}
}
}
QueueTester.main(null);