Generics Hacks
Generics Hacks
/* 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();
}
}
/*
* Animal class extends Generics and defines abstract methods
*/
public class Users extends Generics {
// Class data
public static KeyTypes key = KeyType.name; // static initializer
public static void setOrder(KeyTypes key) {Users.key = key; }
public enum KeyType implements KeyTypes {name, score}
// Instance data
private final String name;
private final int score;
/* constructor
*
*/
public Users(String name, int score)
{
super.setType("Users");
this.name = name;
this.score = score;
}
/* 'Generics' requires getKey to help enforce KeyTypes usage */
@Override
protected KeyTypes getKey() { return Users.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.score.equals(this.getKey())) {
output += this.score;
//output = output.substring(output.length() - 2);
} else {
output += super.getType() + ": " + this.name + ", " + this.score;
}
return output;
}
// Test data initializer
public static Users[] user() {
return new Users[]{
new Users("Bob", 8),
new Users("Jane", 10)
};
}
/* main to test Animal class
*
*/
public static void main(String[] args)
{
// Inheritance Hierarchy
Users[] objs = user();
// print with title
Users.setOrder(KeyType.name);
Users.print(objs);
// print name only
Users.setOrder(KeyType.score);
Users.print(objs);
}
}
Users.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();
}
public T peekLast() {
return this.tail.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);
}
}
import java.util.Random;
import java.util.ArrayList;
import java.lang.Math;
/**
* 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;
}
/**
* Add a list of objects to queue
*/
// RETURN SIZE OF QUEUE
public int queueSize(Queue<T> queueInput) {
int size = 0;
for (T data : queueInput) {
size++;
}
return size;
}
/********************************************************************************* */
// HACK 1
public void addList(T[]... seriesOfObjects) { //accepts multiple generic T lists
for (T[] objects: seriesOfObjects)
for (T data : objects) {
this.queue.add(data);
this.count++;
}
}
public void addListHack(T[]... seriesOfObjects) { //accepts multiple generic T lists
for (T[] objects: seriesOfObjects)
for (T data : objects) {
this.queue.add(data);
this.count++;
printQueue();
}
}
public void deleteList(T[]... seriesOfObjects) { //accepts multiple generic T lists
for (T[] objects: seriesOfObjects)
for (T data : objects) {
this.queue.delete();
this.count--;
printQueue();
}
}
/********************************************************************************* */
// HACK 2
public void sortSteps(T[]... seriesOfObjects) {
addList(seriesOfObjects);
sort();
}
public void sort() {
int size = queueSize(queue);
for (int j = 0; j < size - 1; j++) {
// take first item in queue
T a = this.queue.peek();
T b = null;
// remove the first item
this.queue.delete();
// do a bubble sort
for (int i = 0; i < size - 1; i++) {
b = this.queue.peek();
// add the smaller number to the end of the queue
// this way, the largest number is left at the very back
if ((Integer)a < (Integer)b) {
queue.add(a);
a = this.queue.peek();
this.queue.delete();
} else {
queue.add(b);
this.queue.delete();
}
}
// add the largest number to the back of the queue
// largest number is always a because it is either:
// 1. a = this.queue.peek() (last element of queue = biggest)
// or 2. if b < a, then a is already the biggest number
queue.add(a);
}
for (T data : queue) {
System.out.println(data);
}
}
/********************************************************************************* */
// HACK 3
public void randomSteps(T[]... seriesOfObjects) {
addList(seriesOfObjects);
//random();
}
public boolean matchElem(int ranNum, int[] order) {
for (int i = 0; i < order.length; i++) {
if (ranNum == order[i]) {
return true;
}
}
return false;
}
public void random() {
int size = queueSize(queue);
Random rand = new Random();
int randInt = rand.nextInt(size);
Queue<T> queue2 = new Queue<>();
Queue<T> queue3 = new Queue<>();
boolean match = true;
ArrayList<Integer> originalOrder = new ArrayList<>();
for (int i = 1; i <= size; i++) {
originalOrder.add(i);
}
while (originalOrder.size() > 0) {
// some number between 0 and 7
int num = originalOrder.remove((int)(Math.random() * originalOrder.size()));
int num2 = originalOrder.remove((int)(Math.random() * originalOrder.size()));
/* DEBUGGING
System.out.println("NUM: " + num);
System.out.println("NUM2: " + num2);
*/
if (num2 < num) {
int temp = num2;
num2 = num;
num = temp;
}
// split queue into queue (bigger #) (345678) and queue2 (smaller #) (12)
for (int i = 0; i <= num; i++) {
T a = queue.peek();
queue2.add(a);
queue.delete();
}
// splite queue into queue (678) and queue3 (345)
// queue2 = 12
if (num2 == 8) {
for (int i = 0; i <= num2-num-2; i++) {
T a = queue.peek();
queue3.add(a);
queue.delete();
}
}else {
for (int i = 0; i <= num2-num-1; i++) {
T a = queue.peek();
queue3.add(a);
queue.delete();
}
}
// finding last elements of queues (these numbers should be swapped)
T pos1 = queue2.peekLast();
T pos2 = queue3.peekLast();
/* DEBUGGING
System.out.println("pos1: " + pos1);
System.out.println("pos2: " + pos2);
*/
// size of two queues
int queue2Size = queueSize(queue2);
int queue3Size = queueSize(queue3);
// reshuffle
// move q2's numbers to end of q3
for (int i = 0; i < queue2Size - 1; i++) {
T a = queue2.peek();
queue3.add(a);
queue2.delete();
}
T queue2Last = queue2.peek();
queue2.delete();
// move original q3's numbers to q2
for (int i = 0; i < queue3Size - 1; i++) {
T a = queue3.peek();
queue2.add(a);
queue3.delete();
}
T queue3Last = queue3.peek();
queue3.delete();
// swap numbers
queue2.add(queue2Last);
queue3.add(queue3Last);
size = queueSize(queue);
queue2Size = queueSize(queue2);
queue3Size = queueSize(queue3);
for (int i = 0; i < queue3Size; i++) {
T a = queue3.peek();
queue.add(a);
queue3.delete();
}
for (int i = 0; i < queue2Size; i++) {
T a = queue2.peek();
queue.add(a);
queue2.delete();
}
for (int i = 0; i < size; i++) {
T a = queue.peek();
queue.add(a);
queue.delete();
}
/*DEBUGGING
System.out.println("*************");
for (T data : queue) {
System.out.println(data);
}
System.out.println("****************");
*/
}
for (T data : queue) {
System.out.println(data);
}
}
/********************************************************************************* */
public void stack() {
Stack<T> stacks = new Stack<>();
for (T data : this.queue) {
System.out.println(data);
T a = this.queue.peek();
System.out.println("A: " + a);
this.queue.delete();
stacks.push(a);
}
int size = 0;
for (T data : stacks) {
size++;
}
/*
for (T data : stacks) {
System.out.println(stacks.peek());
}
stacks.pop();
*/
for (int i = 0; i < size; i++) {
System.out.println(stacks.peek());
stacks.pop();
}
}
/**
* 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.addListHack(words);
qWords.deleteList(words);
}
}
QueueTester.main(null);
class QueueTester2 {
public static void main(String[] args)
{
// Create iterable Queue of Integers
Object[] numbers = new Integer[] { 1, 4, 5, 8};
Object[] numbers2 = new Integer[] {2, 3, 6, 7};
QueueManager qNums = new QueueManager("Integers", numbers, numbers2);
qNums.sortSteps(numbers, numbers2);
}
}
QueueTester2.main(null);
class QueueTester3 {
public static void main(String[] args)
{
// Create iterable Queue of Integers
Object[] numbers = new Integer[] {1, 2, 3, 4, 5, 6, 7, 8};
QueueManager qNums = new QueueManager("Integers", numbers);
qNums.randomSteps(numbers);
qNums.random();
//qNums.random();
}
}
QueueTester3.main(null);
class QueueTester4 {
public static void main(String[] args)
{
// Create iterable Queue of Integers
Object[] numbers = new Integer[] {1, 2, 3};
QueueManager qNums = new QueueManager("Integers", numbers);
qNums.stack();
}
}
QueueTester4.main(null);
Hacks #3
- An access modifier controls if a variable in a class can be accessed outside of the class.
public
allows access outside of the class, whileprivate
does not. A constructor contains a piece of code that is ran when the object is initialized. Setters and getters are methods that change the value of the variable or retrieve its value. A class also includes a class header and methods. Methods can contain a parameters or be empty.