jni.h头文件详解(二)

一:struct JNINativeInterface_{}

  结构体的作用:它有点像我们char字符驱动的 file_ops结构体,它定义各种函数对在(jni.h头文件详解一)中定义的各种数据的操作函数集体.

二:它包含那些针对Java中类和对象的相关操作呢如下图.

  

三:下面我们讲详细介绍14个部分方法的用法和解析

3.1.版本信息操作函数.

一.GetVersion

jint (JNICALL *GetVersion)(JNIEnv *env)

--模块信息:该模块主要针对的JNI接口的版本信息操作函数.

函数原型:jint (JNICALL *GetVersion)(JNIEnv *env)

 描 述:它用来返回jni的版本信息.version = (*env)->GetVersion(env);

     我们通过这个方法获取版本信息.并通过回调java的getVersion()方法显示版本号.

 参 数:这个JNIEnv是JNI的运行环境.这个环境中包含了上图的14大块的操作函数等等.

 返回值:返回一个0-65535大小的数.他是一个16位的正整数.高八位是主版本号.低八位是次版本号.

例 程:

--1.1 函数使用Demo流程介绍.

     通过Java对象的构造方法,把当前对象传递到C中.C获取到该对象之后,保存Java对象的引用,并获取相应的方法等.

     获取该对象之后,C会调用获取JNI版本的函数.获取版本号,并调用Java层的getVersion()函数,将版本号显示出来.如图:

--1.2 代码
package com.octopus.test03;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Color;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

public class Act1 extends Activity implements OnClickListener {
	private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT;
	private final int FP = LinearLayout.LayoutParams.FILL_PARENT;
	private Button btn, btn3;
	public static Act1 ref;
	public TextView tv;

	@Override
	protected void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		ref = this;
		LinearLayout layout = new LinearLayout(this);
		layout.setOrientation(LinearLayout.VERTICAL);
		btn = new Button(this);
		btn.setId(101);
		btn.setText("run(Adder)");
		btn.setBackgroundResource(R.drawable.ic_launcher);
		btn.setOnClickListener(this);
		LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(120, 50);
		param.topMargin = 10;
		layout.addView(btn, param);
		btn3 = new Button(this);
		btn3.setId(103);
		btn3.setText("exit");
		btn3.setBackgroundResource(R.drawable.ic_launcher);
		btn3.setOnClickListener(this);
		layout.addView(btn3, param);
		tv = new TextView(this);
		tv.setTextColor(Color.WHITE);
		tv.setText("");
		LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(FP, WC);
		param2.topMargin = 10;
		layout.addView(tv, param2);
		setContentView(layout);
	}

	public void onClick(View v) {
		if (v == btn) {
			int a = 1, b = 1;
			GetVersion adder = new GetVersion();
		} else if (v == btn3) {
			finish();
		}
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}
  
--1.3 Jni层代码
package com.octopus.test03;

import java.lang.ref.WeakReference;

import android.os.Handler;
import android.os.Message;

public class GetVersion {

	private static Handler h;
	static {
		System.loadLibrary("HelloNdk");
	}

	public GetVersion() {

		h = new Handler() {
			public void handleMessage(Message msg) {
				Act1.ref.setTitle(msg.obj.toString());
			}
		};
		nativeSetup(new WeakReference<GetVersion>(this));
	}

	private static void getVersion(Object version_ref, int what,int message)
	{

		String obj1 = "Jni Version is : "+ message;
		Message m = h.obtainMessage(what, obj1);
		h.sendMessage(m);
	}

	private native void nativeSetup(Object weak_this);

}
--1.4 C 层代码
  1 /* DO NOT EDIT THIS FILE - it is machine generated */
  2 #include "com_octopus_test03_GetVersion.h"
  3 /* Header for class com_octopus_test03_GetVersion */
  4
  5 /*
  6  * Class:     com_octopus_test03_GetVersion
  7  * Method:    nativeSetup
  8  * Signature: (Ljava/lang/Object;)V
  9  */
 10
 11 jclass mClass;
 12 jobject mObject;
 13 jmethodID mid;
 14
 15 JNIEXPORT void JNICALL Java_com_octopus_test03_GetVersion_nativeSetup
 16   (JNIEnv *env, jobject this, jobject weak_this)
 17 {
 18     jint version =0;
 19     jclass class = (*env)->GetObjectClass(env,this);
 20     mClass =  (jclass)(*env)->NewGlobalRef(env,class);
 21     mObject = (*env)->NewGlobalRef(env,weak_this);
 22     mid = (*env)->GetStaticMethodID(env, mClass,"getVersion","(Ljava/lang/Object;II)V");
 23
 24     version = (*env)->GetVersion(env);   //我们通过这个方法获取版本信息.并通过回调java的getVersion()方法显示版本号.
 25     (*env)->CallStaticVoidMethod(env,mClass,mid,mObject,1,version);
 26     return ;
 27 }
