Java: How to pass byte[] by reference? - java

You can do it in .NET by using the keyword "ref". Is there any way to do so in Java?

What are you doing in your method? If you're merely populating an existing array, then you don't need pass-by-reference semantics - either in .NET or in Java. In both cases, the reference will be passed by value - so changes to the object will be visible by the caller. That's like telling someone the address of your house and asking them to deliver something to it - no problem.
If you really want pass-by-reference semantics, i.e. the caller will see any changes made to the parameter itself, e.g. setting it to null or a reference to a different byte array, then either method needs to return the new value, or you need to pass a reference to some sort of "holder" which contains a reference to the byte array, and which can have the (possibly changed) reference grabbed from it later.
In other words, if your method looks likes this:
public void doSomething(byte[] data)
{
for (int i=0; i < data.length; i++)
{
data[i] = (byte) i;
}
}
then you're fine. If your method looks like this:
public void createArray(byte[] data, int length)
{
// Eek! Change to parameter won't get seen by caller
data = new byte[length];
for (int i=0; i < data.length; i++)
{
data[i] = (byte) i;
}
}
then you need to change it to either:
public byte[] createArray(int length)
{
byte[] data = new byte[length];
for (int i=0; i < data.length; i++)
{
data[i] = (byte) i;
}
return data;
}
or:
public class Holder<T>
{
public T value; // Use a property in real code!
}
public void createArray(Holder<byte[]> holder, int length)
{
holder.value = new byte[length];
for (int i=0; i < length; i++)
{
holder.value[i] = (byte) i;
}
}
For more details, read Parameter passing in C# and Parameter passing in Java. (The former is better written than the latter, I'm afraid. One day I'll get round to doing an update.)

Actually, in Java, the references are passed-by-value.
In this case, the reference is a byte[] object. Any changes that affect the object itself will be seen from the caller method.
However, if you try to replace the reference, for example using new byte[length], you are only replacing the reference that you obtained by pass-by-value, so you are not changing the reference in the caller method.
Here's an interesting read about this issue: Java is Pass-by-Value Dammit!
Here's an concrete example:
public class PassByValue
{
public static void modifyArray(byte[] array)
{
System.out.println("Method Entry: Length: " + array.length);
array = new byte[16];
System.out.println("Method Exit: Length: " + array.length);
}
public static void main(String[] args)
{
byte[] array = new byte[8];
System.out.println("Before Method: Length: " + array.length);
modifyArray(array);
System.out.println("After Method: Length: " + array.length);
}
}
This program will create a byte array of length 8 in the main method, which will call the modifyArray method, where the a new byte array of length 16 is created.
It may appear that by creating a new byte array in the modifyArray method, that the length of the byte array upon returning to the main method will be 16, however, running this program reveals something different:
Before Method: Length: 8
Method Entry: Length: 8
Method Exit: Length: 16
After Method: Length: 8
The length of the byte array upon returning from the modifyArray method reverts to 8 instead of 16.
Why is that?
That's because the main method called the modifyArray method and sent a copied reference to the new byte[8] by using pass-by-value. Then, the modifyArray method threw away the copied reference by creating a new byte[16]. By the time we leave modifyArray, the reference to the new byte[16] is out of scope (and eventually will be garbage collected.) However, the main method still has reference to the new byte[8] as it only sent the copied reference and not an actual reference to the reference.
That should demonstrate that Java will pass reference using pass-by-value.

