A DESCRIPTION OF THE PROBLEM :
Using the newInstance constructor it is possible to construct a map with keys that do not extend the declared key type.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Full source code provided.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
newInstance should have thrown a runtime exception since the input types do not match the declared types. With the given source code ideally "Exception was caught" should be printed.
ACTUAL -
newInstance creates a map with keys whose type does not extend the declared key type of the map. With the given source code we see a map of <Dog, String> contain a key of type Cat.
---------- BEGIN SOURCE ----------
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
final Map<Animal, String> animalToName = new HashMap<>();
final Cat cat = new Cat( 1, "fish" );
final Dog dog = new Dog( 2, 10 );
animalToName.put( cat, "catName" );
animalToName.put( dog, "dogName" );
try {
final DogNames dogNames = (DogNames) DogNames.class.getConstructors()[0].newInstance( animalToName );
System.out.println( "No Exception caught" );
System.out.println( dogNames.getDogToName() );
} catch( final Exception e ) {
//Ideally an exception would be thrown here and this statement would be printed, however that is not the case.
System.out.println( "Exception was caught" );
}
}
private static class DogNames {
private final Map<Dog, String> dogToName;
public DogNames( final Map<Dog, String> dogToName ) {
this.dogToName = dogToName;
}
public Map<Dog, String> getDogToName() {
return this.dogToName;
}
}
private static class Dog extends Animal {
private final int woofLoudness;
public Dog( final int weight, final int woofLoudness ) {
super( weight );
this.woofLoudness = woofLoudness;
}
@Override
public String toString() {
return String.format( "Dog with weight: %d, woof loudness: %d", this.weight, this.woofLoudness );
}
}
private static class Cat extends Animal {
private final String favoriteFood;
public Cat( final int weight, final String favoriteFood ) {
super( weight );
this.favoriteFood = favoriteFood;
}
@Override
public String toString() {
return String.format( "Cat with weight: %d, favorite food: %s", this.weight, this.favoriteFood );
}
}
private static class Animal {
protected final int weight;
public Animal( final int weight ) {
this.weight = weight;
}
}
}
---------- END SOURCE ----------
FREQUENCY : always