2013-08-27 2 views
2

я могу это сделать:Java - Как создать "анонимный" класс на лету

new Object(){ 
    public void hi(){} 
}.hi(); 

как I (или может я) это сделать:

IWouldRatherStayAnonymous t = new IWouldRatherStayAnonymous extends Thread(){ 
    public void NoNoYouCantCallMe(String s){} 
}; 
t.NoNoYouCantCallMe("some useful data that i will need later, but don't want to save this anonymous class"); 

и если я могу» t синтаксически это делает, может ли кто-нибудь объяснить логику/реализацию дизайна, почему это никогда не сработает?

==========================================

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

Это действительно не ОГРОМНОЕ дело, мне было просто любопытно, если бы это было выполнимо, но, похоже, из некоторых ответов это возможно, но просто не очень красиво.

+0

Удалите слова 'MyThread extends', и это будет работать. Конечно, он ничего не сделает. –

+0

Что еще более важно, ПОЧЕМУ вы не хотите «сохранить» класс? – Strelok

+0

@Strelok save это означает, что его можно случайно использовать в другом месте, кем-то другим, кто может испортить вещи, для определенного анонимного класса, который я знаю для факта, будет использоваться только один раз, только мной. (что не так уж важно для сделки, я согласен, но мне было просто любопытно) –

ответ

1

Есть два способа доступа метода анонимных классов:

  • Реализуя интерфейс или расширение класса, а затем вызвать методы, которые вы реализовали в своем анонимном классе или
  • С помощью отражения (Я предполагаю, что вы знаете, как это делается, но не хотите этого делать).

Java делает not provide a way of capturing the type of the anonymous class statically, например. аналогично ключевому слову C# var.

В вашем случае, вы можете создать абстрактный тип с помощью метода void NoNoYouCantCallMe(String), и использовать этот класс в качестве основы вашего анонимного класса, как это:

abstract class MyThreadBase extends Thread { 
    public abstract void YesICanCallYou(String s); 
} 
... 
MyThreadBase t = new MyThreadBase() { 
    public void YesICanCallYou(String s){} 
}; 
... 
t.YesICanCallYou(); 
0

Одним из вариантов является объявить один, абстрактные класс, который могут использовать анонимные классы:

public interface IDontWorkForSomeReasonThread { 
    public void NoNoYouCantCallMe(String s); 
} 

public static abstract class MyAbstractThread 
extends Thread 
implements IDontWorkForSomeReasonThread { } 

public static void main (String[] args) throws java.lang.Exception { 
    IDontWorkForSomeReasonThread t = new MyAbstractThread() { 
     public void NoNoYouCantCallMe(String s){} 
    }; 

    t.NoNoYouCantCallMe("foo"); 
} 
1

Вы можете создать внутренний класс, просто не делайте его анонимным. Анонимный означает, что у вас нет типа для него.

Я бы предложил либо именованный внутренний класс, либо второй класс в том же файле. Я использую второй довольно часто, он просто не может быть общедоступным.

1

Если вы действительно хотел сделать что-то непристойное, как, что без использования интерфейса или абстрактный класс, вы можете вызвать его с помощью отражения:

@Test 
public void testCrazyStuff() throws IllegalArgumentException, SecurityException, 
    IllegalAccessException, InvocationTargetException, NoSuchMethodException 
{ 
    Object object = new Thread() 
    { 
     public void ICanBeCalled(String s) 
     { 
      System.out.println(s); 
     } 
    }; 
    object.getClass() 
     .getMethod("ICanBeCalled", String.class) 
     .invoke(object, "Whatever string!"); 
} 

Но это бессмысленно ... Это гораздо лучше идти с простым решением наличия интерфейса или абстрактного класса, как и другие.

3

Ваш вопрос немного запутанный, но похоже, что вы хотите класс, который расширяет Thread и реализует некоторый интерфейс, но который не может быть доступен за пределами метода, в котором он используется (что бы исключить даже частные вложенные классы).В этом случае использует local class:

void myMethod() { 
    class Impl extends Thread implements SomeInterface { 
     @Override 
     public void someInterfaceMethod(String s){ } 
    } 
    new Impl().someInterfaceMethod("data"); 
} 

EDIT: В ответ на ваше обновление, вы можете, естественно, дать локальному классу конструктор и передать данные, или просто дайте ему близко над final переменными во внешнем методе ,

1

Вы можете передать данные анонимному внутреннему классу, используя свободный переменный захват, объявляя все переменные, значение которых вы хотите, чтобы захватить как final:

public void myFunction(final int magicNumber) { 
    new Thread() { 
    @Override public void run() { 
     System.out.println("I can access the magic number: " + magicNumber); 
    } 
    }.start(); 
} 
+2

Да, ты прав. Исправлено, чтобы сделать его законным. – jacobm

2

, если я не могу синтаксический это сделать, может кто-нибудь объясните логику/реализацию дизайна , почему это никогда не сработает?

Я могу объяснить. Если у вас есть выражение foo.bar(...) в Java, компилятор должен убедиться, что статический (время компиляции) выражение foo поддерживает метод bar(). В первом случае выражение слева представляет собой выражение для создания анонимного класса, поэтому его статический тип - это анонимный класс, который имеет этот метод.

Однако в вашем втором случае выражение слева представляет собой переменную. Статический тип переменной - это тип, с которым была объявлена ​​переменная. В Java переменные должны быть объявлены с явным типом (нет var или auto, как и некоторые другие языки). Поэтому его статический тип должен иметь именованный тип. Thread и ни один другой именованный тип не поддерживает метод NoNoYouCantCallMe(); только анонимный класс поддерживает этот метод, и вы не можете объявить переменную типа анонимного класса. Вот почему это не является синтаксически возможным.

Однако, я хотел бы просто хотел бы передать некоторые данные на этот анонимный класс только один раз (в идеале конструктор, но вы заметите, что вы фактически не может переопределить конструктор в Thread()).

Это просто. Вам не нужно явно передавать данные в анонимный класс, потому что внутри анонимных классов и локальных классов вы автоматически получаете доступ к переменным final из окружающей области. Поэтому вместо передачи данных вы просто напрямую используете данные извне.

final String someData = "blah"; 

Thread t = new Thread() { 
    public void run() { doStuffWith(someData); } 
}; 
Смежные вопросы