欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android高级岗面试实战03——某人工智能创业公司技术一面

程序员文章站 2024-03-22 14:25:52
...

这家公司很小,小到就一个大一点的办公室,以至于面试时会议室有人开会,所以我是在阳台上面的。

1.malloc,calloc有什么区别?

    void Test( void )
    {
     char *str = (char *) malloc( 100 );
     strcpy( str, "hello" );
     free( str ); 
     str = null;
    }

malloc调用形式为(类型*)malloc(size):在内存的动态存储区中分配一块长度为“size”字节的连续区域,返回该区域的首地址。
calloc调用形式为(类型*)calloc(n,size):在内存的动态存储区中分配n块长度为“size”字节的连续区域,返回首地址。

2.JNI层如何调用java层函数?

说实话,这个问题并没有回答的很好,可能做过,但根本不记得了!

https://blog.csdn.net/hty1053240123/article/details/52126386

https://blog.csdn.net/u010308400/article/details/50327965?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-1.nonecase

个人认为第二篇博客参考的比较好

package com.example.ndkcallback;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class DataProvider {
    //C调用java空方法
    public void helloFromJava(){
        System.out.println("哈哈哈  我被调用了");
    }
    //C调用java中的带两个int参数的方法
    public int Add(int x,int y){
         int result=x+y;
        System.out.println("result:"+result);
        return result;
    }
    //C调用java中参数为string的方法
    public void printString(String s){
        System.out.println(s);
    }

    public static void demo(){
        System.out.println("哈哈哈,我是静态方法");

    }

    public native void callMethod1();
    public native void callMethod2();
    public native void callMethod3();
    public native void callMethod4();
    public native void callMethod5();
}

配置build和Androidl.mk, javah生成头文件

#include "com_example_ndkcallback_DataProvider.h"


JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod1
  (JNIEnv * env, jobject jobject){

    /*
     *
        Class<?> forName = Class.forName("com.example.ndkcallback.DataProvider");
        Method declaredMethod = forName.getDeclaredMethod("helloFromJava", new Class[]{});
        declaredMethod.invoke(forName.newInstance(), new Object[]{});
     *
     *
     */
    ///jclass      (*FindClass)(JNIEnv*, const char*);
    jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/DataProvider");
    //  jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
    // 方法签名  参数和返回值
    jmethodID methodId=(*env)->GetMethodID(env,clazz,"helloFromJava","()V");
    // void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
    (*env)->CallVoidMethod(env,jobject,methodId);
}

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod2
  (JNIEnv *  env, jobject jobject){
    jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/DataProvider");
    jmethodID methodId=(*env)->GetMethodID(env,clazz,"Add","(II)I");
    // jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
    (*env)->CallIntMethod(env,jobject,methodId,3,5);
}

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod3
  (JNIEnv * env, jobject jobject){   // 参数 object  就是native方法所在的类
    jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/DataProvider");
        jmethodID methodId=(*env)->GetMethodID(env,clazz,"printString","(Ljava/lang/String;)V");
        // jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
        jstring str=(*env)->NewStringUTF(env,"hello");

        (*env)->CallVoidMethod(env,jobject,methodId,str);

}

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod4
  (JNIEnv * env, jobject j){
    jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/MainActivity");
    //  jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
    // 方法签名  参数和返回值
    jmethodID methodId=(*env)->GetMethodID(env,clazz,"helloFromJava","()V");
    // void        (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
    // 需要创建DataProvider的 对象
    // jobject     (*AllocObject)(JNIEnv*, jclass);
    jobject obj=(*env)->AllocObject(env,clazz);  // new MainActivity();
    (*env)->CallVoidMethod(env,obj,methodId);

}

JNIEXPORT void JNICALL Java_com_example_ndkcallback_DataProvider_callMethod5
  (JNIEnv * env, jobject j){
    jclass clazz=(*env)->FindClass(env,"com/example/ndkcallback/DataProvider");
    //     jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);
     jmethodID  methodid=(*env)->GetStaticMethodID(env,clazz,"demo","()V");
    //void        (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);
     (*env)->CallStaticVoidMethod(env,clazz,methodid);
}

