代码之家  ›  专栏  ›  技术社区  ›  Alexander Pogrebnyak

JavaCase.Caster()vs. CAST运算符

  •  94
  • Alexander Pogrebnyak  · 技术社区  · 15 年前

    在我的C++时代,关于C风格的Casic操作符的弊端,我很高兴在Java 5中发现了这一点。 java.lang.Class 获得了 cast 方法。

    我认为我们终于有了一个处理演员阵容的OO方法。

    转出 Class.cast 与…不同 static_cast 在C++中。它更像 reinterpret_cast .它不会在预期的地方生成编译错误,而是会延迟到运行时。下面是一个简单的测试案例,演示不同的行为。

    package test;
    
    import static org.junit.Assert.assertTrue;
    
    import org.junit.Test;
    
    
    public class TestCast
    {
        static final class Foo
        {
        }
    
        static class Bar
        {
        }
    
        static final class BarSubclass
            extends Bar
        {
        }
    
        @Test
        public void test ( )
        {
            final Foo foo = new Foo( );
            final Bar bar = new Bar( );
            final BarSubclass bar_subclass = new BarSubclass( );
    
            {
                final Bar bar_ref = bar;
            }
    
            {
                // Compilation error
                final Bar bar_ref = foo;
            }
            {
                // Compilation error
                final Bar bar_ref = (Bar) foo;
            }
    
            try
            {
                // !!! Compiles fine, runtime exception
                Bar.class.cast( foo );
            }
            catch ( final ClassCastException ex )
            {
                assertTrue( true );
            }
    
            {
                final Bar bar_ref = bar_subclass;
            }
    
            try
            {
                // Compiles fine, runtime exception, equivalent of C++ dynamic_cast
                final BarSubclass bar_subclass_ref = (BarSubclass) bar;
            }
            catch ( final ClassCastException ex )
            {
                assertTrue( true );
            }
        }
    }
    

    所以,这是我的问题。

    1. 应该 Class.cast() 被放逐到非专利领域?在那里它有相当多的合法用途。
    2. 编译器是否应在以下情况下生成编译错误: 类() 是否可以在编译时确定使用和非法条件?
    3. Java是否应该提供一个与C++类似的语言构造的CAST操作符?
    7 回复  |  直到 7 年前
        1
  •  100
  •   hexacyanide    8 年前

    我只使用过 Class.cast(Object) 避免“仿制药领域”的警告。我经常看到这样的方法:

    @SuppressWarnings("unchecked")
    <T> T doSomething() {
        Object o;
        // snip
        return (T) o;
    }
    

    通常最好用以下方法来替代:

    <T> T doSomething(Class<T> cls) {
        Object o;
        // snip
        return cls.cast(o);
    }
    

    这是唯一的使用案例 类.cast(对象) 我从来没有遇到过。

    关于编译器警告:我怀疑 类.cast(对象) 对编译器来说不是特别的。它可以在静态使用时进行优化(即 Foo.class.cast(o) 而不是 cls.cast(o) )但我从未见过有人使用它——这使得在编译器中构建这种优化的工作有些毫无价值。

        2
  •  17
  •   Beryllium    11 年前

    首先,你强烈反对做任何演员,所以你应该尽可能地限制它!您失去了Java编译时强类型特性的好处。

    无论如何, Class.cast() 应该主要用于检索 Class 通过反射标记。写东西比较习惯

    MyObject myObject = (MyObject) object
    

    而不是

    MyObject myObject = MyObject.class.cast(object)
    

    编辑:编译时出错

    总之,Java只在运行时执行强制检查。但是,如果编译器能够证明这样的强制转换永远不会成功(例如,将一个类强制转换为另一个不是父类型的类,并将最后一个类类型强制转换为不在其类型层次结构中的类/接口),则会发出错误。从那以后 Foo Bar 是彼此不在层次结构中的类,强制转换永远不会成功。

        3
  •  16
  •   cletus    15 年前

    尝试在语言之间翻译结构和概念总是有问题的,而且常常误导人。铸造也不例外。特别是因为Java是一种动态语言,C++有点不同。

    不管你怎么做,在爪哇所有的铸造都是在运行时完成的。类型信息在运行时保存。C++有点复杂。您可以将C++中的结构转换为另一个结构,而仅仅是对那些结构的字节的重新解释。Java不是这样工作的。

    爪哇和C++中的泛型也大不相同。不要过分关注你如何在Java中做C++的事情。你需要学习如何用Java方式做事。

        4
  •  10
  •   Joachim Sauer    15 年前

    Class.cast() 在Java代码中很少使用。如果使用它,那么通常只在运行时才知道的类型(即通过它们各自的 Class 对象和某些类型参数)。它只在使用泛型的代码中真正有用(这也是它之前没有被引入的原因)。

    它是 类似 reinterpret_cast 因为它会 允许您在运行时中断类型系统,而不是普通的强制转换(即,您可以“中断”泛型类型参数,但不能“中断”真正的类型)。

    C型CAST运算符的缺点一般不适用于Java。看起来像C样式的Java代码最类似于 dynamic_cast<>() 使用Java中的引用类型(记住:Java具有运行时类型信息)。

    通常比较C++的铸造操作符和Java的铸造是相当困难的,因为在爪哇中,只能对对象进行引用和转换(只有原始值可以使用此语法转换)。

        5
  •  3
  •   mmmmmm    15 年前

    C++和Java是不同的语言。

    Java C风格的CAST运算符比C/C++版本更受限制。实际上,JAVA CAST就像C++的DyrimCype,如果你的对象不能被转换到新的类,你将得到一个运行时间(或者如果代码中有足够的信息编译时间)异常。因此,不使用C类型转换的C++思想在Java中不是一个好主意。

        6
  •  0
  •   Amjad Abdul-Ghani    7 年前

    除了删除上面提到的丑陋的强制转换警告之外,class.cast是运行时强制转换,主要用于一般强制转换,由于一般信息将在运行时被删除,并且一些一般信息将被视为对象,这将导致不抛出早期的ClassCastException。

    例如,serviceloder在创建对象时使用此技巧,检查s p=service.cast(c.newInstance());这将引发类强制转换异常 当s p=(s)c.newInstance();不会并且可能显示警告时 '类型安全:未选中从对象强制转换为s' (与object p=(object)c.newInstance();)相同

    -只需检查强制转换对象是否是强制转换类的实例,然后使用强制转换运算符强制转换并隐藏警告。

    动态CAST的Java实现

    @SuppressWarnings("unchecked")
    public T cast(Object obj) {
        if (obj != null && !isInstance(obj))
            throw new ClassCastException(cannotCastMsg(obj));
        return (T) obj;
    }
    
    
    
    
        private S nextService() {
            if (!hasNextService())
                throw new NoSuchElementException();
            String cn = nextName;
            nextName = null;
            Class<?> c = null;
            try {
                c = Class.forName(cn, false, loader);
            } catch (ClassNotFoundException x) {
                fail(service,
                     "Provider " + cn + " not found");
            }
            if (!service.isAssignableFrom(c)) {
                fail(service,
                     "Provider " + cn  + " not a subtype");
            }
            try {
                S p = service.cast(c.newInstance());
                providers.put(cn, p);
                return p;
            } catch (Throwable x) {
                fail(service,
                     "Provider " + cn + " could not be instantiated",
                     x);
            }
            throw new Error();          // This cannot happen
        }
    
        7
  •  0
  •   Wep0n    7 年前

    就个人而言,我以前用过这个来构建一个JSON-to-Pojo转换器。如果用函数处理的jsonObject包含数组或嵌套的jsonObjects(意味着此处的数据不是基元类型或 String ,我尝试使用 class.cast() 以这种方式:

    public static Object convertResponse(Class<?> clazz, JSONObject readResultObject) {
        ...
        for(Method m : clazz.getMethods()) {
            if(!m.isAnnotationPresent(convertResultIgnore.class) && 
                m.getName().toLowerCase().startsWith("set")) {
            ...
            m.invoke(returnObject,  m.getParameters()[0].getClass().cast(convertResponse(m.getParameters()[0].getType(), readResultObject.getJSONObject(key))));
        }
        ...
    }
    

    不确定这是否非常有用,但是正如前面所说,反射是 类() 我能想到,至少你现在有另一个例子。