Programing

Java Class.cast () 대 캐스트 연산자

lottogame 2020. 8. 16. 21:42
반응형

Java Class.cast () 대 캐스트 연산자


C ++ 시절에 C 스타일 캐스트 연산자의 악에 대해 배웠던 나는 처음에는 Java 5 java.lang.Class에서 cast메소드를 얻었음 을 알게되어 기뻤습니다 .

드디어 캐스팅에 대한 OO 방식이 있다고 생각했습니다.

결과 Class.caststatic_castC ++에서 와 동일하지 않습니다 . 더 비슷 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. 컴파일러는를 Class.cast()사용할 때 컴파일 오류를 생성해야 하며 컴파일 타임에 잘못된 조건을 확인할 수 있습니까?
  3. Should Java provide a cast operator as a language construct similar to C++?

I've only ever used Class.cast(Object) to avoid warnings in "generics land". I often see methods doing things like this:

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

It's often best to replace it by:

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

That's the only use case for Class.cast(Object) I've ever come across.

Regarding compiler warnings: I suspect that Class.cast(Object) isn't special to the compiler. It could be optimized when used statically (i.e. Foo.class.cast(o) rather than cls.cast(o)) but I've never seen anybody using it - which makes the effort of building this optimization into the compiler somewhat worthless.


First, you are strongly discouraged to do almost any cast, so you should limit it as much as possible! You lose the benefits of Java's compile-time strongly-typed features.

In any case, Class.cast() should be used mainly when you retrieve the Class token via reflection. It's more idiomatic to write

MyObject myObject = (MyObject) object

rather than

MyObject myObject = MyObject.class.cast(object)

EDIT: Errors at compile time

Over all, Java performs cast checks at run time only. However, the compiler can issue an error if it can prove that such casts can never succeed (e.g. cast a class to another class that's not a supertype and cast a final class type to class/interface that's not in its type hierarchy). Here since Foo and Bar are classes that aren't in each other hierarchy, the cast can never succeed.


It's always problematic and often misleading to try and translate constructs and concepts between languages. Casting is no exception. Particularly because Java is a dynamic language and C++ is somewhat different.

All casting in Java, no matter how you do it, is done at runtime. Type information is held at runtime. C++ is a bit more of a mix. You can cast a struct in C++ to another and it's merely a reinterpretation of the bytes that represent those structs. Java doesn't work that way.

Also generics in Java and C++ are vastly different. Don't concern yourself overly with how you do C++ things in Java. You need to learn how to do things the Java way.


Class.cast() is rarely ever used in Java code. If it is used then usually with types that are only known at runtime (i.e. via their respective Class objects and by some type parameter). It is only really useful in code that uses generics (that's also the reason it wasn't introduced earlier).

It is not similar to reinterpret_cast, because it will not allow you to break the type system at runtime any more than a normal cast does (i.e. you can "break" generic type parameters, but can't "break" "real" types).

The evils of the C-style cast operator generally don't apply to Java. The Java code that looks like a C-style cast is most similar to a dynamic_cast<>() with a reference type in Java (remember: Java has the runtime type information).

Generally comparing the C++ casting operators with Java casting is pretty hard since in Java you can only ever cast reference and no conversion ever happens to objects (only primitive values can be converted using this syntax).


C++ and Java are different languages.

The Java C-style cast operator is much more restricted than the C/C++ version. Effectively the Java cast is like the C++ dynamic_cast if the object you have cannot be cast to the new class you will get a run time (or if there is enough information in the code a compile time) exception. Thus the C++ idea of not using C type casts is not a good idea in Java


Generally the cast operator is preferred to the Class#cast method as it's more concise and can be analyzed by the compiler to spit out blatant issues with the code.

Class#cast takes responsibility for type checking at run-time rather than during compilation.

There are certainly use-cases for Class#cast, particularly when it comes to reflective operations.

Since lambda's came to java I personally like using Class#cast with the collections/stream API if I'm working with abstract types, for example.

Dog findMyDog(String name, Breed breed) {
    return lostAnimals.stream()
                      .filter(Dog.class::isInstance)
                      .map(Dog.class::cast)
                      .filter(dog -> dog.getName().equalsIgnoreCase(name))
                      .filter(dog -> dog.getBreed() == breed)
                      .findFirst()
                      .orElse(null);
}

In addition to remove ugly cast warnings as most mentioned ,Class.cast is run-time cast mostly used with generic casting ,due to generic info will be erased at run time and some how each generic will be considered Object , this leads to not to throw an early ClassCastException.

for example serviceLoder use this trick when creating the objects,check S p = service.cast(c.newInstance()); this will throw a class cast exception when S P =(S) c.newInstance(); won't and may show a warning 'Type safety: Unchecked cast from Object to S'.(same as Object P =(Object) c.newInstance();)

-simply it checks that the casted object is instance of casting class then it will use the cast operator to cast and hide the warning by suppressing it.

java implementation for dynamic cast:

@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
    }

Personally, I've used this before to build a JSON to POJO converter. In the case that the JSONObject processed with the function contains an array or nested JSONObjects (implying that the data here isn't of a primitive type or String), I attempt to invoke the setter method using class.cast() in this fashion:

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))));
    }
    ...
}

Not sure if this is extremely helpful, but as said here before, reflection is one of the very few legitimate use case of class.cast() I can think of, at least you have another example now.

참고URL : https://stackoverflow.com/questions/1555326/java-class-cast-vs-cast-operator

반응형