What is inside code for array.length() in Java? - java

What is stored in 10th location of array
say
int[] array=new int[10];
Say we have values stored from array[0] to array[9], if I were to print elements without using
array.length()
or for (int a: array)
How do I proceed?
My basic question is how will JVM determine end of array, is it when a null is encountered parsing array or when a garbage value is encountered? what is inbuilt code of array.length() function?

What is stored in 10th location of array say
...
my basic question is how will JVM determine end of array, is it when a null is encountered parsing array or when a garbage value is encountered? what is inbuilt code of array.length() function?
Welcome C/C++ programmer :-)
Java uses a different paradigm than C/C++ for arrays. C/C++ uses the terminator/sentinel a.k.a. "garbage") value like NULL to indicate the end of the array. In Java, arrays are more like objects with a special "instance variable"-like variable length that indicates how many slots there are in the array. This special "instance variable" is set at the array's creation and is read-only. Its accessible by saying array.length.
Java expects the code to know when to stop at the end of the array by making sure they don't specify an index greater than length - 1. However, the JVM checks every access to the array for security reasons just in case. If the JVM finds an array index that is less than 0 or greater than length - 1, then the JVM throws an IndexOutOfBoundsException.
What is stored in 10th location of array
Since we can always check the length, there is no need for a marker at the end of the array in Java. There isn't anything special after the last item in the array (it likely will be some other variable's memory).
if I were to print elements without using array.length()
for(int a: array) {
// code of loop body here
}
This code is magically transformed by the compiler to:
for (int i = 0; i < array.length; i++) {
int a = array[i];
// code of loop body here
}
However, the i index variable isn't accessible to the user's code. This code still uses array.length implicitly.

Arrays are objects with a length field. While looping, Java loads the length field and compares the iterator against it.
See 10.7 Array Members in the JLS

