Bueno, estás en presencia de la interfaz que implementan las clases de Map, como HashMap. Este tipo de código es un poco extraño al principio, pero no temas, siguen tratandose de clases y objetos.
crea una interfaz llamada "Map", esta interfaz al igual que una ArrayList o un Vector, deben ser genéricos, ya que a diferencia de nustras clases típicas aquí se podrán contener objetos de todo tipo. Para poder coneter objetos de todo tipo basta con usar la superclase de todos, es decir, "Object", pero si creas una clase cuyos atributos sean Object entonces tendrás que hacer cast cada vez que necesites de los objetos en su estado original.
Por ejemplo si yo sé que tu puedes sostener objetos de 20 kilos, te pones tras una cortina y me preguntas qué estás sosteniendo, pues la realidad es que no tengo ni idea, me tendrías que decir que es una manzana o algo así y yo haría acto de fé para saber qué objeto tienes. Pues lo mismo le pasa a java si le dices: "vas a contener objetos y cuando te los pida quiero que me los des", java no sabrá qué es a menos que se lo digas.
Bueno pues esto es lo que buscan este tipo de declaraciones, le estamos diciendo a java que contendrá objetos de tipo K o V (convención proveniente de Key y Value para la interfaz Map), pues con esto java no se preocupará por el tipo que reciba, pues ahora tiene etiquetas para sus nombres, cuando tú creas una instancia de Map (una vez implementada la interfaz) le deberás decir a java qué tipo de objetos contendrá como:
Ahí y hasta ese momento los objetos toman un tipo fijo. Entonces todos los métodos que dicen yo devuelvo K ahora dirán, yo devuelvo String. En realidad se hace el cast pero ya no de forma tradicional y peligrosa, ahora le das la oportunidad al compilador de verificar que efectivamente reciba ese tipo de datos evitando así al máximo errores en tiempo de ejecución por un cast fallido.