Предисловие
Недавно, во время учебного процесса, я обнаружил проблему. Абстрактные классы не могут построить объект с помощью нового без реализации всех абстрактных методов, но абстрактные методы могут иметь свои собственные методы строительства. Это меня смутило. Поскольку существует метод строительства, и его нельзя создать через новые, могут быть созданы абстрактные классы, когда они не становятся конкретными классами?
В Java абстрактные классы не могут быть созданы напрямую. Однако эта особенность абстрактных классов часто становится проблемным препятствием. Например, если я хочу использовать динамический прокси, чтобы дать абстрактному классу способность выполнять абстрактные методы, будет две трудности: 1. Динамический прокси может создавать только прокси -объект, который реализует интерфейс, но не объект, который наследует абстрактный класс. Для этого стандартного JVM есть некоторые реализации, такие как Javassist, которые можно использовать для выполнения этого с использованием инструментов Bytecode (ProxyFactory).
Если вы хотите построить абстрактный объект класса в Android, у вас может быть только new ClassName() {} или унаследован. Тем не менее, оба метода не могут быть непосредственно эксплуатироваться их классовыми объектами, что приводит к некоторым проблемам, которые не могут достичь необходимых возможностей для абстракции.
Вот подробное описание сцены, упомянутой в первом абзаце:
Во -первых, существует интерфейс -файл, определенный следующим образом (друзья, знакомые с Android, могут видеть, что это интерфейс конфигурации API, предоставляемый для модернизации для генерации объектов прокси):
Общественный интерфейс Realapi {@get ("api1") наблюдается <string> api1 (); @Get ("api2") наблюдается <string> api2 (); @Get ("api3") наблюдается <string> api3 (); //...Other Methods}Затем напишите абстрактный класс для реализации только одного из методов интерфейса (используется для моделирования данных интерфейса):
@Mockapipubbublic абстрактного класса Mockapi реализует Realapi {vesearbe <string> api3 () {return vaseble.just ("Mock Data"); }}Затем нам нужен инструмент, такой как Mockmanager, который объединяет наш существующий объект RealApi и класс Mockapi для построения смешанного объекта. При выполнении методов, уже определенных в Mockapi, он будет непосредственно выполнять их. Когда Mockapi не определяет метод, он вызовет метод Realapi. Метод вызова примерно:
Realapi api = mockmanager.build (Realapi, Mockapi.class);
Через Javassist очень просто завершить вышеуказанную функцию. Создайте ProxyFactory объект, установите его SuperClass Mockapi, затем отфильтруйте абстрактный метод и установите обработчик метода, чтобы вызвать объект RealApi с тем же именем и методом параметров. Реализация кода не будет предоставлена здесь.
Но на Android метод явасиста будет брошен
Вызвано: java.lang.unsupportedOperationException: не может загрузить этот тип файла класса на java.lang.classloader.defineclass (classloader.java:520) на java.lang.reflect.method.invoke (нативный метод) в javassist.util.proxy.factoryhelper.toclass2 (FactoryHelper.java:182)
Подобные исключения. Причина, вероятно, в том, что реализация и стандарты виртуальных машин на Android немного отличаются, поэтому здесь мы поворачиваем направление в другое направление процессора аннотации динамического генерации кода.
Если вы используете процессор аннотации для его реализации, идея намного проще, но процесс все еще немного извилистый:
Сначала определите аннотацию, чтобы отметить абстрактный класс, который необходимо построить
@Target (elementType.type)@Doccorded@horest (armentpolicy.source) public @interface mockapi {} Процессор получает элемент объекта класса на основе аннотации, который является классовым объектом. Поскольку класс еще не существует на стадии предварительного утилизации, невозможно получить объект класса, необходимый во время выполнения с использованием Class.forName . Тем не менее, элемент предоставляет методы, похожие на связанные с отражением класса, и существуют также такие различия, как тип-лист и исполняемый элемент. Каковы абстрактные методы абстрактного класса, аннотируемые с использованием объекта элемента для анализа аннотированного абстрактного класса, генерировать класс реализации (не ABStract), который наследует класс, и реализуют все абстрактные методы в классе. Поскольку эти абстрактные методы не будут на самом деле использованы, они должны быть только в состоянии компилировать и проходить. Я выбрал, что каждое тело метода бросает исключение, что привело к тому, что метод является абстрактным методом и не может быть вызван непосредственно. Метод генерации кода может использовать некоторые инструменты для упрощения работы, таких как автопроцессор и javapoet, который специально реализует код проекта в конце эталонного текста. Сгенерированный код примерно такой:
// Сгенерированное имя класса названо суффиксом исходного имени класса + "$ Impl", чтобы избежать конфликтов с другими именами класса. Это ограничение также используется для отражения открытого класса окончательного класса Mockapi $ IMP Extens Mockapi {@Override public obsterable <string> api1 () {throw new allodalStateException ("api1 () - это абстрактный метод!"); } @Override public asbodable <string> api2 () {throw new allogalstateexception ("api2 () - это абстрактный метод!"); }}Отражите класс реализации, основанный на названии класса абстрактного класса, а затем постройте объект реализации на основе отражения, вызывая его метод конструктора.
// Получить объект, который генерирует конструкцию кода частной статике <t> t getimplobject (class <t> cls) {try {return (t) class.forname (cls.getname () + "$ inmp"). Newinstance (); } catch (Exception e) {return null; }}Построить динамический прокси, передайте его в реальное объект RealAPI и объект реализации абстрактного класса, построенного на предыдущем этапе, и определите, какой объект определяет поведение своего метода, основанное на определении в абстрактном классе: если в абстрактном классе есть определение, то есть метод не является абстрактным методом, объект реализации абстрактного класса будет выполнено; В противном случае он будет выполнен реальным объектом интерфейса.
Public Static <Origin, Mock Extends Origin> Origin Build (Final Origin Origin, Final Class <mock> mockclass) {// Если Mock Class помечен как закрытый, он непосредственно вернет реальный объект интерфейса if (! Isenable (MockClass)) {return Origin; } final MockObject = getImplObject (MockClass); Class <?> Originclass = origin.getClass (). GetInterfaces () [0]; return (Origin) proxy.newProxyInstance (originclass.getClassloader (), новый класс [] {Originclass}, New InvocationHandler () {@Override Public Object Invoke (Object O, Метод метода, объект [] объекты) бросает Throwable {// Получить метод того же имени в определенный абстрактный класс и определить, как метод mockmethETOD = noctOd; mockclass.getDeclaredMethod (method.getName (), method.getParameterTypes ()); mockmethod.invoke (mockobject, объекты);После завершения вышеуказанной работы вы можете использовать метод сборки для построения прокси -объекта, который смешивает реальные интерфейсы и абстрактные методы класса, как упоминалось в начале. Несмотря на то, что вызывный класс по существу жестко кодируется, он автоматически генерируется процессором аннотации без ручного обслуживания. С точки зрения использования, это в основном то же самое, что и использование реализации Javassist.
Я использовал метод, к которому я принадлежу в этой статье для реализации инструмента, который имитирует модернизацию запросов (в конце статьи есть ссылка), но, по сути, его можно использовать для реализации многих потребностей, которые требуют построения абстрактных классов, и все еще необходимо изучить больше сценариев использования.
Реализация исходного кода, упомянутая в статье, может быть найдена в проекте модернизации модернизации или локальной загрузки;
Суммировать
Вышеуказанное - все содержание этой статьи. Я надеюсь, что содержание этой статьи имеет определенную справочную ценность для каждого обучения или работы. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения. Спасибо за поддержку Wulin.com.