【问题标题】:Problems using generics and type inference in Java在 Java 中使用泛型和类型推断的问题
【发布时间】:2013-11-23 14:01:43
【问题描述】:

在此期间,我正在做一个需要某种抽象的项目,但我不知道如何解决与 java 泛型和类型推断相关的一些问题。

这是源代码的简化架构:

public abstract class BaseDataset
{
    // Some data
    // Some methods
}

public class DerivedDataset1 extends BaseDataset
{
    // Some data
    // Implementations of some BaseDataset methods
    // Some additional methods
}

public class DerivedDataset2 extends BaseDataset
{
    // Some data
    // Implementations of some BaseDataset methods
    // Some additional methods
}

public interface BaseMeasure<T extends BaseDataset>
{
    public float evaluate(T dataset);
}

public class DerivedMeasure1 implements BaseMeasure<DerivedDataset1>
{
    @Override
    public float evaluate(DerivedDataset1 dataset)
    {
        // evaluate some measure using DerivedDataset1 methods
        return the evaluated measure;
    }
}

public class DerivedMeasure2 implements BaseMeasure<DerivedDataset2>
{
    @Override
    public float evaluate(DerivedDataset1 dataset)
    {
        // evaluate some measure using DerivedDataset2 methods
        return the evaluated measure;
    }
}

public class SocialNetworkBuilder
{
    public <T extends BaseDataset> void build(T dataset, BaseMeasure<T> measure)
    {
        float weight = measure.evaluate(dataset);

        // ...
    }
}

我的问题是,如果在我的主课中,我会这样写:

public class Application
{
    public static void main(String [] args)
    {
        BaseDataset dataset = new DerivedDataset1();
        BaseMeasure<? extends BaseDataset> measure = new DerivedMeasure1();
        SocialNetworkBuilder socialNetworkBuilder = new SocialNetworkBuilder();
        socialNetworkBuilder.build(dataset, measure);
    }
}

Eclipse 给我错误:“SocialNetworkBuilder 类型中的方法 build(T, BaseMeasure) 不适用于参数 (BaseDataset, BaseMeasure)”

我认为问题在于“构建”方法必须确保数据集和度量属于同一类型 T。

如果我这样做:

public class Application
{
    public static void main(String [] args)
    {
        BaseDataset dataset = new DerivedDataset1();
        BaseMeasure<? extends BaseDataset> measure = new DerivedMeasure1();
        SocialNetworkBuilder socialNetworkBuilder = new SocialNetworkBuilder();
        socialNetworkBuilder.build((DerivedDataset1) dataset, (DerivedMeasure1) measure);
    }
}

它有效,但我无法以这种方式解决我的问题,因为我在编译时不知道我的“数据集”和“测量”实例的派生类型; “dataset”和“measure”应该根据运行时给出的一些参数进行实例化。

我需要在运行时实例化我的“测量”和“数据集”变量,并且仍然能够在它们上调用“构建”方法。

你有解决这个问题的想法吗?

谢谢。

【问题讨论】:

    标签: java generics types inference


    【解决方案1】:

    您的应用程序将在您进行如下更改时编译:

    public class Application
    {
        public static void main(String [] args)
        {
            DerivedDataset1 dataset = new DerivedDataset1();
            BaseMeasure<DerivedDataset1> measure = new DerivedMeasure1();
            SocialNetworkBuilder socialNetworkBuilder = new SocialNetworkBuilder();
            socialNetworkBuilder.build(dataset, measure);
        }
    }
    

    【讨论】:

    • 感谢您的回答。我知道如果我以这种方式更改我的应用程序将编译它,但我需要根据用户参数使用一些特定类来实例化数据集并测量基类......
    • 泛型在编译时进行评估。如果您使用基本类型而不是实际类型,编译器无法知道两者是“兼容的”。所以我认为你应该在这里尝试不使用泛型。想想使用泛型有什么好处!
    • 我能看到泛型的唯一好处是具体的派生措施可以确保他们得到正确的派生数据集。这对他们来说重要吗?
    • 所以我想你可能建议不要在我的 BaseMeasure 类中使用泛型,而是使用 BaseDataset 作为 BaseMeasure 类及其派生类的“评估”方法的参数,对吧?然后,我应该根据上下文将“评估”方法的 BaseDataset 参数转换为 DerivedDataset1 或 DerivedDataset2 ...
    • 是的,我的项目中泛型的唯一好处就是您所描述的那个。好的,我会尝试在没有泛型的情况下重写它。谢谢你的回答:)
    【解决方案2】:

    我认为您的代码没有问题。原则上应该是正确的,但是类型推断功能不够强大,无法处理BaseMeasure&lt;DerivedDataset1&gt;DerivedDataset1 extends BaseDataset之间的传递类型依赖。

    例如,在 Scala 中,您的原始代码可以正常工作。

    object DataSet  extends App {
    
        abstract class BaseDataset  
    
        class DerivedDataset1 extends BaseDataset   
    
        class DerivedDataset2 extends BaseDataset   
    
        trait BaseMeasure[T <: BaseDataset] {
            def evaluate(dataset:T):Float
        }
    
        class DerivedMeasure1 extends BaseMeasure[DerivedDataset1] {
            override def evaluate(dataset: DerivedDataset1) = 0
        }
    
        class DerivedMeasure2 extends BaseMeasure[DerivedDataset2]  {
            override def evaluate(dataset: DerivedDataset2) = 1
        }
    
        class SocialNetworkBuilder {
            def  build[T <: BaseDataset](dataset: T, measure:BaseMeasure[T] ) : Unit = {
                val weight = measure.evaluate(dataset);
                println(weight)
            }
        }
    
        val dataset1 = new DerivedDataset1()
        val measure1 = new DerivedMeasure1()
        val dataset2 = new DerivedDataset2()
        val measure2 = new DerivedMeasure2()
        val socialNetworkBuilder = new SocialNetworkBuilder()
        socialNetworkBuilder.build(dataset1, measure1)
        socialNetworkBuilder.build(dataset2, measure2)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多