Если эксплуатируемые объекты находятся в одной и той же иерархии, приведение скомпилируется наверняка, но во время выполнения может произойти сбой.
Например:
class Animal { }
class Dog extends Animal { }
class Bulldog extends Dog { }
Если вы напишите:
Animal animal = new Animal();
Dog d = (Dog) animal;
Приведенный выше код скомпилируется, но завершится с ошибкой во время выполнения.Потому что все, что может сделать компилятор, это проверить, находятся ли два типа в одном и том же дереве наследования.Компилятор позволяет вещи, которые могут работать во время выполнения.Но если компилятор точно знает, что что-то никогда не будет работать, он выдаст ошибку во время выполнения.Например,
Animal animal = new Animal();
Dog d = (Dog) animal;
String s = (String) animal;
Это, безусловно, завершится ошибкой, поскольку компилятор знает, что String и Dog не находятся в одной иерархии.
Те же правила применяются и к интерфейсам.
Надеюсь, это поможет.