Могу ли я передать цикл в качестве аргументов в конструктор - PullRequest
0 голосов
/ 22 сентября 2018

У меня есть список массивов, который содержит все аргументы, которые нужны конструктору.Ссылка на каждый элемент в массиве и затем предоставление аргументов по отдельности кажется большой работой.Мне интересно, могу ли я передать каждый элемент в списке массивов, просматривая его внутри скобок конструктора.

Я спрашиваю, могу ли я сделать это или что-то подобное для передачи аргументов.

constructor object =new constructor(for(String item: parts));

parts - это список массивов здесь.И все элементы в списке являются строками.

Ответы [ 4 ]

0 голосов
/ 22 сентября 2018

Звучит так, как будто вы ищете что-то, что в других языках программирования, например Groovy, называется принуждением , то есть списками на нужные типы.

Это невозможно в Java до версии 10 , но кто знает, что принесет будущее.

0 голосов
/ 22 сентября 2018

Ваш вопрос приносит больше вопросов, чем ответов: если у вас есть массив или список строк, пусть ваш конструктор возьмет этот массив / список.

Если вам нужно преобразовать содержимое этого массива / списка вбольше вашего объекта, ваш ответ Stream, вам не нужны сложные вещи, такие как рефлексия:

String[] myArray = ...;
MyType[] a = Arrays.stream(myArray).map(MyType::new).toArray(MyType[]::new);

Collection<String> coll = ...;
List<MyType> b = coll.stream().map(MyType::new).collect(Collectors.toList());

