我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java如何实例化一个抽象类对象

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java如何实例化一个抽象类对象

这篇文章主要介绍Java如何实例化一个抽象类对象,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

在Java 中抽象类是不能直接被实例化的。但是很多时候抽象类的该特点成为一个比较麻烦的阻碍。例如如果我想使用动态代理来给一个抽象类赋予其执行抽象方法的能力,就会有两个困难:1. 动态代理只能创建实现接口的一个代理对象,而不能是一个继承抽象类的对象。为此标准的 JVM 中有一些实现,例如 javassist 可以使用字节码工具来完成这一目的(ProxyFactory)。

在 Android 中如果想构造一个抽象类对象,恐怕只有 new ClassName() {} 或者继承之后构造了。但是这两种方法都是不能由其 Class 对象直接操作的,这就导致一些问题上达不到我们需要的抽象能力。

这里详细描述一下第一段所说的场景:

首先有一个 interface 文件定义如下(熟悉 Android 的朋友可以看出这是一个提供给 Retrofit 生成代理对象的 Api 配置接口):

public interface RealApi {  @GET("api1") Observable<String> api1();  @GET("api2") Observable<String> api2();  @GET("api3") Observable<String> api3(); //...其他方法}

其次再写一个抽象类,只实现接口的其中一个方法(用来模拟接口数据):

@MockApipublic abstract class MockApi implements RealApi { Observable<String> api3() { return Observable.just("mock data"); }}

然后我们需要有一个工具,例如 MockManager ,让他结合我们已存在的 RealApi 对象和 MockApi 类,来构造出一个混合对象,该对象在执行 MockApi 中已经定义的方法时,为直接执行,在 MockApi 没有定义该方法时,去调用 RealApi 的方法。其调用方式大概为:

RealApi api = MockManager.build(realApi, MockApi.class);

通过 javassist,完成上述功能很简单,创建一个 ProxyFactory 对象,设置其 Superclass 为MockApi,然后过滤抽象方法,设置 method handler 调用 realApi 对象的同名同参方法。这里就不再给出代码实现。

但是在 Android 上,javassist 的该方法会抛出

Caused by: java.lang.UnsupportedOperationException: can't load this type of class file   at java.lang.ClassLoader.defineClass(ClassLoader.java:520)  at java.lang.reflect.Method.invoke(Native Method)  at javassist.util.proxy.FactoryHelper.toClass2(FactoryHelper.java:182)

类似的异常。原因大概是 Android 上的虚拟机的实现和标准略微不同,所以这里把方向转为了动态代码生成的另一个方向 Annotation Processor。

使用 Annotation Processor 实现的话,思路就简单的多了,但过程还是有些曲折:

首先定义一个注解,用来标记需要构造对象的抽象类

@Target(ElementType.TYPE)@Documented@Retention(RetentionPolicy.SOURCE)public @interface MockApi {}

Processor 根据注解来获得类的 element 对象,该对象是一个类似 class 的对象。因为在预编译阶段,class 尚未存在,此时使用 Class.forName 是不可以获取运行时需要的 Class 对象的,但是 Element 提供了类似 Class 反射相关的方法,也有 TypeElement、ExecutableElement 等区分。使用 Element 对象分析注解的抽象类的抽象方法有哪些,生成一个继承该类的实现类(非抽象),并在该类中实现所有抽象方法,因为不会实际用到这些抽象方法,所以只需要能编译通过就可以了,我选择的方式是每个方法体都抛出一个异常,提示该方法为抽象方法不能直接调用。生成代码的方法可以使用一些工具来简化工作,例如 AutoProcessor 和 JavaPoet,具体实现参考文尾的项目代码,生成后的代码大致像这样:

// 生成的类名使用原类名+"$Impl"的后缀来命名,避免和其他类名冲突,后面也使用该约束进行反射来调用该类public final class MockApi$Impl extends MockApi { @Override public Observable<String> api1() { throw new IllegalStateException("api1() is an abstract method!"); } @Override public Observable<String> api2() { throw new IllegalStateException("api2() is an abstract method!"); }}

根据该抽象类的类名去反射获得该实现类,然后再根据反射调用其构造方法构造出一个实现对象。

// 获得生成代码构造的对象private static <T> T getImplObject(Class<T> cls) { try { return (T) Class.forName(cls.getName() + "$Impl").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 Mock mockObject = getImplObject(mockClass); Class<?> originClass = origin.getClass().getInterfaces()[0]; return (Origin) Proxy.newProxyInstance(originClass.getClassLoader(), new Class[]{originClass}, new InvocationHandler() {  @Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable {    // 获取定义的抽象类中的同名方法,判断是否已经实现  Method mockMethod = null;  try {  mockMethod = mockClass.getDeclaredMethod(method.getName(), method.getParameterTypes());  } catch (NoSuchMethodException ignored) {  }    if (mockMethod == null || Modifier.isAbstract(mockMethod.getModifiers())) {  return method.invoke(origin, objects);  } else {  return mockMethod.invoke(mockObject, objects);  } } });}

完成上述工作以后,就可以像开头所说的那样,使用 build 方法来构造一个混合了真实接口和抽象类方法的代理对象了,虽然调用的类本质上还是硬编码,但是由 Annotation Processor 自动生成免于手动维护,使用上来讲和使用 Javassist 实现还是基本相同的。

我用本文中所属的方法实现了一个模拟 retrofit 请求的工具(文尾有链接),但本质上可以用它来实现很多需要构造抽象类的需求,更多的使用场景还有待挖掘。

文中提到的源码实现可以在项目 retrofit-mock-result 或本地下载中找到;

以上是“Java如何实例化一个抽象类对象”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网行业资讯频道!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java如何实例化一个抽象类对象

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java如何实例化一个抽象类对象

这篇文章主要介绍Java如何实例化一个抽象类对象,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!在Java 中抽象类是不能直接被实例化的。但是很多时候抽象类的该特点成为一个比较麻烦的阻碍。例如如果我想使用动态代理来给一
2023-05-30

java抽象类如何实例化

Java抽象类不能直接实例化,因为抽象类是一种不完整的类,其中可能包含抽象方法,这些方法没有实现。所以,不能直接使用抽象类来创建对象。但是,我们可以通过创建抽象类的子类来实例化抽象类。子类需要实现抽象类中的所有抽象方法才能被实例化。例如,
2023-10-22

如何在 Java 中实例化一个对象?(java怎么实例化一个对象)

在Java编程中,实例化对象是创建类的具体实例的过程。这是面向对象编程的基础概念之一,允许我们根据类的定义创建实际的对象,并使用这些对象来执行各种操作。以下是在Java中实例化对象的详细步骤:一、理解类和对象的概念在J
如何在 Java 中实例化一个对象?(java怎么实例化一个对象)
Java2024-12-17

java不能实例化抽象类如何改

要实例化抽象类,可以通过以下两种方式进行改进:将抽象类改为具体类:将抽象类改为普通类,即去掉抽象修饰符(abstract),并提供具体的实现方法。这样就可以直接实例化该类了。创建一个子类继承抽象类:创建一个继承自该抽象类的具体子类,并实现父
2023-10-22

如何理解 JAVA 中的抽象类和抽象方法(abstract)并进行实例分析?(JAVA抽象类和抽象方法(abstract)实例分析)

在Java编程中,抽象类(abstractclass)和抽象方法(abstractmethod)是两个重要的概念,它们允许开发者创建具有共同特征的类层次结构,并为子类提供一个通用的模板。本文将详细介绍Java抽象类和抽象方法的概念、用法,并通过实例进行分析。
如何理解 JAVA 中的抽象类和抽象方法(abstract)并进行实例分析?(JAVA抽象类和抽象方法(abstract)实例分析)
Java2024-12-13

java如何实例化对象

在Java中,可以使用`new`关键字实例化对象。实例化对象的一般步骤如下:1. 创建一个类:首先需要定义一个类,该类描述了对象的属性和行为。2. 使用`new`关键字创建对象:使用`new`关键字后跟类名和括号,创建对象实例,例如:`Cl
2023-08-24

JAVA抽象类和抽象方法(abstract)实例分析

抽象类和抽象方法是Java中用于实现抽象化的概念。抽象类是一个不能被实例化的类,它可以包含抽象方法和非抽象方法。抽象方法是一个没有具体实现的方法,它只有方法的声明,没有方法体。下面是一个抽象类和抽象方法的实例分析:```java// 定义一
2023-08-16

java抽象类如何写

在Java中,抽象类是一个不能被实例化的类,它可以包含抽象方法和非抽象方法。编写Java抽象类的步骤如下:使用关键字abstract来声明一个抽象类。在抽象类中可以包含抽象方法和非抽象方法。抽象方法使用关键字abstract来声明,而非抽象
java抽象类如何写
2024-03-07

如何书写 Java 抽象类?详细步骤与示例分享(java抽象类如何写)

在Java编程中,抽象类是一种非常重要的概念,它允许我们定义一个类的模板,其中包含抽象方法和具体方法。抽象类不能被实例化,只能被继承。本文将详细介绍如何书写Java抽象类,包括步骤和示例。一、抽象类的定义抽象类是使用a
如何书写 Java 抽象类?详细步骤与示例分享(java抽象类如何写)
Java2024-12-14

怎么在java里实例化一个对象

要在Java中实例化一个对象,需要按照以下步骤进行操作:1. 创建一个类:首先,需要创建一个类来定义对象的属性和行为。类是描述对象的模板,它包含了对象的属性(成员变量)和行为(方法)。2. 实例化对象:在Java中,要实例化一个对象,需要使
2023-09-26

java抽象类如何定义

Java中定义抽象类需要使用关键字"abstract"。抽象类不能被实例化,只能作为其他类的父类,供其他类继承使用。抽象类的定义方式如下:javapublic abstract class AbstractClass {// 抽象方法pub
2023-10-20

python抽象类可以被实例化吗

不可以。抽象类是一种特殊的类,不能直接被实例化。抽象类的主要作用是为其子类提供一个共同的接口,并定义一些通用的方法。抽象类定义了一些抽象方法,这些方法在抽象类中没有具体实现,而是由其子类来实现。只有子类实现了所有抽象方法,才能被实例化。
2023-10-25

Java 类对象与实例对象究竟有哪些区别?(java类对象和实例对象有什么区别)

在Java编程中,类对象和实例对象是两个重要的概念,它们在概念、创建方式、内存占用以及使用场景等方面都存在着明显的区别。一、概念区别类对象是类的模板,它定义了该类的属性和方法。类对象就像是一个模具,通过它可以创建出多个具体的
Java 类对象与实例对象究竟有哪些区别?(java类对象和实例对象有什么区别)
Java2024-12-13

Java抽象类与接口实例分析

这篇“Java抽象类与接口实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java抽象类与接口实例分析”文章吧。1.抽
2023-06-30

java中抽象类、抽象方法、接口与实现接口实例详解

前言对于java中的抽象类,抽象方法,接口,实现接口等具体的概念就不在这里详细的说明了,网上书本都有很多解释,主要是我懒,下面通过一个例子来说明其中的精髓要点,能不能练成绝世武功,踏上封王之路,就看自己的的啦(不要误会,我指的只是我自己啦啦
2023-05-30

jquery如何实例化对象

本文小编为大家详细介绍“jquery如何实例化对象”,内容详细,步骤清晰,细节处理妥当,希望这篇“jquery如何实例化对象”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。jQuery是一款常用的 JavaScri
2023-07-06

一日一技:在 Python 里面如何实现一个抽象类

在某个在线教育的网站上设计模式相关的课程中,某老师说 Python 不支持抽象类和接口。

php抽象类为什么不能实例化

PHP的抽象类(abstract class)是一种特殊的类,它不能被实例化。抽象类是为了被继承而存在的,它定义了一组方法的接口,但没有具体的实现。抽象类的目的是为了作为其他类的基类,其他类通过继承抽象类来实现其定义的方法。抽象类的主要特点
2023-10-07

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录