Помогите перевести с 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 шт):
В первом случае компилятор ругается из-за того, что вы пытаетесь в необобщенном статическом методе 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("Вася");
...