简体   繁体   English

如何让我的代码与泛型一起工作?

[英]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.我目前正在学习泛型,首先我制作了一个类,它用整数制作了一个 stackArrayList,之后我希望它被每个数字使用,所以我确实把数字放在方法的任何地方,它有点工作,但我认为这个不是安静正确,我最大的问题是我不能对班级编号使用任何加法或减法。

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.因此,我尝试实现 N extends Number 但这也不起作用,因此我什至不能将从 Method pop() 返回的 Number 放入变量中,告诉我 pop() 必须返回一个 int 然后。

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;
    }
    
}

The problem is that Number does not support the + operator, even though all its implementations ( Double , Float etc.) do support it.问题是Number不支持+运算符,即使它的所有实现( DoubleFloat等)都支持它。

What you can do is to define an inner interface to your class which exposes a sum method:您可以做的是为您的类定义一个内部接口,该接口公开一个sum方法:

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:然后,您将在StackArrayList<N extends Number>类中声明一个字段,该类包含此接口的实现:

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:因此,您将使用此实现返回addFirstTwo()方法中前两个数字的总和:

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:当需要使用Number的具体实现初始化StackArrayList时,您只需通过方法引用将实现的sum传递给它:

    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.在 Java 8 之前,您需要在变量的声明和实例化中指定类型。 For example, the interface List<T> is implemented by the class ArrayList<T> .例如,接口List<T>由类ArrayList<T>

Before Java 8, if you wanted a list of Integer you needed to do:在 Java 8 之前,如果您想要一个Integer列表,您需要执行以下操作:

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

After Java 8, you can simply state:在 Java 8 之后,您可以简单地声明:

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

Indeed, the type Integer will be inferred to ArrayList by the declaration List<Integer> .实际上,类型Integer将通过声明List<Integer>推断为ArrayList

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.这就是为什么当我初始化我的StackArrayList<> ,我没有将Double传递给它,因为我已经将它传递给了声明,所以变量已经知道它的类型是什么。

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.上面解释了为什么不应该通过Double的原因。 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;如果您检查StackArrayList的新构造StackArrayList ,我添加了一个成员,它是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.这个成员是final ,这意味着它应该在你初始化类时被初始化,我通过将它传递给构造函数来实现。

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 .具体来说,我已经声明了接口SumPerformer<N>只公开一个称为sum方法,返回一个N并接受输入两个不同的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 ...)而这个方法,是所有Number孩子( DoubleInteger ...)的sum()方法

If you go into the class Double , you will see that there is this method:如果你进入类Double ,你会看到有这个方法:

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 .当类型N extends NumberDouble时,上述方法的签名与您的接口匹配。

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 .因此,在您的课程中,您只需调用接口.sum()来总结您的两个数字,并将实现细节(基本上是a + b )留给具体实现,这不是由您完成的,而是由 Java 完成的本身在扩展Number的 JDK 类中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM