Массив указателей на функции в 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, потому что я нахожу это более удобно, когда мне нужно передать функцию, только чтобы объявить возвращаемый тип делегата метода.
Все зависит от программиста.
Я читал белые страницы о том, почему делегаты не поддерживают, но я не согласен и предпочитаю думать нестандартно по этой теме.