【问题标题】:Java extend Generic Type ParameterJava 扩展通用类型参数
【发布时间】:2015-01-15 23:13:53
【问题描述】:

我来自 C++,我正在尝试继承 Java 中的通用参数类型。基本上,我正在尝试模拟以下 C++ 模式:

在 C++ 中,我可以做到:

#include <iostream>

class Node
{
        Node* next;
};


class BaseVisitor
{
    public:
        BaseVisitor(Node* ptr)
        {
            std::cout<<ptr<<"\n\n";
            delete ptr;
        }
        ~BaseVisitor() {};

    protected:
        virtual Node* Generate() = 0;
};


class DynamicVisitor : public BaseVisitor
{
    public:
        DynamicVisitor(Node* ptr) : BaseVisitor(ptr) {}

    protected:
        virtual Node* Generate()
        {
            std::cout<<"Dynamic Visitor\n";
            return new Node();
        }
};

class StaticVisitor : public BaseVisitor
{
    public:
        StaticVisitor(Node* ptr) : BaseVisitor(ptr) {}

    protected:
        virtual Node* Generate()
        {
            std::cout<<"Static Visitor\n";
            return NULL;
        }
};



template<typename T>
class TestVisitor : public T  //THIS is where the magic happens..
{
    public:
        TestVisitor() : T(this->Generate()) {} //allows me to call "Generate".
};

int main()
{
    TestVisitor<DynamicVisitor> foo = TestVisitor<DynamicVisitor>();
    TestVisitor<StaticVisitor> bar = TestVisitor<StaticVisitor>();
}

输出:

Dynamic Visitor
0x605ed0

Static Visitor
NULL

如何在 Java 中做同样的事情?我试过了:

public class Node {
    Node next;
}

public abstract class BaseVisitor {
    public BaseVisitor(Node n) {System.out.println(n);}

    protected abstract Node generate();
}

public class DynamicVisitor extends BaseVisitor {
    public DynamicVisitor(Node n) {
        super(n);
    }

    @Override
    protected Node generate() {
        return new Node();
    }
}

public class StaticVisitor extends BaseVisitor {

    public StaticVisitor(Node n) {
        super(n);
    }

    @Override
    protected Node generate() {
        return null;
    }
}

public class TestVisitor<T extends BaseVisitor> extends T { //error.. Cannot extend "T".. No magic happens..
    public TestVisitor() {
        super(this.generate()); //cannot call generate()..
    }
}
  1. 这种模式叫什么?我称它为“基础工厂”模式,但我不确定它的真实名称,所以我不确定要搜索什么..

  2. 如何在 Java 中执行与 C++ 中相同的操作?有没有“任何方式”在 Java 中做同样的模式?

【问题讨论】:

  • 这就是 C++ zings 而 java zangs 的地方。在 C++ 中,模板基本上是花哨的预处理器宏,会导致生成不同的运行时对象。在 java 中,在运行时只有一个模板化类的版本(其类型参数被删除)。这禁止您执行上述操作。但是,您可以使用匿名类或 java 8 lambda 提出解决方案。

标签: java c++ templates generics


【解决方案1】:

不,不能在 java 中执行此操作,抱歉。最接近的可能是“委托模式”:

public interface NodeGenerator {  Node generate(); }
public class StaticGenerator implements NodeGenerator { 
    public Node generate() { return null; }
}
public class DynamicGenerator implements NodeGenerator {
    public Node generate() { return new Node(); }
}

public class TestVisitor extends BaseVisitor {
     public TestVisitor(NodeGenerator g) { super(g.generate()); }
}

在 java 8 中,您可以使它看起来更好(但可能效率更低),而无需额外的接口和类:

public class TestVisitor extends BaseVisitor {
    public TestVisitor(Supplier<Node> g) { super(g.get()); }
}

// ... and then you can do things like

TestVisitor staticVisitor = new TestVisitor(() -> null);
TestVisitor dynamicVisitor = new TestVisitor(() -> new Node());

【讨论】:

  • 您为什么认为它可能效率较低
  • 好吧,我说“可能”,因为我不确定这是如何实现的。我想到的是这样的:NodeGenerator ng = new StaticNodeGenerator(); for(int i = 0; i &lt; 10000; i++) { new TestVisitor(ng); }for(int i = 0; i &lt; 10000; i++) { new TestVisitor(() -&gt; null); }。在我看来,后一种方法会多分配 10000 个对象(这是可以避免的),并且可能会生成 10000 个额外的匿名类(这是不可避免的)。
  • 您可以将第一个示例替换为匿名类,并获得几乎与 java 8 版本一样简洁的代码!
  • @GiovanniBotta 每次调用约 50 个额外字符(3 行)... :-/
  • lambda 版本不捕获任何东西,因此不需要分配额外的对象。这些供应商调用将作为 JVM 的方法调用执行。
猜你喜欢
  • 1970-01-01
  • 2012-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多