Code reuse without generics - java

Say that I need to create 3 linked lists one for int, one for Strings and one for a different type of custom object. If I was using generics it would be easy to do this just by creating one linked list but is there a way to avoid writing the same repetetive code 3 times if I was not using generics?

If you use Integer instead of int, then yes. In this case, all three objects are subclasses of Object so your Linked List class could just deal with Objects.
The code would look, roughly, like:
class MyLinkedList{
public void add(Object){...}
public Object remove(Object){...}
...
}

Before the introduction of generics in Java 1.5 the Collections all used the type Object, so you would have a linked list of Objects. You then had to make sure yourself that you were adding, retrieving and casting the right types.
I don't see any reason why you shouldn't or wouldn't use generics since using Java 1.4 is hardly necessary or recommended anymore.

You couldn't use the same code for ints vs Strings, but assuming you meant Integers, then you would have to create a LinkedList that stored java.lang.Objects, which by the way, is what generic based LinkedLists do.

You can abstract out the type that the linked list handles into your own type, say StringOrIntOrCustom, that has one of each type, and a flag that specifies which one is the valid one to use. However, you'd need to do a lot of checking to make sure you're not doing an operation that a type does not support whenever you use this data type.

You could do it with out generics, but you would have no compile time type safety checking and you will have to add all the type casting manually.
But then again you will essentially doing what the compiler does when you use generics. Now it's just error prone and manual.

Yes, you can do this, and it's not that hard.
abstract class ListNode {
public ListNode next_;
};
interface ListNodeFactory {
public ListNode createListNode();
}
You then create a List class the manipulates ListNode objects. It will have a function it calls to create a new ListNode when it needs one. The add method would take a ListNodeFactory argument. I would suggest most of the methods be protected because no client that's not a derived class is likely to use it.
The you create a derived class from List for each type. You will have to wrap each method with one that takes the type you want. You will also have to create a ListNodeFactory implementation that creates new list nodes with the appropriate type in them. It will also have to cast the ListNode objects it gets out from traversals or removals to the appropriate types in order to get at the data. Here is an example:
class IntListNode extends ListNode {
public int data_;
public IntListNode(int x) {
data_ = x;
}
}
class IntListNodeFactory implements ListNodeFactory {
IntListNodeFactory() {
nextdataset_ = false;
}
IntListNodeFactory(int x) {
nextdataset_ = true;
data_ = x;
}
void setNextData(int x) {
nextdataset_ = true;
nextdata_ = x;
}
public ListNode createListNode() {
if (!nextdataset_) {
throw Exception("Tried to create a node with no data!");
} else {
ListNode result = new IntListNode(data_);
nextdataset_ = false;
return result;
}
}
}

Related

One constructor with one argument that creates two different objects

So I'm taking a Java class, and one of the assignments we were given involves abstract data types (ADTs). In this assignment, we're supposed to implement an ADT known as Stack through a class called LinkedStack. LinkedStack has one constructor, but in the test cases my professor provided us, a new LinkedStack object can create either a new LinkedList object or a new ArrayList object. My issue with this is that no matter how I define my argument, I still get an error saying that the argument is incompatible with the classes.
I've tried a logical test to see whether the argument was called as a LinkedList or an ArrayList, which I think is a good thing, but I can't figure out how to properly assign the argument.
I've tried setting the argument to a Stack and then casting to a LinkedStack, with a private final variable being of of type "Stack", I've also tried calling the argument as a List, but I can't seem to get rid of the errors preventing me from starting the compiling process.
This is what we start out with:
interface Stack {
public void push(Object d){
}
public Object pop(){
}
public Object peek(){
}
public boolean isEmpty(){
}
}
public class ListStack implements Stack{
public ListStack(/*argument*/){
}
}
//Separate test case file
//example of the test cases
public void peekTest1() {
Stack q = new ListStack(new LinkedList());
// assertion cases follow
}
public void peekTest2() {
Stack q = new ListStack(new ArrayList());
// assertion cases follow
}
If you look for a type that you can use for /*argument*/, you can do it like this:
public class ListStack implements Stack {
public ListStack(List list) {
}
/* note that you must implement all methods from the interface */
}
Why use type List? List is the common interface, implemented by LinkedList and ArrayList. So you can use one of them in the constructor.
Note: You should not use raw types. List and the classes that implement this interface have a type parameter. When possible you should rather use something like List<String> or List<T>. But maybe, you will learn this in a later lesson.

