Массив указателей на функции в Java

Я прочитал этот вопрос, и я до сих пор не уверен, можно ли указывать указатели на методы в массиве на Java, если кто-нибудь знает, возможно или нет, это будет реальной помощью. Я пытаюсь найти изящное решение для хранения списка строк и связанных функций без написания беспорядка сотен "if".

Приветствия

Ответ 1

Java не имеет указателя на функцию (или "делегат" на языке С#). Такие вещи, как правило, выполняются с анонимными подклассами.

public interface Worker {
  void work();
}

class A {
  void foo() { System.out.println("A"); }
}

class B {
  void bar() { System.out.println("B"); }
}

A a = new A();
B b = new B();

Worker[] workers = new Worker[] {
  new Worker() { public void work() { a.foo(); } },
  new Worker() { public void work() { b.bar(); } }
};

for (Worker worker : workers) {
  worker.work();
}

Ответ 2

Вы можете добиться того же результата с помощью шаблона-функтора. Например, имея абстрактный класс:

abstract class Functor
{
  public abstract void execute();
}

Ваши "функции" были бы фактически методом execute в производных классах. Затем вы создаете массив функторов и заполняете его apropriated производными классами:

class DoSomething extends Functor
{
  public void execute()
  {
    System.out.println("blah blah blah");
  }
}

Functor [] myArray = new Functor[10];
myArray[5] = new DoSomething();

И затем вы можете вызвать:

myArray[5].execute();

Ответ 3

Возможно, вы можете использовать массив Method. Возьмите их с помощью API Reflection (отредактируйте: они не являются функциями, поскольку они не являются автономными и должны быть связаны с экземпляром класса, но они выполняют эту работу - просто не ожидайте чего-то вроде закрытия)

Ответ 4

В Java нет указателей (только ссылки), и у нее нет функций (только методов), поэтому вдвойне невозможно для нее иметь указатели на функции. Что вы можете сделать, так это определить интерфейс с помощью одного метода в нем, предложить своим классам, предлагающим такой метод, объявить, что они реализуют упомянутый интерфейс, и создать вектор со ссылками на такой интерфейс, который будет заполнен ссылками на конкретные объекты на который вы хотите назвать этим методом. Единственное ограничение, конечно, состоит в том, что все методы должны иметь одну и ту же подпись (количество и тип аргументов и возвращаемые значения).

В противном случае вы можете использовать отражение/интроспекцию (например, класс Method), но это обычно не самый простой и естественный подход.

Ответ 5

Я нашел подход к размышлению самым чистым - я добавил поворот к этому решению, поскольку у большинства производственных классов есть вложенные классы, и я не видел примеров, демонстрирующих это (но я тоже не искал очень долго). Моя причина для использования рефлексии заключается в том, что мой метод "updateUser()" ниже имел кучу избыточного кода и только одну строку, которая изменилась (для каждого поля в пользовательском объекте) посередине, которая обновила объект пользователя:

NameDTO.java

public class NameDTO {

    String first, last;

    public String getFirst() {
        return first;
    }

    public void setFirst(String first) {
        this.first = first;
    }

    public String getLast() {
        return last;
    }

    public void setLast(String last) {
        this.last = last;
    }   
}

UserDTO.java

public class UserDTO {

    private NameDTO name;
    private Boolean honest;

    public UserDTO() {
        name = new NameDTO();
        honest = new Boolean(false);
    }

    public NameDTO getName() {
        return name;
    }

    public void setName(NameDTO name) {
        this.name = name;
    }

    public Boolean getHonest() {
        return honest;
    }

    public void setHonest(Boolean honest) {
        this.honest = honest;
    }
}

Example.java

import java.lang.reflect.Method;

public class Example {

    public Example ()  {
        UserDTO dto = new UserDTO();

        try {
            Method m1 = dto.getClass().getMethod("getName", null);
            NameDTO nameDTO = (NameDTO) m1.invoke(dto, null);

            Method m2 = nameDTO.getClass().getMethod("setFirst", String.class);
            updateUser(m2, nameDTO, "Abe");

            m2 = nameDTO.getClass().getMethod("setLast", String.class);
            updateUser(m2, nameDTO, "Lincoln");

            m1 = dto.getClass().getMethod("setHonest", Boolean.class);
            updateUser(m1, dto, Boolean.TRUE);
            System.out.println (dto.getName().getFirst() + " " + dto.getName().getLast() + ": honest=" + dto.getHonest().toString());

        } catch (Exception e) {
            e.printStackTrace();
        } 
    }

    public  void updateUser(Method m,  Object o, Object v) {
        //  lots of code here
        try {
            m.invoke(o, v);
        } catch (Exception e) {
            e.printStackTrace();
        } 
        // lots of code here -- including a retry loop to make sure the
        // record hadn't been written since my last read
    }

    public static void main(String[] args) {
        Example mp = new Example();
    }
}

Ответ 6

Вы правы, что в java нет указателей, поскольку ссылочные переменные такие же, как и синтаксис в C/С++, содержащий ссылку на объект, но нет *, поскольку JVM может перераспределять кучу, когда это необходимо, заставляя указатель быть потерянным с адреса, который может привести к сбою. Но метод - это просто функция внутри объекта класса и не более того, поэтому вы ошибаетесь, говоря, что функций нет, потому что метод - это просто функция, инкапсулированная внутри объекта. Что касается указателей функций, команда java поддерживает использование интерфейсов и вложенных классов, которые все отлично и денди, но будучи программистом на С++/С#, который время от времени использует java, я использую класс Delegate, который я создал для java, потому что я нахожу это более удобно, когда мне нужно передать функцию, только чтобы объявить возвращаемый тип делегата метода. Все зависит от программиста. Я читал белые страницы о том, почему делегаты не поддерживают, но я не согласен и предпочитаю думать нестандартно по этой теме.