如何使用Java泛型从字符串中检索T

如何使用Java泛型从字符串中检索T,java,generics,Java,Generics,我试图将Java泛型用于我的特定用例。有一个泛型类Node,在本例中会有很多实现类,比如NodeBoolean public abstract class Node<T> { T defaultValue; public Node(T defaultValue) { this.defaultValue = defaultValue; } protected abstract T par

我试图将Java泛型用于我的特定用例。有一个泛型类
Node
,在本例中会有很多实现类,比如
NodeBoolean

public abstract class Node<T>
    {
        T defaultValue;

        public Node(T defaultValue) {
            this.defaultValue = defaultValue;
        }

        protected abstract T parse(String input) ;
        public T getValue()
        {
            try
            {
                // here will be some logic to get String value from some db or any other source
                String input = "true";
                return parse(input);
            } catch (Exception e) {
                return defaultValue;
            }
        }
    }
我在这种方法中面临的问题

  • 假设类
    节点
    的构造函数有多个变体,那么所有实现类也需要为可见性定义它们。这个问题可以用Builder模式解决,但我只是想知道其他可能的解决方案

  • 将有很多实现类只有一个重写方法
    parse
    。我正在寻找一种基于
    defaultValue
    instanceof
    来定义所有不同解析器的方法,在泛型类
    Node
    自身的给定示例中。然后这个
    节点
    类就不是
    抽象的

  • 我想给出定义
    parse
    方法的功能,该方法采用
    String
    并根据用户需求返回
    T
    值,同时创建
    节点
    类本身的对象。通过这种方式,如果我只有一个出现的
    节点的特定对象类型,则可以创建
    ,而无需定义任何新的实现类

  • 我正在寻找一个解决上述三个问题的解决方案。如果我在任何时候都不清楚,请告诉我

  • 我认为公开构造函数,或者使用构建器或工厂模式是这里唯一的可能性。但是,下一个答案可以缓解这一问题

  • 与其将
    parse
    方法作为抽象方法,为什么不将函数传递到处理解析的节点中呢


  • 公共类节点{
    私人T值;
    私有函数解析器;
    公共节点(T默认值,
    函数分析器){
    this.defaultValue=defaultValue;
    this.parser=解析器;
    }
    公共T getValue()
    {
    //根据解析器的不同,每次调用它时重新解析可能会很昂贵!
    尝试
    {
    //下面是一些从某个db或任何其他源获取字符串值的逻辑
    字符串输入=“true”;
    返回parser.apply(输入);
    }捕获(例外e){
    返回默认值;
    }
    }
    }
    
    现在可以通过执行此操作创建节点

    Node<Boolean> node = new Node<>(s -> Boolean.parseBoolean(s))
    
    Node Node=new Node->Boolean.parseBoolean
    
    您还可以在解析器函数中设置默认值,从而无需将其存储在节点中—这取决于您的需求

  • 见第2条
  • 编辑 我在这里使用了Java8的函数接口和lambdas,但在Java1.0中,通过定义自己的函数接口,也可以轻松地实现这一点

    public interface Function<I, O> {
        O apply(I);
    }
    
    公共接口功能{
    O适用第(I)款;
    }
    
    然后以某种方式实现它——具体类、匿名类,等等——正如您需要进行的解析所需

    Node<Boolean> node = new Node<>(new Function<String, Boolean>() {
        public Boolean apply(String s) {
            return Boolean.parseBoolean(s);
        }
    });
    
    Node节点=新节点(新函数(){
    公共布尔应用(字符串s){
    返回Boolean.parseBoolean;
    }
    });
    
    编辑2

    对于有关预定义类型的评论,您可以采取几种不同的方法

    public class NodeFactory {
        private static final Function <String, Boolean> BOOLEAN_PARSER = s -> Boolean.parseBoolean(s);
        .// plus more for integers, double, etc, as required
    
        private NodeFactory() {
            // no-op
        } 
    
        public static Node<Boolean> booleanNode(boolean defaultValue){
            return new Node<Boolean>(defaultValue,
                                     BOOLEAN_PARSER);
        }
    
        // plus more for integer, double, etc, as required
    }
    
    公共类节点属性{
    私有静态最终函数BOOLEAN\u PARSER=s->BOOLEAN.parseBoolean(s);
    .//根据需要为整数、双精度等加上更多
    私有NodeFactory(){
    //无操作
    } 
    公共静态节点booleanNode(布尔默认值){
    返回新节点(默认值,
    布尔逻辑分析器);
    }
    //根据需要为整数、双精度等加上更多
    }
    
    或者你可以走延长线

    public class BooleanNode extends Node<Boolean> {
        public BooleanNode(boolean defaultValue) {
            super(defaultValue,
                  s -> Boolean.parseBoolean(s)); // or use a static parser as in the factory example
        }
    }
    
    公共类BooleanNode扩展节点{
    公共布尔节点(布尔默认值){
    超级(默认值,
    s->Boolean.parseBoolean(s));//或使用工厂示例中的静态解析器
    }
    }
    

    在任何情况下,保持
    节点
    非抽象性可以为您的用户提供很大的灵活性,但您的用例可能不需要这样做。

    您必须扩展
    节点
    类吗?还是仅仅创建一个匿名类?它实际上是“允许用户定义解析方法”

    在客户机中,我们将有以下内容

    Node<Boolean> booleanNode = NodeFactory.createNode(Boolean.class);
    Node<Integer> integerNode = NodeFactory.createNode(Integer.class);
    
    Node booleanNode=NodeFactory.createNode(Boolean.class);
    Node integerNode=NodeFactory.createNode(Integer.class);
    
    也许您应该补充一点,这需要Java 8?使用这种方法,您可以有如下方便的方法来创建节点:
    公共静态节点boolNode(){return new Node(Boolean::parseBoolean);}
    。(还请注意,您可以在这里使用方法引用语法。)(除了Java 1.0没有泛型或菱形,以防有人维护一个非常旧的代码库)@SteveChaloner,但我还想给用户一些常见的预定义解析器,这样他们就不必再编写它了。像
    节点node1=新节点->布尔值.parseBoolean(s))节点node2=新节点->布尔值.parseBoolean(s))
    node1
    和node2
    都使用相同的解析器定义,因此我不想重复它,并使用一些预定义的允许我强制用户使用特定类型的特定解析器。如果您选择instanceof路径,这不会影响节点的泛型类型吗?是的,我需要扩展
    节点
    类,因为所有实现类之间都应该共享很多逻辑。很抱歉,我认为这个问题措辞不恰当。我想问的是,您是否需要创建一个“完整类”(通常意味着一个专用的.java文件)或匿名类就足够了。仅供参考,创建匿名类类似于扩展抽象类,但是在另一个类中完成的。在我的建议中,所有扩展
    节点
    类的类都将在
    NodeFactory
    中声明,而不是在一个.javaf中声明
    public class NodeFactory {
        private static final Function <String, Boolean> BOOLEAN_PARSER = s -> Boolean.parseBoolean(s);
        .// plus more for integers, double, etc, as required
    
        private NodeFactory() {
            // no-op
        } 
    
        public static Node<Boolean> booleanNode(boolean defaultValue){
            return new Node<Boolean>(defaultValue,
                                     BOOLEAN_PARSER);
        }
    
        // plus more for integer, double, etc, as required
    }
    
    public class BooleanNode extends Node<Boolean> {
        public BooleanNode(boolean defaultValue) {
            super(defaultValue,
                  s -> Boolean.parseBoolean(s)); // or use a static parser as in the factory example
        }
    }
    
    Node<Boolean> booleanNode = new Node<Boolean>(true) {
        @Override
        protected Boolean parse(String input) {
            return Boolean.parseBoolean(input);
        }
    };
    
    class NodeFactory {
        public <T> static createNode(Class<T> classType) {
            if (classType == Boolean.class) {
                return newBooleanNode();
            } else if (classType == Integer.class){
                return newIntegerNode();
            }
        } 
    
        private Node<Boolean> newBooleanNode() {
            return new Node<Boolean>(true) {
                @Override
                protected Boolean parse(String input) {
                    return Boolean.parseBoolean(input);
                }
            }
        }
    
        private Node<Integer> newIntegerNode() {
            return new Node<Integer>(0) {
                @Override
                protected Boolean parse(String input) {
                    return Integer.parseInt(input);
                }
            }
        }
    }
    
    Node<Boolean> booleanNode = NodeFactory.createNode(Boolean.class);
    Node<Integer> integerNode = NodeFactory.createNode(Integer.class);