Вы, безусловно, можете сделать больше: если у вас есть конструктор с арностью 3 (пример: 3 String):

  • Сначала мы создаем поток [0, size () / arity], который является номером объекта, который вам нужно построить.Умножьте его на арность, и вы получите индекс первого элемента, который будет передан вашему конструктору.
  • Мы сопоставляем index с MyObj: safeGet позаботится о извлечении значения из списка (этобудет работать и с массивом, но вам просто нужно использовать вместо него length и [].
  • MyObj иметь конструктор, принимающий каждый ваш кортеж.Если конструктору необходимо преобразовать один из исходного объекта (String) в другой (например, целое число), то вам, вероятно, лучше использовать статический метод valueOf, выполняющий String для объекта.
  • Из Stream мы возвращаем массив, но вы можете использовать collect(toList()) для списка.

Вот первый пример:

  public static void main(final String[] args) {

    final List<String> list = Arrays.asList("A", "B", "C", "D", "E", "F");
    // fails if list.size() is not multiple of 3
    final int arity = 3;
    final MyObj[] myObj = IntStream.range(0, list.size() / arity).map(n -> arity * n)
    .mapToObj(index -> new MyObj(safeGet(list, index, 0), safeGet(list, index, 1), safeGet(list, index, 2)))
    .toArray(MyObj[]::new)
    ;

  }

  private static <T> T safeGet(final List<T> list, final int baseIndex, final int relativeIndex) {
    final int index = baseIndex + relativeIndex;
    return index < list.size() ? list.get(index) : null;
  }

  static class MyObj {
    public MyObj(final String a, final String b, final String c) {
    }
  }

Вот второй пример с конструктором, принимающим int вместо String:

  public static void main(final String[] args) {

    final List<String> list = Arrays.asList("A", "0", "C", "D", "2", "F");
    // fails if list.size() is not multiple of 3
    final int arity = 3;
    final MyObj[] myObj = IntStream.range(0, list.size() / arity).map(n -> arity * n)
        .mapToObj(index -> MyObj.valueOf(list, index))
        .toArray(MyObj[]::new)
        ;

    Arrays.stream(myObj).forEach(System.out::println);
  }

  private static <T> T safeGet(final List<T> list, final int baseIndex, final int relativeIndex) {
    final int index = baseIndex + relativeIndex;
    return index < list.size() ? list.get(index) : null;
  }

  static class MyObj {
    public MyObj(final String a, final int b, final String c) {
    }

    public static MyObj valueOf(final List<String> source, final int baseIndex) {
      final String a = safeGet(source, baseIndex, 0);
      final int b = Integer.parseInt(safeGet(source, baseIndex, 1));
      final String c = safeGet(source, baseIndex, 2);
      return new MyObj(a, b, c);

    }

  }
0 голосов
/ 22 сентября 2018

Предполагается, что ваш constructor объявлен так:

public contructor(String s1, String s2, String s3, String s4)

Ваша идея не является правильным подходом к этому.Что если parts не имеет ровно 4 элемента?Вам нужен перегруженный конструктор, который занимает весь список:

public constructor(List<String> strings)
{
    this(strings.get(0), strings.get(1), strings.get(2), strings.get(3));
}

Таким образом, вы можете вызывать конструктор во многих разных местах с разными списками, но вам нужно только «деконструировать» список в одномместо (перегруженный конструктор).Например:

constructor a = new constructor(list1);
constructor b = new constructor(parts);

constructor c1 = new constructor(Arrays.asList("1", "2", "3", "4");
// same as:
constructor c2 = new constructor("1", "2", "3", "4");

Обратите внимание, что пример работает только как минимум с 4 элементами в списке:

constructor e1 = new constructor(Arrays.asList("foo", "bar")); // will error
constructor e2 = new constructor(Collections.emptyList()); // will error
0 голосов
/ 22 сентября 2018

// Я переименовал ваш класс "Конструктор" в "MyClass", так как первый может сбивать с толку

В Java нет прямого синтаксиса для этого.Но с помощью фабрики вы можете достичь чего-то вроде:

final String[] args = {"one", "two", "three"};
final MyClass obj = newMyClass(args); // effect of new Constructor(args[0], args[1], args[2])
final MyClass obj = newMyClass(args[0], args[1], args[2]); // works too, thanks to the variadic declaration syntax

Для этого вам понадобится фабрика, либо с генерацией кода на основе процессора аннотаций, либо созданная во время инициализации приложения с помощьюsun.misc.Unsafe (кстати, так делают некоторые высокопроизводительные сериализаторы).

Пример:

package net.bobah.uf4j;

import org.junit.Test;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiConsumer;

import static java.lang.System.out;
import static net.bobah.uf4j.MyTest.MyClassFactory.newMyClass;

public class MyTest {

    @Test
    public void runTest() throws Exception {
        final MyClass ctor = newMyClass("one", "two", "three");
        out.println(Arrays.asList(ctor.str1, ctor.str2, ctor.str3));
        // prints [one, two, three]
    }

    public static class MyClass {
        private final String str1;
        private final String str2;
        private final String str3;

        public MyClass(String str1, String str2, String str3) {
            this.str1 = str1;
            this.str2 = str2;
            this.str3 = str3;
        }

    }

    public static class MyClassFactory {
        private static Unsafe getUnsafe() {
            try {
                Field f = Unsafe.class.getDeclaredField("theUnsafe");
                f.setAccessible(true);
                return (Unsafe) f.get(null);
            } catch (IllegalAccessException | NoSuchFieldException cause) {
                throw new RuntimeException(cause);
            }
        }

        private static final Unsafe unsafe = getUnsafe();

        private static final List<BiConsumer<MyClass, String>> fieldInitializers = new ArrayList<>();

        static {
            // this can be extended to support one-to-many mappings from args to fields, or to do type transformation on the way
            for (Field field : MyClass.class.getDeclaredFields()) {
                if (String.class.equals(field.getType())) {
                    final long offset = unsafe.objectFieldOffset(field);
                    fieldInitializers.add((obj, val) -> {
                        unsafe.putObject(obj, offset, val);
                    });
                }
            }
        }

        public static MyClass newMyClass(String... args) throws InstantiationException {
            assert args.length == fieldInitializers.size();

            // create uninitialized instance
            final MyClass obj = (MyClass) unsafe.allocateInstance(MyClass.class);

            // inject final fields
            for (int i = 0; i < args.length; ++i) {
                fieldInitializers.get(i).accept(obj, args[i]);
            }

            return obj;
        }
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...