Чтобы решить вашу проблему, вы можете использовать reified
тип :
inline fun <reified CONTEXT> castToContext() = data as? CONTEXT
Причина, по которой это не сработало, как вы ожидаете, заключается в том, что универсальные типыстирается во время выполнения.
Если мы посмотрим на байт-код, то увидим, что везде, где записан ваш CONTEXT
-общий тип, он становится java/lang/Object
:
private final castToContext()Ljava/lang/Object;
L0
LINENUMBER 12 L0
ALOAD 0
GETFIELD CastTest.data : Ljava/lang/Object;
DUP
INSTANCEOF java/lang/Object // (1)
IFNE L1 // (1)
POP // (2)
ACONST_NULL // (2)
L1
ARETURN
L2
LOCALVARIABLE this LCastTest; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
Итакбезопасное приведение фактически делает проверку, не является ли данный объект типа java/lang/Object
(1), и устанавливает значение, которое будет возвращено null
, если это так.Но так как он имеет тип java/lang/Object
, значение просто возвращается как есть.На вызывающей стороне, однако, байт-код выглядит следующим образом:
LINENUMBER 4 L0
ALOAD 0
INVOKESPECIAL CastTest.castToContext ()Ljava/lang/Object; // the call
CHECKCAST TypeA // the type check
ARETURN
Он делает дополнительные CHECKCAST TypeA
после вызова castToContext
, и там вы получаете ClassCastException
, поскольку значение не было обнулено (универсальный типинформация была стерта во время выполнения).