Reputation: 3467
I've run into some funky behavior with generics and I was wondering if someone could shed some light as to why this is happening. To start, I have a class Foo
which has a field id. The hashCode
method on Foo
just returns the id. In another class I create a Map<Foo, Double> bar = new HashMap<Foo, Double()
.
Then, at a later part of the code the strangeness starts, and I am able to do the following (simplified here):
Long baz = new Long(1);
bar.get(baz);
So, my question is, Why doesn't the compiler and catch this and report it as an error?
EDIT: I made one mistake in my initial question in that get
is the method that works, not put
. I have posted the full code below.
Map<WebPage, Double> scoresForPhrase = new HashMap<WebPage, Double>();
// Now that we have a list of matching docs, we can calculate the
// Score of each word in the phrase for each document
for (String term: phrase.getWords()) {
TreeSet<Posting> wordPostings = wordMap.get(term);
for(Long doc: matchingDocs) {
if (docDenomScores.get(doc) == null) {
docDenomScores.put(doc, getDocTotal(doc));
}
// The set is of postings, which are compared by docId, so
// we need a temporary one to enable searching
Posting temp = new Posting(doc, new ArrayList<Integer>());
Posting wordPosting = wordPostings.ceiling(temp);
WebPage page = (WebPage) mWebpageDb
.getPageIdToWebPageTable().get(doc);
score = getTermScore(wordPosting, page,
wordPostings.size());
score = score * queryTermWeights.get(term);
Double curScore = scoresForPhrase.get(doc);
}
}
As for the Foo
class, it is:
public class WebPage implements Serializable {
private static final long serialVersionUID = -4907557806357281837L;
private String mUrl;
private int mMaxTf;
private long mPageId;
private long mLastTimeUpdated;
private List<Long> mParentIds;
private long mContentLength;
private String mTitle;
private List<Long> mChildren;
private List<String> mAllUrls;
public WebPage(String url, long pageId, long lastTimeUpdated,
List<Long> parentIds, long contentLength, String title, List<Long> children,
List<String> allUrls) {
super();
this.mUrl = url;
this.mPageId = pageId;
this.mLastTimeUpdated = lastTimeUpdated;
this.mParentIds = parentIds;
this.mContentLength = contentLength;
this.mTitle = title;
this.mChildren = children;
this.mAllUrls = allUrls;
this.mMaxTf = 0;
}
public void setUrl(String mUrl) {
this.mUrl = mUrl;
}
public void setPageId(int mPageId) {
this.mPageId = mPageId;
}
public void setLastTimeUpdated(long mLastTimeUpdated) {
this.mLastTimeUpdated = mLastTimeUpdated;
}
public void setParentIds(List<Long> mParentId) {
this.mParentIds = mParentId;
}
public void setContentLength(long mContentLength) {
this.mContentLength = mContentLength;
}
public void setChildren(List<Long> mChildren) {
this.mChildren = mChildren;
}
public void setAllUrls(List<String> allUrls) {
this.mAllUrls = allUrls;
}
public void setMaxTf(int newTf) {
this.mMaxTf = newTf;
}
public String getUrl() {
return mUrl;
}
public long getPageId() {
return mPageId;
}
public long getLastTimeUpdated() {
return mLastTimeUpdated;
}
public List<Long> getParentIds() {
return mParentIds;
}
public long getContentLength() {
return mContentLength;
}
public List<Long> getChildren() {
return mChildren;
}
public String getTitle() {
return mTitle;
}
public List<String> getAllUrls() {
return mAllUrls;
}
public int getMaxTf() {
return mMaxTf;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof WebPage)) {
return false;
} else {
return ((WebPage)o).mPageId == mPageId;
}
}
@Override
public int hashCode() {
return (int)mPageId;
}
public String toString() {
return mUrl;
}
}
Upvotes: 0
Views: 162
Reputation: 32969
So two things. First, remember that due to type-erasure there is no runtime checking of generic types. The Map<Foo, Double>
simply becomes Map<Object, Object>
.
Second, with regards to a compiler warning or error, you should get a warning or error if bar
is declared of type Map<Foo, Double>
. But if it is declared as Map
, no warning or error. My guess is that bar
is defined as Map bar
.
UPDATE
The reason there is no error on get
is that by definition get
takes an Object
not the generic type. It is one of the odd things about the interface.
Upvotes: 3
Reputation: 16516
Your Map<Foo, Double>
might have been casted to Map
:
Map<Foo, Double> barOriginal = new HashMap<Foo, Double();
// ...
Map bar = barOriginal;
// ...
Long baz = new Long(1);
bar.put(baz, new Double(1));
Upvotes: 0