上面代码大家需要注意一点:()V代表参数为空,返回为void;(Ljava/lang/String;)V代表参数为String类型,返回为void;(II)I代表参数值为(int,int)返回值也为int。

3.OKHttp支持哪些版本Http协议?

支持 spdy、http2.0

4.自定义相机用的camera几?

https://blog.csdn.net/dongxianfei/article/details/91445918

比较camera和camera2的区别!感觉问题都比较偏。

5.JNI方法注册方式,你用的哪一种?(*****)

分为静态注册和动态注册

https://www.jianshu.com/p/18e3a9e9cec9

静态注册

原理:根据函数名来建立 java 方法与 JNI 函数的一一对应关系;

实现流程:

编写 java 代码;

利用 javah 指令生成对应的 .h 文件;

对 .h 中的声明进行实现;

弊端:

编写不方便,JNI 方法名字必须遵循规则且名字很长;

编写过程步骤多,不方便;

程序运行效率低,因为初次调用native函数时需要根据根据函数名在JNI层中搜索对应的本地函数,然后建立对应关系,这个过程比较耗时;

typedef struct {
    const char* name; // Java方法的名字
    const char* signature; //Java方法的签名信息
    void*  fnPtr; //JNI中对应的方法指针
} JNINativeMethod;
#include <jni.h>
#include <string>

#include<android/log.h>

#define TAG "test-jni"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型

/**
 * 静态注册方式,方法名按照标准写法Java_包名_类名_方法名
 */
extern "C" JNIEXPORT jstring JNICALL Java_com_jianjin33_demo2_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) 
{
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

// 接下来是动态注册的方式,需要实现jni.h中的JNI_OnLoad方法

// 方法名可以随意些
extern "C" JNIEXPORT jstring JNICALL native_stringFromJni2(JNIEnv *env, jclass clazz)
{
    return env->NewStringUTF("动态注册jni函数返回结果");
}

static int registerNativeMethods(JNIEnv* env, const char* className,
                                 JNINativeMethod* gMethods, int numMethods)
{
    jclass clazz;
    clazz = env->FindClass(className);
    if (clazz == NULL) {
        return JNI_FALSE;
    }
    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
        return JNI_FALSE;
    }
    return JNI_TRUE;
}

#define JNIREG_CLASS "com/jianjin33/demo2/MainActivity" // 指定要注册的类
// JNINativeMethod结构体就是文章开头介绍的
static JNINativeMethod gMethods[] = {
        { "stringFromJni2", "()Ljava/lang/String;", (void*)native_stringFromJni2}, // 绑定
};
static int registerNatives(JNIEnv* env)
{
    if (!registerNativeMethods(env, JNIREG_CLASS, gMethods, sizeof(gMethods) / sizeof(gMethods[0])))
        return JNI_FALSE;
    return JNI_TRUE;
}

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
{
    LOGI("%s","开始走JNI_OnLoad");
    JNIEnv* env = NULL;
    jint result = -1;
    if (vm->GetEnv((void**) &env, JNI_VERSION_1_6) != JNI_OK) {
        return -1;
    }
    assert(env != NULL);

    if (!registerNatives(env)) { // 注册
        return -1;
    }
    result = JNI_VERSION_1_6;
    return result;
}

java代码

static {
        System.loadLibrary("native-lib");
    }
public native String stringFromJNI(); // 静态注册方式
public native String stringFromJNI2(); // 动态注册方式

静态注册:根据函数名来建立Java函数和JNI函数之间的关联关系,要求JNI层函数的名字必须遵守特定的格式,所以书写起来比较长,并且,初次调用本地函数时要根据函数名搜索JNI层函数来建立关联关系,会影响运行效率。
动态注册:扩展性较好,避免了静态注册的不足之处。