Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 泛型与cast_Java_Generics_Reflection - Fatal编程技术网

Java 泛型与cast

Java 泛型与cast,java,generics,reflection,Java,Generics,Reflection,我尝试编写一个类,该类使用参数名并可以返回给定对象的相应参数。目前,我的班级是这样的: public class ParamValue<T> { private String paramName; @SuppressWarnings("unchecked") public T getValue(Object obj) throws Exception { Class<?> c = obj.getClass();

我尝试编写一个类,该类使用参数名并可以返回给定对象的相应参数。目前,我的班级是这样的:

public class ParamValue<T> {

    private String paramName;

    @SuppressWarnings("unchecked")
    public T getValue(Object obj) throws Exception {

        Class<?> c = obj.getClass();
        Field param = c.getDeclaredField(paramName);
        boolean isAccessible = param.isAccessible();
        param.setAccessible(true);
        Object value = param.get(obj);
        param.setAccessible(isAccessible);
        return (T) value;
    }

    // get set ...
}
ParamValue<Point> pvPoint = new ParamPoint();

ParameterizedType superclassType = (ParameterizedType) pvPoint.getClass().getGenericSuperclass();
Type paramType = superclassType.getActualTypeArguments()[0];

// print true
System.out.println(paramType.equals(Point.class));
我们可以这样做以获得长期价值:

    ExampleClass ec = new ExampleClass();
    ec.setValue(12L);

    ParamValue<Long> pvString = new ParamValue<>();
    pvString.setParamName("value");

    // print 12
    System.out.println(pvString.getValue(ec));
ExampleClass=newexampleclass();
ec.设定值(12L);
ParamValue pvString=新的ParamValue();
pvString.setParamName(“值”);
//打印12
System.out.println(pvString.getValue(ec));
现在,如果我将“ParamValue”声明为一个点,例如,它仍然有效:

    ExampleClass ec = new ExampleClass();
    ec.setValue(12L);

    ParamValue<Point> pvPoint = new ParamValue<>();
    pvPoint.setParamName("value");

    // print 12
    System.out.println(pvPoint.getValue(ec));
ExampleClass=newexampleclass();
ec.设定值(12L);
ParamValue pvPoint=新的ParamValue();
pvPoint.setParamName(“值”);
//打印12
System.out.println(pvPoint.getValue(ec));
但,由于该点不能转换为长,我预期会出现一些异常,比如ClassCastException

我知道java编译器在编译时会进行一些类型擦除,但我认为编译器会自动尝试强制转换到“pvPoint.getValue(ec)”的输出,并失败

有人能解释一下这是怎么回事吗


感谢您,ClassCastException是一个RuntimeException,这意味着它将只在运行时抛出,而不是在编译时抛出。由于您的值引用
Object value=param.get(obj)
属于Object类型,应允许强制转换为类型,因为所有类都扩展了Object。getValue方法接受任何对象作为参数,因此在编译时,无论声明的参数化类型如何,都将接受任何类


如果需要类型安全性,可以将该方法的参数声明为
您正在禁止编译器警告您正在执行未经检查的强制转换,因此编译器将无法捕获它。在运行时,类型信息不可用

如果希望代码实际抛出ClassCastException,可以添加一个存储实际目标类的字段。这样还可以删除
@SuppressWarnings
注释。生成的类将如下所示:

    public <T> T getValue(Class<T> returnType, Object obj) throws Exception {
        Class<?> c = obj.getClass();
        Field param = c.getDeclaredField(paramName);
        boolean isAccessible = param.isAccessible();
        param.setAccessible(true);
        Object value = param.get(obj);
        param.setAccessible(isAccessible);
        return returnType.cast(value);
}
     if (returnType.isInstance(value)) {
        return returnType.cast(value);
    } else {
        // could be replaced with a return null
        throw new ClassCastException("Exception message");          
    }
class ParamValue<T> {

    private final Class<T> clazz;
    private final String paramName;

    ParamValue(Class<T> clazz, String paramName)
    {
        this.clazz = clazz;
        this.paramName = paramName;
    }

    public T getValue(Object obj) throws Exception {

        Class<?> c = obj.getClass();
        Field param = c.getDeclaredField(paramName);
        boolean isAccessible = param.isAccessible();
        param.setAccessible(true);
        Object value = param.get(obj);
        param.setAccessible(isAccessible);
        return clazz.cast(value);
    }
}
    ExampleClass ec = new ExampleClass();
    ec.setValue(12L);

    ParamValue<Point> pvPoint = new ParamValue<>(Point.class, "value");

    // print 12
    System.out.println(pvPoint.getValue(ec));
类参数值{
私人期末班;
私有最终字符串参数名;
ParamValue(类clazz,字符串paramName)
{
this.clazz=clazz;
this.paramName=paramName;
}
公共T getValue(对象obj)引发异常{
c类=obj.getClass();
Field param=c.getDeclaredField(paramName);
布尔值isAccessible=param.isAccessible();
参数setAccessible(true);
对象值=参数获取(obj);
参数设置可访问(可访问);
返回clazz.cast(值);
}
}
可以这样调用:

    public <T> T getValue(Class<T> returnType, Object obj) throws Exception {
        Class<?> c = obj.getClass();
        Field param = c.getDeclaredField(paramName);
        boolean isAccessible = param.isAccessible();
        param.setAccessible(true);
        Object value = param.get(obj);
        param.setAccessible(isAccessible);
        return returnType.cast(value);
}
     if (returnType.isInstance(value)) {
        return returnType.cast(value);
    } else {
        // could be replaced with a return null
        throw new ClassCastException("Exception message");          
    }
class ParamValue<T> {

    private final Class<T> clazz;
    private final String paramName;

    ParamValue(Class<T> clazz, String paramName)
    {
        this.clazz = clazz;
        this.paramName = paramName;
    }

    public T getValue(Object obj) throws Exception {

        Class<?> c = obj.getClass();
        Field param = c.getDeclaredField(paramName);
        boolean isAccessible = param.isAccessible();
        param.setAccessible(true);
        Object value = param.get(obj);
        param.setAccessible(isAccessible);
        return clazz.cast(value);
    }
}
    ExampleClass ec = new ExampleClass();
    ec.setValue(12L);

    ParamValue<Point> pvPoint = new ParamValue<>(Point.class, "value");

    // print 12
    System.out.println(pvPoint.getValue(ec));
ExampleClass=newexampleclass();
ec.设定值(12L);
ParamValue pvPoint=新的ParamValue(Point.class,“value”);
//打印12
System.out.println(pvPoint.getValue(ec));
强制转换
(T)
在运行时不会执行任何操作。它只会使编译器平静下来

该方法有多个重载,其中一个重载不接受
对象
参数。因此,不会在代码中执行强制转换

在这些情况下,您会看到一个
ClassCastException

  • 将值存储在所需类型的变量中:

    final Point value = pvPoint.getValue(ec); // CCE
    System.out.println(value);
    
  • ParamValue
    提供一个
    Class
    实例以进行运行时检查:

    public class ParamValue<T> {
        private final Class<T> clazz;
    
        public ParamValue(Class<T> clazz) {
            this.clazz = clazz;
        }
    
        public T getValue(Object obj) throws Exception {
            Class<?> c = obj.getClass();
            Field param = c.getDeclaredField(paramName);
            boolean isAccessible = param.isAccessible();
            param.setAccessible(true);
            Object value = param.get(obj);
            param.setAccessible(isAccessible);
            return clazz.cast(value); // instead of (T) value
        }
    
        // get set ...
    }
    
    公共类参数值{
    私人期末班;
    公共价值(类别分类){
    this.clazz=clazz;
    }
    公共T getValue(对象obj)引发异常{
    c类=obj.getClass();
    Field param=c.getDeclaredField(paramName);
    布尔值isAccessible=param.isAccessible();
    参数setAccessible(true);
    对象值=参数获取(obj);
    参数设置可访问(可访问);
    返回clazz.cast(值);//而不是(T)值
    }
    //准备好。。。
    }
    
    然后:

    ParamValue<Point> pvPoint = new ParamValue<>(Point.class);
    pvPoint.setParamName("value");
    System.out.println(pvPoint.getValue(ec)); // CCE
    
    ParamValue pvPoint=新的ParamValue(Point.class);
    pvPoint.setParamName(“值”);
    System.out.println(pvPoint.getValue(ec));//CCE
    

  • 我发现了一件奇特的东西,以防有人进来。 如果我像这样扩展“ParamValue”类:

    public class ParamPoint extends ParamValue<Point> {
    }
    
    公共类ParamPoint扩展ParamValue{
    }
    
    类型擦除仅部分应用,不会引发异常,但仍可以按如下方式测试类型:

    public class ParamValue<T> {
    
        private String paramName;
    
        @SuppressWarnings("unchecked")
        public T getValue(Object obj) throws Exception {
    
            Class<?> c = obj.getClass();
            Field param = c.getDeclaredField(paramName);
            boolean isAccessible = param.isAccessible();
            param.setAccessible(true);
            Object value = param.get(obj);
            param.setAccessible(isAccessible);
            return (T) value;
        }
    
        // get set ...
    }
    
    ParamValue<Point> pvPoint = new ParamPoint();
    
    ParameterizedType superclassType = (ParameterizedType) pvPoint.getClass().getGenericSuperclass();
    Type paramType = superclassType.getActualTypeArguments()[0];
    
    // print true
    System.out.println(paramType.equals(Point.class));
    
    ParamValue pvPoint=新的ParamPoint();
    ParameteredType superclassType=(ParameteredType)pvPoint.getClass().getGenericSuperclass();
    类型paramType=superclassType.getActualTypeArguments()[0];
    //打印真实
    System.out.println(paramType.equals(Point.class));
    

    希望这对其他人有所帮助。

    您指的是哪个Point类?java.awt.Point,但我不确定这是否重要。如果编译器知道强制转换何时有效,则无需强制转换。根据定义,强制转换在运行时进行。谢谢。不幸的是,我不能使用extends来完成我想做的事情。我想我需要一些工作来验证参数化类型,但是使用类型擦除,这将是一件痛苦的事情…为什么不能使用extends?检查上面的代码,对你不起作用吗?我可以在条目中有任何类型的对象。像绳子一样,长。。。等我不能每个都有一个超类。我无法预测这个类可以处理哪个对象。根据你所说的,这意味着你有一个非常通用的类,它应该处理任何类型的方法参数和任何返回的类型。您所能做的最好的事情就是记录抛出的异常类型,并让此类的客户机在他们认为合适的时候处理它们。我建议声明每个抛出的异常(但不是RuntimeException子类),并记录ClassCastException的可能性。因为它是一个RuntimeException,所以不应该将它添加到throw子句中。