1.5.Android.mk文件如下:
SRC_PATH_ROOT:=$(LOCAL_PATH)/../../src
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := HelloNdk
LOCAL_SRC_FILES := com_octopus_test03_GetVersion.c
include $(BUILD_SHARED_LIBRARY)
--1.6 测试当前JNI的版本为65542

.

转载请说明出处:  http://blog.csdn.net/shaohuazuo/

.

3.2.
类模块相关操作.

(DefineClass,FindClass)

jclass (JNICALL *DefineClass)  (JNIEnv *env, const char
*name, jobject loader, const jbyte *buf, jsize len);

jclass (JNICALL *FindClass) (JNIEnv *env, const char
*name);

--模块信息:这个模块主要是C或者C++中如何获取Java的Class类对象. 这个接口再Android上没有得到支持.

一:DefineClass

函数原型:jclass (JNICALL *DefineClass)  (JNIEnv *env, const char *name, jobject loader,
const jbyte *buf, jsize len);

 描 述: 从二进制的.class的数据缓冲区中加载类.

 参 数: env    java本地接口指针.

name   需要加载类的简短名称.比如下载需要加载一个com/zuoshaohua/Test.java这个类,那么该名称就是 Test

loader 类加载器对象.该类用来加载java字节码.class文件

buf    这个是字节码缓冲区数组.

len    该数组的长度.

返回值:

返回一个jclass类型的结构体.他对应的是Java中的类相关信息.

例 程:

--1.1 相关的java背景知识说.可以参考http://blog.csdn.net/lovingprince/article/details/4317069博客,

Java类加载器.也就是我们的loader参数的详细介绍.

在这里我们简单的说说loader的作用.在Java语言中loader是一个将 .class文件加载到内存的一个类加载器.

--1.2 例程的业务逻辑介绍:

写一个测试的java类.他用来输出一个字符串..我们把他编译成一个.class文件.然后使用DefineClass进行加载.

并再Activity中输出该字符串.

--1.3代码  (注释 界面代码和上一个实例是一样的.)
package com.octopus.test03;

import java.lang.ref.WeakReference;

import android.os.Handler;
import android.os.Message;

public class DefindClassTest {
	ClassLoader loader;
	private static Handler h;
	static {
		System.loadLibrary("HelloNdk");
	}

	public DefindClassTest() {

		h = new Handler() {
			public void handleMessage(Message msg) {
				Act1.ref.setTitle(msg.obj.toString());
			}
		};
		loader = DefindClassTest.class.getClassLoader();
		if(loader==null){
			System.out.println("loader error\n");
		}
                //将获得的类加载器,传入到C层.
                nativeSetup(new WeakReference<ClassLoader>(loader));

	}

	private static void getVersion(Object version_ref, Object test, int what,int message)
  	{
		String obj1 = "Jni Version is : "+ message+ "C Create obj is"+ test;
		Message m = h.obtainMessage(what, obj1);
		h.sendMessage(m);
	}

	private native void nativeSetup(Object weak_this);

}
--1.4 jni中c端实现代码
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "com_octopus_test03_DefindClassTest.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

/*
 * Class:     com_octopus_test03_DefindClassTest
 * Method:    nativeSetup
 * Signature: (Ljava/lang/Object;)V
 */

/*
   jclass (JNICALL *DefineClass) (JNIEnv *env, const char *name, jobject loader, const jbyte *buf,jsize len);
   */

jclass mClass;
jobject mObject;
jmethodID mid;