Is it possible to define a method that accepts any number of nested lists?

I have no particular use for this in mind, but is it possible to write a method that accepts any number of nested lists in Java?
I got as far as this:
private <T extends List<? extends T>> void masterOfLists(final T list) {
}
The small issue with this now is that it never ends. I neither want to lose generics, so simply accepting an Object and try casting it to a List every pass is not an option in my question.
I hoped it would be clear enough, but appereantly it isn't for some, I want the method masterOfLists to accept the following examples (and way more):
masterOfLists(new ArrayList<Object>())
masterOfLists(new ArrayList<List<Object>>())
masterOfLists(new ArrayList<List<List<Object>>>())
masterOfLists(new ArrayList<List<List<List<Object>>>>())
Instead of Object it may also be a concrete type like String.
The used List may be any type of list, like ArrayList or LinkedList or your custom implementation.
Using pure List won't help you here, you need to define a recursive class.
As an additional source of inspiration you can take a look at my code for Recursive Tic-Tac-Toe
You could create a class something like this:
public class Recursive<T> {
List<Recursive<T>> sub;
T value;
boolean hasSub() {
return sub != null;
}
T getValue() {
return value;
}
void forEach(Consumer<T> t) {
if (hasSub())
sub.forEach(t);
else t.accept(value);
}
}
You can use logic in this class to prevent it from both having a sub-list and an actual value, using constructors and/or setters.
And then if you want to iterate over it and print out all the sub-items recursively, you can use
Recursive<T> recursive;
recursive.forEach(System.out::println);
Then your method can look like this:
private <T> void masterOfLists(final Recursive<T> list) {
You won't get anywhere using pure Lists because the generic type of the list is not available at runtime, and the generics will only create a mess for you here. Using a recursive class is much easier.
The 'cheap' solution is to extend the ArrayList class with your own name, and force the Generics on the subclass. The SubClass is still an ArrayList....:
public class NestingList extends ArrayList<NestingList> {
// all we do is set the Generics...
}

Is it possible to create comparators based on a dynamic type?

I have been trying to create a comparator through a field of an object, and I can't seem to be able to morph the comparator's type to what I want.
I'm trying to do something like this:
public class Sort {
private ArrayList list;
public Class<?> type;
private Object obj = "Continent";
Sort(ArrayList list, String type) throws ClassNotFoundException
{
this.list = list;
this.type = Class.forName(type);
}
Comparator a = new Comparator<this.type>(){
#Override
public int compare(b.area o1, b.area o2) {
// TODO Auto-generated method stub
return 0;
}
};
is it possible or would I need to write out the methods for each individual class case?
Part I
is it possible [...]?
Not the way you're trying it. You're confusing compile time and run time, i.e.:
Generics are a pure compile time concept in Java. In fact, the generic type is removed during compilation (that's called type erasure). It only exists to give you type safety before compilation, meaning while writing your code.
But the instance type is only assigned at run time. And because you don't know its type during compile time, you had to use a wildcard generic for it. So you only know the type, when you're executing your code.
So you can see that you can't use the information you gathered while executing your code to help you write it.
I highly recommend you read Oracle's tutorial on generics.
Part II
would I need to write out the methods for each individual class case?
I'm with Paul on this. I'm sure we can help you but you should give us an idea of what you're trying to accomplish.
...
Based on on your comment, I think the following would be a good solution.
Your model of the reality consists of continents, countries and cities. Hence you should have classes Continent, Country and City. Since you're modeling population, all of them should have a method getPopulation(). And this is one thing they have in common; all of those things are populated. The way to address this common structure / behavior in Java is to create an interface (let's call it Populated) with a method getPopulation() and have all of those classes implement it:
public interface Populated {
int getPopulation();
}
public class Country implements Populated {
#Override
public int getPopulation() {
...
}
}
// same for Continent and City
Now you have three classes but they can all be treated as one thing, as being populated. For example you can collect them in a list:
List<Populated> populated = new ArrayList<>();
populated.add(new Country());
populated.add(new City());
...
And this list can be sorted with a comparator which works for instances of Populated:
public class PopulationComparator implements Comparator<Populated> {
public int compare(Populated left, Populated right) {
return left.getPopulation() - right.getPopultion();
}
}

Java How to produce generic class that accepts a String and integer?

I'm trying to get familiar with generics in java. I'm still unsure how create a simple class to take two types (String, Integer). Below is a trivial attempt at working with generics in my contexts.
public class Container <T>
{
public T aString()
{
//Do i know I have a string?
}
public T anInt()
{
//How do I know I have an integer?
}
public Container<T>()
{
//What would the constructor look like?
}
}
I'm referencing this page oracle generics but I'm still not sure what I'm doing here. Do you first figure out what type your "T" in the class?
Is generic programming genuinely used for interfaces and abstract classes?
Well that Container class can actually hold a String, Integer or any type, you just have to use it correctly. Something like this:
public class Container<T> {
private T element;
public T getElement() {
return element;
}
public void setElement(T element) {
this.element = element;
}
public Container(T someElement) {
this.element = someElement;
}
}
And you can use it like this:
Container<Integer> myIntContainer = new Container<Integer>();
myIntContainer.setElement(234);
or...
Container<String> myStringContainer = new Container<String>();
myStringContainer.setElement("TEST");
If the class does significantly different things for String and Integer, maybe it should be two classes, each specialized for one of those types.
I see generics as being useful for situations in which references of different types can be handled the same way. ArrayList<String> and ArrayList<Integer> don't need any code that is specific to String or Integer.
Class type = Integer.class
Integer i = verifyType("100",type);
for integer, similar with string...
reference Java Generics with Class <T>
If you want to use String and Integer you'll probably have to use Object as the type. This removes most of the benefit of Generics frankly and you should probably check that you actually have a sound model and reason for inter-weaving strings and integers.
But yes, it's useful for interfaces, custom classes and abstracts. It means you can guarantee the object is of the right type and removes the need to implement them each time for each type of thing.

When to create a generic class

I haven't used generics before and I am wondering when I should use them and what the advantages are. I think it might be appropriate for a collection that I made since java always uses generics for collections as well but if I call the methods I created the type is already set in the function so it would give an error anyway. When should I use a generic class? Could you give an example because I am not sure how to use it. At the moment my code is as follows:
public class NodeList {
private static final int MAX_AMOUNT_OF_NODES = 12;
private HashMap<String, Node> nodeList;
public NodeList(){
nodeList = new HashMap<String, Node>(MAX_AMOUNT_OF_NODES);
}
public Node get(String id){
return nodeList.get(id);
}
public boolean add(Node node){
if(nodeList.size() <= MAX_AMOUNT_OF_NODES){
nodeList.put(node.id, node);
return true;
}
return false;
}
}
You can look at the existing API for guidance. For example, all the Collections are generic. That is because all collections contain elements of a type.
From that, it makes sense that generic classes should be used when you would have to create the exact same code again and again for different types. If you have to do that, generics might offer you some benefit.
As far as an example, the docs are a good place to start.
From that link, the first code sample is
public class Box<T> {
// T stands for "Type"
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
Conceptually, there is a Box class that is going to contain something. What it contains does not matter, because the type is specific by the programmer. A Box instance can contain basically anything. When the programmer needs to create a box, he/she specifies the type.
Box<SomeClass> myBox = new Box<SomeClass>();
Think about it this way -- if you wanted to create a general Box that could hold anything without generics, you would have to
1) have the field f be an Object, or
2) create a Box class for every type a box could contain.
With generics, you only need one class, and you can specify the exact type. Maybe if you are doing something and your approach involved either 1 or 2 above, it's better to use generics.
If Node is a class that can hold a piece of data with certain type (like String, for example) then you should generify Node and subsequently NodeList to prevent type errors.
If you don't, then you leave it up to the user of your NodeList to ensure that she never adds an Integer when the list is only supposed to hold Strings. Generics is primarily about catching type problems at compile time rather than runtime.
It's pretty simple to do so, change something like this:
public class Node {
Object data;
//...
}
to something like this:
public class Node<T> {
T data;
//...
}
public class NodeList<T> {
public Node<T> get(String id) {
//...
}
public boolean add(Node<T> node) {
//...
}
}
Your NodeList looks like it could potentially have a second type parameter for the key type, which right now you're constraining to String.
You can generically type the methods arguments as well as the class itself. Here's an example from Java's java.util.List interface:
public interface List<E> {
//...
boolean add(E e);
//...
}
Generics are a way for Java to force a collection data structure (HashMap in your case) to accept only a specific types of objects. This means that at compile time, if you tried something like:
nodeList.add(1, new Node());
it would fail and not compile since 1 is not a String object. It is generally a way to write tidier code.
Check this link as well:http://en.wikipedia.org/wiki/Generics_in_Java

Categories

Resources