URL.openConnection()的实现,以便可以进行强制转换

时间:2018-07-19 21:49:13

标签: java casting abstract-class

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

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.net.www.protocol.http.HttpURLConnection无法转换为java.net.JarURLConnection”

为什么openConnection()返回URLConnection,然后如果它实际上是HttpURLConnection并转换为JarURLConnection会失败?

2 个答案:

答案 0 :(得分:1)

由于c1不是c2类型,因此您的示例将在运行时导致ClassCastException。

向下广播:从超类转到实现是不安全的,因此这就是为什么您需要使用(C3)显式强制转换它,而向上广播(从C3到C1)则是安全的,并且您不需要键入。

代码发生的事情是,您删除了旧类型并尝试使用显式强制转换来重新分配代码,这将在运行时导致ClassCastException(从C3到C2)。

例如,以下内容不可编译:

 C3 c3 = (C3) new C2();

尽管这样做(但在运行时崩溃):

 C3 c3 = (C3) (C1) new C2();

URLConnection的示例工作会导致openConnection确实返回HttpUrlConnection的实例,但仍需要对其类型进行不安全的强制转换。请注意,可以从openConnection返回Http s UrlConnection,但是由于它扩展了HttpUrlConnection,因此可以将其强制转换。

答案 1 :(得分:0)

Java支持两种类型的转换

  • Upcasting-将类层次结构中的子类的实例强制转换为其父类之一
  • 向下转换-在类层次结构中将超类引用转换为其子类实例类型。

拇指法则

  • 类层次结构从实例类型开始为其父类类型
  • 不相关的类不能转换

在您的示例中

  • C3类是其子类,而C1类是其超类(层次结构:C3-> C1->对象)
  • C2类是其子类,而C1类是其超类(层次结构:C2-> C1->对象)
  • C1类(层次结构:C1->对象)
  • C3和C2类无关
  • C1类与C2和C3不相关
C1 c1 = c3; (有效。这是一个上调。子类C3的实例类型已分配给其超类类型c1)

现在c1引用了其子类型C3的实例。可以将其强制转换为其实例类型,也可以强制转换为其超级类型

c3 =(C3)c1; (有效。这是一个向下转换。引用类型C1被强制转换为其实例类型C3)

c2 =(C2)c1; (无效。尝试将C3的实例强制转换为不相关的类类型C2)

c3 =(C3)(新C1())(无效。C1与C3不相关)

c2 =(C2)(新C1())(无效。C1与C2不相关)