当前位置: 首页 > 知识库问答 >
问题:

如何使用泛型将两个具有相同主体的方法转换为一个方法?

谷梁博易
2023-03-14

我有以下两种方法:

public class LoaderService {
    public static Config loadConfigFile() {
        try (var jsonReader = new JsonReader(new FileReader(Path.PROJECT_RESOURCES + "config" + Extension.JSON))) {
            return new Gson().fromJson(jsonReader, Config.class);
        } catch (IOException e) {
            return Config.builder().build();
        }
    }

    public static UriContainer loadUriContainerFile() {
        try (var jsonReader = new JsonReader(new FileReader(Path.PROJECT_RESOURCES + "URI container" + Extension.JSON))) {
            return new Gson().fromJson(jsonReader, UriContainer.class);
        } catch (IOException e) {
            return UriContainer.builder().build();
        }
    }
}

正如您所看到的,主体是相同的——我可以通过方法参数传递文件名。这些方法从JSON文件加载内容。他们身体上唯一的显著区别是所应用的课程类型<我想到了类似的事情:

public class LoaderService<T> {
    public T loadFile(String fileName) {
        try (var jsonReader = new JsonReader(new FileReader(fileName))) {
            return new Gson().fromJson(jsonReader, T.class);
        } catch (IOException e) {
            return T.builder().build();
        }
    }

但是我有错误:

return T.builder().build();
// ---> Cannot resolve method 'builder' in 'T'

我的dto-例如配置:

package dto;

import lombok.Builder;
import lombok.Value;

@Value
@Builder
public class Config {
    String url;
    String username;
    String password;
    String jdbcDriverPath;
    String driverClassName;
    String hostname;
    String port;
    String serverPath;
}

有可能在上述情况下应用泛型吗<对不起,如果这个问题没有意义,因为我只是在学习泛型

共有1个答案

莘聪
2023-03-14

您想要的是不可能的,因为您无法抽象静态方法的概念。

为什么你认为“FooFactory”是一个java迷因?工厂就是这样:抽象出构建器方法的概念。

然而,如果发生任何异常,只返回一个“空白”实例的想法似乎是极不明智的。这个错误有无数个原因,当然“扔掉所有关于这个错误的信息并返回一个空白实例”是一个很好的公式,可以花上几个小时追踪bug,一个只做奇怪事情的应用程序,因为代码一直在运行,当意外事件发生时会丢弃调试信息。

也许您打算只在该文件不存在的特定场景中返回一个空白实例。在这种情况下,我将捕获FileNotFoundException

将名为loadFile的方法声明为抛出IOException是100%合理的。如果您发现调用者中存在“烦人”问题,请记住,publicstaticvoidmain应该声明为抛出异常。

您需要抽象构建器的概念,或者至少抽象“使我成为默认空白实例”的概念。

让我们使用供应商(它被称为供应商,但我们在这里使用它作为工厂):

public static <T> T loadFile(Class<T> type, Supplier<T> defaultMaker) {
  try (var jsonReader = new JsonReader(new FileReader(fileName))) {
    return new Gson().fromJson(jsonReader, type);
  } catch (IOException e) {
    // I really, really wouldn't do this, but...
    return defaultMaker.get();
  }
}

为什么T.class不起作用?为什么T.builder()不起作用?因为泛型是javac想象出来的。运行时不知道。大多数泛型都被彻底删除了(它们无法在编译中生存),而在没有的地方,就java而言,它就是。exe是一个注释。

因此,T. class?这是不可能的:T是编译时的东西,而不是运行时的东西。Javac不知道T是什么,因此T. class是不可能的。同样的论点解释了为什么T. Builder()不可能工作。Java对T一无所知。它可以是任何东西。它显然可以是没有Builder()方法的类型。

因此,泛型最好被认为是一种“链接”工具。它把事情联系起来。因此,如果你只在一个地方使用泛型,它是无用的,或者是一个丑陋的黑客。

通过拥有

如果您仔细考虑,运行时不需要知道t是什么。这是一条需要记住的有用规则:如果你的代码不能工作,除非运行时知道t是什么,那么你就不能这样做。

泛型是复杂的;默认情况下,它们是不变的(子类型不是任何给定类型的有效替换;这与普通类型不同,在普通类型中,您可以将字符串表达式等指定给Object类型的变量。在泛型中则不是这样;您不能指定List类型的表达式

这个错误会花费你几天的时间,所以,修复它,记住它,更新你的IDE来标记它。

永远不要使用文件阅读器1

这门课不合目的。如果您的IDE具有“禁止”事物的功能(如果您使用它,则将其标记为错误),则添加它。

问题是,FileReader使用平台默认编码,谁知道这可能是什么。JSON需要UTF_8。

正确的做法是:

Files.newBufferedReader(filePath)

而不是新建文件读取器。这是因为文件默认为UTF-8,而不是“平台默认值”。或者,newjsonreader(newinputstreamreader)(newfileinputstream(fileName)),标准字符集。UTF_8))

请注意,如果您在一个默认为UTF-8的平台上,则不可能测试此错误,然而,当有人在一个没有(大多数平台都没有)的平台上运行您的代码时,它会在您的脸上爆炸尝试读取包含非ASCII字符的JSON文件。

这些缺陷会造成巨大的损失,因为您没有对它们进行测试,所以它们往往会投入生产。

[1] 从JDK11开始,有一个采用字符集的FileReader构造函数。然而,JDK11(实际上是JDK8)有了新的文件API,这是一个重大改进。因此,没有理由使用FileReader:在过时的JDK版本上,由于使用了平台默认编码(如果目的是将其视为JSON,那么这是错误的),它会被破坏,而在现代JDK版本上,有更好的替代方案。不管怎样,FileReader都是错误的答案。

 类似资料:
  • 因此,上述结构在ClassA中也同样存在。 假设我想编码2个其他类ClassC(使用ClassA的实例)和ClassD(使用ClassB的实例)。除了ClassA和ClassB的实例之外,ClassC和ClassD的代码完全相同。 从示例中可以看出,ClassC和ClassD具有相同的功能,但对tmp使用了不同的类

  • 我有两个数据类型不同的方法,但正文相同。我没有使用任何。我只使用这些方法来引发异常。有没有什么方法可以将这两种方法结合起来,或者有什么方法可以优化代码? PS:我不想使用接口或一些具有普通逻辑的新方法。

  • 在JLS 8第8.4.8.1节中,有一条声明: 在某些参数化下,泛型超类C中的具体方法可以与该类中的抽象方法具有相同的签名。在这种情况下,具体方法是继承的,而抽象方法不是。然后应将继承的方法视为覆盖其来自C的抽象对等体。 有人能为泛型类提供这种参数化的例子吗?我不能。

  • 我想说得具体一点。我有一个名为Result的类和一个名为Result的派生类 这些类在方法中用作返回类型。为此,我创建了这个helper类: 正如您所看到的,上面的代码对于成功有两种返回类型,一种是如果您不想返回任何东西,另一种是如果您想返回一些东西,但是失败的结果永远不会返回什么东西。这是不必要的,只是一个错误消息。这使我想到以下问题:当我想创建一个可以使用返回类型返回Success,而不使用返

  • 我有一个采访问题-C#,是否可以在一个类中实现,从接口继承有两个具有相同名称和相同签名的方法?

  • 我有以下的方法,这是添加产品使用注入的服务!它是在静态调用内部调用的,因此它是静态的! 它工作良好,但我需要使它通用,以便我可以使用不同的服务与它。像这样的东西! 然而,第二个方法抱怨AddProduct方法不明确,不确定如何确保它从相关服务调用了正确的方法!