Java 中接口作为方法参数

问题描述 投票:0回答:9

我前几天去面试,被问到这样的问题。

问:反转链表。给出以下代码:

public class ReverseList { 
    interface NodeList {
        int getItem();
        NodeList nextNode();
    }
    void reverse(NodeList node) {

    }
    public static void main(String[] args) {

    }
}

我很困惑,因为我不知道接口对象可以用作方法参数。面试官稍微解释了一下,但我还是不太确定。有人可以启发我吗?

java oop interface
9个回答
81
投票

这实际上是使用界面的最常见和最有用的方法之一。接口定义了一个契约,您的代码可以与任何实现该接口的类一起使用,而不必知道具体的类 - 它甚至可以与编写代码时尚不存在的类一起使用。

Java 标准 API 中有很多示例,尤其是集合框架中。例如, Collections.sort() 可以对实现

List
接口的任何内容(不仅仅是
ArrayList
LinkedList
,尽管实现您自己的
List
并不常见)及其内容实现
Comparable
接口进行排序(不仅仅是
String
或数字包装类 - 并且让您自己的类实现
Comparable
来实现此目的是 相当 常见)。


43
投票

传递给方法的不是接口“对象”,仍然只是一个常规对象。这只是一种说法“此参数将接受任何支持此接口的对象”。它相当于接受基类类型的某个对象,即使您传递的是子类。


11
投票

这称为接口编程。您不需要对节点列表的特定实现类进行编码,而是对所有这些实现所实现的接口进行编码。

这样,如果有人在您编写反向方法后编写了新的、更好的

NodeList
实现,您的代码仍然可以工作,并且您不必为
NodeList
的每个新实现调整代码。


7
投票

参数需要一个对象,该类实现一个接口(参数)。

pseudo Java 中代码:

void reverse(NodeList node) {
    // your code
}

等于:

reverse(x) {
    if(x == null || x instanceof NodeList) {
         // your code
    }else throw new RuntimeException("Some sort of error.");
}

注意;在此处阅读有关接口的更多信息:http://java.sun.com/docs/books/tutorial/java/IandI/interfaceAsType.html


3
投票

这是一种可能的实现:

public class ReverseList { 
interface NodeList {
    int getItem();
    NodeList nextNode();
}

static class Node implements NodeList {
    private int item;
    private Node next;

    @Override
    public int getItem() {
        return item;
    }

    public void setItem(int si) {
        item = si;
    }

    @Override
    public NodeList nextNode() {
        return this.next;
    }

    public void setNext(Node n) {this.next=n;}

}

Node reverse(NodeList head) {
    Node node = (Node) head;
    Node previous = null;
    while(node.nextNode() !=null) {
        Node tempNext = (Node) node.nextNode();
        node.setNext(previous);
        previous = node;
        node = tempNext;
    }
    node.setNext(previous);
    return node;

}
public static void main(String[] args) {
    //Initialization block
    ReverseList rl = new ReverseList();
    Node n1= new Node(); n1.setItem(1);
    Node n2=new Node(); n2.setItem(2);
    Node n3 =new Node(); n3.setItem(3);
    n1.setNext(n2); n2.setNext(n3); n3.setNext(null);

    //Reversing the list
    System.out.println("Before reversal");      
    System.out.println(n1.getItem() +"->" 
                    + n1.nextNode().getItem() + "->"
                    + n1.nextNode().nextNode().getItem() + "->"
                    +n1.nextNode().nextNode().nextNode());


    rl.reverse(n1);

    System.out.println("\nAfter reversal");
    System.out.println(n3.getItem() +"->" 
            + n3.nextNode().getItem() + "->"
            + n3.nextNode().nextNode().getItem() + "->"
            +n3.nextNode().nextNode().nextNode());
        }
}

程序输出:

Before reversal
1->2->3->null

After reversal
3->2->1->null

我很好奇是否可以通过使用匿名类来解决这个问题。有什么想法吗?


3
投票

在学习 lambda 的东西时也有同样的困惑。 该视频没有解释这个概念,但它可以让您清楚地了解它如何将接口作为参数传递。

https://www.youtube.com/watch?v=mk3erzL70yM


1
投票

恕我直言,使用接口的主要好处是能够轻松测试。假设您有一个名为 PatientManager 的接口。

您可以为“CachingPatientManager”或“LDAPPatientManager”等可想象的事物编写特定的单元测试,用例可能有无数种。

好处是接口编程变得高度可重用和可测试。


1
投票

您无法创建接口的实例(/object)。 是的,您可以将接口作为函数中的参数传递。但问题似乎不完整。接口不由任何类实现。缺了点什么。如果您尝试运行它,编译器将不会显示任何错误。

但是,在reverse()方法中,您需要创建一个实现NodeList接口的类的实例。我希望这是有道理的。


0
投票

也许为时已晚,但我仍然在这里留下我的答案,因为我发现你的问题很有帮助。


当接口用作方法的参数类型时,意味着该方法接受任何包含该接口的实现的对象。

这种用法有一个很好的例子,就是当你尝试将

ArrayList
传递给方法时。如您所知,您可以将您的
ArrayList
传递为
List
,如下所示:

public int getListSize(List<String> myList){
   return myList.size();
}

然后,这将使您能够灵活地传递任何实现 List 方法的对象。例如,您可以这样做:

List<String> myList1 = new ArrayList<>();
List<String> myList2 = new LinkedList<>();
List<String> myList3 = new Vector<>();

int size1 = getListSize(myList1); // Valid, myList1 is an ArrayList
int size2 = getListSize(myList2); // Valid, myList2 is a LinkedList
int size3 = getListSize(myList3); // Valid, myList3 is a Vector
© www.soinside.com 2019 - 2024. All rights reserved.