Passagem por referência em JAVA com STRING

Senhores,

Estou acessando um método de uma DLL de um equipamento via JNA, onde este método tem como assinatura int metodo_qualquer( int a, string *b ), onde o parâmetro “b” é um passado como referência, haja visto, que depois da execução do método este terá um valor no qual deverei tratalo. Mas no JAVA, até onde entendo, a passagem de parâmentro funciona por valor, ou seja é passado para o método uma cópia da referência String. Portanto no final da execução do método o valor do parâmentro “b” não muda. Veja exemplo mostrado a seguir:

String b = “teste 1”
System.out.println(“b-” + b); // Imprime “teste 1”
metodo_qualquer(1,b)
System.out.println(“b-” + b); // Imprime “teste 1”

public int metodo_qualquer(a,b) {
String b = “teste 2”;
return 0;
}

Desta forma, alguem tem alguma dica de como poderei ter o valor da parâmetro “b” alterado mesmo depois da execução do método “metodo_qualquer”. Vale lembrar que a DLL que possui o método “metodo_qualquer” eu não tenho acesso, haja visto, que esta foi desenvolvida em C.

Obrigado.

Cara,

a passagem de parametros em java para objetos é por referencia. Até para String.
O que acontece é que Strings são imutáveis, então toda vez que você vai fazer alguma alteração nela você tem que atribuir novamente o valor na sua váriavel.
Por que você não retorna um char* com o novo valor atualizado? É um problema?

Falou.

Leia a documentação.

https://jna.dev.java.net/#char_buffer

[quote=Mr_Arthur]Cara,

a passagem de parametros em java para objetos é por referencia. Até para String.
O que acontece é que Strings são imutáveis, então toda vez que você vai fazer alguma alteração nela você tem que atribuir novamente o valor na sua váriavel.
Por que você não retorna um char* com o novo valor atualizado? É um problema?

Falou.[/quote]

Não tenho controle do método, o método está encapsulado na DLL.

Alguém ja usou a classe ByReference do JNA ? Não estou sabendo como usa-la! Pode me ajudar a resolver o problema.

Senhores,

Vejam o código postado a seguir, onde antes da execução do método “objModifica.modifica2(
objString.getValue())” o valor da variável "objString " era “Teste - Antes” e depois da execução do método “objModifica.modifica2(objString.getValue())” o conteudo da variável deveria ter sido modificado para “Teste - Depois” e não alterou. Ou seja, o meu objetivo de passar o parâmetro “objString” como referência, para o método objModifica.modifica2() não foi alcançado.

Alguem tem alguma sugestão?

Obrigado a Todos.

[code]


Classe Main


package teste;
public class Main{
public static void main(String[] args) {
StringByReference objString = new StringByReference(“Teste - Antes”);
System.out.println("(Valor Antes do Metodo) ->"+objString.getValue());
Modifica objModifica = new Modifica();
objModifica.modifica2(objString.getValue());
System.out.println("(Valor Depois do Metodo) ->"+objString.getValue());
}
}


Classe StringByReference


package teste;
import com.sun.jna.ptr.ByReference;
class StringByReference extends ByReference {
public void setValue(String value) {
getPointer().setString(0L, value);
}
public String getValue() {
return getPointer().getString(0L);
}
public StringByReference(String value) {
super(value.getBytes().length + 1);
setValue(value);
}
}


Classe Modifica


package teste;
public class Modifica{
public void modifica2(String obj) {
obj = “Teste - Depois”;
}
}


Saída do Programa:


(Valor Antes do Metodo) ->Teste - Antes
(Valor Antes do Metodo) ->Teste - Antes[/code]

Você leu a documentação que lhe foi passada? Basicamente você não pode passar strings por referência, e ponto final. Em vez disso, você deve alocar um array de bytes grande suficiente para o programa em C poder copiar a string (ou seja, o char*) que ele irá retornar, e então você tem de pegar esse array de bytes (que deve conter os caracteres e mais um \0) e passar para o método Native.toString(byte[]). Esse método pega o byte[] que foi alterado pelo método em C, e então acha o terminador da string em C (ou seja, um ‘\0’), muda sua codificação de ANSI para Unicode, e retorna uma String com o valor desejado.
Qual é o tamanho do array a ser passado? Você tem de olhar a documentação do método em C. Por exemplo, se você for chamar uma API do Windows que copia num char* o nome de um arquivo, esse tamanho é MAX_PATH + 1, ou seja, 256. Para outros métodos valem outros valores.

Parece tosco, mas é assim mesmo. Acho que só o C# (que tem o tal do “Interop”) tem algo que é bem menos tosco, mas você tem de usar uma série de “attributes” (o equivalente do .NET às nossas “annotations”) para poder dizer exatamente o que deve ser feito - se é o caso de criar um byte[] e ver onde é que termina, ou se é o caso de um BSTR, ou outra coisa mais esquisita ainda.

