`
jacktanlikejava
  • 浏览: 8515 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

Java reflect vs. Qt Meta-Object

 
阅读更多

Java的反射机制被广泛的应用在当今各种流行的开源框架中。只要你打开spring,struts或是hibernate的源代码,就可以发现Java反射的身影。利用反射,我们可以在系统运行时通过字符串来获取各种对象的类型,然后通过类型我们可以实例化对象并调用对象的相关方法。当然这一切对于Java来说都是非常的简单和容易理解,因为Java有虚拟机的存在,这个运行时系统就好比一个对象类型数据库,我们只要提供查询条件,就可以返回给我们所需要的对象类型。如下Java代码展示如何应用Reflect特性:

package org.storevm;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

public class MyClass {

    private String name;

    public MyClass() {

    }

    public void say() {

        System.out.println(name);

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public static void main(String[] args) throws Exception {

        Class clazz = Class.forName("org.storevm.MyClass");

        Object obj = clazz.newInstance();

        Field field = clazz.getDeclaredField("name");

        field.setAccessible(true);

        field.set(obj, "jacktan");

        Method method = clazz.getMethod("say", new Class[] {});

        method.invoke(obj, new Object[] {});

    }

}

上述代码的功能是:

1. 用字符串“org.storevm.MyClass”获取类型对象;

2. 将类型对象实例化为MyClass对象;

3. 从类型对象中获取name属性并设置为可读写状态;

4. 设置name属性的值为“jacktan”字符串;

5. 从类型对象中获取say方法对象;

6. 调用MyClass对象的say方法;

使用Java的反射,我们可以在不引用MyClass对象实例的情况下完成对MyClass对象的所有功能操作。

C++中并没有很强的内省功能,不过Qt 框架为C++扩展了一套类似Java反射的强大类型内省机制,我们称之为“Meta-Object”。通过这套系统,我们也可以非常容易的实现上述Java中实现的功能。不过相比较,Qt C++的编码要复杂一些,代码的可读性也不是很好,对于Java开发人来说可能看的不太习惯。如下代码展示了Qt C++中实现内省的特性:

头文件:cresultset.h

#ifndef CRESULTSET_H

#define CRESULTSET_H

 

#include<QObject>

#include<QString>

 

class CResultSet:public QObject

{

    Q_OBJECT

    Q_PROPERTY(QString m_name READ getName WRITE setName)

public:

    Q_INVOKABLE explicit CResultSet(QObject *parent = 0);

    Q_INVOKABLE CResultSet(const CResultSet &); //重新实现拷贝构造函数


    Q_INVOKABLE void say();

 

    Q_INVOKABLE QString getName() const {return m_name;}

    Q_INVOKABLE void setName(const QString &name){m_name = name;}

 
    CResultSet& operator=(const CResultSet &); //重载赋值操作符

private:

    QString m_name;

};

#endif// CRESULTSET_H


要实现C++的内省,首先必须公有继承Qt的QObject类,然后使用Q_OBJECT宏来标识需要实现内省。如果不继承QObject类而直接使用Q_OBJECT宏,则编译报错。Q_PROPERTY宏用以标识可被内省的成员变量,括号内看上去非常奇怪写法(看到下面就知道为什么要如此的写法)定义了成员变量的类型,名称以及读写该成员变量的setter和getter函数。Q_INVOKABLE宏用以标识可被内省的成员函数,这里需要注意的是,我们在类的构造函数上也标识了Q_INVOKEABLE宏,之后就能看到这样做的原因。为了实现内省,这些宏的标识是必须的,如果不在成员变量或成员函数上使用这些宏,则在调用indexOfProperty和indexOfMethod等函数时将永远返回-1,即无法使用内省。相比Java的实现,Qt的宏更具操控性,控制粒度更加细致,但是增加了编码量。

另外要提一下继承QObject时需要关注的问题。在QObject类中,赋值操作符和拷贝构造函数被定义为私有的,也就是说,通过继承QObject的类是无法进行赋值操作和对象拷贝的。为了解决这个问题,我们必须重新实现拷贝构造函数并重载赋值操作符。

以下代码为cpp文件的内容:cresultset.cpp

#include "cresultset.h"

#include <QDebug>

 

CResultSet::CResultSet(QObject *parent) :

    QObject(parent)

{

}

 

//拷贝构造函数

CResultSet::CResultSet(const CResultSet &other)
{
    *this=other;

}

 

void CResultSet::say()
{

    qDebug() << this->m_name;

}

 

//赋值操作符重载
CResultSet& CResultSet::operator =(const CResultSet &other)

{
    this->m_name = other.m_name;

    return *this;

}

以下代码为Meta-Object特性的调用:main.cpp

#include <QtGui/QApplication>

#include <QDebug>

#include <QMetaObject>

#include <QMetaProperty>

 

int main(int argc,char *argv[])

{

    QApplicationa(argc, argv);

    QMetaObject metaObject = CResultSet::staticMetaObject;
    
    QObject* rs = metaObject.newInstance();   

    int pidx = (rs->metaObject())->indexOfProperty("m_name");

    qDebug() << pidx;

    QMetaProperty property = (rs->metaObject())->property(pidx);

    property.write(rs, QVariant("jacktan111"));

    QMetaObject::invokeMethod(rs, "say", Qt::DirectConnection);

    return a.exec();
}

首先使用类(此类必须继承自QObject)的静态函数staticMetaObject获取QMetaObject对象,该对象中包含了所有元对象信息,包括类名,成员函数,成员变量,信号和槽等,类似于Java中的Class类。然后通过QMetaObject对象的newInstance函数返回QObject的指针,这步类似Java中的Class.newInstance方法。接下去就是一些操作元对象的操作。比如通过实例对象的QMetaObject对象的indexOfProperty函数可以返回指定成员变量名称的索引值,比如利用该索引值调用QMetaObject::property(int)函数,就能得到QMetaProperty对象,该对象类似Java中的Field类,保存了有关于成员变量的相关元数据。QMetaProperty对象中read和write函数分别用于成员变量的读写。写到这里,相信大家都明白了吧!之前的Q_PROPERTY宏为什么定义成如此奇怪的形状。正是通过READ和WRITE指定的函数名称来实现QMetaProperty对象中的read和write函数。

使用QMetaObject对象的静态函数invokeMethod可以调用指定对象的成员函数,前提是被调用的成员函数必须被Q_INVOKABLE宏所修饰。成员函数的调用有2种方式:同步的和异步的,同步使用Qt:: DirectConnection参数,异步使用Qt:: QueuedConnection参数。上述C++代码的功能与Java版本实现的功能完全一样。即通过内省特性为一个实例化对象的成员变量赋值,并调用指定的成员函数。相比之下,Java的内省更容易理解且使用起来也更自然一些,至少没有那些让人看的很费解的宏定义。

最后说说Qt这个C++开发框架,它的强大自不必多说,时间证明了一切。尤其是其跨平台的能力绝对不亚于号称一次编写,随处运行的Java。只要做过跨平台开发的人都知道,要真正实现跨平台应用程序是何其的困难,光是编译源代码这一关就能彻底摧毁你对跨平台应用程序的美好期望,所以为什么Java会那么不厌其烦的宣扬它的跨平台能力。对于开发人员来说根本无需关心编写的代码将来要运行在什么平台上,但是Java的跨平台是借助了JVM的力量,JVM本身并不是跨平台的。每个平台有其自己特定的JVM实现,只是对开发人员来说这一切是透明的,无需开发人员关注。C++是编译成本地代码执行的,没有JVM这种just in time的运行时系统。所以从这点看Qt实现的跨平台比Java更强大,但是天下无免费晚餐,Qt为了实现跨平台,把所有的负担转嫁给了程序员,为了实现跨平台,程序员需要更加缜密的思维和使用大量令人费解的宏定义。

Java的弱势是其GUI方面,虽然现在基于浏览器的应用程序满天飞,但是GUI程序并没有因此而退出历史舞台,在很多场合GUI程序以其界面的统一性以及高性能被广泛的应用在如嵌入式系统,工业应用等领域。这也是QtGUI为什么能活跃到现在的原因。在某些企业应用中,Java和C++可以完美的组合起来,比如,Java用于编写业务逻辑组件,充分发挥其面向对象建模的优势。而C++ Qt GUI则可利用跨语言的通讯机制与Java服务器组件进行交互,从而实现高性能的用户界面体验。而在另外一些场合,我们则可以利用Qt C++的高性能编写服务器端业务处理,而使用Java编写B/S界面解决统一部署的问题,充分结合2种开发语言的优势。所以最为一个好的设计人员,不能拘泥于一种语言的实现平台,应该海纳百川,充分利用各种平台的优势加以结合,创建趋于完美的应用系统。

Qt在很多方面借鉴了Java的设计理念,比如Qt的GUI组件模型,Qt的内省,Qt的布局管理器,Qt的MVC模型等等,处处可见Java设计的影子。所以如果你是一个Java开发人员,那当你遇到Qt时,肯定会有一种似曾相识的感觉。


分享到:
评论

相关推荐

    scala-reflect-2.12.14-API文档-中文版.zip

    赠送jar包:scala-reflect-2.12.14.jar; 赠送原API文档:scala-reflect-2.12.14-javadoc.jar; 赠送源代码:scala-reflect-2.12.14-sources.jar; 赠送Maven依赖信息文件:scala-reflect-2.12.14.pom; 包含翻译后...

    scala-reflect-2.12.14-API文档-中英对照版.zip

    赠送jar包:scala-reflect-2.12.14.jar; 赠送原API文档:scala-reflect-2.12.14-javadoc.jar; 赠送源代码:scala-reflect-2.12.14-sources.jar; 赠送Maven依赖信息文件:scala-reflect-2.12.14.pom; 包含翻译后...

    解决axis2-CodegenWizardPluginBUG- java.lang.reflect.InvocationTargetException

    标题中的“解决axis2-CodegenWizardPluginBUG- java.lang.reflect.InvocationTargetException”指的是在使用Apache Axis2的CodegenWizardPlugin工具时遇到的一个错误。这个工具是Axis2框架的一部分,用于自动生成...

    scrcpy投屏 AssertionError: java.lang.reflect.InvocationTargetExcep

    标题中的问题“scrcpy投屏 AssertionError: java.lang.reflect.InvocationTargetException”是用户在尝试使用Scrcpy时遇到的一个常见错误。这个错误通常意味着在执行某个方法时,Java运行时环境遇到了未预期的情况。...

    kotlin-reflect.jar

    kotlin-reflect.jar

    Java与模式.part25-27.rar

    这部分可能会讲解`Class`类、`Constructor`、`Method`和`Field`,以及`java.lang.reflect.Proxy`和`InvocationHandler`接口。 6. **Java I/O与NIO**:Java的输入/输出系统是处理数据流的关键,而NIO(非阻塞I/O)为...

    kotlin-reflect-1.3.70.jar

    Could not download kotlin-reflect.jar 这个问题 是墙的原因 没有下载下来kotlin-reflect.jar的jar包资源...把下载的kotlin-reflect-1.3.70.jar,放在版本文件的子目录中,重新启动电脑就可以。网上都有对应的操作指引

    backport-util-concurrent-3.1.jar geronimo-stax-api_1.0_spec-1.0.1.jar 下载

    An error ocCurred while completing process -java.lang.reflect.InvocationTargetException (1).关闭 Eclipse (2).copy %AXIS2_HOME%\lib\ 下的 backport-util-concurrent-3.1.jar 和 geronimo-stax-api_1.0_...

    Java API 文档 jdk-17.0.2-doc-all

    1. **核心类库**:Java API文档首先会介绍Java的基础类库,如`java.lang`包,其中包含了许多基础类,如`String`、`Integer`、`Object`等。这些类提供了基本的数据类型转换、字符串操作和对象操作等功能。 2. **集合...

    java反射 反编译:.class--&gt;.java

    反编译指的是将已编译的字节码文件(`.class`)转换回源代码文件(`.java`)。虽然Java反射API不直接提供这样的功能,但可以通过第三方库如JAD(Java反汇编器)或者jadclipse插件实现。这种能力在调试和理解已有的...

    java.lang.reflect.Proxy 学习资料 讲解 例子 源码

    java.lang.reflect.Proxy 学习资料 讲解 例子 源码 java.lang.reflect.Proxy 学习资料 讲解 例子 源码 java.lang.reflect.Proxy 学习资料 讲解 例子 源码

    reflect-object-in-unity2d

    reflect-object-in-unity2d

    java 帮助文档 chm格式 java中文帮助文档chm格式.docx

    ##### 3.19 `java.lang.reflect` - **用途**:提供用于获取类和对象反射信息的类和接口。 - **关键类**:`Class`, `Constructor`, `Field` ##### 3.20 `java.math` - **用途**:提供用于执行任意精度数学运算的类。...

    MyEclipse axis2 wsdl java.lang.reflect.invocationtargetexception

    MyEclipse axis2 wsdl java.lang.reflect.invocationtargetexception code gen 大家要注意一定要仔细,这个问题基本上缺少包引起的,而且一定要clean 如果需要axis2插件 以及这个plugins中的包在我的其他资源里面有

    Java.lang.reflect 包下常用的类及方法简介

    在Java编程语言中,`java.lang.reflect`包是核心库的一部分,它提供了运行时访问类、接口、字段和方法的能力。这个包对于理解和操作对象的动态特性至关重要,尤其是在实现反射机制时。反射允许我们在程序运行期间...

    powermock-reflect-2.0.9.jar中文-英文对照文档.zip

    中文-英文对照文档,中英对照文档,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【***.jar中文文档.zip】,再解压其中的 【***-...

    Java reflect 机制详解

    免费共享,很详细的介绍了反射机制的原理,适合追根究底的java学习者

    The.Cucumber.for.Java.Book.Behaviour-Driven.Development

    New chapters cover features unique to the Java version of Cucumber, and reflect insights from the Cucumber team since the original book was published. Until now it's been difficult for teams ...

    scala-reflect-2.11.8-API文档-中英对照版.zip

    赠送jar包:scala-reflect-2.11.8.jar; 赠送原API文档:scala-reflect-2.11.8-javadoc.jar; 赠送源代码:scala-reflect-2.11.8-sources.jar; 赠送Maven依赖信息文件:scala-reflect-2.11.8.pom; 包含翻译后的API...

Global site tag (gtag.js) - Google Analytics