Java Lists(也是Collection)有方法实现(add()
,get()
),那么它们如何成为INTERFACES?
我希望:
List <Integer> nums = ArrayList <Integer>();
nums.add(5);
上面的代码会出错,因为add()应该在ArrayList中实现而不是List(作为一个接口)但是情况并非如此,代码工作正常。 有人可以解释一下吗?
答案 0 :(得分:2)
这只是行动中的多态性。 ArrayList
是一个List
,因此可以分配给List
类型的变量。
接口定义了实现它的任何类的契约。它没有实现这些方法(需要注意的是:从Java 8开始,这种情况正在发生变化)。
变量nums
是List
,但由于分配,其具体类型为ArrayList
。运行时将其视为多态,因此运行时动态绑定<{1}} add
存储在nums
中的实际类型:即它调用add
ArrayList
上的方法。
我建议在同一部分阅读The Java Tutorials > Polymorphism和接口页面。
答案 1 :(得分:1)
您似乎对interface
是什么感到困惑,或者至少对您如何使用它们感到困惑。 Java中的interface
定义了一组方法签名,其中任何类implements
接口必须提供(或者是abstract
)。 ArrayList
是一个实现List
接口的类。执行以下操作时:
List<Integer> nums = ArrayList<Integer> ()
您正在创建ArrayList
的实例,该实例实现List
的所有方法,并将其分配给可以包含任何实现List
的对象的变量。这意味着在使用nums
时,您只能访问List
公开的方法。但是,实际上被称为的方法是ArrayList
。
Java鼓励使用interfaces
,因为它们并不绑定到特定的继承链。请考虑以下方法签名:
public <T> void foo(List<T> input)
public <T> void bar(ArrayList<T> input)
foo
方法可以执行任何实现List
的方法;这可能是标准库对象之一,如ArrayList
或LinkedList
,或者它可以是用户定义的类,除标准List
操作外,它还提供完全不同的功能。这使它更灵活; foo
只是声明期望一个看起来像List
的对象,但不关心该对象是什么。
另一方面,bar
方法直接使用ArrayList
。如果您稍后意识到要使用其他收藏品,则会陷入困境,因为您只能使用ArrayList
或扩展ArrayList
的类。
答案 2 :(得分:1)
接口是一个契约,并且保证它背后有一些具体的实现。例如,您可以使用
List<Integer> nums = ArrayList<>();
或强>
List<Integer> nums = LinkedList<>();
它们的内部实现方面不同(但ArrayList
和LinkedList
都符合List
接口指定的合同。最后,在Java 8+ interface
(s)中可以有default methods。
答案 3 :(得分:1)
implements List
是一个承诺,该类具有在接口List
中声明的所有方法。如果对象中只需要List
个方法,那么只要该类实现List
,它实际上是哪个类并不重要。
List nums = new ArrayList ();
声明nums
为List
引用。这意味着它指向的任何对象必须是实现List
的类的实例,因此具有List
声明的所有方法。
nums.add(5);
使用任何对象add
引用必须提供的nums
方法,因为它必须实现List
。
答案 4 :(得分:0)
正如您在此处所见(OpenJDK源代码):http://www.docjar.com/html/api/java/util/List.java.html
列表是一个具有无实现的界面。您需要声明一个ArrayList或另一个实现此接口的List
答案 5 :(得分:0)
你应该学习继承。 List是一个不包含任何实现的接口。但ArrayList包含List接口的所有实现。
当你调用nums.add(5)时,你会看到正在调用List.add()方法但实际上它在后台调用了ArrayList.add(5)方法。这是继承的秘诀
请检查:http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html
答案 6 :(得分:0)
方法体是根据引用持有的对象的实际类型动态加载(在运行时)(称为late or dynamic binding),因此对于代码
List <Integer> nums = ArrayList <Integer>();
nums
引用中的实际对象将是ArrayList
类的实例,因此add/get
的代码将从ArrayList
加载。
List
实际上并没有实现get()
方法,而是调用
nums.add(5);
这对编译器来说不是问题,因为它知道ArrayList
将包含来自List
接口的所有抽象(无主体)方法的某些实现。