简体   繁体   中英

Java: What is an alternative to using generics in this design?

I'm working on an open-source Java library that will allow one to compute certain quantities, such as Gini index, of an attribute that takes on a finite number of values. (Formally, it computes the Gini index of the discrete distribution associated with the attribute A , but this is not relevant here.)

For example, one will be able to do the following

String[] namesArray = {"primary_school", "high_school", "university"};
Calculator<String> calc =new Calculator<String>(namesArray);

// p.getEducationLevel() returns `"primary_school"`, `"high_school"`, or `"university"`.
for (Person p : peopleCollection) {
    calc.increment(p.getEducationLevel());
}

// e.g. the Gini index of the distribution
double currentStat = calc.getCurrentValue();

The idea is to allow users of the library to use their own type to refer to attribute values; in this case, I am using strings (eg "primary_school" ). But I might want to use integers or even my own type AttributeValue .

I solve this by defining

public class Calculator<T> {
    /* ... */
}

However, using generics causes some problems in the implementation: for example, if I want to maintain a collection of pairs of type (T, double) , I have to do nasty type casts:

public class Calculator<T>
        /* ... */
        private Queue<StreamElement<T>> slidingWindow;
        /* ... */
        class StreamElement<T> {
                private T label;
                private double value;

                StreamElement(T label, double value) {
                        this.label = label;
                        this.value = value;
                }

                public T getLabel() {
                        return label;
                }
                public double getValue() {
                        return value;
                }
        }
        /* ... */
            slidingWindow.add(new StreamElement<T>(label, value));
            if (slidingWindow.size() > windowSize) {
                    StreamElement lastElement = slidingWindow.remove();
                    // XXX: Nasty type cast
                    decrement((T)lastElement.getLabel(), lastElement.getValue());
            }
        /* ... */
}

Here is the warning produced by javac :

Calculator.java:163: warning: [unchecked] unchecked cast
            decrement((T)lastElement.getLabel(), lastElement.getValue());
                                             ^
  required: T
  found:    Object
  where T is a type-variable:
    T extends Object declared in class Calculator
1 warning

Update. If I do not do the type cast, I get

Calculator.java:163: error: no suitable method found for decrement(Object,double)
            decrement(lastElement.getLabel(), lastElement.getValue());
            ^
    method Calculator.decrement(T) is not applicable
      (actual and formal argument lists differ in length)
    method Calculator.decrement(T,double) is not applicable
      (actual argument Object cannot be converted to T by method invocation conversion)
  where T is a type-variable:
    T extends Object declared in class Calculator
1 error

Questions:

  • What is a proper, clean way to do the type cast?
  • What would be an alternative to using generics here?
  • More concretely, would it be better to instead define a class Label which user could extend to MyLabel and then use MyLabel for attribute values? This means that Calculator would no longer be a generic type; in the implementation we'd have class StreamElement { Label label; /* ... */ } class StreamElement { Label label; /* ... */ } et cetera.

I think you just made some mistake.

This is the correct implementation:

        /* ... */
            slidingWindow.add(new StreamElement<T>(label, value));
            if (slidingWindow.size() > windowSize) {
                    // Don't forget the generic argument at StreamElement
                    StreamElement<T> lastElement = slidingWindow.remove();
                    decrement(lastElement.getLabel(), lastElement.getValue());
            }
        /* ... */

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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