JNI - Passagem por Referência

Bom dia galera!

Nesta última semana estou estudando o tempo todo Java -> DLL JNI -> DLL. Fiz muitos progressos. Estou conseguindo passar parâmetros e receber retorno de funções da DLL.

Só que nem tudo são flores…

Na minha DLL tem um método com a seguinte assinatura:

EXPORT void swap(int*, int*);

Como vcs podem ver as duas variáveis são passadas por referência. Essa função faz o seguinte:

int a =3; int b=2;
printf("antes da troca a=%d b=%d",a,b); //antes da troca a=3 b=2
swap(a,b);
printf("depois da troca a=%d b=%d",a,b); //antes da troca a=2 b=3

Agora vem o problema:

A assinatura do meu método em Java é:

public native void swap(int a, int b);

E sabendo que valores primitivos são passados por valor, como faço para obter o mesmo comportamento que obtenho em C++?

Obs: Já troquei a assinatura por swap(Integer a, Integer b) e simplesmente não houve a troca, ou seja, o JNI passou a cópia do valor e não da referência.

Não se assuste, mas você vai precisar usar:

public native void swap(int[] a, int[] b);

C não possui passagem por referência, é sempre por valor. Apenas permite o uso de ponteiros para qualquer variavel.

A resposta mais simples para você é: se não consegue fazer um swap de duas variáveis int em Java puro, não vai conseguir fazer usando JNI. Java não é C# e não admite parâmetros por referência. Mesmo em C# a passagem de parâmetros por referência é a exceção, em vez da regra, e requer o uso da palavra-chave “ref”, tanto na declaração quanto na chamada do método.

De qualquer maneira, digamos que você usasse esse esquema do swap para duas variáveis do tipo Integer.
Uma característica das classes wrapper é que os valores representados são imutáveis.
Não é difícil em JNI acessar os membros privados da classe Integer que representam o valor, mas aí você estaria violando essa característica da classe Integer. Isso é mais grave quando você estiver usando o Java 5.0. É que nessa versão do Java existem 256 valores prefixados da classe Integer (de -128 a +127) já prealocados pela JVM. Se por acaso você passar um desses valores para sua função, vai provocar erros esquisitos depois em seu programa.

Bom dia, você poderia me indicar sites,onde eu possa estudar e pegar PDF falando sobre JNI.

Preciso aprender urgente, pois meu projeto de conclusao do curso depende disso.

att,
JP

A documentação da Sun é ótima.

Entendo, obrigado.

É que para meu projeto eu preciso pegar dados do hardware do computador e os processos ativos no sistema.

Uma outra pergunta, JNI só funciona com DLLs feitas em C/C++/Delphi, ou também com .NET?

Hum, .NET é um bicho diferente; a maior parte dos trabalhos de interoperabilidade mostrados pela Sun entre Java e .NET usam Web Services, não JNI.

Então no meu caso é melhor utilizar C ou Delphi.

A resposta mais simples para você é: se não consegue fazer um swap de duas variáveis int em Java puro

Acho que não fui muito claro em minha pergunta…

Graças a Deus o problema não está no Java. Se fosse em Java, dava pirueta cambalhota…

O problema é…

Muitas APIs retornam valores nos próprios argumentos da função. Por exemplo: funcao(paramIN, paramOUT, paramOUT).

paramIN a passagem é feita por valor e paramOUT são variáveis passadas por referência.

Só que parece que com JNI SEMPRE a passagem de varíaveis é feita por VALOR e não por referência.

A resposta mais simples para você é

Thingol, nunca subestime ninguém! Por melhor que vc seja vc não pode achar que a pessoa para quem vc está dando a resposta não está a altura da mesma. A resposta mais simples que tem é a própria resposta.

Flw!

Consegui galera! Acho que ontem ainda estava sobre o efeito de anestesia! :slight_smile:

JAVA:

public native void swap(int[] a, int[] b);

C JNI:

JNIEXPORT void JNICALL Java_PrototipoJNI_swap
  (JNIEnv *env, jobject obj, jintArray arg0, jintArray arg1) {
	typedef void (*pfunc)();
  
	HANDLE hdll;
  
	pfunc swap;
  
	hdll = LoadLibrary("strfunctions.dll");  
  
	swap = (pfunc)GetProcAddress(hdll, "swap");  
	
	jint *arg0a = (*env)->GetIntArrayElements(env, arg0, 0);
	jint *arg1a = (*env)->GetIntArrayElements(env, arg1, 0);

	printf("C++ Antes da troca arg0 = %d arg1= %d \n",(int)arg0a[0],(int)arg1a[0]);
	swap(&arg0a,&arg1a);  
	printf("C++ Depois da troca arg0 = %d arg1= %d \n",(int)arg0a[0],(int)arg1a[0]);	
	(*env)->ReleaseIntArrayElements(env, arg0, arg0a, 0);
	(*env)->ReleaseIntArrayElements(env, arg1, arg1a, 0);		
}

DLL header:

EXPORT void swap(int*, int*);

Flw galera, valeu mesmo!

Não quis ofender ninguém quanto a conseguir ou não trocar duas variáveis int. É o modo de dizer que foi infeliz.

sem ressentimentos thingol!!! :wink:

Um abraço!!!