QQ个性网:专注于分享免费的QQ个性内容

关于我们| 网站公告| 广告服务| 联系我们| 网站地图

搜索
编程 JavaScript Java C++ Python SQL C Io ML COBOL Racket APL OCaml ABC Sed Bash Visual Basic Modula-2 Logo Delphi IDL Groovy Julia REXX Chapel X10 Forth Eiffel C# Go Rust PHP Swift Kotlin R Dart Perl Ruby TypeScript MATLAB Shell Lua Scala Objective-C F# Haskell Elixir Lisp Prolog Ada Fortran Erlang Scheme Smalltalk ABAP D ActionScript Tcl AWK IDL J PostScript IDL PL/SQL PowerShell

Java中的抽象类与接口(2)

日期:2025/04/05 16:01来源:未知 人气:53

导读:Java里面除了抽象类和接口的区别这种头疼并且不容易搞明白的问题,还有很多很重要的问题,并且有些也很好玩。所以,抽象类和接口,到底有啥区别,可以留到今后的工作中慢慢体会。因为随着阅历的增长、对对面向对象的理解和能熟练使用继承结构以后,这将不再是个问题。有一个比较有意思的问题比这个有趣:既然AbstractList实现了List接口,那为什么ArrayList继承了Abstrac......

Java里面除了抽象类和接口的区别这种头疼并且不容易搞明白的问题,还有很多很重要的问题,并且有些也很好玩。所以,抽象类和接口,到底有啥区别,可以留到今后的工作中慢慢体会。因为随着阅历的增长、对对面向对象的理解和能熟练使用继承结构以后,这将不再是个问题。

有一个比较有意思的问题比这个有趣:既然AbstractList实现了List接口,那为什么ArrayList继承了AbstractList之后还要再实现List接口呢?通过运行代码就能明白:

public class Test1 { public interface List { void get(); }

public static abstract class AbstractList implements List { public abstract void get(); }

public static class Class1 extends AbstractList implements List { @Override public void get() { System.out.println("Class1.get()"); } }

public static class Class2 extends AbstractList { @Override public void get() { System.out.println("Class2.get()"); } }

private static T invoke(final T obj) { final InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(obj, args); } }; return (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler); }

public static void main(String[] args) { _//这个可以调用成功 ___List list1 = invoke(new Class1()); list1.get(); _//这个会抛异常,这是因为_ Class1 隐式实现 List ,而 Class2 显示实现 List _ ___List list2 = invoke(new Class2()); list2.get(); } }

可以看到,Class1继承了AbstractList之后又显式实现了List接口,而Class2仅仅只是继承了AbstractList。然后通过反射再重新声明Class1和Class2时,回会发现Class2抛异常了——这就是为什么需要显式再实现一次List的原因——如果想要获取已实现接口的子类的动态代理,那这个子类就必须显式实现接口。

说直白点,就是没有直接实现接口的类,用反射的时候就要小心了。

另一个比较有趣,而且面试的时候可能会问的比较多的问题,会是下面关于类的多重继承问题。

假设有如下条件:

1、接口A和接口B拥有相同的方法

2、接口B继承接口A,C是独立接口

3、类D有和A、B相同的方法

用代码来解释就是:

public interface A { default void hello() { System.out.println("Hello from A"); } }

public interface B extends A { default void hello() { System.out.println("Hello from B"); } }

public interface C { default void hello() { System.out.println("Hello from C"); } }

public class D { public void hello() { System.out.println("Hello from D"); } }

那么问题来了:

1、类E同时实现A、B,会调用A、B哪个父类接口的方法呢?

public class E implements A, B { public static void main(String[] args) { new E().hello(); } }

2、类E继承D,同时实现A、B,会调用A、B、D哪个父类的方法呢?

public class E extends D implements A, B { public static void main(String[] args) { new E().hello(); } }

3、当E同时实现A、B、C时,会调用A、B、C哪个父类接口的方法呢?

public class E implements A, B, C { @Override public void hello() { C.super.hello(); }

public static void main(String[] args) { new E().hello(); } }

4、当E同时实现A、B、C且继承自D时,会调用A、B、C、D哪个父类接口的方法呢?

public class E extends D implements A, B, C { public static void main(String[] args) { new E().hello(); } }

其实这就是Java中设计的继承原则,分别如下:

1、第一个问题遵循子类优先原则:当接口之间有继承关系时,子接口的优先级最高

2、第二个问题遵循类优先原则:继承自类的方法优先级最高(E实现D的方法)

3、第三个问题遵循指定关系原则:当接口之间无继承关系时,编译器会强制指定方法的具体实现(例如接口B和接口C无继承关系,那么此时需要在B和C之间选一个)

4、第四个问题可参照第二个问题的原则解释:类优先原则

Java里面的多重继承也就这么点东西了。

关于我们|网站公告|广告服务|联系我们| 网站地图

Copyright © 2002-2023 某某QQ个性网 版权所有 | 备案号:粤ICP备xxxxxxxx号

声明: 本站非腾讯QQ官方网站 所有软件和文章来自互联网 如有异议 请与本站联系 本站为非赢利性网站 不接受任何赞助和广告