Internally, the JVM can track the length of an array however it sees fit. There's actually a bytecode instruction called arraylength that the Java compiler emits whenever you try to get the length of an array, indicating that it's up to the JVM to determine the best way to track the length of an array.
Most implementations probably store arrays as a block of memory whose first entry is the length of the array and whose remaining elements are the actual array values. This allows the implementation to query the length of the array, along with any value in the array, in O(1). If the implementation wanted to, though, it could store the elements followed by a sentinel value (as you've suggested), but I don't believe that any implementations do this because the cost of looking up the length would be linear in the size of the array.
As for how the foreach loop works, the compiler translates that code into something like this:
for (int i = 0; i < arr.length; ++i) {
T arrayElem = arr[i];
/* ... do work here ... */
}
And finally, with regards as to what the 10th element of a 10-element array is, there's no guarantee that there's even an object at that location. The JVM could easily allocate space for the array in a way where there is no tenth element. Since you can't ever actually get this value in Java (it would throw an exception if you tried), there's no requirement that the JVM even have something meaningful there.
Hope this helps!

Define what a "garbage value" is. (Hint: since everything is binary, there is no such thing unless you use a sentinel value, and that's just bad practice).
The length of the array is stored inside the Array instance as a member variable. It's nothing complex.

In a comment on another, the OP writes:
I agree array.length is the conventional method, I was looking for any other option if available.
There is no other reasonable implementation option open to the JVM implementer ... on any mainstream hardware architecture.
In particular, the sentinel approach ONLY detects the case where an application fetches an array element one index beyond the end.
If it fetches 2 or more indexes beyond, then it misses the sentinel and proceeds to access memory whose contents are unknown.
If it stores, then the sentinel is not consulted.
If it needs to directly access the array size as part of the application algorithm, searching for a sentinel is a very inefficient way of doing it. (Not to mention unreliable; e.g. if null is a valid array element.)
Sentinels don't work for (most) primitive arrays because there is no value that can be used as a sentinel. (The idea of a primitive array holding a null is nonsensical from the JLS perspective, since null is not type compatible with any Java primitive type.)
The garbage collector needs an array length in all cases.
In short, the length has to be stored in the array to deal with the other cases. Storing a sentinel as well means you are wasting space storing redundant information, and CPU cycles creating the sentinel and copying it (in the GC).

Okay, here I go :-)
Ways to deal with "arrays" in C
In C there are numerous ways to deal with array. For the remainder I will talk about string* (and use the variable strings which has a type of string*). This is because t[] "effectively decomposes" into t* and char* is the type of a "C string". Thus string* represents a pointer to "C string". This glosses over a number of pedantic issues in C w.r.t. "arrays" and "pointers". (Remember: just because a pointer can be accessed as p[i] doesn't make the type an array in C parlance.)
Now, strings (of type string*) has no way to know it's size -- it only represents a pointer to some string, or NULL perhaps. Now, let's look at some of the ways we can "know" the size:
Use a sentinel value. In this I am assuming the use NULL as the sentinel value (or it might be -1 for an "array" of integers, etc.). Remember that C has no such requirement that arrays have a sentinel value so this approach, like the following two, is just convention.
string* p;
for (p = strings; p != NULL; p++) {
doStuff(*p);
}
Track the array size externally.
void display(int count, string* strings) {
for (int i = 0; i < count; i++) {
doStuff(strings[i]);
}
}
Bundle the "array" and the length together.
struct mystrarray_t {
int size;
string* strings;
}
void display(struct mystrarray_t arr) {
for (int i = 0; i < arr.size i++) {
doStuff(arr.strings[i]);
}
}
Java uses this last approach.
Every array object in Java has a fixed sized which can be accessed as arr.length. There is special byte-code magic to make this work (arrays are very magical in Java), but at the language level this is exposed as just a read-only integer field that never changes (remember, each array object has a fixed size). Compilers and the JVM/JIT can take advantage of this fact to optimize the loop.
Unlike C, Java guarantees that trying to access an index out of bounds will result in an Exception (for performance reasons, even if it were not exposed, this would require the JVM kept track of the length of each array). In C this is just undefined behavior. For instance, if the sentinel value wasn't within the object (read "the desired accessibly memory") then example #1 would have lead to a buffer-overflow.
However, there is nothing to prevent one from using sentinel values in Java. Unlike the C form with a sentinel value, this is also safe from IndexOutOfBoundExceptions (IOOB) because the length-guard is the ultimate limit. The sentinel is just a break-early.
// So we can add up to 2 extra names later
String names[] = { "Fred", "Barney", null, null };
// This uses a sentinel *and* is free of an over-run or IOB Exception
for (String n : names) {
if (n == null) {
break;
}
doStuff(n);
}
Or possibly allowing an IOOB Exception because we do something silly like ignore the fact that arrays know their length: (See comments wrt "performance").
// -- THERE IS NO EFFECTIVE PERFORMANCE GAIN --
// Can ONLY add 1 more name since sentinel now required to
// cleanly detect termination condition.
// Unlike C the behavior is still well-defined, just ill-behaving.
String names[] = { "Fred", "Barney", null, null };
for (int i = 0;; i++) {
String n = strings[i];
if (n == null) {
break;
}
doStuff(n);
}
On the other hand, I would discourage the use of such primitive code -- better to just use a suitable data-type such as a List in almost all cases.
Happy coding.

In terms of how you'd print all the elements in the array without using either a for each loop or the length field, well in all honesty you just wouldn't. You could potentially just have a for loop like the following:
try {
for(int i=0 ; ; i++) {
System.out.println(arr[i]);
}
}
catch(IndexOutOfBoundsException ex) {}
But that's an awful way to do things!

how will you print elements without using array.length or foreach loop
You could of course loop through the array without bounds checking and then catch (and swallow) the ArrayIndexOutOfBoundsException in the end:
try {
int i = 0;
while (true) {
System.out.println(arr[i++]);
}
catch (ArrayIndexOutOfBoundsException e) {
// so we are past the last array element...
}
This technically works, but it is bad practice. You should not use exceptions for flow control.

All array access outside the interval [0, 9] gives an ArrayIndexOutOfBoundsException, not only position 10. So, conceptually you could say that your whole memory (reaching with indexes from Integer.MIN_VALUE to Integer.MAX_VALUE) is filled with sentinel values, apart from the space of the array itself, and when reading or writing to a position filled with a sentinel, you get your exception. (And each array has its own whole memory to spend).
Of course, in reality no one has a whole memory for each array to spend, so the VM implements the array accesses a bit smarter. You can imagine something like this:
class Array<X> {
private final int length;
private final Class<X> componentType;
/**
* invoked on new X[len] .
*/
public Array<X>(int len, Class<X> type) {
if(len < 0) {
throw new NegativeArraySizeException("too small: " + len);
}
this.componentType = type;
this.len = len;
// TODO: allocate the memory
// initialize elements:
for (int i = 0; i < len; i++) {
setElement(i, null);
}
}
/**
* invoked on a.length
*/
public int length() {
return length;
}
/**
* invoked on a[i]
*/
public X getElement(int index) {
if(index < 0 || length <= index)
throw new ArrayIndexOutOfBoundsException("out of bounds: " + index);
// TODO: do the real memory access
return ...;
}
/**
* invoked on a[i] = x
*/
public X setElement(int index, X value) {
if(index < 0 || length <= index) {
throw new ArrayIndexOutOfBoundsException("out of bounds: " + index);
}
if(!componentType.isInstance(value)) {
throw new ArrayStoreException("value " + value + " is of type " +
value.getClass().getName() + ", but should be of type "
+ componentType.getName() + "!");
}
// TODO: do the real memory access
return value;
}
}
Of course, for primitive values the component type check is a bit simpler, since already the compiler (and then the VM bytecode verifier) checks that there are the right types, sometimes doing a type conversion, too. (And the initialization would be with the default value of the type, not null.)

Related

Need help using java.lang.reflect.Array to sort arrays

An interview question was to write this method to remove duplicate element in an array.
public static Array removeDuplicates(Array a) {
...
return type is java.lang.reflect.Array and parameter is also java.lang.reflect.Array type.
How would this method be called for any array?
Also not sure about my implementation:
public static Array removeDuplicates(Array a)
{
int end=Array.getLength(a)-1;
for(int i=0;i<=end-1;i++)
{
for(int j=i+1;j<=end;j++)
{
if(Array.get(a, i)==Array.get(a, j))
{
Array.set(a, j, Array.get(a, end));
end--;
j--;
}
}
}
Array b=(Array) Array.newInstance(a.getClass(), end+1);
for(int i=0;i<=end;i++)
Array.set(a, i, Array.get(a, i));
return b;
}
You may want to consider using a different data structure such as a hashmap to detect the duplicate (O(1)) instead of looping with nested for loops (O(n^2)). It should give you much better time complexity.
There are various problem with this code. Starting here:
if(Array.get(a, i)==Array.get(a, j))
Keep in mind that those get() calls return Object. So, when you pass in an array of strings, comparing with == simply will most likely result in wrong results (because many objects that are in fact equal still have different references --- so your check returns false all the time!)
So, the first thing to change: use equals() instead of == !
The other problem is:
end--;
Seriously: you never ever change the variable that controls your for loop.
Instead: have another counter, like
int numberOfOutgoingItems = end;
and then decrease that counter!
For your final question - check the javadoc; for example for get(). That reads get(Object array, int index)
So you should be able to do something like:
int a[] = ...;
Object oneValue = Array.get(a, 0);
for example.
Disclaimer. I have to admit: I don't know if the Array implementation is smart enough to automatically turn the elements of an int[] into an Integer object.
It could well be that you have to write code first to detect the exact type of array (if it is an array of int for example); to instead call getInt() instead of getObject().
Beyond that, some further reading how to use reflection/Array can be found here

Using variables instead of a long statement?

I am facing a confusion while working with objects. I searched google but couldn't find actual words to search for. The question is:
I am working with objects which consist some other object. For example:
public void mapObjects(A a, B b) {
a.setWeight(BigDecimal.valueOf(b.getWeight));
//Now my doubt lies here
if (a.getCharges.getDiscounts.getDiscountList != null) {
for(int i = 0; i < a.getCharges.getDiscounts.getDiscountList.size(); i++){
b.getList().get(0).setDiscountValue(a.getCharges.getDiscounts.getDiscountList.get(i).getValue());
b.getList().get(0).setDiscountName(a.getCharges.getDiscounts.getDiscountList.get(i).getValue);
}
}
}
The above code is just an example. The project in which I am working uses similar type of coding style. The usage of a.getCharges.getDiscounts.getDiscountList() kind of code always bugs me. Because I am again and again calling the same statement.
When I asked a senior why dont we save this statement into a simple List<> variable. He told me that it will use extra references which will increase overhead. Can using a variable be that much overhead than calling getters again and again?
As Java exchanges references not actual object, if you take a local variable it will just add a reference variable entry in stack frame.
This memory would be very less, almost negligible
This memory will be released once the method is completed because this will be local to the method
Despite that, you can gain significant performance gains if you use local variables. You are extracting same information within loop multiple times.
a.getCharges.getDiscounts.getDiscountList.size() is called multiple times. It should be a local variable.
b.getList().get(0) is being called multiple times. It should be a local variable.
a.getCharges.getDiscounts.getDiscountList is called multiple times. It should be a local variable.
Changing these to local variables would results in good performance gains, because unnecessary method calls would be saved.
Point your senior to this. If it works for limited resources on Android, I guess the technique of storing in local variables everything used in a for cycle is actually beneficial for performance anywhere.
In the excerpt below, note that we aren't even speaking about the overhead introduced by calling the (virtual) list.size() method, only storing the array.length as a local variable produces notable differences in performance.
public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
public void two() {
int sum = 0;
for (Foo a : mArray) {
sum += a.mSplat;
}
}
zero() is slowest, because the JIT can't yet optimize away the cost of getting the array length once for every iteration through the loop.
one() is faster. It pulls everything out into local variables, avoiding the lookups. Only the array length offers a performance benefit.
two() is fastest for devices without a JIT, and indistinguishable from one() for devices with a JIT. It uses the enhanced for loop syntax introduced in version 1.5 of the Java programming language.
Just make the discountList field never null - ie initialized to an empty list - and iterate over it. Something like:
for (Discount discount : a.getCharges().getDiscounts().getDiscountList()) {
b.getList().get(0).setDiscountValue(discount.getValue());
b.getList().get(0).setDiscountName(discount.getName());
}
Your "senior" may need to do some research. The "performance impact" of doing this is a few bytes per object and a few microseconds per access. If he's really hung up about memory, initialise it with a LinkedList, which has almost no memory footprint.
In Java a variable V pointing to an object instance O is simply a numeric value pointing to a memory location where the object's data is stored.
When we assign Vto another variable V1 all that happens is that V1 now points to the same memory location where data for O is stored. This means that new memory is not allocated when you do simple assignment unlike C++ code where the = operator can be be overloaded to do a deep-copy in which case new memory is actually allocated. Illustrating with an example below
Consider a class like below
class Foo {
private List<String> barList = new ArrayList<>();
//class methods...
//getter for the list
List<String> getBarList() {
return this.barList;
}
}
public static void main(String[] args) {
Foo f = new Foo()
//the below lien will print 0 since there is no bar string added
System.out.println("Bar list size: " + f.getBarList().size());
// add a bar string. Observe here that I am simply getting the list
// and adding - similar to how your code is currently structured
f.getBarList().add("SomeString");
//now get a reference to the list and store it in a variable.
// Below anotherList only points to the same memory location
// where the original bar list is present. No new memory is allocated.
List<String> anotherList = f.getBarList();
//print the content of bar list and another list. Both will be same
for(String s : f.getBarList()) {
System.out.println(s);
}
for(String s: anotherList) {
System.out.println(s);
}
//add a new bar string using the reference variable
anotherList.add("Another string");
//print the content of bar list and another list. Both will be same. If anotherList had separate memory allocated to it then the new string added would be only seen when we print the content of anotherList and not when we print the content of f.getBarList(). This proves that references are only some numeric addresses that point to locations of the object on heap.
for(String s : f.getBarList()) {
System.out.println(s);
}
for(String s: anotherList) {
System.out.println(s);
}
}
Hope this helps.

Select subarray without copying into new buffer?

I have float[] array of length 100. Is there a way I can select (pseudocode):
x = array[10:19];
To get elements 10,11,12,...,19 without copying over into another buffer? I'm in a mobile application where I don't want to waste space or time doing this. I'd rather just reference the pointers the system uses for array.
The most efficient way to do this would be to use System.arrayCopy(), which is much faster and more efficient than copying manually using a loop. It will require another array, but any approach you use (beyond just passing the original array around with a couple of ints representing the offset to use) will do this, and it's relatively cheap - the memory consuming bit is usually the objects that it's referencing rather than the array itself, and they are not copied.
No, there is no API to do that. The closest solution to this would be building your own class that wraps an existing array, and does the re-indexing:
class SubArray {
private final float[] data;
private final int offset;
private final int length;
public SubArray(float[] data, int offset, int length) {
this.data = data;
this.offset = offset;
this.length = length;
}
public float get(int index) {
if (index >= length) throw ...
return data[index + offset];
}
public void set(int index, float value) {
if (index >= length) throw ...
data[index + offset] = value;
}
}
If the result that you need is a new object that behaves like an array in all respects, including the indexing operator, you would need to make a copy.
(Update) Precondition: You should store the data in a Float[] instead of a float[], the performance-hit should be minimal.
You can use: Arrays.asList(array).subList(10, 20).
The Arrays.asList(array) does the following:
Returns a fixed-size list backed by the specified array. (Changes to the returned list "write through" to the array.) This method acts as bridge between array-based and collection-based APIs, in combination with Collection.toArray(). The returned list is serializable and implements RandomAccess.
Source
And then .subList(10, 20) returns you a List.
Then if you really want to work with arrays in the end, you could take the following lines:
List<Float> subList = Arrays.asList((Float[])array).subList(10, 20);
Float[] subArray = subList.toArray(new Float[subList.size()]);
(Update) Changed Arrays.asList(array) to Arrays.asList((Float[])array) such that it is correct now.
From documentation:
Returns an array containing all of the elements in this list in proper sequence (from first to last element); the runtime type of the returned array is that of the specified array. If the list fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the runtime type of the specified array and the size of this list.
If the list fits in the specified array with room to spare (i.e., the array has more elements than the list), the element in the array immediately following the end of the list is set to null. (This is useful in determining the length of the list only if the caller knows that the list does not contain any null elements.)
Like the toArray() method, this method acts as bridge between array-based and collection-based APIs. Further, this method allows precise control over the runtime type of the output array, and may, under certain circumstances, be used to save allocation costs.
Suppose x is a list known to contain only strings. The following code can be used to dump the list into a newly allocated array of String:
Source
This should ensure that no data is wasted, the only thing to be careful about could be autoboxing.
UPDATE: Changed my answer such that it now is correct under a precondition.
What is the problem of using a simple for loop? Objects are in java called by reference.
So, executing copying the array does not copy the objects.
float[] subarray = new float[10];
for(int i = 10, j = 0; i < 19; i++, j++) {
subarray[j] = x[i];
}
The array[0] is a reference to the object of x[0].
edit: This only applies for objects, and i don't know if it also applies to a float

Foreach vs common for loop

I just started learning Java and the first thing I came across is the foreach loop, not knowing the way it works the first thing I did was:
int[] array = new int [10];
for (int i: array){
i = 1;
}
And obviously failed to assign 1 to every element of the array. Then I added System.out.print(i); (after i = 1;) to the body of the loop and saw that the output of the screen was 1111111111 but since doing something with i inside the loop is valid that most likely i is a copy of every element of the array, ain't it? (first questions)
If the above is true doesn't this mean that the foreach loop is much slower then the common for loop since it involves making copies of each element of the array? Or since Java doesn't have pointers and pointer arithmetic, the oprator[] may be designed in some other "badly" fashion that copying every element is actually faster?
And if the above assumptions are true, why one would use an obviously slower foreach loop instead of a common forloop?
In short the questions:
Is i the copy of each element of the array? If not what is it
then?
Isn't the foreach loop slower then the common one? If not, how
"badly" is then operator[] designed?
There is nothing more except readability to win in a foreach loop?
In the code
for (int i: array){
You declare a variable i that on each loop iteration gets the value of the next element in the array, it isn't a reference to that element.
In
i = 1;
you assign a new value to the variable, not to the element in the array.
You cannot set the values of array elements with a foreach loop directly. Use a normal for loop for that
for (int i = 0; i < array.length; i++) {
array[i] = ...; // some value
}
In the above example, you are using the declared variable i as an index to the element in the array.
array[i]
is accessing the element itself whose value you can modify.
Ans obviously failed to assign 1 to every element of the array. The I
added System.out.print(i); to the body of the loop and saw that the
output of the screen was 1111111111 but since doing something with i
inside the loop is valid that most likely i is a copy of every element
of the array, ain't it? (first questions)
You must have put the System.out.print(i) after the i = 1, otherwise you would get 0000000.
If the above is true doesn't this mean that the foreach loop is much
slower then the common for loop since it involves making copies of
each element of the array? Or since Java doesn't have pointers and
pointer arithmetic, the oprator[] may be designed in some other
"badly" fashion that copying every element is actually faster?
Have a look here to see how the foreach loop works. For arrays,
for (int i: array){
i = 1;
}
is equivalent to
for (int index = 0; index < array.length; index++) {
int i = array[index];
i = 1;
}
So it isn't slower. You're doing one more primitive creation on the stack.
It depends on the implementation. For arrays, it's not slower in any way. It just serves different purposes.
why one would use an obviously slower foreach loop instead of a common
forloop?
One reason is for readability. Another is when you don't care about changing the element references of the array, but using the current references.
Take a reference type example
public class Foo {
public int a;
}
Foo[] array = new Foo[3];
for (int i = 0; i < array.length; i++) {
array[i] = new Foo();
array[i].a = i * 17;
}
for (Foo foo : array) {
foo.a = 0; // sets the value of `a` in each Foo object
foo = new Foo(); // create new Foo object, but doesn't replace the one in the array
}
With primitive types such a thing doesn't work.
for (int index = 0; index < array.length; index++) {
int i = array[index];
i = 1; // doesn't change array[index]
}
From Item 46 in Effective Java by Joshua Bloch :
The for-each loop, introduced in release 1.5, gets rid of the clutter
and the opportunity for error by hiding the iterator or index variable
completely. The resulting idiom applies equally to collections and
arrays:
// The preferred idiom for iterating over collections and arrays
for (Element e : elements) {
doSomething(e);
}
When you see the colon (:), read it as “in.” Thus, the loop above
reads as “for each element e in elements.” Note that there is no
performance penalty for using the for-each loop, even for arrays. In
fact, it may offer a slight performance advantage over an ordinary for
loop in some circumstances, as it computes the limit of the array
index only once. While you can do this by hand (Item 45), programmers
don’t always do so.
Advantages
Readability
It increases the abstraction level - instead of having to express the low-level details of how to loop around a list
or array (with an index or iterator), the developer simply states that
they want to loop and the language takes care of the rest.
Disadvantage:
Cannot access the index or to remove an item.
To sum up,
the enhanced for loop offers
A concise higher level syntax to loop over a list or array which
1.1 improves clarity
1.2 readability.
However, it misses : allowing to access the index loop or to remove an item.
Setting the values by reference didn't work because int is a primitive type. For any kind of Object[] it would work. Making a copy of a primitive type is very fast, and will be done by the processor many times without your realising.
The foreach loop is more readable, but it's also more writeable. A common programmer error is:
for (int i = 0; i < 10; i++)
{
for(int j = 0; j < 10; i++) //oops, incrementing wrong variable!
{
//this will not execute as expected
}
}
It's impossible to make this error using a foreach loop.
The for statement also has another form designed for iteration through Collections and arrays This form is sometimes referred to as the enhanced for statement, and can be used to make your loops more compact and easy to read.
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html
So, you're right. Readability is the main win here. For further information on the for each loop, or enhanced for loop, here a blog entry from oralce.
The for each utilized the functionality of the Iterable<E> interface, so the performance depends on the implementation.

jvm crash on reading arraylist from java class with jni

I have troubles reading an arraylist from a java class with jni. In the java class the arraylist is defined like this
public static List XTN_STC_search_result = new ArrayList();
The arraylist then gets filled with a string, a score value as double and an array of integers.
So the structure looks like this:
[
[label str 1, score value 1, [int 1, int 2, int n]],
[label str 2, score value 2, [int 1, int 2],
...
]
On the JNI C side i do the following to read that arraylist.
After reading the static field and get the object I go into the loop iterating over the array to read all values. All goes well, I can read every single arraylist entry, the label string, the double value and can access the array of integers with a nested loop. Within the nested loop if fetch the integer array entry with getObjectArrayElement and it seems to get that value. Afterwards I test it on NULL and it is not NULL. To be pedantic I I double check if that array entry (of the integer array) is an instance of Integer with isInstanceOf. That very call crashes my program with SIGSEGV and JVM bails out.
Below you see the code snippet of the problemtic area ...
int
XTN_ce_java_get_cluster(XTN_VM_IDX vm_idx) {
...
/* java result object , the arraylist to read */
jobjectArray result_obj;
/* result object array (element of result_obj) */
jobjectArray jv_result_object_array;
jint jv_result_object_array_size;
/* element to hold phrase, score and nested integer array */
jobject jv_object_array_cluster_elem;
jint jv_object_array_cluster_elem_size;
...
/* get arraylist */
jv_result_object_array = (*(Record.env))->GetObjectArrayElement(
Record.env, result_obj, 1 );
jv_result_object_array_size = (*(Record.env))->GetArrayLength(Record.env,
jv_result_object_array );
...
/* loop over arraylist entries */
for (i = 0; i < jv_result_object_array_size; i++) {
/* read label string */
if ( (*(Record.env))->IsInstanceOf(Record.env,
(jobject)jv_object_array_cluster_elem, classString)) {
...
} else if ( (*(Record.env))->IsInstanceOf(Record.env, jv_object_array_cluster_elem, classObject)) {
/* we are about to read the integer array from the arraylist ... */
/* get size of integer array */
jv_object_array_cluster_elem_size = (*(Record.env))->GetArrayLength(
Record.env, jv_object_array_cluster_elem);
/* this case should not happen, the integer array has a minimum entry of 1 element */
if (jv_object_array_cluster_elem_size <= 0)
continue;
for (j = 0; j < jv_object_array_cluster_elem_size; j++) {
/* get element from integer array */
jv_cluster_data_array_elem = (*(Record.env))->GetObjectArrayElement(
Record.env, jv_object_array_cluster_elem, j);
/* check if null */
if (jv_cluster_data_array_elem == NULL) {
break;
/* now check type */
/* THIS CALL CRASHES JVM */
if ( (*(Record.env))->IsInstanceOf(Record.env, jv_cluster_data_array_elem,
classInteger)) {
fprintf(stdout, "got array entry of type integer */
}
...
} /* inner loop integer array */
} /* outer loop object array */
return 1;
}
I do not understand why it crashes there, even though I seem not to be able to access that field for reading (with GetIntField() for example). If I leave out the isInstanceOf call (just looping over the integer array) all goes fine, it loops over the complete arraylist, reads my strings and doubles, loops over the nested integer array and finishes successfully. Honestly the
Does anybody have a hint for me where to look or what to improve? I hope the provided code snippet of the arraylist reader function is complete enough to understand my problem. Maybe somebody can point me to the right direction on this issue, hopefully :-))
I use
JRE version: 6.0_22-b04
Java VM: Java HotSpot(TM) 64-Bit Server VM (17.1-b03 mixed mode linux-amd64 )
on Ubuntu
Thanks so much in advance for helping me out on this.
Update 2010/12/06:
==================
As Peter suggested, I completely reworked the object reader function using the
Java methods of the object through the native interface. Additionally it
turned out, that I even do not need that very arraylist I constructed in
the Java class, I rather used and read the internal class Results Object
List directly and its object methods to read the results I need. So in short,
now it is more efficient and I was able to skip that Arraylist construction
completey and spare one processing step.
First I thought, using the Java methods of that very class through JNI would
give me a much higher response time, using Java methods through JNI is surely
not very fast (compared to using the Java methods in Java directly). Using JNI
as a bridge from C to Java costs performance and computing time. But anyway, I
figured out, I am about 200ms faster (using the same data set) than my old
reader method with the arraylist, so I even gained some performance.
Ok, to put it in short, using JNI and the Object methods of the Java class
spared me a lot of headache and the code now is much more readable.
Conclusion: I would like to encourage everybody that is facing a similar
problem using the Object methods of the class you work with through JNI.
The first thing to note is that ArrayList != an array. The methods you are using to access the arraylist only work for an array.
I suggest you access the ArrayList by calling the methods of the List just as you would in Java.

Categories