Segue o fragmento de código com o uso de vetor de tipo byte. E também não funcionou. Vale lembrar que meu desejo é que o ao passar o parâmetro “msgCatraca” para o método “WRTReadAccess”, depois da execução do método a variável “msgCatraca” deverá conter o conteudo lido pelo equipamento em questão (catraca). Portanto esta variável sempre retorna o conteúdo em BRANCO.

Alguem tem mais alguma sugestão ???

    [code]FileWriter writerCmd = null;
    PrintWriter saidaCmd = null;
    try {
        writerCmd = new FileWriter("log2_catraca.txt");
        saidaCmd = new PrintWriter(writerCmd, true);
        byte[] msgCatraca = new String("").getBytes();
        // Numero do Equipamento
        int numEquipamento = 2;
        // Mensagem a ser retornado pela Catraca
        //  - numEquipamento: Numero do Equipamento
        //  - msgCatraca: Mensagem em BRANCO que será preenchido pelo método "WRTReadAccess" da DLL do equipamento
        int retMsg = demo.WRTReadAccess(numEquipamento, msgCatraca);
        saidaCmd.println("Retorno I             - " + retMsg); // Retorno da mensagem
        saidaCmd.println("Retorno (msgCatraca)  - " + Native.toString(msgCatraca)); // Retornou sempre BRANCO
    } catch (IOException ex) {
        Logger.getLogger(Threads.class.getName()).log(Level.SEVERE, null, ex);
    } finally {
        try {
            saidaCmd.close();
            writerCmd.close();
        } catch (IOException ex) {
            Logger.getLogger(Threads.class.getName()).log(Level.SEVERE, null, ex);
        }
    }[/code]
 byte[] msgCatraca = new String("").getBytes(); 

Isto gera um array que é muito pequeno (tem exatamente 0 bytes).

Quando você fez isso, você passou um array tão pequeno que me espanto que não tenha havido um erro do tipo “programa Java cai sozinho e cria um arquivo hs_err_pid.log em algum diretório”.

Passe um byte array bem maior, e por favor leia o manual da sua API para saber qual é o tamanho adequado para passar para a sua API. Você NUNCA deve passar um array vazio. Eu chutaria que você precisa pasasr pelo menos um array de 1000 bytes.

entanglement

Realmente você estava certo, funcionou do modo que você disse, apenas coloquei a mensagem como um vetor do tipo byte de tamanho fixo.
Te devo um salgado.

Mas quando eu tiver um casso assim, como eu faço?

String dados = rs.getText("coluna1");
if(dados.equals("Olá")){
     metodo(dados,"Mundo");
}else{
     metodo(null,null);
}

ou

String dados = rs.getText("coluna1");
if(dados.equals("Olá")){
     metodo(dados,"Mundo");
}else{
     metodo("","");
}

[quote=Mr_Arthur]Cara,

a passagem de parametros em java para objetos é por referencia. Até para String.
.[/quote]

Cuidado! Todas as passagens em java são por valor. Todas!

O processo é assim, a variável de origem e a variável de parametros são diferentes. O valor da variável de origem é copiado para variável de parametro.
A passage por referencia acontece quando as variáveis de origem e parametro são a mesma. Isto não existe em java. Todas as variáveis são diferentes e são os valores que são copiados.

É por isto que a interação com JNDI costuma ser por arrays.

Sua definição existe, mas não é a única - ela diverge entre os vários autores.

Passar dados por ponteiros, em C++ também é considerado passagem por referência. E funciona exatamente igual ao Java. O método recebe uma cópia do ponteiro, e não do objeto apontado.
Quando falamos em “passar por referência” estamos falando do dado, no caso, o objeto.

Todas as variáveis que apontam para objetos em Java são referências. Portanto, todos os métodos passam o objeto através de referências, não de cópias de seu valor.

De qualquer forma, você estava respondendo a uma pessoa que postou há 3 anos atrás, já que nosso amigo caiofabioa ressuscitou o tópico sem prévio aviso.

[quote=caiofabioa] String dados = rs.getText("coluna1"); if(dados.equals("Olá")){ metodo(dados,"Mundo"); }else{ metodo(null,null); }
ou

String dados = rs.getText("coluna1"); if(dados.equals("Olá")){ metodo(dados,"Mundo"); }else{ metodo("",""); } [/quote]

Isso não tem absolutamente nada a ver com o assunto de passagem de parâmetros.

A abordagem vai depender do que estiver implementado no metodo(String, String).

Mas, de maneira geral, a segunda forma é preferível, já que ela atende ao padrão do objeto nulo:

E, por favor, não ressuscite tópicos à toa. Principalmente, sem deixar claro que está fazendo isso.