JNIEXPORT void JNICALL Java_com_octopus_test03_DefindClassTest_nativeSetup
(JNIEnv *env, jobject this, jobject weak_this){

	int fd;
	off_t len;
	jint ret;
	int pos;
	off_t tmplen;
	jbyte *buf = NULL;
        jclass testclass;
	jint version =0;
	jobject mOjbect1;
	jobject obj1;
	jclass class = (*env)->GetObjectClass(env,this);
	mClass =  (jclass)(*env)->NewGlobalRef(env,class);

	//我们需要获取到DefineClassTest该类的类加载器.
	mObject = (*env)->NewGlobalRef(env,weak_this); 

	//使用c读取我们需要加载的文件.
	fd = open("/system/Test.class",O_RDONLY);
	len = lseek(fd, 0, SEEK_END);
	buf = calloc(len,1);
	if(buf == NULL){
		printf("calloc error \n");
		return;
	}
	lseek(fd, 0,SEEK_SET);
	pos = 0;
	tmplen = len;
	while(tmplen > 0){
		ret += read(fd,buf+ret,tmplen-ret);
		pos +=ret;
		tmplen -=ret;
	}
	close(fd);

	//使用DefineClass函数加载这个类
	testclass = (*env)->DefineClass(env,"Test",mObject,buf,len);
 
        if(testclass == NULL)
	{
		return;
	}
        free(buf);

        obj1 = (*env)->AllocObject(env,testclass);
	//生成一个对象,并调用该对象的方法.
	mid = (*env)->GetStaticMethodID(env, mClass,"getVersion","(Ljava/lang/Object;Ljava/lang/Object;II)V");
	version = (*env)->GetVersion(env);
	(*env)->CallStaticVoidMethod(env,mClass,mid,this,obj1,1,version);

	return ;

}

二: FindClass

函数原型:jclass (JNICALL *FindClass) (JNIEnv *env, const char *name);

 描 述: 该函数用于加载本地定义的类。它将搜索由CLASSPATH 环境变量为具有指定名称的类所指定的目录和 zip 文件。

该CLASSPATH一般为:

#set java environment

JAVA_HOME=/home/xxx/java/jdk1.6.0_12

export JRE_HOME=/home/xxx/java/jdk1.6.0_12/jre

export CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib:$CLASSPATH

export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH

findClass函数的java背景知识在我的博客由介绍:

 参 数: env    java本地接口指针.

name   需要加载类的简短名称.比如下载需要加载一个com/zuoshaohua/Test.java这个类,该参数就是 "com/zuoshaohua/Test"

返回值:

返回一个jclass类型的结构体.他对应的是Java中的类相关信息.它是类的字节码对象. 

 例 程:

--2.1 流程:

    1.MainActivity的onCreate()方法中初始化一个ManPerson.

    2.在ManPerson的构造函数最后我们会调用nativeSetup把ManPerson对象传递到C中.

    3.我们会再C中得到ManPerson的属性Id信息,并保存起来.并使用findClass()方法获取Person类字节码对象,并生成Person对象的全集引用.

    4.当我们点击应用层的btn时,C会获取ManPerson的信息.使用bean的setXxx()给Person对象赋值.并返回给对象到java层.

   --2.2类图:

--2.3 Activity代码
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >
    <TextView
        android:id="@+id/personView"
        android:layout_width="260dp"
        android:layout_height="100dp"
        android:layout_alignParentTop="true"
        android:layout_marginTop="28dp" />

    <Button
        android:id="@+id/exit"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_alignBaseline="@+id/run"
        android:layout_alignBottom="@+id/run"
        android:layout_marginLeft="30dp"
        android:layout_toRightOf="@+id/run"
        android:text="EXIT" />

    <Button
        android:id="@+id/run"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_alignLeft="@+id/personView"
        android:layout_below="@+id/personView"
        android:layout_marginLeft="31dp"
        android:layout_marginTop="22dp"
        android:text="RUN" />

</RelativeLayout>
package com.zuoshaohua;