Java uses pass by value for method arguments.
Primitives (int, boolean, etc.) are special cases in Java.. not objects per se. In this case, a copy of the primitive (argument) is passed into the function. This gels well with the pass by value theory.
For Objects, what happens is that the ref to the object is passed by value (a copy of the reference is made rather than the object)... but both references point to the same object. So if you modify an object parameter in a method, the actual object will be modified.
This article should help you out..
http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html
As for the OP's question, just pass in the reference to the byte[] array to the method. The net result would be similar to pass by reference. If you modify the byte array, the caller will be able to see the changes post method execution.
Update to quell the resistance :) => indicates output
.NET Land
class Counter
{
private int m_count = 0;
public override string ToString()
{
return String.Format("Counter ID{0} : Value {1}", this.GetHashCode(), m_count);
}
public void Increment()
{ m_count++; }
}
class MakeAPass
{
public void PassByValueAndModify(int i)
{ i = 20; }
public void PassByRefAndModify(ref int i)
{ i = 20; }
public void PassByValueAndModify(Counter c)
{ c.Increment(); }
public void PassByRefAndModify(ref Counter c)
{ c.Increment(); }
public void PassByRefAndReassign(ref Counter c)
{
c = new Counter();
for (int i=0; i<5; ++i)
c.Increment();
}
}
static void Main(string[] args)
{
MakeAPass obj = new MakeAPass();
int intVal = 10;
obj.PassByValueAndModify(intVal);
Console.WriteLine(intVal); // => 10
obj.PassByRefAndModify(ref intVal);
Console.WriteLine(intVal); // => 20
Counter obCounter = new Counter();
obj.PassByValueAndModify(obCounter);
Console.WriteLine(obCounter.ToString()); // => Counter ID58225482 : Value 1
obj.PassByRefAndModify(ref obCounter);
Console.WriteLine(obCounter.ToString()); // => Counter ID58225482 : Value 2
obj.PassByRefAndReassign(ref obCounter);
Console.WriteLine(obCounter.ToString()); // => Counter ID54267293 : Value 5
}
Java Land
Minor mods reqd: Use hashCode() and + to concat strings in Counter.java...
class MakeAPass
{
public void PassByValueAndModify(int i)
{ i = 20; }
// can't be done.. Use Integer class which wraps primitive
//public void PassByRefAndModify(ref int i)
public void PassByValueAndModify(Counter c)
{ c.Increment(); }
// same as above. no ref keyword though
//public void PassByRefAndModify(ref Counter c)
// this can't be done as in .net
//public void PassByRefAndReassign(ref Counter c)
public void PassAndReassign(Counter c)
{
c = new Counter();
for (int i=0; i<5; ++i)
c.Increment();
}
}
public static void main(String args[])
{
MakeAPass obj = new MakeAPass();
int intVal = 10;
obj.PassByValueAndModify(intVal);
System.out.println(intVal); // => 10
//obj.PassByRefAndModify(ref intVal);
//System.out.println(intVal); // can't get it to say 20
Counter obCounter = new Counter();
obj.PassByValueAndModify(obCounter);
System.out.println(obCounter.ToString()); // => Counter ID3541984 : Value 1
//obj.PassByRefAndModify(ref obCounter);
//Console.WriteLine(obCounter.ToString()); // no ref. but can make it 2 by repeating prev call
obj.PassAndReassign(obCounter);
System.out.println(obCounter.ToString()); // => Counter ID3541984 : Value 1
// can't get it to say 5
}

Related

I'm trying to give the value of an array of a class to another array with the same class, is there something I'm missing here?

