Cache Staheli Cache Staheli - 6 months ago 21
Java Question

Can't access methods of a java generics class

I recently wrote some code that was full of code-duplication, and I wanted to improve it. I have sets of objects that are very similar, but not quite similar enough, as I'll explain below.

I'll start with the first set of objects. I have three objects,

TagProbability
,
WordProbability
, and
TokenProbability
. These all have exactly the same methods, they have one data member of a different type. Two of them have a
String
and the other has an
enum
that I created,
SpeechTag
. I wanted to extract this into a single class, since most of their methods have basically the same implementation. I know that you can accomplish this type of thing using generics:

This is what I am using:

public class WordProbability extends ProbabilityPair<Str>
{
public WordProbability(String tag)
{
super(tag);
}
...
}


Where
ProbabilityPair
has the following structure.

public abstract class ProbabilityPair<T>
{
public T key;
private int count;
private double probability;

protected ProbabilityPair(T key)
{
this.key = key;
count = 1;
probability = 0d;
}

public void increment()
{
++count;
}
...
}


This seems to be working. Each of these three classes extend from
ProbabilityPair
with their correct
key
. I am trying to take this a step further. I have three other objects that are essentially containers for different
ProbabilityPair
's.

Here is an example of one of the containers:

public class Words
{
public List<WordProbability> words;
public int totalCount;

public Words()
{
words = new ArrayList<>();
totalCount = 0;
}

public void add(WordProbability word)
{
if (words.contains(word))
{
words.get(words.indexOf(word)).increment();
} else
{
words.add(word);
}
++totalCount;
}
...
}


I tried to extract the
add
method into another generic class,
Container
as follows:

public class Container<ProbabilityPair>
{
private List<ProbabilityPair> members;
private int totalCount;

public void add(ProbabilityPair member)
{
if (members.contains(member))
{
members.get(members.indexOf(member)).increment();
} else
{
members.add(member);
}
++totalCount;
}
}


But the line
members.get(members.indexOf(member)).increment();
doesn't compile. It can't find the method. It is in ProbabilityPair, as you can see in the above snippet.

I think I am misunderstanding how generics would work in this instance, but I can't figure out what I am doing wrong.

EDIT Let me explain a little further. Each container functions more like a set than a list, really. It holds one of each
ProbilityPair
, and that pair holds it's count (and by association, probability). So, when I add, I check to see if it is there, and if it is, increment the count instead of adding a new object.

Answer
public class Container<ProbabilityPair>

Declares a type variable called ProbabilityPair which gets erased to Object.

Object does not have an increment method. So the call fails.


You should add a bound to your type variable, and change it's name to not clash with your ProbabilityPair type.

public class Container<T extends ProbabilityPair<?>> {
    private List<T> members;
    ...
}