import com.zuoshaohua.ndk.ManPerson;
import com.zuoshaohua.ndk.NativeExec;
import com.zuoshaohua.ndk.Person;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener{
    private Button runbtn;
    private Button exitbtn;
    private ManPerson manPerson;
    private TextView  personView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       exitbtn = (Button) this.findViewById(R.id.exit);
       runbtn = (Button) this.findViewById(R.id.run);
       personView = (TextView) this.findViewById(R.id.personView);
       manPerson = new ManPerson("zuoshaohua",33,"男");
       runbtn.setOnClickListener(MainActivity.this);
       exitbtn.setOnClickListener(this);
    } 

	@Override
	public void onClick(View arg0) {
		int id = arg0.getId();
		switch (id) {
		case R.id.run:
			Person p = (Person)NativeExec.nativeExec();   //获取c代码生成对象.
			personView.setText("name ="+ p.getName()+ "age="+p.getAge()+"gender="+p.getGender()); //输出这个对象的值.
			break;
		case R.id.exit:
			this.finish();
			break;
		default:
			this.finish();
			break;
		}
	}
}
 --2.4 jni代码
package com.zuoshaohua.ndk;

public class ManPerson {

	private String name;
	private int age;
	private String gender;

	static
	{
		System.loadLibrary("HelloNdk");         //加载动态库文件.
	}

	public ManPerson(String name, int age, String gender){
		this.name = name;
		this.age = age;
		this.gender =gender;
		nativeSetup();
	}

	private native void nativeSetup();
}
package com.zuoshaohua.ndk;

public class NativeExec {
	public static native Object nativeExec();
}
package com.zuoshaohua.ndk;

public class Person {
	private String name;
	private int age;
	private String gender;

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}

	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}

}
--2.5 c层代码
#include "com_zuoshaohua_ndk_ManPerson.h"
#include "com_zuoshaohua_ndk_NativeExec.h"
/*
 * Class:     com_zuoshaohua_ndk_ManPerson
 * Method:    nativeSetup
 * Signature: ()V
 */

jobject m_obj, p_obj;
jfieldID name_id,age_id,gender_id;

jmethodID pname_mid,page_mid,pgender_mid;

JNIEXPORT void JNICALL Java_com_zuoshaohua_ndk_ManPerson_nativeSetup
  (JNIEnv *env, jobject this)
{		

#if 1

	jclass clz = (*env)->GetObjectClass(env,this);   //通过ManPerson的对象获取ManPerson字节码对象.

	m_obj = (*env)->NewGlobalRef(env,this);       //将这个对象设置为全局引用.
 
	name_id = (*env)->GetFieldID(env,clz,"name","Ljava/lang/Object;"); //获取ManPerson对象的属性.	

    age_id = (*env)->GetFieldID(env,clz,"age","I");

    gender_id = (*env)->GetFieldID(env,clz,"gender","Ljava/lang/Object;");		

	jclass personclz = (*env)->FindClass(env,"com/zuoshaohua/ndk/Person"); //通过FindClass方法获取Person类的字节码对象.

	jmethodID  constr =(*env)->GetMethodID(env,personclz,"<init>", "()V"); //获取这个对象无参的构造函数.

	jobject ref = (*env)->NewObject(env,personclz,constr);           //生成Person对象.

	p_obj = (*env)->NewGlobalRef(env, ref);                    //将Person对象设置为全局引用.

	pname_mid = (*env)->GetMethodID(env,personclz,"setName","(Ljava/lang/Object;)V"); //获取Person的Setxxx()方法的ID.

    page_mid = (*env)->GetMethodID(env,personclz,"setAge", "(I)V"); 

   pgender_mid = (*env)->GetMethodID(env,personclz,"setGender","(Ljava/lang/Object;)V");
#endif
}

/*
 * Class:     com_zuoshaohua_ndk_NativeExec
 * Method:    nativeExec
 * Signature: ()Ljava/lang/Object;
 */
JNIEXPORT jobject JNICALL Java_com_zuoshaohua_ndk_NativeExec_nativeExec
  (JNIEnv *env, jclass this)
{
#if 1
	jint age = 0;
	jstring name,gender;

	name = (*env)->GetObjectField(env,m_obj,name_id);         //获取ManPerson属性的值.
	gender = (*env)->GetObjectField(env,m_obj,gender_id);
	age = (*env)->GetIntField(env,m_obj,age_id);

	(*env)->CallVoidMethod(env, p_obj,pname_mid,name);	 //调用Person的Setxxx()方法给Person对象赋值.
	(*env)->CallVoidMethod(env, p_obj,page_mid,age);
	(*env)->CallVoidMethod(env, p_obj,pgender_mid,gender);
	//(*env)->SetIntField(env,p_obj,age_id,10);         //返回Person对象.
	return p_obj;
#endif
}

转载请注明出处: http://blog.csdn.net/shaohuazuo/article/details/42932813

3.3 java反射相关模块

jmethodID (JNICALL *FromReflectedMethod)(JNIEnv *env, jobject method);

jfieldID (JNICALL *FromReflectedField) (JNIEnv *env, jobject field);

jobject (JNICALL *ToReflectedMethod)(JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic);

jobject (JNICALL *ToReflectedField) (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic);

函数背景知识介绍: 请看博客(Java反射机制)  

java.lang.reflect:

提供类和接口,以获得关于类和对象的反射信息。在安全限制内,

反射允许编程访问关于加载类的字段、方法和构造方法的信息,

并允许使用反射字段、方法和构造方法对其底层对等项进行操作。

更多相关知识可以参考http://www.javaweb.cc/help/JavaAPI1.6/

也可以进入博客:?????????????

一:FromReflectedMethod

函数原型: jmethodID (JNICALL *FromReflectedMethod)(JNIEnv *env, jobject method);

 描 述: 通过java.lang.reflect中Method类的对象获取一个函数的MethodID.
就可以调用Java中某个方法.

 参 数: env    java native interface porint,(java本地接口指针)

    method    这个是jva.lang.reflect.Method对象.

要获取Method对象第一步.需要获取Class对象.再通过Class对象获取Method.

1.获取Class对象的三种方法是:

        1.1)
类名.class,例如 Class pclass =  Person.class

        1.2) 对象.getClass(),例如,Class  pclass = new Person().getClass()

        1.3) Class.forName(“类名”),例如,Class pclass = Class.forName(“com.zuoshaohua.Person”);

2.获取Method对象,详细方法介绍可以参考http://www.javaweb.cc/help/JavaAPI1.6/手册

2.1)Class.getMethods(),

2.2)Class.getMethod(String,
Class[])
,

2.3)Class.getDeclaredMethods(),

     2.4)Class.getDeclaredMethod(String,
Class[])

1.5) ToReflectedMethod()通过C中的JNI标准获取Methdod对象.

返回值:返回一个方法的MethodID指针.

二:FromReflectedField

函数原型: jfieldID (JNICALL *FromReflectedField) (JNIEnv *env, jobject field);

 描 述:通过java.lang.reflect中Field类的对象获取字段对象.可以获取这个字段的jfieldID了.

 参 数:  env  
java native interface porint,(java本地接口指针)

field   Field对象,这个对象主要用来描述java中的字段信息.通过这个类对象.我们可以获得

          这个字段的名称,类型等等信息.

     
1.获取这个对象由如下5种方法:

1.1)Class.getDeclaredField(String name);

返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。

1.2)Class.getDeclaredFields();

返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。

1.3)Class.getField(String name);

返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。

1.4)Class.getField();

返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。 

1.6)ToReflectedFile()

通过C中JNI标准中提供的上面的函数,也可以获取Field对象.

返回值:返回一个字段的jfieldID指针.

三:ToReflectedMethod

函数原型: jobject (JNICALL *ToReflectedMethod)(JNIEnv *env, jclass cls, jmethodID methodID,
jboolean isStatic);

 描 述: 这个方法是通过方法的methodId返回一个java.lang.reflect.Method对象,是FromReflectedMethod的反操作.

参 数: env      java
native interface porint,(java本地接口指针)

cls       该方法的类对象.可以通过FindClass()获取.如果知道对象的话可以使用GetObjectClass()来获取这个jclass对象.

methodID      
这个对象是jmethodID指针.可以通过GetMethodID方法获取.

 isStatic     该方法是不是静态的,JNI标准中提供了两个宏表示.JNI_FALSE,和JNI_TRUE.

返回值:返回一个Method对象.也就是说再FromReflectedMethod
中多了一种方法可以获取Method对象的方法.

四:ToReflectedField

函数原型: jobject (JNICALL *ToReflectedField) (JNIEnv *env, jclass cls, jfieldID fieldID,
jboolean isStatic);

 描 述: 通过filedID可以返回一个java.lang.reflect.Field对象.

 参 数: env java
native interface porint,(java本地接口指针)

cls  该方法的类对象.可以通过FindClass()获取.如果知道对象的话可以使用GetObjectClass()来获取这个jclass对象.

methodID 
这个对象是jField指针.可以通过GetFieldID方法获取.

isStatic 
该方法是不是静态的,JNI标准中提供了两个宏表示.JNI_FALSE,和JNI_TRUE.

返回值: 返回一个Field对象.

五:例程

  1.1 流程     

   1. 定义一个Person类.这个Person类三个属性.name, age, gender.还有getxxx()和setxxx()方法.

2. 定义一个Android的界面.它的MainActivity类关联了一个Person对象.也就是,Person类是Activity的一个属性.

3. 在MainActivity中,静态初始化这个Person对象.我们使用该静态对象.p.getClass()获取类Class对象clz. 

4. 我们需要获取这个Class中的Method对象和Field对象.clz.getMethod(); clz.getField对象.

     通过 ReflectMethodDeom本地方法和ReflectFieldDemo本地方法传入到C层.

   5. c通过这两个对象获取到对象的jfieldID对象和jmethodID.并进行相应的操作.

  1.2    类图

  1.3   代码  

   1. MainActivity代码

package com.zuoshaohua.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener {
	private static Person  p = new Person("zuoshaohua",33,"男");
	private Button runBtn;
	private Button exitBtn;
	TextView textView;
	static {
	    System.loadLibrary("reflect");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {

    	super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        runBtn  = (Button)this.findViewById(R.id.run);
        exitBtn = (Button)this.findViewById(R.id.exit);
        textView = (TextView)this.findViewById(R.id.personView);

        this.runBtn.setOnClickListener(this);
        this.exitBtn.setOnClickListener(this);

    }

    private void refelectTest(){
    	Class<? extends Person> c =  p.getClass();
    	try {

    		StringBuffer sb = new StringBuffer();

    		Method method = c.getMethod("setAge", int.class);

    		//Field field = c.getField("age");

    		Field field = c.getDeclaredField("age");
    		sb.append("oldName ="+p.getName()+"oldAge="+p.getAge()+ "oldGender="+p.getGender()+"\n");

		    Field field1 = ReflectFieldDemo(p,field);   //调用本地方法.将描述age字段的Field对象传进去.

		    //field1.set(p, "shaohuazuo");

		    Method m1 = ReflectMethodDemo(p,method);    //调用本地方法.将描述setAge()方法的Method对象传入到C层代码.

		    sb.append("oldName1 ="+p.getName()+"oldAge1="+p.getAge()+ "oldGender1="+p.getGender()+"\n");

		    Object args[] = new Object[1];

			args[0] = new  String("shaohuazuo");

			m1.invoke(p, args);                         //调用返回的方法.

			field1.setAccessible(true);

		    String name =(String)field1.get(p);

		    sb.append("newName ="+name+"newAge="+p.getAge()+"newGender="+p.getGender());

		    textView.setText(sb.toString());    

		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    private  static native Field ReflectFieldDemo(Person p,Field f);
    private  static native Method ReflectMethodDemo(Person p, Method m);

	@Override
	public void onClick(View arg0) {
		// TODO Auto-generated method stub
		switch(arg0.getId())
		{
		case R.id.run:
			refelectTest();
			break;
		case R.id.exit:
			this.finish();
			break;
			default:
				this.finish();
				break;
		}
	}
}

2. Person.java代码

package com.zuoshaohua.reflect;

public class Person {

	private String name;
	private int age;
	private String gender;

	public Person(String string, int age, String gender) {
		this.name = name;
		this.age = age;
		this.gender = gender;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}	

}

3. 生成.h头文件.

[email protected]:~/work/android/jni/Reflect/jni$

javah -o reflect.h -classpath ../bin/classes com.zuoshaohua.reflect.MainActivity

4. reflect.h代码

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_zuoshaohua_reflect_MainActivity */

#ifndef _Included_com_zuoshaohua_reflect_MainActivity
#define _Included_com_zuoshaohua_reflect_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_zuoshaohua_reflect_MainActivity
 * Method:    ReflectFieldDemo
 * Signature: (Lcom/zuoshaohua/reflect/Person;Ljava/lang/reflect/Field;)Ljava/lang/reflect/Field;
 */
JNIEXPORT jobject JNICALL Java_com_zuoshaohua_reflect_MainActivity_ReflectFieldDemo
  (JNIEnv *, jclass, jobject, jobject);

/*
 * Class:     com_zuoshaohua_reflect_MainActivity
 * Method:    ReflectMethodDemo
 * Signature: (Lcom/zuoshaohua/reflect/Person;Ljava/lang/reflect/Method;)Ljava/lang/reflect/Method;
 */
JNIEXPORT jobject JNICALL Java_com_zuoshaohua_reflect_MainActivity_ReflectMethodDemo
  (JNIEnv *, jclass, jobject, jobject);

#ifdef __cplusplus
}
#endif
#endif

5. reflect.c代码

#include "reflect.h"
#include <android/log.h>
#include <stdio.h>

#if 0

jmethodID (JNICALL *FromReflectedMethod) (JNIEnv *env, jobject method);
jfieldID (JNICALL *FromReflectedField) (JNIEnv *env, jobject field);

jobject (JNICALL *ToReflectedMethod) (JNIEnv *env, jclass cls, jmethodID methodID, jboolean isStatic);

jobject (JNICALL *ToReflectedField) (JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic);

#endif
jclass clazz;
/*
 * Class:     com_zuoshaohua_reflect_MainActivity
 * Method:    ReflectFieldDemo
 * Signature: (Lcom/zuoshaohua/reflect/Person;Ljava/lang/reflect/Field;)Ljava/lang/reflect/Field;
 */

JNIEXPORT jobject JNICALL Java_com_zuoshaohua_reflect_MainActivity_ReflectFieldDemo
  (JNIEnv * env, jclass this, jobject pthis, jobject fthis)
{
	jint age =0;
	jclass clz =(*env)->GetObjectClass(env,pthis);     //通过Person对象获取他的Class对象信息,从而得到一个jclass对象.

	jfieldID age_id = (*env)->FromReflectedField(env,fthis); //通过Field对象获取Person属性的jfieldID指针.

	age = (*env)->GetIntField(env,pthis,age_id);               //通过这个对象和age_id获取这个属性的值.

	__android_log_print(ANDROID_LOG_INFO, "ReFlectFieldDemo", "age: %d", age);

	jfieldID name_id = (*env)->GetFieldID(env,clz,"name","Ljava/lang/String;");  //获取name字段的jfieldID.

    __android_log_print(ANDROID_LOG_INFO, "ReFlectFieldDemo", "end!!!!!");

	return (*env)->ToReflectedField(env,clz,name_id,JNI_FALSE);    //通过jfieldID生成一个Java的Field对象.并返回.

}

/*
 * Class:     com_zuoshaohua_reflect_MainActivity
 * Method:    ReflectMethodDemo
 * Signature: (Lcom/zuoshaohua/reflect/Person;Ljava/lang/reflect/Method;)Ljava/lang/reflect/Method;
 */
JNIEXPORT jobject JNICALL Java_com_zuoshaohua_reflect_MainActivity_ReflectMethodDemo
  (JNIEnv *env , jclass this, jobject pthis, jobject mthis)
{
	//我们使用mthis.来获取jmethodID指针.并通过该指针调用到set方法.来改变Person属性的值.
	jclass pclazz = (*env)->GetObjectClass(env,pthis); 

	jmethodID setAgeId = (*env)->FromReflectedMethod(env,mthis); 

	(*env) ->CallVoidMethod(env,pthis,setAgeId,100);  

	__android_log_print(ANDROID_LOG_INFO,"ReflectMethodDemo","is callVoidMethod Done!!!!\n"); 

	jmethodID setName_id = (*env)->GetMethodID(env,pclazz,"setName","(Ljava/lang/String;)V"); 

	return (*env)->ToReflectedMethod(env, pclazz,setName_id, JNI_FALSE);
}

6. Android.mk代码

  SRC_PATH_ROOT:=$(LOCAL_PATH)/../../src
  LOCAL_PATH := $(call my-dir)

  include $(CLEAR_VARS)

  LOCAL_MODULE    := reflect
  LOCAL_SRC_FILES := reflect.c
  LOCAL_LDLIBS := -llog
  #LOCAL_SHARED_LIBRARIES :=libc
  include $(BUILD_SHARED_LIBRARY)
  1.4  测试结果

转载请注明出处: http://blog.csdn.net/shaohuazuo/article/details/42932813

时间: 2024-10-10 05:10:18

jni.h头文件详解(二)的相关文章

jni.h头文件详解二

作者:左少华 博客:http://blog.csdn.net/shaohuazuo/article/details/42932813 转载请注明出处:http://blog.csdn.net/shaohuazuo 一:struct JNINativeInterface_{} 结构体的作用:它有点像我们char字符驱动的 file_ops结构体,它定义各种函数对在(jni.h头文件详解一)中定义的各种数据的操作函数集体. 二:它包含那些针对Java中类和对象的相关操作呢如下图. 三:下面我们讲详细

单片机reg51.h头文件详解(1)

51单片机头文件reg51.h详解 我们在用c语言编程时往往第一行就是头文件,51单片机为reg51.h或reg52.h,51单片机相对来说比较简单,头文件里面内容不多,像飞思卡尔.ARM系列的单片机头文件往往内容就非常多,尽管如此,对一些初次接触单片机的朋友来说,51的头文件还是搞不太清楚,今天具体来说明一下.       1)"文件包含"处理概念 所谓"文件包含"是指在一个文件内将另外一个文件的内容全部包含进来.因为被包含的文件中的一些定义和命令使用的频率很高,

jni.h头文件学习笔记

Now :2015年 6月 8日 星期一 22时17分05秒 CST Note: 这篇笔记是我半年前写的,当时因为某些原因经常需要写jni方面的代码,所以就深入学习了下jni方面的知识,现在再来看之前写的东西,一句话概括就是深度不够,废话太多.因为这是一个不全的笔记(还有一部分想写的内容未能写上),所以当初想分享给其他同事的也不好意思分享. #-------------Add Now-------------# jni是java native interface的简写,是java和c/c++通信

【笔记, 转载】 linux常用头文件详解

转自: http://blog.chinaunix.net/uid-26495963-id-3142054.html 感谢原作者的无私与奉献! 一. C/C++头文件一览 C #include <assert.h> //设定插入点 #include <ctype.h> //字符处理 #include <errno.h> //定义错误码 #include <float.h> //浮点数处理 #include <iso646.h>        //

linux常用头文件详解

POSIX标准定义的头文件 <dirent.h>        目录项 <fcntl.h>         文件控制 <fnmatch.h>    文件名匹配类型 <glob.h>    路径名模式匹配类型 <grp.h>        组文件 <netdb.h>    网络数据库操作 <pwd.h>        口令文件 <regex.h>    正则表达式 <tar.h>        TAR

ios多线程之NSThread头文件详解

1.NSThread 头文件中的相关方法 //获取当前线程 +(NSThread *)currentThread; //创建线程后自动启动线程 + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument; //是否是多线程 + (BOOL)isMultiThreaded; //线程字典 - (NSMutableDictionary *)threadDictionary; //线

JNI头文件详解(三)对象操作

JNI 中Java对象操作: 对象操作相关函数: (AllocObject,NewObject,NewObjectA,NewObjectV,GetObjectRefType,IsInstanceOf,IsSameObject) 1.对比函数特性. 1.1  AllocObject 函数和NewObject,NewObjectA,NewObjectV,之间的区别, 共同点 不同点:   AllocObject不需要调用如何构造函数产生一个Java对象.而NewObject,NewObjectA,N

Android清单文件详解(二) ---- 应用程序权限声明

我们知道,Android系统的各个模块提供了非常强大的功能(比如电话,电源和设置等),通过使用这些功能,应用程序可以表现的更强大,更灵活.不过,使用这些功能并不是无条件的,而是需要拥有一些权限.接下来,我们就开始讲解另一个非常重要的知识点--应用程序权限声明,其中主要包括应用程序的权限声明,自定义应用程序的访问权限和SDK版本限定. 1.<uses-permission>--应用程序的权限申请 权限 描述 android.permission.ACCESS_NETWORK_STATE 允许应用

MyBatis之Mapper XML 文件详解(二)-sql和入参

sql 这个元素可以被用来定义可重用的 SQL 代码段,可以包含在其他语句中.它可以被静态地(在加载参数) 参数化. 不同的属性值通过包含的实例变化. 比如: <sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql> 这个 SQL 片段可以被包含在其他语句中,例如: <select id="selectUsers" resultType=&