我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Android组件Activity的启动过程是什么

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Android组件Activity的启动过程是什么

这篇文章主要介绍了Android组件Activity的启动过程是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Android组件Activity的启动过程是什么文章都会有所收获,下面我们一起来看看吧。

在分析之前,我先介绍几个类:
  • Activity:这个大家都熟悉,startActivity方法的真正实现在Activity中

  • Instrumentation:用来辅助Activity完成启动Activity的过程

  • ActivityThread(包含ApplicationThread + ApplicationThreadNative +IApplicationThread):真正启动Activity的实现都在这里

源码分析

首先看入口

code:Activity#startActivity

@Override public void startActivity(Intent intent) {  startActivity(intent, null); } @Override public void startActivity(Intent intent, Bundle options) {  if (options != null) {   startActivityForResult(intent, -1, options);  } else {   // Note we want to go through this call for compatibility with   // applications that may have overridden the method.   startActivityForResult(intent, -1);  } } public void startActivityForResult(Intent intent, int requestCode) {  startActivityForResult(intent, requestCode, null); }

说明:显然,从上往下,最终都是由startActivityForResult来实现的

接着看

code:Activity#startActivityForResult

public void startActivityForResult(Intent intent, int requestCode, Bundle options) {  //一般的Activity其mParent为null,mParent常用在ActivityGroup中,ActivityGroup已废弃  if (mParent == null) {   //这里会启动新的Activity,核心功能都在mMainThread.getApplicationThread()中完成   Instrumentation.ActivityResult ar =    mInstrumentation.execStartActivity(     this, mMainThread.getApplicationThread(), mToken, this,     intent, requestCode, options);   if (ar != null) {    //发送结果,即onActivityResult会被调用    mMainThread.sendActivityResult(     mToken, mEmbeddedID, requestCode, ar.getResultCode(),     ar.getResultData());   }   if (requestCode  = 0) {    // If this start is requesting a result, we can avoid making    // the activity visible until the result is received. Setting    // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the    // activity hidden during this time, to avoid flickering.    // This can only be done when a result is requested because    // that guarantees we will get information back when the    // activity is finished, no matter what happens to it.    mStartedActivity = true;   }   final View decor = mWindow != null ? mWindow.peekDecorView() : null;   if (decor != null) {    decor.cancelPendingInputEvents();   }   // TODO Consider clearing/flushing other event sources and events for child windows.  } else {   //在ActivityGroup内部的Activity调用startActivity的时候会走到这里,内部处理逻辑和上面是类似的   if (options != null) {    mParent.startActivityFromChild(this, intent, requestCode, options);   } else {    // Note we want to go through this method for compatibility with    // existing applications that may have overridden it.    mParent.startActivityFromChild(this, intent, requestCode);   }  } }

说明:上述代码关键点都有注释了,可以发现,真正打开activity的实现在Instrumentation的execStartActivity方法中,去看看

code:Instrumentation#execStartActivity

public ActivityResult execStartActivity(   Context who, IBinder contextThread, IBinder token, Activity target,   Intent intent, int requestCode, Bundle options) {  //核心功能在这个whoThread中完成,其内部scheduleLaunchActivity方法用于完成activity的打开  IApplicationThread whoThread = (IApplicationThread) contextThread;  if (mActivityMonitors != null) {   synchronized (mSync) {    //先查找一遍看是否存在这个activity    final int N = mActivityMonitors.size();    for (int i=0; i<N; i++) {     final ActivityMonitor am = mActivityMonitors.get(i);     if (am.match(who, null, intent)) {      //如果找到了就跳出循环      am.mHits++;      //如果目标activity无法打开,直接return      if (am.isBlocking()) {       return requestCode  = 0 ? am.getResult() : null;      }      break;     }    }   }  }  try {   intent.migrateExtraStreamToClipData();   intent.prepareToLeaveProcess();   //这里才是真正打开activity的地方,核心功能在whoThread中完成。   int result = ActivityManagerNative.getDefault()    .startActivity(whoThread, who.getBasePackageName(), intent,      intent.resolveTypeIfNeeded(who.getContentResolver()),      token, target != null ? target.mEmbeddedID : null,      requestCode, 0, null, null, options);   //这个方法是专门抛异常的,它会对结果进行检查,如果无法打开activity,   //则抛出诸如ActivityNotFoundException类似的各种异常   checkStartActivityResult(result, intent);  } catch (RemoteException e) {  }  return null; }

说明:我想再说一下这个方法checkStartActivityResult,它也专业抛异常的,看代码,相信大家对下面的异常信息不陌生吧,就是它干的,其中最熟悉的非Unable to find explicit activity class莫属了,如果你在xml中没有注册目标activity,此异常将会抛出。

 static void checkStartActivityResult(int res, Object intent) {  if (res  = ActivityManager.START_SUCCESS) {   return;  }  switch (res) {   case ActivityManager.START_INTENT_NOT_RESOLVED:   case ActivityManager.START_CLASS_NOT_FOUND:    if (intent instanceof Intent && ((Intent)intent).getComponent() != null)     throw new ActivityNotFoundException(       "Unable to find explicit activity class "       + ((Intent)intent).getComponent().toShortString()       + "; have you declared this activity in your AndroidManifest.xml?");    throw new ActivityNotFoundException(      "No Activity found to handle " + intent);   case ActivityManager.START_PERMISSION_DENIED:    throw new SecurityException("Not allowed to start activity "      + intent);   case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:    throw new AndroidRuntimeException(      "FORWARD_RESULT_FLAG used while also requesting a result");   case ActivityManager.START_NOT_ACTIVITY:    throw new IllegalArgumentException(      "PendingIntent is not an activity");   default:    throw new AndroidRuntimeException("Unknown error code "      + res + " when starting " + intent);  } }

接下来我们要去看看IApplicationThread,因为核心功能由其内部的scheduleLaunchActivity方法来完成,由于IApplicationThread是个接口,所以,我们需要找到它的实现类,我已经帮大家找到了,它就是ActivityThread中的内部类ApplicationThread,看下它的继承关系:

private class ApplicationThread extends ApplicationThreadNative;

public abstract class ApplicationThreadNative extends Binder implements IApplicationThread;

可以发现,ApplicationThread还是间接实现了IApplicationThread接口,先看下这个类的结构

Android组件Activity的启动过程是什么

看完ApplicationThread的大致结构,我们应该能够猜测到,Activity的生命周期中的resume、newIntent、pause、stop等事件都是由它触发的,事实上,的确是这样的。这里,我们为了说明问题,仅仅看scheduleLaunchActivity方法

code:ApplicationThread#scheduleLaunchActivity

public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,   ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,   int procState, Bundle state, List<ResultInfo  pendingResults,   List<Intent  pendingNewIntents, boolean notResumed, boolean isForward,   String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {  updateProcessState(procState, false);  ActivityClientRecord r = new ActivityClientRecord();  r.token = token;  r.ident = ident;  r.intent = intent;  r.activityInfo = info;  r.compatInfo = compatInfo;  r.state = state;  r.pendingResults = pendingResults;  r.pendingIntents = pendingNewIntents;  r.startsNotResumed = notResumed;  r.isForward = isForward;  r.profileFile = profileName;  r.profileFd = profileFd;  r.autoStopProfiler = autoStopProfiler;  updatePendingConfiguration(curConfig);  queueOrSendMessage(H.LAUNCH_ACTIVITY, r); }

说明:上述代码很好理解,构造一个activity记录,然后发送一个消息,所以,我们要看看Handler是如何处理这个消息的,现在转到这个Handler,它有个很短的名字叫做H

code:ActivityThread#H

//这个类太长,我只帖出了我们用到的部分 private class H extends Handler {  public void handleMessage(Message msg) {   if (DEBUG_MESSAGES) Slog.v(TAG, "    handling: " + codeToString(msg.what));   switch (msg.what) {    //这里处理LAUNCH_ACTIVITY消息类型    case LAUNCH_ACTIVITY: {     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");     ActivityClientRecord r = (ActivityClientRecord)msg.obj;     r.packageInfo = getPackageInfoNoCheck(       r.activityInfo.applicationInfo, r.compatInfo);     //这里处理startActivity消息     handleLaunchActivity(r, null);     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);    } break;    case RELAUNCH_ACTIVITY: {     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");     ActivityClientRecord r = (ActivityClientRecord)msg.obj;     handleRelaunchActivity(r);     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);    } break;    case PAUSE_ACTIVITY:     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");     handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);     maybeSnapshot();     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);     break;    ...   } }

说明:看来还要看handleLaunchActivity

code:ActivityThread#handleLaunchActivity

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); if (r.profileFd != null) { mProfiler.setProfiler(r.profileFile, r.profileFd); mProfiler.startProfiling(); mProfiler.autoStopProfiler = r.autoStopProfiler; } // Make sure we are running with the most recent config. handleConfigurationChanged(null, null); if (localLOGV) Slog.v( TAG, "Handling launch of " + r); //终于到底了,大家都有点不耐烦了吧,从方法名可以看出, //performLaunchActivity真正完成了activity的调起, //同时activity会被实例化,并且onCreate会被调用 Activity a = performLaunchActivity(r, customIntent); if (a != null) { r.createdConfig = new Configuration(mConfiguration); Bundle oldState = r.state; //看到没,目标activity的onResume会被调用 handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed); if (!r.activity.mFinished && r.startsNotResumed) { // The activity manager actually wants this one to start out // paused, because it needs to be visible but isn't in the // foreground. We accomplish this by going through the // normal startup (because activities expect to go through // onResume() the first time they run, before their window // is displayed), and then pausing it. However, in this case // we do -not- need to do the full pause cycle (of freezing // and such) because the activity manager assumes it can just // retain the current state it has. try { r.activity.mCalled = false; //同时,由于新activity被调起了,原activity的onPause会被调用 mInstrumentation.callActivityOnPause(r.activity); // We need to keep around the original state, in case // we need to be created again. But we only do this // for pre-Honeycomb apps, which always save their state // when pausing, so we can not have them save their state // when restarting from a paused state. For HC and later, // we want to (and can) let the state be saved as the normal // part of stopping the activity. if (r.isPreHoneycomb()) { r.state = oldState; } if (!r.activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onPause()"); } } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { throw new RuntimeException( "Unable to pause activity " + r.intent.getComponent().toShortString() + ": " + e.toString(), e); } } r.paused = true; } } else { // If there was an error, for any reason, tell the activity // manager to stop us. try { ActivityManagerNative.getDefault() .finishActivity(r.token, Activity.RESULT_CANCELED, null); } catch (RemoteException ex) { // Ignore } } }

说明:关于原activity和新activity之间的状态同步,如果大家感兴趣可以自己研究下,因为逻辑太复杂,我没法把所有问题都说清楚,否则就太深入细节而淹没了整体逻辑,研究源码要的就是清楚整体逻辑。下面看最后一个方法,这个方法是activity的启动过程的真正实现。

code:ActivityThread#performLaunchActivity

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")"); ActivityInfo aInfo = r.activityInfo; if (r.packageInfo == null) { r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE); } //首先从intent中解析出目标activity的启动参数 ComponentName component = r.intent.getComponent(); if (component == null) { component = r.intent.resolveActivity( mInitialApplication.getPackageManager()); r.intent.setComponent(component); } if (r.activityInfo.targetActivity != null) { component = new ComponentName(r.activityInfo.packageName, r.activityInfo.targetActivity); } Activity activity = null; try { java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); //用ClassLoader(类加载器)将目标activity的类通过类名加载进来并调用newInstance来实例化一个对象 //其实就是通过Activity的无参构造方法来new一个对象,对象就是在这里new出来的。 activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); if (r.state != null) { r.state.setClassLoader(cl); } } catch (Exception e) { if (!mInstrumentation.onException(activity, e)) { throw new RuntimeException( "Unable to instantiate activity " + component + ": " + e.toString(), e); } } try { Application app = r.packageInfo.makeApplication(false, mInstrumentation); if (localLOGV) Slog.v(TAG, "Performing launch of " + r); if (localLOGV) Slog.v( TAG, r + ": app=" + app + ", appName=" + app.getPackageName() + ", pkg=" + r.packageInfo.getPackageName() + ", comp=" + r.intent.getComponent().toShortString() + ", dir=" + r.packageInfo.getAppDir()); if (activity != null) { Context appContext = createBaseContextForActivity(r, activity); CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity " + r.activityInfo.name + " with config " + config); activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config); if (customIntent != null) { activity.mIntent = customIntent; } r.lastNonConfigurationInstances = null; activity.mStartedActivity = false; int theme = r.activityInfo.getThemeResource() if (theme != 0) { activity.setTheme(theme); } activity.mCalled = false; //目标activity的onCreate被调用了,到此为止,Activity被启动了,接下来的流程就是Activity的生命周期了, //本文之前已经提到,其生命周期的各种状态的切换由ApplicationThread内部来完成 mInstrumentation.callActivityOnCreate(activity, r.state); if (!activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onCreate()"); } r.activity = activity; r.stopped = true; if (!r.activity.mFinished) { activity.performStart(); r.stopped = false; } if (!r.activity.mFinished) { if (r.state != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); } } if (!r.activity.mFinished) { activity.mCalled = false; mInstrumentation.callActivityOnPostCreate(activity, r.state); if (!activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onPostCreate()"); } } } r.paused = true; mActivities.put(r.token, r); } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { if (!mInstrumentation.onException(activity, e)) { throw new RuntimeException( "Unable to start activity " + component + ": " + e.toString(), e); } } return activity; }

关于“Android组件Activity的启动过程是什么”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Android组件Activity的启动过程是什么”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Android组件Activity的启动过程是什么

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android组件Activity的启动过程是什么

这篇文章主要介绍了Android组件Activity的启动过程是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Android组件Activity的启动过程是什么文章都会有所收获,下面我们一起来看看吧。在分析
2023-07-06

Android组件Activity的启动过程深入分析

这篇文章主要介绍了Android组件Activity的启动过程,Activity作为Android四大组件之一,他的启动没有那么简单。这里涉及到了系统服务进程,启动过程细节很多,这里我只展示主体流程。activity的启动流程随着版本的更替,代码细节一直在进行更改,每次都会有很大的修改
2023-05-15

android activity启动流程是什么

Android Activity的启动流程如下:1. 调用`startActivity()`方法或者`startActivityForResult()`方法启动目标Activity。2. 系统会检查启动目标Activity是否存在,并且是否
2023-08-08

activity启动流程是什么

Activity启动流程是指在Android应用中启动Activity的一系列操作。它包括以下步骤:1. 调用startActivity()方法:通过调用startActivity()方法,向系统发出启动Activity的请求。2. 系统检
2023-09-11

Android中 Activity的启动过程有哪些

Android中 Activity的启动过程有哪些,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。分析Android Activity的启动过程
2023-05-30

Android中APP的启动过程是什么

在Android中,APP的启动过程主要包括以下几个步骤:1. 用户点击APP图标或通过其他方式触发APP启动的事件。2. 系统根据APP的包名和启动模式,查找并启动对应的Activity组件。3. 系统会依次调用Activity的生命周期
2023-08-08

android应用启动过程是什么

Android应用的启动过程可以分为以下几个步骤:1. 用户点击应用图标:用户在设备上点击应用图标,触发应用的启动。2. 系统启动应用进程:Android系统根据应用的包名,启动对应的应用进程。3. 应用进程初始化:应用进程启动后,会进行一
2023-09-09

[图解]Android源码分析——Activity的启动过程

Activity的启动过程一.Launcher进程请求AMSLauncher.java的startActivitySafely方法的执行过程:Activity.java中startActivity方法的执行过程:startActivityF
2022-06-06

activity启动的方法是什么

Activity启动的方法是调用startActivity()或startActivityForResult()方法。startActivity()方法用于启动一个新的Activity,而startActivityForResult()方法
2023-09-11

Android中的ActivityThread和APP启动过程是什么

ActivityThread是Android中负责管理所有Activity的线程,它负责处理Activity的生命周期、事件分发、消息处理等工作。APP启动过程如下:用户点击应用图标,系统会启动应用的进程。系统会创建一个Activity
Android中的ActivityThread和APP启动过程是什么
2024-03-08

android启动流程是什么

Android启动流程是指从手机开机到系统完全启动的过程。具体的流程如下:1. 电源按下:当用户按下电源键时,电源管理芯片会向处理器发送一个启动信号。2. 启动引导加载程序(Bootloader):处理器接收到启动信号后,会从内存中的固定地
2023-10-11

android launcher启动流程是什么

Android Launcher的启动流程如下:1. 用户点击设备上的Home按钮或者通过其他方式启动Launcher应用。2. 系统会检查是否有其他应用正在运行,如果有,则会将其置于后台。3. Launcher应用会被激活并开始启动。4.
2023-10-20

spring容器启动过程是什么

Spring容器的启动过程如下:1. 加载配置文件:Spring容器需要加载一个或多个配置文件,配置文件可以是XML文件、Java注解或者Java配置类。2. 创建BeanFactory:Spring容器会根据配置文件中的定义,创建一个Be
2023-09-14

Android framework ATMS启动流程是什么

这篇文章主要介绍“Android framework ATMS启动流程是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Android framework ATMS启动流程是什么”文章能帮助大家解
2023-07-05

Android应用程序的启动流程是什么

本篇内容介绍了“Android应用程序的启动流程是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!应用进程的启动流程本文基于Android
2023-07-05

Android广播Broadcast的启动流程是什么

这篇“Android广播Broadcast的启动流程是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android广播B
2023-07-05

Android Service启动绑定流程是什么

这篇文章主要介绍了Android Service启动绑定流程是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Android Service启动绑定流程是什么文章都会有所收获,下面我们一起来看看吧。一、Ser
2023-07-05

Android系统启动流程的重要性是什么

Android系统启动流程的重要性在于确保系统能够正常启动并运行。启动流程包括各个组件的初始化、资源加载、服务启动等步骤,这些步骤的顺序和正确执行对于系统的稳定性和性能至关重要。重要性体现在以下几个方面:1. 系统稳定性:启动流程的正确执行
2023-10-11

VB.NET监视启动过程的具体步骤是什么

VB.NET监视启动过程的具体步骤是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。大家可能会对VB.NET启动过程的实现不是很陌生,因为这一操作技巧是比较基础的,初学者在学
2023-06-17

elasticsearch节点间通信的transport启动过程是什么

这篇文章主要介绍“elasticsearch节点间通信的transport启动过程是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“elasticsearch节点间通信的transport启动过程
2023-06-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录