-2

This is an interview question:

Suppose you are coding for an Android system which utilizes JNI and some C++ code to read data from a serial interface (uart, for example).

The bottom level stuff will be taken care of by the C++ code, and eventually data will be fed to a Java interface where it will be treated as the type String.

The question is: suppose the Java code handling the reading goes something like this:

private void parseSerialData(String input){

 if (input==null){
//DO SOMETHING HERE
    }
}

Will it ever be possible for the conditions of the if block be met?

My understanding of Java tells me it is never going to be possible because (I could be thoroughly wrong) null in Java is way to denominate "there is no reference", null isn't an object, and it wasn't instantiated from a class. At the DVM or JVM level, as long as a variable was declared, a reference was made, even though there may be no memory allocated for it on the stack.

Therefore it is impossible for a local variable as a parameter of a method to not have a reference to begin with, not to mention it was given a reference later on which points at a String object (even though this object may have no information with it, it is nevertheless, a non-null object) and as such, the if condition will never be met.

But I couldn't decide if this question is a trick question and I have omitted something? Especially considering that there's C++ in the fray, and I have no idea what it is like to pass a C++ null reference to Java, if it makes sense at all?

So, will the if condition be met, ever?

  • 1
    I would expect problems, return of NULL for example, if the JNI environment could not allocate storage for the `String`. This raises the question, why not just return the byte array and let Java convert it to `String`? Java has much better handling of Java `Strings` than C++ does. I can't imagine that messing with the character encoding would be easier in C++ than in Java. – user4581301 Mar 09 '19 at 01:54
  • 2
    If a variable is declared there is allways a reference unless primitive. Having a reference(variable) on the stack doesn't mean that the value of this reference can't be Null(that value is what you are checking). – kai Mar 09 '19 at 02:01
  • @kai Under what circumstances will a reference be present but at the same time, be null unintentionally? – ElasticHeart Mar 09 '19 at 04:29
  • @user4581301 Other than not being able to allocate memory for the String, what are the possible scenarios where the reference for a local variable could be null? Also, consider that the possibility of not being able to allocate memory for String, why would a byte array eliminates that problem? – ElasticHeart Mar 09 '19 at 04:31
  • Sending the byte array probably wouldn't help with the potential for `null`, but it makes the conversion of those bytes into `String` friendly characters easier. Someone has to have an answer to that bit written up. [And here it is!](https://stackoverflow.com/a/24564937/4581301) – user4581301 Mar 09 '19 at 05:00
  • Well I could understand intentionally but unintentionally? Thats what nullpointer errors famous for. If you get them unintentionally you may be seaching for ages where they came from. Btw. I am not a big fan of nullpointer checks as nullpointer errors result from bugs that needs fixing instead of ignoring/hiding. Taking that into accout there are no cases other than some library calls returning null that should need checks.(but don't be dogmatic!) – kai Mar 09 '19 at 05:11

1 Answers1

3

Yes, of course input can be null. It simply depends on what the C++ code does. Here is a complete example. It wasn't clear from your description whether the native method returns the String or passes it as a parameter from a native method to a java method, so I included an example of each.

This program calls f five times. The first three times simply pass a constant value. The following two times wait for input (in a native method) and pass either null or non-null to f depending on whether the input is empty or not.

Test.java

public class Test
{
    static {
        System.loadLibrary("Test");
    }

    public static void main(String [] args)
    {
        Test obj = new Test();
        obj.main();
    }

    void main()
    {
        f(null);
        f("not null");
        String s1 = null;
        f(s1);
        String s2 = n1();
        f(s2);
        n2();
    }

    public void f(String s)
    {
        if (s == null)
            System.out.println("null");
        else
            System.out.println(s);
    }

    native String n1();
    native void n2();
}

Test.cc

#include <stdio.h>
#include <jni.h>
#include "Test.h"

static jstring get_string(JNIEnv *env);

JNIEXPORT jstring JNICALL Java_Test_n1(JNIEnv *env, jobject obj)
{
    return get_string(env);
}

JNIEXPORT void JNICALL Java_Test_n2(JNIEnv *env, jobject obj)
{
    jstring s = get_string(env);
    jclass cls = env->GetObjectClass(obj);
    jmethodID f = env->GetMethodID(cls, "f", "(Ljava/lang/String;)V");
    env->CallVoidMethod(obj, f, s);
}

static jstring get_string(JNIEnv *env)
{
    char buf[20];
    if (fgets(buf, sizeof buf, stdin) == NULL)
        return NULL;
    if (buf[0] == '\n')
        return NULL;
    return env->NewStringUTF(buf);
}

Build instructions

$ javac Test.java
$ javah Test
$ gcc --std=c++11 -I $JAVA_HOME/include -I $JAVA_HOME/include/linux  -fPIC -shared -o libTest.so Test.cc
$ /usr/bin/java -Djava.library.path=. Test
prl
  • 11,716
  • 2
  • 13
  • 31