不能使用在方法级别声明的泛型类型,该方法参数需要在其他地方声明的泛型类型 [英] Can't use generic type declared at method level for method argument that requires a generic type that's declared somewhere else

查看:103
本文介绍了不能使用在方法级别声明的泛型类型,该方法参数需要在其他地方声明的泛型类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的最终目标是有一个 StateTransitionTable ,客户可以创建一个条目,它包含一个 mainState 并声明它可以从该主状态跳转(存储在 ArrayList 中)。这个应用程序 Script 运行在一个循环上,并且转换表应该有些自我运行。



请不要使用enums来推荐我;它们不能很好地扩展

每个州都应该可以访问 Script TransitionTable 实例。该脚本将执行它的职责,并且该表将使用索引转换到下一个状态。索引取决于转换添加到条目的顺序。创建的第一个条目是使用的第一个条目。



在应用程序的循环中,应该访问存储在当前条目中的状态,并且 process 应该从中调用。 脚本调用< T扩展脚本>进程(T),传入当前脚本实例:

  //这个方法被重复调用
public void loop(){
table.process(this);
}

该方法获取 mainState currentEntry 中调用,并调用过程(T,TransitionTable)方法,传入 Script 实例和当前表实例。从状态的过程方法中,我应该可以使用脚本参数访问有关脚本的信息,并使用该表进行转换。看起来我已经有了一切,除了1条语句给我一个错误。

  public interface State< T extends Script> ; {
void process(T脚本,TransitionTable表);

TransitionTable:

  public class TransitionTable {
private Map< State<?> ;, StateNode> entries = new HashMap<>();
private StateNode currentNode,startNode;

public< T扩展脚本> void process(T脚本){
currentNode.mainState.process(script,this); //编译时错误在这里
}

public StateNode createEntry(State <?> state){
StateNode node = new StateNode(state);
map.put(state,node);

if(startNode == null)
startNode = currentNode = node;

返回节点;
}

public void transitionTo(int index){
State<?> nextState = currentNode.states.get(index);
if(nextState == null)
nextNode = startNode.mainState;

currentNode = entries.get(nextNode);
}

public static final class StateNode {
private ArrayList< State<>> states = new ArrayList<>;
私人国家<?> mainState;

public StateNode(State <?> state){
mainState = state;
}

public StateNode addTransition(State <?> state){
states.add(state);
返回此;



code
$ b

对于记录,通用 process 的类型声明是一种便宜的黑客,它允许使用实际的脚本类型。虽然可以输入不同的类型,但它将始终是相同的类型。

我得到的错误是:


方法过程捕获#4-of,StateTransitionTable)在类型State中不适用于参数(T,StateTransitionTable)

我理解推理背后:有一个机会,客户端将为方法的类型参数指定一个子类型,该类型参数不同于 State 的类型参数。我不明白的是我应该如何对付这样的情况。



我知道有这样的设计问题的标签,但我不知道不记得它的名字。如果有人可以补充说,这将不胜感激。如果您觉得我遗漏了任何相关信息,请告诉我们。

界面状态< T扩展脚本> {

}

我们不能确定<$ c $直到 State 的子类被实例化,c> T 才会成为。我们知道它将是 Script 的子类型,但我们无法确定是哪一个。



由于我们不要在 TransitionTable 中实例化任何状态,我们不知道正在使用哪个 Script 子类型状态被传递给 TransitionTable 。由于我们不确定哪个子类型用于状态,因此我们不能确定< T扩展脚本> 是否是正确的子类型。



为了解决这个问题,我做了 TransitionTable 接受一个泛型类型参数;国家的类型。我将 StateNode 从静态嵌套类更改为常规嵌套类,因此它继承了泛型类型:

  public class TransitionTable< T extends Script<>> {
私人地图< T,StateNode> entries = new HashMap<>()
private StateNode current,start;

public T getCurrentState(){
return current.state;
}

public StateNode createNode(T state){
StateNode entry = new StateNode(state);
entries.put(state,entry);

if(startNode == null){
startNode = currentNode = entry;
}
返回条目;
}

public class StateNode {
private ArrayList< T> nodes = new ArrayList<>();
私人T状态;

private StateNode(T state){
this.state = state;


public StateNode addTransition(T state){
nodes.add(state);
返回此;



code
$ b

然后将处理过程提升到在那里我声明所有类型:

 状态< DemoScript> start = new StartState(); 
State< DemoScript> walkToA = new WalkToAState();
State< DemoScript> walkToB = new WalkToBState();
State< DemoScript> dance = new DanceState();

TransitionTable<状态< DemoScript>> table = new TransitionTable();
table.createNode(start).addTransition(walkToA).addTransition(walkToB);
table.createNode(dance).addTransition(walkToA).addTransition(walkToB);
table.createNode(walkToA).addTransition(dance);
table.createNode(walkToB).addTransition(dance);

public void loop(){
table.getCurrentState()。process(this,table);
}

不要对它的详细程度发表评论;我将在未来改善这一点。

My ultimate goal is to have a StateTransitionTable, where the client can create an entry which consists of a mainState and states it can jump to from that main state (stored in an ArrayList). This application, Script, runs on a loop, and the transition table should be somewhat self-operating.

Please do not recommend me using enums for this; they do not scale well

Each state should have access to both the Script and the TransitionTable instances. The script is to carry-out it's duty, and the table is to transition to the next state, using an index. The indexes depend on the order the transitions were added to the entry. The first entry created is the first entry used.

In the application's loop, the state stored in the current entry should be accessed, and process should be called from it. Script calls <T extends Script> process(T), passing in the current script instance:

//this method is called repeatedly
public void loop() {
    table.process(this);
}

That method grabs the mainState from the currentEntry and invokes the process(T, TransitionTable) method, passing in the Script instance and the current table instance. From within the state's process method, I should be able to access information about the script using the script parameter, and make my transitions using the table. It seems I have everything in order, except for 1 statement that is giving me an error.

public interface State<T extends Script> {
    void process(T script, TransitionTable table);
}

TransitionTable:

public class TransitionTable {
    private Map<State<?>, StateNode> entries = new HashMap<>();
    private StateNode currentNode, startNode;

    public <T extends Script> void process(T script) {
        currentNode.mainState.process(script, this); //Compile-time error here
    }

    public StateNode createEntry(State<?> state) {
        StateNode node = new StateNode(state);
        map.put(state, node);

        if(startNode == null)
            startNode = currentNode = node;

        return node;
    }

    public void transitionTo(int index) {
        State<?> nextState = currentNode.states.get(index);
        if(nextState == null)
             nextNode = startNode.mainState;

        currentNode = entries.get(nextNode);
    }

    public static final class StateNode {
        private ArrayList<State<?>> states = new ArrayList<>;
        private State<?> mainState;

        public StateNode(State<?> state) {
            mainState = state;
        }

        public StateNode addTransition(State<?> state) {
            states.add(state); 
            return this;
        }
    }
}

For the record, the generic type declaration for process is a cheap hack to allow usages of the actual script's type. Although a different type can be entered, it will always be the same type. Cheap hack.

The error I get is:

The method process(capture#4-of ?, StateTransitionTable) in the type State is not applicable for the arguments (T, StateTransitionTable)

I understand the reasoning behind this: There's a chance the client will specify a subtype for the method's type parameter that differs from State's type parameter. What I don't understand is how I'm supposed to counter-act a situation like this.

I know there's a tag for design problems like this, but I don't remember it's name. If someone could add that in, it would be appreciated. If you feel I've left out any relevant info, please let me know

解决方案

interface State<T extends Script> {

}

We can't be sure what T will be until a subclass of State is instantiated. We know it will be a subtype of Script, but we can't be sure which one.

Since we don't instantiate any of the states within the TransitionTable, we don't know which Script subtype is being used for the states being passed into TransitionTable. Since we aren't sure which subtype is being used for the state, we can't be sure that <T extends Script> will be the correct subtype.

To fix this, I made TransitionTable accept a generic type argument; the type of the state. I changed StateNode from a static nested class to a regular nested class, so it inherits the generic type:

public class TransitionTable<T extends Script<?>> {
    private Map<T, StateNode> entries = new HashMap<>()
    private StateNode current, start;

    public T getCurrentState() {
        return current.state;
    }

    public StateNode createNode(T state) {
        StateNode entry = new StateNode(state);
        entries.put(state, entry);

        if (startNode == null) {
            startNode = currentNode = entry;
        }
        return entry;
    }

    public class StateNode {
        private ArrayList<T> nodes = new ArrayList<>();
        private T state;

        private StateNode(T state) {
            this.state = state;
        }

        public StateNode addTransition(T state) {
            nodes.add(state);
            return this;
        }
    }
}

Then brought the processing up to where I declare all my types:

State<DemoScript> start = new StartState();
State<DemoScript> walkToA = new WalkToAState();
State<DemoScript> walkToB = new WalkToBState();
State<DemoScript> dance = new DanceState();

TransitionTable<State<DemoScript>> table = new TransitionTable();
table.createNode(start).addTransition(walkToA).addTransition(walkToB);
table.createNode(dance).addTransition(walkToA).addTransition(walkToB);
table.createNode(walkToA).addTransition(dance);
table.createNode(walkToB).addTransition(dance);

public void loop() {
    table.getCurrentState().process(this, table);
}

Don't make comments on how verbose it is; I shall be improving that in the future

这篇关于不能使用在方法级别声明的泛型类型,该方法参数需要在其他地方声明的泛型类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