The class is called Exposicion and has a String and an INT value, so I used it as an array to grab some input from the user.
class Exposicion {
public String nombreExpo;
public int duracionExpo;
Exposicion(String nombreExpo, int duracionExpo) {
this.nombreExpo = nombreExpo;
this.duracionExpo = duracionExpo;
}
}
With the Function SortExpo I plan to copy only the values of the array as long as the INT values don't add up to 180, but java flags an error when doing:
arrExpoT[posHor].nombreExpo = arrExpoS[k].nombreExpo;
This is the whole function
void SortExpo(Exposicion[] arrExpoS,int posicion,Exposicion[] arrExpoT){
int poshor=0;
int total=0;
for (int k = 0; k < posicion; k++) {
if ( total < 180 || arrExpoS[poshor].nombreExpo != "TOMADO123") {
arrExpoT[poshor].nombreExpo = arrExpoS[k].nombreExpo;
arrExpoT[poshor].duracionExpo = arrExpoS[k].duracionExpo;
arrExpoS[poshor].nombreExpo = "TOMADO123";
total = total + arrExpoS[k].duracionExpo;
poshor++;
} else {
k = posicion;
}
}
}
Error
I've added the .java file in this link
Also Main.java if this helps
You are getting a NullPointerException because "expo1" and "sala1" variables are both null. You have to pass a reference to an object on both variables. Something like this:
class SalaExpo(){
Exposicion[] expo1=new Exposicion[100];
}
public class ConsoleMenu {
private SalaExpo sala1;
void execute(){
sala1 = new SalaExpo();
}
}
Also you should poblate the sala1.expo1 array, like this (don't know if this is what you are intending but you should do this in order not to get a NullPointerException) :
void GuardarExpo(Exposicion[] arrExpoG,int posicion,Exposicion[] arrSala) {
/*
Bunch
of
code
*/
arrExpoG[posicion] = new Exposicion(inputNombre,inputDuracion);
arrSala[posicion]=arrExpoG[posicion];
}
Finally, you should use the variable "posicion" instead of "sala1.expo1.length" to pass as argument to the "imprimirExpo" method, since the array "sala1.expo1" has a length of 100, that means a lot of null elements since you are not poblating it all:
ImprimirExpo(sala1.expo1,posicion);
instead of:
ImprimirExpo(sala1.expo1,sala1.expo1.length);

Calling methods from other classes using array objects in Java

Why does this code not work? It seems I cannot set the variable to '10' with the Array, but with a normal object it works.
What am I doing wrong?
Class- 1
public class apples {
public static void main(String[] args) {
carrots carrotObj = new carrots();
carrotObj.setVar(5);
System.out.println(carrotObj.getVar());
carrots carrotArray[] = new carrots[3];
carrotArray[1].setVar(10);
System.out.println(carrotArray[1].getVar());
}
}
Class- 2
public class carrots {
private int var = 0;
public int getVar() {
return var;
}
public void setVar(int var) {
this.var = var;
}
}
Console Output:
5
Exception in thread "main"
java.lang.NullPointerException
at apples.main(apples.java:17)
You created an array, but when an array of objects is created, they are all initialized to null -- the default value for object reference variables. You need to create some objects and assign them to slots in the array.
carrots carrotArray[] = new carrots[3];
// Place this code
carrotArray[1] = new carrots();
carrotArray[1].setVar(10);
You could do something similar for position 0 and 2.
Additionally, the Java convention is to capitalize class names, e.g. Carrots.
You need to initialize all the elements of the array; since they are not primitive data types their default value is null.
carrots carrotArray[] = new carrots[3];
for(int i=0; i < carrotArray.length; i++){
carrotArray[i] = new carrots();
}
carrotArray[1].setVar(10);
System.out.println(carrotArray[1].getVar());

adding an unknown number of parameters to a method call in Java

I have a method that I want to expand (rather than writing a new method which does basically the same thing), by adding an unknown number of parameters to the end of the list of parameters.
If I do this, will I have to change all the calls to the method? I guess the question is, does the unknown parameter include the case there being no parameter passed in at all?
For instance, if I have a method:
queryFactory(int [] typeArgs, int queryType, int[] ... args){}
Could I call:
queryFactory(typeArgsInstce, queryTypeInstce)
And then when I need to add parameters to the query call:
queryFactory(typeArgsInstce, queryTypeInstce, argsInstce)
Where argsInstce is an array of integers containing extra arguments.
I would like to just edit this method rather than writing a new one which does almost the exact same thing except it has some arguments to add to queries. I will simply write another method if by editing this one I will have to change every other call to this method.
public static void main(String[] args) {
method(1); // <- compile error
method(1,2);
method(1,2,3);
method(1,2,3,4);
}
private static void method(int i1, int i2, int...i3) {
// do something
}
So to answer the question in words: we need 2 arguments at minimum. This passes an empty array ´i3[]´ to the method. Arguments number 3 and above are treated as array values.
It makes no difference...
public static void main(String[] args) {
method(new int[]{1}); // <- compile error
method(new int[]{1},2);
method(new int[]{1},2,new int[]{3,4});
method(new int[]{1},2,new int[]{3,4},new int[]{5,6});
}
private static void method(int[] i1, int i2, int[]...i3) {
// do something
}
The varargs parameter has to be the last so it won't conflict with the first array
As you asked Could I call: you can call here is the example
public static void main(String[] args) {
int[] i = { 1, 2, 3 };
int[] i1 ={1,1,1,1};
System.out.println("Sum: " + sum(i,2,i1));
System.out.println("Sum: " + sum(i,2));
}
static int sum(int[] numbers1,int num,int[]... numbers2) {
int t[][] = numbers2;
int total = 0;
for (int i = 0; i < t.length; i++) {
for (int j = 0; j < t[i].length; j++) {
System.out.print(t[i][j]);
total += t[i][j];
}
}
for(int test : numbers1)
total+=test;
total+=num;
return total;
}
I understand that you don't want to change the signature of your method because you will need to change every call of that method, so you could create a method that have the 3 args with all the code, and overload the same method with only 2 args, but in this method you only call the method with 3 args, the last arg will be null. I know is not that you want, but you wouldn't repeat the code and change the signature of the method.
public void queryFactory(int [] typeArgs, int queryType, int... args){
// do something
}
public void queryFactory(int [] typeArgs, int queryType){
queryFactory(typeArgs,queryType,null);
}

accessing elements of an array which has been passed as a parameter - Java

I have a method which takes an array as a parameter from another class:
public void memPass(Memory[] memLocList) {
memList = memLocList;
for (int i = 0; i < 10; i++) {
System.out.println(memList[i].getSomething());
}
}
-EDIT-
The above prints out 10 values (integers) but if I try the same in the other method with an integer between 0 & 10 I get an NPE.
Can anyone tell me how to access the elements of this array from another method, which also takes in a parameter from another class?
I'm trying to do something along these lines:
public void accessArray(int mem) {
int someInt = memList[mem].getSomething();
}
-EDIT- Sorry, I should add that this gives a NullPointerException.
-NEW EDIT-
OK, I've now edited the code so that all I have in the class is:
public class PLoop {
// instance variable
public Memory[] memlist;
// method 1
public void memPass(Memory[] memLocList) {
memList = memLocList;
System.out.println(memList.length);
}
// method 2
public void accessArray(int mem) {
System.out.println(memList.length);
}
}
The first method prints an integer representing the length of "memList" and the second gives an NPE.
If I'm understanding you right, you want to be able to store memLocList then access it later? If so, I can't see what creating an instance variable wouldn't work.
public class Test {
public Memory[] memlist;
public void memPass(Memory[] memLocList) {
memList = memLocList;
}
public void accessArray(int mem) {
int someInt = memList[mem].getSomething();
}
}
Of course, I don't work in Java enough any more, so it might not be possible to create and assign an instance variable like that. But you could always store the elements in another container.
public class Test {
public List<Memory> memlist;
public void memPass(Memory[] memLocList) {
memlist = new ArrayList<Memory>(Arrays.asList(memLocList));
}
public void accessArray(int mem) {
int someInt = memList.get(mem).getSomething();
}
}
Sorry if I have any syntax errors. But you get the main idea.
If memList is an instance variable of that class and this is the same class in both situations (both methods) then this is obviously a null value at some index of memList.
private static class Memory {
private static int index = 0;
public int getSomething() {
return index++;
}
}
private static class Test {
public Memory[] memlist;
public void memPass(Memory[] memLocList) {
memlist = memLocList;
}
public void accessArray(int mem) {
int someInt = memlist[mem].getSomething();
System.out.println(someInt);
}
}
public static void main(String args[]) {
Test t = new Test();
Memory[] memList = new Memory[4];
memList[0] = new Memory();
memList[1] = null;
t.memPass(memList);
t.accessArray(0);
t.accessArray(0);
t.accessArray(1); //NPE thrown because null value in array
//or
Test t2 = new Test();
t2.accessArray(0); //NPE thrown because array is null (different instance)
}
In your implementation, you are already assuming that the array being passed to the method has 10 elements and that each of these array items has a value, hence, at some point you encounter a NullPointerException. This is dangerous especially when you are just processing an array that is passed as an argument to the method. To ensure that you are only accessing the elements that are available in the array, you need to check what the length of the array is. Also, you need to ensure that whenever you call the methods of an element in an array, (or do anything with it), check first whether it is actually there. For your for loop, you can do something like this:
if (memList != null) {
for (int i = 0; i < memList.length; i++) {
if (memList[i] != null) {
System.out.println(memList[i].getSomething());
}
}
}
That way it is safe from nullpointer exceptions. Using the same concept, you can also apply it to your method like this:
public void accessArray(int mem) {
if (mem > -1 && memList != null && memList.length > mem && memList[mem] != null){
int someInt = memList[mem].getSomething();
}
}
Of course this is assuming that the method with the for loop and the accessArray method are in the same class (or parent-child class) and memList is an instance variable.
And to save the elements of the array as a deep copy of memLocList, you can use what #GJK has suggested which is Arrays.asList to an instance variable and apply the same concept of nullpointer checking that I mentioned above.

Java bug or feature?

Ok, here is the code and then the discussion follows:
public class FlatArrayList {
private static ArrayList<TestWrapperObject> probModel = new ArrayList<TestWrapperObject>();
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int [] currentRow = new int[10];
int counter = 0;
while (true) {
for (int i = 0; i < 10; i++) {
currentRow[i] = probModel.size();
}
TestWrapperObject currentWO = new TestWrapperObject(currentRow);
probModel.add(counter, currentWO);
TestWrapperObject testWO = probModel.get(counter);
// System.out.println(testWO);
counter++;
if (probModel.size() == 10) break;
}
// Output the whole ArrayList
for (TestWrapperObject wo:probModel) {
int [] currentTestRow = wo.getCurrentRow();
}
}
}
public class TestWrapperObject {
private int [] currentRow;
public void setCurrentRow(int [] currentRow) {
this.currentRow = currentRow;
}
public int [] getCurrentRow() {
return this.currentRow;
}
public TestWrapperObject(int [] currentRow) {
this.currentRow = currentRow;
}
}
What is the above code supposed to do? What I am trying to do is load an array as a member of some wrapper object (TestWrapperObject in our case). When I get out of the loop,
the probModel ArrayList has the number of elements it is supposed to have but all have the same value of the last element (an array of size 10 with each item equal to 9). This is not the case inside the loop. If you perform the same "experiment" with a primitive int value everything works fine. Am I missing something myself regarding arrays as object members? Or did I just encounter a Java bug? I am using Java 6.
You are only creating one instance of the currentRow array. Move that inside the row loop and it should behave more like you expect.
Specifically, the assignment in setCurrentRow does not create a copy of the object, but only assigns the reference. So each copy of your wrapper object will hold a reference to the same int[] array. Changing the values in that array will make the values appear to change for all other wrapper objects that hold a reference to the same instance of the array.
i don' t want to sound condescending, but always try to remember tip #26 from the excellent pragmatic programmer book
select isn't broken
it is very rare to find a java bug. keeping this in mind often helps me to look over my code again, turn it around, and shake out the loose bits until i finally discover where i was wrong. of course asking for help early enough is very encouraged, too :)

Categories

Resources