URL.openConnection()的实现,以便可以对其进行广播



我不明白为什么抽象类可以被强制转换为它的任何子类。例如:

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无关(

最新更新