【问题标题】:The overriding of anonymous internal class methods does not work [duplicate]匿名内部类方法的覆盖不起作用[重复]
【发布时间】:2020-01-08 08:05:34
【问题描述】:

你能用这种方式覆盖一个方法吗?

public class test {

    public static void main(String[] args) throws IOException {        
        File dir = new File("M:\\Java\\Test") {
            @Override
            public String[] list() { 
                String[] listA = super.list();                
                for (String s : listA) {
                    s = "test" + s;
                }                
                return listA;
            }
        };
        String[] listB = dir.list();
        for (String s : listB) {
            System.out.println(s);
        }
    }
}

我预计:

test1.txt
test10.txt
test2.txt
test3.txt
test4.txt
test5.txt
test6.txt
test7.txt
test8.txt
test9.txt

我收到了:

1.txt
10.txt
2.txt
3.txt
4.txt
5.txt
6.txt
7.txt
8.txt
9.txt

我无法提出新问题,而且它涉及相同的代码,所以我会在这里提问。是嵌套方法覆盖导致的编译器错误吗?

public class test {

    public static void main(String[] args) throws IOException {
        File dir = new File("M:\\Java\\Test") {
            @Override
            public String[] list() {
                String[] listA = super.list(new FilenameFilter() {
                    @Override
                    public boolean accept(File file, String string) {
                        return string.contains(".txt");
                    }
                });
                for (int i = 0; i < listA.length; i++) {
                    listA[i] = "test" + listA[i];
                }                                
                return listA;
            }
        };
        String[] listB = dir.list();
        for (String s : listB) {
            System.out.println(s);
        }
    }
}

我收到了:

    Exception in thread "main" java.lang.StackOverflowError  
        at java.io.File.list(File.java:1155)  
        at findmyorder.test$1.list(test.java:22)  
        at java.io.File.list(File.java:1155)  
        at findmyorder.test$1.list(test.java:22)  
        at java.io.File.list(File.java:1155)  
        at findmyorder.test$1.list(test.java:22)  
        at java.io.File.list(File.java:1155)  
        at findmyorder.test$1.list(test.java:22)  
        at java.io.File.list(File.java:1155)  
        at findmyorder.test$1.list(test.java:22)  
        at java.io.File.list(File.java:1155)  
        at findmyorder.test$1.list(test.java:22)  
        at java.io.File.list(File.java:1155) 

它看起来像一个无限循环。将FilenameFilter 添加到list() 函数后出现问题。 这是嵌套@Override的结果吗?

【问题讨论】:

  • 您正在更改迭代变量 s 而不是数组 listA 的值

标签: java overriding


【解决方案1】:

String 是一个不可变的类,所以s = "test" + s; 在这里没有影响。你应该使用这样的东西:

File dir = new File(".") {
  @Override
  public String[] list() {
    String[] listA = super.list();
    if (listA != null) {
      for (int i = 0; i < listA.length; i++) {
        listA[i] = "test" + listA[i];
      }
    }
    return listA;
  }
};
String[] listB = dir.list();
if (listB != null) {
  for (String s : listB) {
    System.out.println(s);
  }
}

【讨论】:

    【解决方案2】:

    问题在于这一行:

    s = "test" + s;
    

    所做的只是更新s 变量。它对列表中的字符串没有任何影响。

    相反,使用更新后的名称构建一个新数组,然后将其返回。

    @Override
    public String[] list() { 
        String[] listA = super.list();                
        String[] listB = new String[listA.length]; // ***
        int n = 0;                                 // ***
        for (String s : listA) {
            listB[n++] = "test" + s;               // ***
        }                
        return listB;                              // ***
    }
    

    旁注:File#list 可以返回null:

    返回:

    一个字符串数组,命名此抽象路径名表示的目录中的文件和目录。如果目录为空,则数组将为空。 如果此抽象路径名不表示目录,或者发生 I/O 错误,则返回 null。

    (我的重点)

    ...所以您需要处理这种可能性:

    @Override
    public String[] list() { 
        String[] listA = super.list();                
        if (listA == null) {                       // ***
            return null;                           // ***
        }                                          // ***
        String[] listB = new String[listA.length];
        int n = 0;
        for (String s : listA) {
            listB[n++] = "test" + s;
        }                
        return listB;
    }
    

    【讨论】:

    • 我不知道为什么我没有像the answer 那样更新listA 我现在看到Shubhendu 发布了。没有充分的理由,真的;这可能会更好,因为 File 类正在移交数组以供调用者使用,它不会为自己的目的而保留它...
    【解决方案3】:

    这个

    String[] listA = super.list();                
    for (String s : listA) {
      s = "test" + s;
    }                
    return listA;
    

    不符合您的预期。试试

    for (int i = 0; i < listA.length; i++) {
      listA[i] = "test" + listA[i];
    }
    

    【讨论】:

      【解决方案4】:

      这里:

      String[] listA = super.list();                
      for (String s : listA) {
         s = "test" + s;
      }                
      

      您创建一个 new 字符串对象,并将其分配给 以前 指向数组成员的引用。

      然后:

       return listA;
      

      你返回那个数组。

      您的代码确实不会更改数组的内容。您迭代数组,为每个条目创建一个新字符串。然后你把那个新字符串扔掉,然后返回原始的、未修改的数组。

      你可以像这样的一个班轮:

      return Arrays.stream(super.list()).map(s -> s = "test" + s).toArray(String[]::new);
      

      除此之外,我会非常小心地使用这样的多态性。文件的合同说:此方法返回“子文件”名称。合同没有说:它返回被操纵的文件名。因此,对于实际的生产代码使用,我宁愿创建一个实现其“自己的”合同的帮助程序/实用程序类,它说:“给我一个文件列表,我以有意义的方式在它们前面加上前缀”。

      【讨论】:

      • String[] listB = dir.list(); for (String s : listB) { s = "test" + s; System.out.println(s);那么为什么这段代码有效呢?
      • 对不起。我是一个新的论坛用户。我不知道公约。我会记住这一点的。
      • @kAEm 虽然没有必要更改接受。无论如何:我很高兴你很快就得到了你的问题的答案!
      【解决方案5】:

      您返回的是相同的列表。用这个替换你的 for 循环:

              for(int i=0;i<listA.length;i++)
              {
                  listA[i] = "test" + listA[i];
              }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-15
        • 1970-01-01
        • 1970-01-01
        • 2018-09-12
        相关资源
        最近更新 更多