Skip to content
Advertisement

How do I make my code work with Generics?

I am currently learning about Generics, first I made the Class which makes a stackArrayList with Integers, after that I wanted it to be used by every Number so I did put the Number in everywhere in the Methods, it kind of worked but I think this is not quiet correct, my biggest Problem is that I cant use any addition or subtraction with the Class Number.

So I tried implement the N extends Number but that does not work either and with that I can’t even put a Number which returns from the Method pop() inside of a variable, telling me that pop() must return an int then.

Can someone explain to me please, what I did there? I can grasp the logic behind of it but cannot understand it to the fullest.

public class StackArrayList<N extends Number> {

    private ArrayList<N> stackList = new ArrayList<>();
    
    
    
    public void push (N value) {
        if(value == null) {
            System.out.println("value null not allowed");
            return;
        }
        stackList.add(0,value);
        
    }
    public N pop() {
        N popInt = stackList.get(0);
        stackList.remove(0);
        return popInt;
    }
    public N addFirstTwo() {
        if(stackList.size()==1) {
            return stackList.get(0);
        }
        if (stackList.size() == 0) {return null;}
        
        
        if(stackList.get(0) instanceof Integer) {
            N summe;
            summe = 
            push(summe);
            return summe;
        }else if(stackList.get(0) instanceof Double){
            summe = pop().doubleValue()+pop().doubleValue();
            push(summe);
            return summe;
        }else if(stackList.get(0) instanceof Float){
            summe = pop().floatValue()+pop().floatValue();
            push(summe);
            return summe;
        }else if(stackList.get(0) instanceof Long){
            summe = pop().longValue()+pop().longValue();
            push(summe);
            return summe;
        }
        
        push(summe);
        return summe;
    }
    
}

Advertisement

Answer

The problem is that Number does not support the + operator, even though all its implementations (Double, Float etc.) do support it.

What you can do is to define an inner interface to your class which exposes a sum method:

interface SumPerformer<N> {
    N sum(N n1, N n2);
}

Then, you will declare a field into your StackArrayList<N extends Number> class that holds an implementation of this interface:

private final SumPerformer<N> sumPerformer;

And so, you will use this implementation to return the sum of the two first numbers inside your addFirstTwo() method:

public N addFirstTwo() {
    if (stackList.isEmpty()) {
        return null;
    }
    if (stackList.size() == 1) {
        return stackList.get(0);
    }
    return sumPerformer.sum(stackList.get(0), stackList.get(1));
}

When it’s time to initialize your StackArrayList with a concrete implementation of Number, you will simply pass it the implementation’s sum by method reference:

    StackArrayList<Double> stackArrayListDoubles = new StackArrayList<>(Double::sum);
    StackArrayList<Long> stackArrayListLongs = new StackArrayList<>(Long::sum);
    StackArrayList<Integer> stackArrayListInts = new StackArrayList<>(Integer::sum);

Full code:

public static final class StackArrayList<N extends Number> {

    private final List<N> stackList = new ArrayList<>();
    private final SumPerformer<N> sumPerformer;

    public StackArrayList(SumPerformer<N> sumPerformer) {
        this.sumPerformer = sumPerformer;
    }

    public N pop() {
        N popInt = stackList.get(0);
        stackList.remove(0);
        return popInt;
    }

    public void push(N value) {
        if (value == null) {
            System.out.println("value null not allowed");
            return;
        }
        stackList.add(0, value);

    }

    public N addFirstTwo() {
        if (stackList.isEmpty()) {
            return null;
        }
        if (stackList.size() == 1) {
            return stackList.get(0);
        }
        N sum = sumPerformer.sum(stackList.get(0), stackList.get(1));
        push(sum);
        return sum;
    }

    interface SumPerformer<N> {
        N sum(N n1, N n2);
    }

}

Answers to the questions raised in the comments

Doesn’t the Variable need to be inside the <> ?

No. The <> (called diamond operator) is used to infer a specific type to a class which takes a “generic” type (you can read more about generics).

Before Java 8, you needed to specify the type both in the declaration and the instantiation of the variable. For example, the interface List<T> is implemented by the class ArrayList<T>.

Before Java 8, if you wanted a list of Integer you needed to do:

List<Integer> list = new ArrayList<Integer>();

After Java 8, you can simply state:

List<Integer> list = new ArrayList<>();

Indeed, the type Integer will be inferred to ArrayList by the declaration List<Integer>.

This is why, when I initialize my StackArrayList<>, I’m not passing Double to it because I already pass it to the declaration, so the variable already knows what is its type.

shouldnt it just pass down the Number i initialize the Object with ?

Careful, you’re mixing up stuff. The reason why you shouldn’t pass Double is explained above. However, here I am doing something else.

If you check the new constructor of StackArrayList, I’ve added a member which is private final SumPerformer<N> sumPerformer;.

This member is final, it means it should be initialized when you initialize the class, and I do that by passing it into the constructor.

But so what am I passing to the constructor? I am passing a concrete implementation of the abstract interface that I define.

Specifically, I have declared the interface SumPerformer<N> to expose only one method which is called sum, returns a N and takes in input two distinct N.

A concrete implementation of this interface, hence, should be a method with the same signature.

And this method, is the sum() method of all Number children (Double, Integer…)

If you go into the class Double, you will see that there is this method:

public static double sum(double a, double b) {
    return a + b;
}

The above method’s signature matches with your interface when the type N extends Number is Double.

So, in your class, you simply call the interface .sum() to sum up your two numbers, and you leave the implementation details (the a + b, basically) to the concrete implementation which is not done by you, but by Java itself in the JDK’s classes that extend Number.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement