
编译HelloWorld类
1 public class HelloWorld {
2 public native void displayHelloWorld();
3
4 public native void printxx(String str);
5
6 static {
7 SystemloadLibrary("hello");
8 // Systemload("hello");
9 }
10
11 public static void main(String[] args) {
12 HelloWorld hw = new HelloWorld();
13 hwdisplayHelloWorld();
14 for (int i = 0;; ++i) {
15 hw
16 printxx("wo kaowo kaowo kaowo kaowo kaowo kaowo kaowo kaowo kaowo kaowo kao");
17 if (i % 1000 == 0) {
18 try {
19 Threadsleep(10);
20 } catch (InterruptedException e) {
21 }
22 }
23 }
24 }
25 }
对编译完的class执行
javah HelloWorld
1 / DO NOT EDIT THIS FILE - it is machine generated /
2 #include jnih
3 / Header for class HelloWorld /
4
5 #ifndef _Included_HelloWorld
6 #define _Included_HelloWorld
7 #ifdef __cplusplus
8 extern "C" {
9 #endif
10 /
11 Class: HelloWorld
12 Method: displayHelloWorld
13 Signature: ()V
14 /
15 JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld
16 (JNIEnv , jobject);
17
18 /
19 Class: HelloWorld
20 Method: printxx
21 Signature: (Ljava/lang/String;)V
22 /
23 JNIEXPORT void JNICALL Java_HelloWorld_printxx
24 (JNIEnv , jobject, jstring);
25
26 #ifdef __cplusplus
27 }
28 #endif
29 #endif
30
编译
cl -I%java_home%include -I%java_home%includewin32 -LDHelloWorldc -Fehellodll
1 #include jnih
2 #include "HelloWorldh"
3 #include stdioh
4 JNIEXPORT void JNICALL Java_HelloWorld_displayHelloWorld(JNIEnv env, jobject obj)
5 {
6 printf("Hello world! ");
7 return;
8 }
9
10 JNIEXPORT void JNICALL Java_HelloWorld_printxx
11 (JNIEnv env, jobject obj, jstring prompt){
12
13 const char str = (env)-GetStringUTFChars(env, prompt, 0);
14 printf("%s",prompt);
15 (env)-ReleaseStringUTFChars(env, prompt, str);
16
17 return;
18 }
19
20
3Java类型和本地类型对应
在如下情况下,需要在本地方法中应用java对象的引用,就会用到类型之间的转换:
1)java方法里面将参数传入本地方法;
2)在本地方法里面创建java对象;
3)在本地方法里面return结果给java程序。
分为如下两种情况:
Java原始类型
像booleans、integers、floats等从Java程序中传到本地方法中的原始类型可以直接使用,下面是java中的原始类型和本地方法中的类型的对应:
Java类型
本地类型
字节(bit)
boolean
jboolean
8, unsigned
byte
jbyte
8
char
jchar
16, unsigned
short
jshort
16
int
jint
32
long
jlong
64
float
jfloat
32
double
jdouble
64
void
void
n/a
也就是说如果我在方法中传进去了一个boolean的参数的话,那么我在本地方法中就有jboolean类型与之对应。同理,如果在本地方法中return一个jint的话,那么在java中就返回一个int类型。 中国网管论坛
Java对象
Java对象做为引用被传递到本地方法中,所有这些Java对象的引用都有一个共同的父类型jobject(相当于java中的Object类是所有类的父类一样)。下面是JNI实现的一些jobject的子类:
4本地方法中访问java程序中的内容
1)访问String对象:
#p#副标题#e#
从java程序中传过去的String对象在本地方法中对应的是jstring类型,jstring类型和c中的char不同,所以如果你直接当做char使用的话,就会出错。因此在使用之前需要将jstring转换成为c/c++中的char,这里使用JNIEnv的方法转换。下面是一个例子:
代码3:
JNIEXPORT jstring JNICALL Java_Prompt_getLine
(JNIEnv env, jobject obj, jstring prompt)
{
char buf[128];
const char str = (env)-GetStringUTFChars(env, prompt, 0);
printf("%s", str);
(env)-ReleaseStringUTFChars(env, prompt, str);
这里使用GetStringUTFChars方法将传进来的prompt(jstring类型)转换成为UTF-8的格式,就能够在本地方法中使用了。
注意:在使用完你所转换之后的对象之后,需要显示调用ReleaseStringUTFChars方法,让JVM释放转换成UTF-8的string的对象的空间,如果不显示的调用的话,JVM中会一直保存该对象,不会被垃圾回收器回收,因此就会导致内存溢出。
下面是访问String的一些方法:
GetStringUTFChars将jstring转换成为UTF-8格式的char
GetStringChars将jstring转换成为Unicode格式的char
ReleaseStringUTFChars释放指向UTF-8格式的char的指针
ReleaseStringChars释放指向Unicode格式的char的指针
NewStringUTF创建一个UTF-8格式的String对象
NewString创建一个Unicode格式的String对象
GetStringUTFLengt获取UTF-8格式的char的长度
GetStringLength获取Unicode格式的char的长度
2) 访问Array对象:
和String对象一样,在本地方法中不能直接访问jarray对象,而是使用JNIEnv指针指向的一些方法来是用。
访问Java原始类型数组:
1)获取数组的长度:
代码4:
JNIEXPORT jint JNICALL Java_IntArray_sumArray
(JNIEnv env, jobject obj, jintArray arr)
{
int i, sum = 0;
jsize len = (env)-GetArrayLength(env, arr);
如代码4所示,这里获取数组的长度和普通的c语言中的获取数组长度不一样,这里使用JNIEvn的一个函数GetArrayLength。
bitsCN_com
2)获取一个指向数组元素的指针:
代码4:
jint body = (env)-GetIntArrayElements(env, arr, 0);
使用GetIntArrayElements方法获取指向arr数组元素的指针,注意该函数的参数,第一个是JNIEnv,第二个是数组,第三个是数组里面第三个是数组里面开始的元素
3)使用指针取出Array中的元素
代码5:
for (i=0; ilen; i++) {
sum += body[i];
}
这里使用就和普通的c中的数组使用没有什么不同了
4)释放数组元素的引用
代码6:
(env)-ReleaseIntArrayElements(env, arr, body, 0);
和 *** 作String中的释放String的引用是一样的,提醒JVM回收arr数组元素的引用。
这里举的例子是使用int数组的,同样还有boolean、float等对应的数组。
获取数组元素指针的对应关系:
函数
数组类型
GetBooleanArrayElements
boolean
GetByteArrayElements
byte
GetCharArrayElements
char 中国网管博客
GetShortArrayElements
short
GetIntArrayElements
int
GetLongArrayElements
long
GetFloatArrayElements
float
GetDoubleArrayElements
double
释放数组元素指针的对应关系:
Function
Array Type
ReleaseBooleanArrayElements
boolean
ReleaseByteArrayElements
byte
ReleaseCharArrayElements
char
ReleaseShortArrayElements
short
ReleaseIntArrayElements
int
ReleaseLongArrayElements
long
ReleaseFloatArrayElements
float
ReleaseDoubleArrayElements
double
访问自定义Java对象数组
The JNI provides a separate set of functions to access elements of object arrays You can use these functions to get and set individual object array elements
Note: You cannot get all the object array elements at once
GetObjectArrayElement returns the object element at a given index
www_bitscn_com
SetObjectArrayElement updates the object element at a given index
3) 访问Java对象的方法:
在本地方法中调用Java对象的方法的步骤:
①。获取你需要访问的Java对象的类:
jclass cls = (env)-GetObjectClass(env, obj);
使用GetObjectClass方法获取obj对应的jclass。
②。获取MethodID:
jmethodID mid = (env)-GetMethodID(env, cls, "callback", "(I)V");
使用GetMethdoID方法获取你要使用的方法的MethdoID。其参数的意义:
envJNIEnv
cls第一步获取的jclass
"callback"要调用的方法名
"(I)V"方法的Signature
③。调用方法:
(env)-CallVoidMethod(env, obj, mid, depth);
使用CallVoidMethod方法调用方法。参数的意义:
envJNIEnv
#p#副标题#e#
obj通过本地方法穿过来的jobject
mid要调用的MethodID(即第二步获得的MethodID)
depth方法需要的参数(对应方法的需求,添加相应的参数) 中国网管博客
注:这里使用的是CallVoidMethod方法调用,因为没有返回值,如果有返回值的话使用对应的方法,在后面会提到。
方法的Signature
方法的Signature是由方法的参数和返回值的类型共同构成的,下面是他们的结构:
"(argument-types)return-type"
其中Java程序中参数类型和其对应的值如下:
Signature
Java中的类型
Z
boolean
B
byte
C
char
S
short
I
int
J
long
F
float
D
double
L fully-qualified-class;
fully-qualified-class
[ type
type[]
( arg-types ) ret-type
method type
一个Java类的方法的Signature可以通过javap命令获取:
javap -s -p Java类名
给调用的函数传参数:
通常我们直接在methodID后面将要传的参数添加在后面,但是还有其他的方法也可以传参数:
CallVoidMethodV可以获取一个数量可变的列表作为参数; www_bitscn_com
CallVoidMethodA可以获取一个union。
调用静态方法:
就是将第二步和第三步调用的方法改为对应的:
GetStaticMethodID获取对应的静态方法的ID
CallStaticIntMethod调用静态方法
调用超类的方法:
用的比较少,自己看啦。^_^。
4)访问Java对象的属性:
访问Java对象的属性和访问Java对象的方法基本上一样,只需要将函数里面的Method改为Field即可
#p#副标题#e#
C++通过java反射得到,java赋值以后,用c++获取那个变量的指针,然后根据指针取值,java中还是有引用类型,加上强制转换,C++中是有个默认的处理方法,传值给它,它如果需要boolean类型,就会把那个值转换成boolean类型。
引用参数是由调用部位传入实参的地址(写在留言板上)的形参。
在形参表中以符号“&”开始的参数即为引用参数。如果一个形参是引用参数,调用部位将把实参的地址传递给子程序。子程序可以改变传递给引用参数的任何实参,因为子程序 *** 作的是真正的变量,而不是它的副本。
把参数声明成引用,实际上改变了缺省的按值传递参数的传递机制,在按值传递时,函数 *** 纵的是实参的本地拷贝。
Systemarraycopy()
函数原型:public
static
void
arraycopy(Object
src,
int
srcPos,
Object
dest,
int
destPos,
int
length)
src:源数组;
srcPos:源数组要复制的起始位置;
dest:目的数组;
destPos:目的数组放置的起始位置;
length:复制的长度。
包含有对象类型的数组。无论可变还是不可变,通过copy,mutableCopy都不能将数组内的model完全copy一份,虽然得到的数组是新的,但数组中model的指针指向的还是之前的model。此时,如果改变了数组中model的值,原数组会受到影响。
如果对象是单层的(没有嵌套的模型),此时,model遵循NSCopying,NSMutableCopying协议,实现copyWithZone和mutableCopyWithZone方法。
Array通过 initWithArray:copyItems: 方法可以得到一个完全拷贝过的数组(数组内的model也是全新的model)。
如果数组内的model有嵌套,例如
可以看出,改动B数组中的firstObject,A中的name没有跟着改变,但A中的gender发生了变化。
接下来再试一下,gender类也遵循NSCopying,NSMutableCopying协议。看下是什么效果。
如上图所示,依然不能满足要求。
此时。需要你在copyWithZone方法中,new一个新的Gender对象(newGender),将person的gender各个属性的值,手动赋值给这个newGender。再将newGender赋值给person。
其实,person遵循NSCopying协议,系统会帮你去调用copyWithZone,但是copyWithZon具体的实现,还是你自己决定的。就相当于自己手动new了一个新对象,然后赋值,最后把这个新对象return出来。 跟你自己在工具类中,写一个model间数据转化的方法是一个道理。
将A数组序列化为一个Data,再将Data解归档为一个新的数组。此时的数组就是一个全新的数组。
person和gender类都需要遵循NSCoding协议,实现initWithCoder 和 encodeWithCoder方法。
再试一次, bingo!
在Objective-C中如果想将一个数组赋值给另外一个数组,同时想让两个数组之间相互独立(即改变其中的一个数组,不影响另外的一个),有很多的办法,比如我们可以直接copy,用类方法创建新数组。这样得到的数组和原来的数组就是两个完全独立的数组了,即使数组中的元素是对象。
在swift中情况和Objective-C中稍有不同,根据官方文档的介绍
即,如果数组中的元素是整形,字符串,结构体等简单数据类型,那么当你将一个数组赋值给另外的数组时,数组中的元素会被拷贝一份,两个数组中的元素相互独立。
而如果数组中的元素是类的实例,那么会有些不同
即,当数组的元素是类的实例时,简单的将一个数组赋值给另外的数组后,由于两个数组中元素所引用的对象相同,当你改变其中一个数组中元素的属性时,另外的数组中同样引用的元素对应的属性也会随之改变,除非数组中的元素只想不同的类的实例
由于这样的特性就会产生一些问题,比如从页面1中将一个含有特定类实例的数组传递给第二个页面,在第二个页面中对这个数组中的某些元素的属性进行了更改,那么就会影响到第一个页面的对应数组中的该元素,常见的场景就是含有model的数组的传递。
根据官方文档介绍由于swift加强了结构体的功能,同时数组中元素如果是结构体的话,会自动进行拷贝(前面说过),所以遇到这种情况如果可以用结构体的话就不要用类(但是结构体有时确实很不方便呀,不太习惯创建model的时候用结构题呀)。
在Model类中遵守Coping协议,同时实现对应的方法,具体如下:
这样Model的实例就可以调用copy方法来拷贝一个新的对象了,如果对于数组来说就这样:
在copyPlantsArr中就是拷贝后的新的数组,两个数组之间相互独立(办法有点麻烦😭),也可以将上一步替换为给数组增加扩展(这个没有亲自试过)
上面就是我找到swift中实现数组的深拷贝的办法了,总感觉有点麻烦,希望有知道更简单,好用办法的兄弟给我留言,谢谢。
希望我的文章对你有帮助,努力,坚持,与君共勉。
深拷贝的三种实现方式如下:
1、使用递归的方式实现深拷贝
//使用递归的方式实现数组、对象的深拷贝functiondeepClone1(obj){
//判断拷贝的要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝
varobjClone=Array、isArray(obj)?[]:{};
//进行深拷贝的不能为空,并且是对象或者是
if(obj&&typeofobj==="object"){
for(keyinobj){
if(obj、hasOwnProperty(key)){
if(obj[key]&&typeofobj[key]==="object"){
objClone[key]=deepClone1(obj[key]);
2、通过JSON对象实现深拷贝
//通过js的内置对象JSON来进行数组对象的深拷贝
functiondeepClone2(obj){
var_obj=JSON、stringify(obj),
objClone=JSON、parse(_obj);
returnobjClone;
}JSON对象实现深拷贝的一些问题
3、通过jQuery的extend方法实现深拷贝
vararray=[1,2,3,4];
varnewArray=$、extend(true,[],array);
构造函数
在C++面向对象程序设计中,通过构造函数对对象进行初始化,它可以为对象在计算机内存中开辟内存空间,也可以为对象的数据成员提供初始值。构造函数是一个与类同名,没有返回值的特殊成员函数,每当创建一个对象时(包括使用new动态创建对象),编译系统就会自动调用构造函数。
构造函数象类以外的一般函数和类成员函数一样可以重载和带缺省参数,构造函数的重载为对象的生成提供了各种灵活的手段。
构造函数分为缺省构造函数(默认构造函数)和用户自定义构造函数。当程序员没有定义构造函数时,系统会提供一个无参的缺省构造函数。如果用户自定义了一个构造函数,编译器提供的缺省构造函数就自动消失了。
#include<stdioh>
#include<stdlibh>
#define MAX_COL 3
#define MAX_ROW 4
void print(int p,int iRow,int iCol)
{
int iR,iC;
printf("\n");
for(iR=0;iR<iRow;iR++)
{
for(iC=0;iC<iCol;iC++)
{
printf("%d\t",p);
p++;
}
printf("\n");
}
}
void copy(int pd,int ps,int iSize)
{
int i;
for(i=0;i<iSize;i++)pd++=ps++;
}
void main()
{
int s1[MAX_ROW][MAX_COL],s2[MAX_ROW][MAX_COL];
int i,p;
p=(int )s1;
for(i=0;i<MAX_COLMAX_ROW;i++)p++=rand();
print((int )s1,MAX_ROW,MAX_COL);
copy((int )s2,(int )s1,MAX_ROWMAX_COL);
print((int )s2,MAX_ROW,MAX_COL);
}
xoaxa兄也不错,提醒楼主,使用指针是可以考结构体的,要是你老实巴交的写,非累死不可。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)