传递参数的Java泛型
希望有人能帮我摆脱这种困惑 我提出了这个方法:传递参数的Java泛型,java,generics,Java,Generics,希望有人能帮我摆脱这种困惑 我提出了这个方法: public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) { } publicstaticvoidmymethod(Map){ } 使用参数T以确保用作键的类与MyInterface中用作参数的类相同 现在我想传递一个映射,其中不同的类作为键,当然,还有MyInterface的相应实现 但它不起作用,因为类型参数而导致语法
public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) {
}
publicstaticvoidmymethod(Map){
}
使用参数T以确保用作键的类与MyInterface中用作参数的类相同
现在我想传递一个映射,其中不同的类作为键,当然,还有MyInterface的相应实现
但它不起作用,因为类型参数而导致语法错误。这是代码,我希望是不言自明的
import java.util.HashMap;
import java.util.Map;
public class Test {
public static void main(String[] args) {
Map<Class<?>, MyInterface<?>> map = new HashMap<Class<?>, MyInterface<?>>();
// Map<Class<Object>, MyInterface<Object>> map = new HashMap<Class<Object>, MyInterface<Object>>();
map.put(Object.class, new MyObjectImpl());
//if I use Map<Class<Object>, MyInterface<Object>> I get a compiler error here
//because map<String> is not map<Object> basically
map.put(String.class, new MyStringImpl());
//this would be possible using <?>, which is exactly what I don't want
// map.put(String.class, new MyIntegerImpl());
//<?> generates anyways a compiler error
myMethod(map);
}
//use T to make sure the class used as key is the same as the class of the parameter "object" in doSomething
public static <T> void myMethod(Map<Class<T>, MyInterface<T>> map) {
}
interface MyInterface<T> {
void doSomething(T object);
}
static class MyObjectImpl implements MyInterface<Object> {
@Override
public void doSomething(Object object) {
System.out.println("MyObjectImpl doSomething");
}
}
static class MyStringImpl implements MyInterface<String> {
@Override
public void doSomething(String object) {
System.out.println("MyStringImpl doSomething");
}
}
static class MyIntegerImpl implements MyInterface<Integer> {
@Override
public void doSomething(Integer object) {
System.out.println("MyIntegerImpl doSomething");
}
}
}
import java.util.HashMap;
导入java.util.Map;
公开课考试{
公共静态void main(字符串[]args){
Map>Map=newhashmap>();
//Map Map=newhashmap();
put(Object.class,新的MyObjectImpl());
//如果我使用Map,我会在这里得到一个编译器错误
//因为地图基本上不是地图
put(String.class,新的MyStringImpl());
//这将是可能的使用,这正是我不想要的
//put(String.class,新的MyIntegerImpl());
//无论如何都会生成一个编译器错误
myMethod(map);
}
//使用T确保用作键的类与doSomething中参数“object”的类相同
公共静态void myMethod(映射){
}
接口MyInterface{
无效剂量测定(T对象);
}
静态类MyObjectImpl实现MyInterface{
@凌驾
公共void doSomething(对象){
System.out.println(“MyObjectImpl doSomething”);
}
}
静态类MyStringImpl实现MyInterface{
@凌驾
公共void doSomething(字符串对象){
System.out.println(“MyStringImpl doSomething”);
}
}
静态类MyIntegerImpl实现MyInterface{
@凌驾
公共void doSomething(整数对象){
System.out.println(“MyIntegerImpl doSomething”);
}
}
}
我认为这是不可能的:
Class
仅接受T.Class
作为值<代码>类将不接受字符串。类
,即使对象是字符串的超类
因此,任何键为Class
的映射只能有一个元素,键值为T.Class
的映射,无论T
的值是多少
编译器将只接受具有确定值T作为参数的映射。您无法写入映射>
,因为每个映射都是?假设不同:它与要求T具有相同值的映射不匹配
这就是说,myMethod将只接受单条目映射,这似乎并不有用。将您的方法签名更改为
public static <T> void myMethod(Map<Class<? extends T>, MyInterface<? extends T>> map) {
}
publicstaticvoidmymethod(Map您不能这样做,因为Map
的put()
方法在键和值之间没有定义约束。如果您想确保正确填充映射(即创建这样的约束),将地图隐藏在将检查正确性的API后面,例如:
public <T> void registerInterface(Class<T> clazz, MyInterface<T> intf) {
map.put(clazz, intf);
}
公共无效注册表接口(clazz类,MyInterface intf){
地图放置(clazz,intf);
}
然后,只需调用registerInterface
而不是手动填充映射。据我所知,您不能像Java中描述的那样声明映射。您所能做的就是执行类型检查和/或添加约束
Guava提供了一些解决您问题的方法。因此,一种方法是使用MapConstraints.constrainedMap
(如下面的示例)
import java.text.ParseException;
导入java.util.HashMap;
导入java.util.Map;
导入com.google.common.collect.MapConstraint;
导入com.google.common.collect.MapConstraints;
公共班机{
接口MyInterface{
无效剂量测定(T对象);
类getType();
}
静态类MyObjectImpl实现MyInterface{
@凌驾
公共void doSomething(对象){
System.out.println(“MyObjectImpl doSomething”);
}
@凌驾
公共类getType(){
返回Object.class;
}
}
静态类MyStringImpl实现MyInterface{
@凌驾
公共void doSomething(字符串对象){
System.out.println(“MyStringImpl doSomething”);
}
@凌驾
公共类getType(){
返回字符串.class;
}
}
静态类MyIntegerImpl实现MyInterface{
@凌驾
公共void doSomething(整数对象){
System.out.println(“MyIntegerImpl doSomething”);
}
@凌驾
公共类getType(){
返回Integer.class;
}
}
公共静态void main(字符串[]args)引发异常{
Map>Map=MapConstraints.constrainedMap(新HashMap>()),
新映射约束>(){
@凌驾
public void checkKeyValue(类键,MyInterface值){
如果(值==null){
抛出新的NullPointerException(“值不能为null”);
}
if(value.getType()!=key){
抛出新的IllegalArgumentException(“值的类型不正确”);
}
}
});
put(Integer.class,新的MyIntegerImpl());
put(String.class,新的MyStringImpl());
put(Object.class,新的MyObjectImpl());
map.put(Float.class,new MyIntegerImpl());//以Impl
结尾的类名通常是过度工程化的症状(例如,它意味着给定接口只有一个实现,无法强制实施)。算了吧,这是行不通的。泛型只能定义同质映射。您不能对条目强制任何内容
public <T> void registerInterface(Class<T> clazz, MyInterface<T> intf) {
map.put(clazz, intf);
}
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
import com.google.common.collect.MapConstraint;
import com.google.common.collect.MapConstraints;
public class Main {
interface MyInterface<T> {
void doSomething(T object);
Class<T> getType();
}
static class MyObjectImpl implements MyInterface<Object> {
@Override
public void doSomething(Object object) {
System.out.println("MyObjectImpl doSomething");
}
@Override
public Class<Object> getType() {
return Object.class;
}
}
static class MyStringImpl implements MyInterface<String> {
@Override
public void doSomething(String object) {
System.out.println("MyStringImpl doSomething");
}
@Override
public Class<String> getType() {
return String.class;
}
}
static class MyIntegerImpl implements MyInterface<Integer> {
@Override
public void doSomething(Integer object) {
System.out.println("MyIntegerImpl doSomething");
}
@Override
public Class<Integer> getType() {
return Integer.class;
}
}
public static void main(String[] args) throws ParseException {
Map<Class<?>, MyInterface<?>> map = MapConstraints.constrainedMap(new HashMap<Class<?>, Main.MyInterface<?>>(),
new MapConstraint<Class<?>, MyInterface<?>>() {
@Override
public void checkKeyValue(Class<?> key, MyInterface<?> value) {
if (value == null) {
throw new NullPointerException("value cannot be null");
}
if (value.getType() != key) {
throw new IllegalArgumentException("Value is not of the correct type");
}
}
});
map.put(Integer.class, new MyIntegerImpl());
map.put(String.class, new MyStringImpl());
map.put(Object.class, new MyObjectImpl());
map.put(Float.class, new MyIntegerImpl()); //<-- Here you will get an exception
}
}