简体   繁体   English

如何访问另一个类的枚举类型? 有没有一种方法可以将字符串(映射键)用作期望枚举的方法的参数 <?> 类型?

[英]How to access enum type of another class? Is there a way to use a String (a map key) as an argument of a method expecting Enum<?> type?

I'd be extremely grateful if anyone could point out what I'm doing wrong. 如果有人能指出我做错了的事,我将不胜感激。

I have an interface IDoubleSource, which I implement in a Person class. 我有一个接口IDoubleSource,该接口在Person类中实现。 There is a LinearRegression class with a method that takes an IDoubleSource argument, but I will pass in the Person class. 有一个带有方法的LinearRegression类,该方法带有IDoubleSource参数,但我将传入Person类。

As part of the IDoubleSource interface, an enum called Variables and a method called getDoubleValue(Enum) must be defined. 作为IDoubleSource接口的一部分,必须定义一个名为Variables的枚举和一个名为getDoubleValue(Enum)的方法。 Below, I show how I have done this in Person, and that the enum types are used to specify switch cases in the getDoubleValue() method. 下面,我展示了如何在Person中完成此操作,以及枚举类型用于在getDoubleValue()方法中指定切换用例。

The problems: 问题:

1) In LinearRegression, there is a method computeScore((MultiKeyCoefficient)Map, IDoubleSource), where the last argument is an interface. 1)在LinearRegression中,有一个方法computeScore((MultiKeyCoefficient)Map,IDoubleSource),其中最后一个参数是接口。 I cannot seem to access the Variables enum of the instance of the implementation of IDoubleSource within the computeScore method, despite having the interface imported into the LinearRegression class. 尽管我已经将接口导入到LinearRegression类中,但是我似乎无法在computeScore方法中访问IDoubleSource实现实例的Variables枚举。 It just doesn't register that an IDoubleSource has an enum called Variables (though I can call the getDoubleValue() method fine). 它只是没有注册IDoubleSource有一个名为Variables的枚举(尽管我可以很好地调用getDoubleValue()方法)。 Is there anything I'm obviously doing wrong, that prevents me accessing the enum Variables? 我显然在做错什么,阻止我访问枚举变量吗?

2) The getDoubleValue(Enum) method in Person class is designed to return a double value that depends on the value of the enum Variable passed to it. 2)Person类中的getDoubleValue(Enum)方法旨在返回一个双精度值,该值取决于传递给它的枚举变量的值。 By looping through the keys (which are of String type) of a (MultiKeyCoefficient)Map in the LinearRegression class, I would like to use the keys to specify the enum values that I want as an argument to getDoubleValue(Enum) in the LinearRegression class (I would like getDoubleValue() to return several different values based on the Enum values it receives in the loop). 通过遍历LinearRegression类中(MultiKeyCoefficient)Map的键(字符串类型),我想使用这些键来指定我想要的枚举值作为LinearRegression类中的getDoubleValue(Enum)的参数(我希望getDoubleValue()根据在循环中收到的Enum值返回几个不同的值)。 However, I cannot use the (String) key in place of the expected enum as I get a ClassCastException java.lang.String cannot be cast to java.lang.Enum. 但是,我无法使用(String)键代替期望的枚举,因为我收到ClassCastException java.lang.String无法转换为java.lang.Enum。 How can I use the keys of the map to specify the Enums? 如何使用地图的键指定枚举?

I'm not very familiar with using Enum types in Java, which may be a large part of my problem. 我对在Java中使用Enum类型不太熟悉,这可能是我遇到的大部分问题。

Now the code details: 现在,代码详细信息:

I implement the following interface: 我实现以下接口:

IDOUBLESOURCE INTERFACE 空闲资源接口

public interface IDoubleSource {

    public enum Variables {
    Default;
}

/**
 * Return the double value corresponding to the given variableID
 * @param variableID A unique identifier for a variable.
 * @return The current double value of the required variable.
 */
public double getDoubleValue(Enum<?> variableID);

}

by creating the class: 通过创建类:

PERSON CLASS 人事课

public class Person implements IDoubleSource {

    public enum Variables {

