我不明白为什么抽象类可以被强制转换为它的任何子类。例如:
URL url = new URL("http://www.google.com");
HttpURLConnection httpURL = (HttpURLConnection) url.openConnection();
我注意到openConnection((返回一个URLConnection实例,它是一个抽象类。如何实现它(使用一个更简单的例子(,以便将其转换为子类?
例如,如果我有:
abstract class C1
{
abstract void f1();
abstract void f2();
}
class C2 extends C1
{
@Override
void f1() {
System.out.println("f12");
}
@Override
void f2() {
System.out.println("f22");
}
void f3() {
System.out.println("f32");
}
}
class C3 extends C1 {
@Override
void f1() {
System.out.println("f13");
}
@Override
void f2() {
System.out.println("f23");
}
void f3() {
System.out.println("f33");
}
}
public class Main {
public static void main(String args[]) {
C2 c2 = new C2();
C3 c3 = new C3();
C1 c1 = c3;
c3 = (C3) c1;
c2 = (C2) c1;
}
}
则c3=(c3(c1;会起作用,但第二个演员不行(我理解这种情况(。
那么,我们怎么能知道openConnection((是否返回了正确的子类(这样它在抛出时就不会导致运行时异常(呢?我假设返回对象的形式可能是:
return (URLConnection) obj;
其中obj被声明为HttpUrlConnection或JarURLConnection。
或者返回一些使用lambda表达式或匿名方法声明的obj(不带强制转换(。
更新:
JarURLConnection hpCon = (JarURLConnection) hp.openConnection();
实际上会导致运行时异常:"线程中的异常"main"java.lang.ClassCastException:sun.netwww.protocol.http.HttpURLConnection无法转换为java.net.JarURLConnection">
为什么openConnection((返回URLConnection,那么如果它实际上是HttpURLConnection并且转换为JarURLConnection会失败?
您的示例将在运行时产生ClassCastException,因为c1不是c2类型。
下强制转换:从一个超类到一个实现是不安全的,所以这就是为什么你需要用(C3(显式强制转换它,而上强制转换(从C3到C1(是安全的,你不需要键入它。
代码中发生的情况是,您删除了旧类型,并尝试使用显式强制转换重新签名,这将在运行时导致ClassCastException(从C3到C2(。
例如,请注意以下内容不可编辑:
C3 c3 = (C3) new C2();
虽然这样做(但在运行时崩溃(:
C3 c3 = (C3) (C1) new C2();
URLConnection的示例有效,因为openConnection确实返回了HttpUrlConnection的实例,但仍然需要对其类型进行不安全的强制转换。请注意,HttpsUrlConnection可以从openConnection返回,但由于它扩展了HttpUrlConnection,因此可以按原样进行广播。
Java支持两种类型的转换
- Upcasting-将类层次结构中的子类实例强制转换为它的一个超类
- Downcasting-在类层次结构中将超类引用转换为其子类实例类型
Thumb规则
- 类层次结构从实例类型开始到其超类类型
- 无法强制转换不相关的类
在您的示例中
- 类C3是子类,类C1是其超类(层次结构:C3->C1->Object(
- 类C2是子类,类C1是它的超类(层次结构:C2->C1->Object(
- 类C1(层次结构:C1->Object(
- C3级和C2级不相关
- C1类与C2和C3无关
C1 C1=c3;(有效。它是一个upcast。子类C3的实例类型被分配给它的超类类型c1(
现在c1正在引用其子类型C3的一个实例。它可以被转换为其实例类型,也可以转换为任何超级类型
c3=(c3(c1;(有效。它是一个向下转换。引用类型C1转换为其实例类型C3(
c2=(c2(c1;(无效。正在尝试将C3的实例强制转换为不相关的类类型C2(
c3=(c3((新的C1((((无效。C1与c3无关(
c2=(c2((新的C1((((无效。C1与c2无关(