Помогите перевести с C# на Java

Всем привет! Есть вот такой класс на шарпе:

namespace Load_Testing_Tool.Generators;

/// <summary>
/// Генератор распределения
/// </summary>
/// <typeparam name="TEnum">Тип енама</typeparam>
internal class DispersionGenerator<TEnum>
where TEnum : struct, Enum
{
private const int SAMPLE_SIZE = 1_000;

private readonly TEnum[] _collection = new TEnum[SAMPLE_SIZE];
private readonly Random _rnd = new();

/// <summary>
/// Создания генератора распределения
/// </summary>
/// <param name="pairs">Набор значений и частоты их присутствия в последовательности (относительные значения)</param>
public DispersionGenerator(params (TEnum key, float proportion)[] pairs)
{
if (Math.Round(pairs.Sum(x => x.proportion)) != 100)
{
throw new InvalidDataException("Сумма пропорций элементов должна быть 100");
}

var collectionIndex = 0;
for (var pairIndex = 0 ; pairIndex < pairs.Length ; pairIndex++)
{
var count = Math.Round(_collection.Length * (pairs[pairIndex].proportion / 100));

for (var i = 0 ; i < count ; i++)
{
_collection[collectionIndex++] = pairs[pairIndex].key;
}
}
}

/// <summary>
/// Создание генератора с равным распределением
/// </summary>
/// <param name="keys">Значения для распределения</param>
public DispersionGenerator(params TEnum[] keys)
: this(GetWithProportions(keys))
{
}

/// <summary>
/// Получение очередного значения последовательности
/// </summary>
/// <returns>Значение последовательности</returns>
public TEnum GetNext()
{
var index = _rnd.Next(0, SAMPLE_SIZE);

return _collection[index];
}

private static (TEnum key, float proportion)[] GetWithProportions(TEnum[] keys)
{
var proportion = (float)100 / keys.Length;

return keys.Select(x => (key: x, proportion)).ToArray();
  }
}

Мне нужно перевести его на джаву. Онлайн-конвертер выдал вот такой вариант:

    import java.util.Random;
import java.util.stream.Stream;

public class DispersionGenerator<TEnum extends Enum<TEnum>> {
    private static final int SAMPLE_SIZE = 1000;

    private final TEnum[] collection = (TEnum[]) new Enum[SAMPLE_SIZE];
    private final Random randomGenerator = new Random();

    /**
     * Creates a distribution generator
     *
     * @param pairs a set of values and their frequencies in the sequence (relative values)
     */
    public DispersionGenerator(Pair<TEnum, Float>[] pairs) {
        if (Math.round(Stream.of(pairs).map(pair -> pair.proportion).reduce(0f, Float::sum)) != 100) {
            throw new IllegalArgumentException("The sum of the proportions must be 100");
        }

        int collectionIndex = 0;
        for (int pairIndex = 0; pairIndex < pairs.length; pairIndex++) {
            int count = Math.round(collection.length * (pairs[pairIndex].proportion / 100));

            for (int i = 0; i < count; i++) {
                collection[collectionIndex++] = pairs[pairIndex].key;
            }
        }
    }

    /**
     * Creates a generator with equal distribution
     *
     * @param keys values for distribution
     */
    public DispersionGenerator(TEnum[] keys) {
        this(getWithProportions(keys));
        // Если метод getWithProportions не статический, то появляется ошибка "Cannot reference 'DispersionGenerator.getWithProportions()' before supertype constructor has been called"
    }

    /**
     * Gets the next value in the sequence
     *
     * @return the next value in the sequence
     */
    public TEnum getNext() {
        int index = randomGenerator.nextInt(SAMPLE_SIZE);
        return collection[index];
    }

//этот метод Idea предлагает сделать не статическим   
private static Pair<TEnum, Float>[] getWithProportions(TEnum[] keys) {
        float proportion = 100f / keys.length;
        Pair<TEnum, Float>[] result = new Pair[keys.length];

        for (int i = 0; i < keys.length; i++) {
            result[i] = new Pair<>(keys[i], proportion);
        }
        return result;
    }

    public static class Pair<K, V> {
        public final K key;
        public final V proportion;

        public Pair(K key, V proportion) {
            this.key = key;
            this.proportion = proportion;
        }
    }
}

НО: Idea на этот вариант выдает ошибку и предлагает сделать метод getWithProportions не статическим. 1ая ошибка Вот только если сделать это, появляется новая ошибка, и как исправлять её уже не понятно.2ая ошибка

Подскажите, пожалуйста, как можно избавиться от обеих ошибок?


Ответы (1 шт):

Автор решения: m. vokhm

В первом случае компилятор ругается из-за того, что вы пытаетесь в необобщенном статическом методе getWithProportions() использовать параметр типа. Но статическим методам недоступен экземпляр, они могут работать без создания экземпляра, а параметр типа конкретизируется только при создании экземпляра. Например, в выражении List<String> list = new ArrayList<>() создается экземпляр ArrayList, работающий с конкретным типом String. Таким образом, параметры типа в обычных статических методах использовать нельзя (подробнее см. документацию)

Исправляется эта ситация очень просто. Нужно сам метод тоже сделать обобщенным, с тем же параметром типа:

private static <TEnum> Pair<TEnum, Float>[] getWithProportions(TEnum[] keys) {
... 

Но вторая ошибка, когда мы делаем метод нестатическим, на мой взгляд, более интересна. Сообщение об ошибке гласит can not reference method before supertype constructor has been called. На самом деле это не совсем точная диагностика. Суть проблемы в том, что вы пытаетесь вызвать метод экземпляра до того, как этот экземпляр был создан -- во время работа конструктора он еще только в процессе создания. В каких-то случаях действительно можно предварительно вызвать конструктор супертипа, но вообще важно понимать, что нестатические методы используют состояние объекта, которое во время создания объекта еще не до конца определено. Я бы в таком случае пересмотрел дизайн объекта, так, чтобы отделить создание объекта от использования его состояния. Можно, например, использовать статические фабричные методы типа вот такого:

class Person {
  ...
  public static Person withName(String name) {
    Person p = new Person();
    p.setName(name);
    return p;
  }  
  ...
} 

...
Person vasya = Person.withName("Вася"); 
...
→ Ссылка