            nChildren,
            durationInCouple,       
            ageDiff;
        }

public Person() {
...
}


public double getDoubleValue(Enum<?> variableID) {

    switch ((Variables) variableID) {
    case nChildren:
        return getNChildren();

    case durationInCouple:
        return (double)getDurationInCouple();
    case ageDiff:
        return getAgeDiff();            
    default:
        throw new IllegalArgumentException("Unsupported variable");
    }

In another package, I have a Class: 在另一个包中,我有一个类:

LINEARREGRESSION CLASS 线性回归类

public class LinearRegression
    private MultiKeyCoefficientMap map = null;

    public LinearRegression(MultiKeyCoefficientMap map) {
        this.map = map;
    }

....

public double score(IDoubleSource iDblSrc) {
        return computeScore(map, iDblSrc);
    }   

    public static double computeScore(MultiKeyCoefficientMap coeffMap, IDoubleSource iDblSrc) {     
        try {
            final Map<String, Double> varMap = new HashMap<String, Double>(); 

for (Object multiKey : coeffMap.keySet())
            {
                final String key = (String) ((MultiKey) multiKey).getKey(0);

                Enum<?> keyEnum = (Enum<?>) key;   //Throws class cast exception
                double value = iDblSrc.getDoubleValue(keyEnum);
                varMap.put(key, value);

            }
            return computeScore(coeffMap, varMap);  
        } catch (IllegalArgumentException e) {
            System.err.println(e.getMessage());
            return 0;
    }


    }
 }

public static double computeScore(MultiKeyCoefficientMap amap, Map<String, Double> values)
{
    //Do some stuff  
}

I'm very grateful that you've taken the time to read through this code. 非常感谢您花时间阅读此代码。 Please do let me know if you have any idea what I'm doing wrong! 如果您知道我在做什么错,请告诉我!

Many Thanks and Best Wishes, 非常感谢和最良好的祝愿,

R [R

The key incorrect assumption you have is that the IDoubleSource.Variables enum is connected in some way to the Person.Variables enum. 关键的错误假设是IDoubleSource.Variables枚举以某种方式连接到Person.Variables枚举。 They're totally unrelated. 它们是完全无关的。 (They just happen to have the same simple name.) (它们恰好具有相同的简单名称。)

When a class (like Person ) implements an interface (like IDoubleSource ), that class is declaring that it will provide implementations of the (non- default ) methods in that interface. 当类(如Person )实现接口(如IDoubleSource )时,该类声明将在该接口中提供(非default )方法的实现。 Any inner classes, inner enums, or inner interfaces within the implemented interface are only relevant if they appear in the signatures of one of the interface methods that must be implemented. 已实现的接口内的任何内部类,内部枚举或内部接口出现在必须实现的一种接口方法的签名中时,它们才有意义。

So you could change your interface to: 因此,您可以将界面更改为:

public interface IDoubleSource {
    public enum Variables {
        Default;
    }

    public double getDoubleValue(Variables variableID);
}

... but then the only legal value to pass in to any implementation of getDoubleValue is Default -- implementors of IDoubleSource can't extend the set of allowed enum values. ...但是,传递给getDoubleValue 任何实现唯一合法值是Default - IDoubleSource实现者无法扩展允许的枚举值集。

I think what you really want to do is to declare that implementors of IDoubleSource must declare what type of enum they deal in: 我认为您真正想做的是声明IDoubleSource实现者必须声明他们处理的枚举类型:

public interface IDoubleSource<T extends Variables & Enum<T>> {
    public interface Variables { }

    public double getDoubleValue(T variableID);
}

What you're saying here is that an implementor of the getDoubleValue() method must use some enum type as its arg, and that type must also implement the Variables interface. 您在这里所说的是getDoubleValue()方法的实现者必须使用某种枚举类型作为其arg,并且该类型还必须实现Variables接口。 (If there are no meaningful methods to put in that inner inteface, you can drop it for simplicity.) (如果没有任何有意义的方法可以放入该内部接口,则可以将其删除以简化操作。)

Then your implementation would look like this: 然后,您的实现将如下所示:

public class Person implements IDoubleSource<PersonVariables> {
    public enum PersonVariables implements Variables {
            nChildren,
            durationInCouple,       
            ageDiff;
    }

    public double getDoubleValue(PersonVariables variableID) {
        switch (variableID) { //no cast necessary here!
        case nChildren:
            // ...
        default:
            // this is now really impossible
            // if the rest of your program has no unsafe casts
            throw new IllegalArgumentException("Unsupported variable");
        }
    }
}

The last trick, then, is to enhance the signature of your computeScore method to ensure that the iDblSrc argument uses the same enum type as those found in the map: 然后,最后一个技巧是增强您的computeScore方法的签名,以确保iDblSrc参数使用在地图中找到的枚举类型相同的枚举类型:

public static <T extends IDoubleSource.Variable & Enum<T>>
double computeScore(MultiKeyCoefficientMap<T,?> coeffMap,
                    IDoubleSource<T> iDblSrc);

Then the keys in the map won't be String s at all, but rather instances of the right enum type. 然后,映射中的键根本就不是String ,而是正确的枚举类型的实例。

There are multiple problems here: 这里有多个问题:

  1. An enum declared in an interface (or class) implemented (extended) by another class is NOT overridden by the implementing class. 在由另一个类实现(扩展)的接口(或类)中声明的枚举不会被实现类覆盖。 So what you have above is two completely different enums, which happen to have the same local name. 因此,您上面有两个完全不同的枚举,它们碰巧具有相同的本地名称。 But one is IDoubleSource.Variables, with one value: IDoubleSource.Variables.Default, and the other is Person.Variables, with three values, one of which is Person.Variables.nChildren 但是一个是IDoubleSource.Variables,具有一个值:IDoubleSource.Variables.Default,另一个是Person.Variables,具有三个值,其中一个是Person.Variables.nChildren
  2. As the OP pointed out, you cannot simply cast a String (which presumably has a value matching the name of some enum) to an enum, and have it resolve to the expected enum value. 正如OP所指出的,您不能简单地将String(其值可能与某些枚举的名称匹配)转换为枚举,并使其解析为预期的枚举值。

Given these two things, and that it seems you want to select different processing for subtype specific types of things, then at worst, you could pass the string key as an argument, and then vary the logic internally. 有了这两件事,似乎您要为特定于子类型的事物选择不同的处理,那么在最坏的情况下,您可以将字符串键作为参数传递,然后在内部改变逻辑。 But really, you have come up with a scheme where you need to have knowledge of the subtype in order to request appropriate (supported) processing. 但实际上,您提出了一个方案,在该方案中,您需要了解子类型才能请求适当的(受支持的)处理。 This does not allow for the type of decoupling that is intended when using an interface/implementing class(es). 这不允许使用接口/实现类时打算进行的解耦。 You may want to review the objectives here and work out a better design. 您可能需要在此处查看目标并制定出更好的设计。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 无法访问Enum <?>。valueOf(String)方法的泛型类型(或如何获取.class的泛型参数)? - Can't access Enum<?>.valueOf(String) method for generic type (or how to get .class of generic argument)? 如何使用 Mapstruct 将 Enum 属性映射到另一种类型的 Enum - Java - How to map Enum attribute into an Enum of another type with Mapstruct - Java 当枚举类型引用是一个类时,如何将String转换为枚举值 <?> ? - How to convert String to enum value when enum type reference is a Class<?>? 休眠如何在Map中映射Enum键和值 <enum,enum> 作为一个字符串 - Hibernate how to map Enum key and value in Map<enum,enum> as a String 如何创建到枚举类型的映射? - How to create a map to an enum type? 方法 valueOf(Class<t> , String) 类型的 Enum 不适用于 arguments (Class <enum<t> &gt;,字符串) </enum<t></t> - The method valueOf(Class<T>, String) in the type Enum is not applicable for the arguments (Class<Enum<T>>, String) 如何将解析的字符串转换为枚举类型作为 java 中的参数 - How to convert parsed string into enum type as an argument in java 如何访问另一个 class 中的枚举? - How to access the enum in another class? 如何使用字符串作为获取枚举的方法的参数? - How can I use a string as argument for a method that takes an enum? 字符串和枚举类型变量的复合主键 - Composite primary key for a String and an enum type variable
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM