我不明白为什么可以将抽象类强制转换为其任何子类。 例如:
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会失败?
答案 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支持两种类型的转换
拇指法则
在您的示例中
c3 =(C3)c1; (有效。这是一个向下转换。引用类型C1被强制转换为其实例类型C3)
c2 =(C2)c1; (无效。尝试将C3的实例强制转换为不相关的类类型C2)
c3 =(C3)(新C1())(无效。C1与C3不相关)
c2 =(C2)(新C1())(无效。C1与C2不相关)