==========================上===========================

这里简单的介绍了Android的java环境基础,在后面一节中会结合具体的实例来理解这一节的内容。

一、Dalvik虚拟机

Dalvik是android的程序的java虚拟机,代码在dalvik/下,

./
|-- Android.mk
|-- CleanSpec.mk
|-- MODULE_LICENSE_APACHE2
|-- NOTICE
|-- README.txt
|-- dalvikvm 虚拟机的实现库
|-- dexdump
|-- dexlist
|-- dexopt
|-- docs
|-- dvz
|-- dx
|-- hit
|-- libcore
|-- libcore-disabled
|-- libdex
|-- libnativehelper 使用JNI调用本地代码时用到这个库
|-- run-core-tests.sh
|-- tests
|-- tools
`-- vm

二、android的java框架

android层次中第3层是java框架,第四层就是java应用程序。

android的java类代码,主要是在frameworks/base/core/java/下,

./
|-- android
|-- com
|-- jarjar-rules.txt
`-- overview.html

我们再看一下frameworks/base/目录

./
|-- Android.mk
|-- CleanSpec.mk
|-- MODULE_LICENSE_APACHE2
|-- NOTICE
|-- api
|-- awt
|-- build
|-- camera
|-- cmds
|-- common
|-- core
|-- data
|-- docs
|-- graphics
|-- include
|-- keystore
|-- libs
|-- location
|-- media
|-- native
|-- obex
|-- opengl
|-- packages
|-- preloaded-classes
|-- sax
|-- services
|-- telephony
|-- test-runner
|-- tests
|-- tools
|-- vpn
`-- wifi

这里也有android的java框架代码。

三、JNI

在android中,通过JNI,java可以调用C写的代码,主要的实现是在frameworks/base/core/jni,通过查看Android.mk,我们可以看到最后生成了libandroid_runtime.so,具体实现JNI功能需要上面我们介绍的libnativehelper.so,

四、系统服务之java

1、binder,提供android的IPC功能

2、servicemanager,服务管理的服务器端

3、系统进程zygote,负责孵化所有的新应用

============================中===========================

在我平时工作中主要是进行linux网络子系统的模块开发、linux应用程序(C/C++)开发。在学习和从事驱动模块开发的过程中,如果你对linux系统本身,包括应用程序开发都不了解,那么读内核代码就如同天书,毫无意义,所以我分析框架也是从基本系统api开始的,当然也不会太多涉及到应用程序开发。

好,开始这节主要是讲一个简单的adnroid应用程序,从应用程序出发,到框架代码。

分析的应用程序我们也奉行拿来主义:froyo/development/samples/HelloActivity

./
|-- Android.mk
|-- AndroidManifest.xml
|-- res
|-- src
`-- tests

其他的就多说了,看代码

1./*
2. * Copyright (C) 2007 The Android Open Source Project
3. *
4. * Licensed under the Apache License, Version 2.0 (the "License");
5. * you may not use this file except in compliance with the License.
6. * You may obtain a copy of the License at
7. *
8. *      http://www.apache.org/licenses/LICENSE-2.0
9. *
10. * Unless required by applicable law or agreed to in writing, software
11. * distributed under the License is distributed on an "AS IS" BASIS,
12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13. * See the License for the specific language governing permissions and
14. * limitations under the License.
15. */ 
16.package com.example.android.helloactivity;  17.import android.app.Activity;  18.import android.os.Bundle;  19./** 20. * A minimal "Hello, World!" application.
21. */ 
22.public class HelloActivity extends Activity {  23.    public HelloActivity() {  24.    } 
25.    /** 26.     * Called with the activity is first created.
27.     */ 
28.    @Override  29.    public void onCreate(Bundle savedInstanceState) {  30.        super.onCreate(savedInstanceState);  31.        // Set the layout for this activity.  You can find it   32.        // in res/layout/hello_activity.xml   33.        setContentView(R.layout.hello_activity); 
34.    } 
35.}

每一个写过android程序的人都应该是从这个代码起步的吧?那好,那么我们研究android框架也从这里启航。

首先是

1.import android.app.Activity; 
2.import android.os.Bundle; 
记住,我们这里不是讲JAVA,我们要讲的是android.app.Activity,回顾上节的内容,android的JAVA框架代码放在froyo/frameworks/base/,
其中Activity的代码放在框架代码的core/java/android/app/Activity.java,大概看一下

1.public class Activity extends ContextThemeWrapper 
2.        implements LayoutInflater.Factory,

3.        Window.Callback, KeyEvent.Callback, 
4.        OnCreateContextMenuListener, ComponentCallbacks { 
5.    private static final String TAG = "Activity";  6.    /** Standard activity result: operation canceled. */  7.    public static final int RESULT_CANCELED    = 0;  8.    /** Standard activity result: operation succeeded. */  9.    public static final int RESULT_OK           = -1;  10.    /** Start of user-defined activity results. */  11.    public static final int RESULT_FIRST_USER   = 1;  12.    private static long sInstanceCount = 0; 
同样的Bundle的代码core/java/android/os/Bundle.java

1.public final class Bundle implements Parcelable, Cloneable {

2.    private static final String LOG_TAG = "Bundle";

3.    public static final Bundle EMPTY; 
呵呵,其实写多应用程序,然后看看这些代码,会有更加豁然开朗的感觉,所以列出以上目录给大家参考,所有的java框架代码都在那个目录下,到这里今天要讨论的第一个问题就到这里了。

我所在的公司是网络设备供应商,其实和android本身不搭边,android只是平时的爱好而已,所以很多地方如果写错了敬请原谅,当然也计划去做做android系统开发,例如驱动或者是框架开发,这是后话。

=========================下===================

上节讲到了JAVA框架代码和应用程序的关系,那么框架代码和驱动层是怎么联系的呢?这就是这一节的内容:JNI

java使用一种叫做jni的技术来支持对C/C++代码的调用,在anroid中jni的代码放在froyo/frameworks/base/core/jni下,当然在java框架代码的目录下还有其他地方也多多少少放了jni代码,大家可以打开源码来看看。

整体关系如下图:

| java应用程序

--------------------------------------- Android系统api

| java框架

|本地接口声明

--------------------------------------

| JNI
--------------------------------------

| C/C++代码

继续拿来主义,C/C++中调试用printf,内核调试用printk,呵呵,android调试用log,那么我们就分析log的实现。

log的java代码froyo/frameworks/base/core/java/android/util/Log.java,

1./*
2. * Copyright (C) 2006 The Android Open Source Project
3. *
4. * Licensed under the Apache License, Version 2.0 (the "License");
5. * you may not use this file except in compliance with the License.
6. * You may obtain a copy of the License at
7. *
8. *      http://www.apache.org/licenses/LICENSE-2.0
9. *
10. * Unless required by applicable law or agreed to in writing, software
11. * distributed under the License is distributed on an "AS IS" BASIS,
12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13. * See the License for the specific language governing permissions and
14. * limitations under the License.
15. */ 
16.package android.util;  17.import com.android.internal.os.RuntimeInit;  18.import java.io.PrintWriter;  19.import java.io.StringWriter;  20./** 21. * API for sending log output.
22. *
23. * <p>Generally, use the Log.v() Log.d() Log.i() Log.w() and Log.e()
24. * methods.
25. *
26. * <p>The order in terms of verbosity, from least to most is
27. * ERROR, WARN, INFO, DEBUG, VERBOSE.  Verbose should never be compiled
28. * into an application except during development.  Debug logs are compiled
29. * in but stripped at runtime.  Error, warning and info logs are always kept.
30. *
31. * <p><b>Tip:</b> A good convention is to declare a <code>TAG</code> constant
32. * in your class:
33. *
34. * <pre>private static final String TAG = "MyActivity";</pre>
35. *
36. * and use that in subsequent calls to the log methods.
37. * </p>
38. *
39. * <p><b>Tip:</b> Don't forget that when you make a call like
40. * <pre>Log.v(TAG, "index=" + i);</pre>
41. * that when you're building the string to pass into Log.d, the compiler uses a
42. * StringBuilder and at least three allocations occur: the StringBuilder
43. * itself, the buffer, and the String object.  Realistically, there is also
44. * another buffer allocation and copy, and even more pressure on the gc.
45. * That means that if your log message is filtered out, you might be doing
46. * significant work and incurring significant overhead.
47. */ 
48.public final class Log {

49.    /**

50.     * Priority constant for the println method; use Log.v.
51.     */ 
52.    public static final int VERBOSE = 2;

53.    /**

54.     * Priority constant for the println method; use Log.d.
55.     */ 
56.    public static final int DEBUG = 3;

57.    /**

58.     * Priority constant for the println method; use Log.i.
59.     */ 
60.    public static final int INFO = 4;

61.    /**

62.     * Priority constant for the println method; use Log.w.
63.     */ 
64.    public static final int WARN = 5;

65.    /**

66.     * Priority constant for the println method; use Log.e.
67.     */ 
68.    public static final int ERROR = 6;

69.    /**

70.     * Priority constant for the println method.
71.     */ 
72.    public static final int ASSERT = 7;

73.    /**

74.     * Exception class used to capture a stack trace in {@link #wtf()}.
75.     */ 
76.    private static class TerribleFailure extends Exception {

77.        TerribleFailure(String msg, Throwable cause) { super(msg, cause); }  78.    } 
79.    private Log() {

80.    } 
81.    /**

82.     * Send a {@link #VERBOSE} log message.
83.     * @param tag Used to identify the source of a log message.  It usually identifies
84.     *        the class or activity where the log call occurs.
85.     * @param msg The message you would like logged.
86.     */ 
87.    public static int v(String tag, String msg) {

88.        return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);

89.    } 
90.    /**

91.     * Send a {@link #VERBOSE} log message and log the exception.
92.     * @param tag Used to identify the source of a log message.  It usually identifies
93.     *        the class or activity where the log call occurs.
94.     * @param msg The message you would like logged.
95.     * @param tr An exception to log
96.     */ 
97.    public static int v(String tag, String msg, Throwable tr) {

98.        return println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '/n' + getStackTraceString(tr));

99.    } 
100.    /**

101.     * Send a {@link #DEBUG} log message.
102.     * @param tag Used to identify the source of a log message.  It usually identifies
103.     *        the class or activity where the log call occurs.
104.     * @param msg The message you would like logged.
105.     */ 
106.    public static int d(String tag, String msg) {

107.        return println_native(LOG_ID_MAIN, DEBUG, tag, msg);

108.    } 
109.    /**

110.     * Send a {@link #DEBUG} log message and log the exception.
111.     * @param tag Used to identify the source of a log message.  It usually identifies
112.     *        the class or activity where the log call occurs.
113.     * @param msg The message you would like logged.
114.     * @param tr An exception to log
115.     */ 
116.    public static int d(String tag, String msg, Throwable tr) {

117.        return println_native(LOG_ID_MAIN, DEBUG, tag, msg + '/n' + getStackTraceString(tr));

118.    } 
119.    /**

120.     * Send an {@link #INFO} log message.
121.     * @param tag Used to identify the source of a log message.  It usually identifies
122.     *        the class or activity where the log call occurs.
123.     * @param msg The message you would like logged.
124.     */ 
125.    public static int i(String tag, String msg) {

126.        return println_native(LOG_ID_MAIN, INFO, tag, msg);

127.    } 
128.    /**

129.     * Send a {@link #INFO} log message and log the exception.
130.     * @param tag Used to identify the source of a log message.  It usually identifies
131.     *        the class or activity where the log call occurs.
132.     * @param msg The message you would like logged.
133.     * @param tr An exception to log
134.     */ 
135.    public static int i(String tag, String msg, Throwable tr) {

136.        return println_native(LOG_ID_MAIN, INFO, tag, msg + '/n' + getStackTraceString(tr));

137.    } 
138.    /**

139.     * Send a {@link #WARN} log message.
140.     * @param tag Used to identify the source of a log message.  It usually identifies
141.     *        the class or activity where the log call occurs.
142.     * @param msg The message you would like logged.
143.     */ 
144.    public static int w(String tag, String msg) {

145.        return println_native(LOG_ID_MAIN, WARN, tag, msg);

146.    } 
147.    /**

148.     * Send a {@link #WARN} log message and log the exception.
149.     * @param tag Used to identify the source of a log message.  It usually identifies
150.     *        the class or activity where the log call occurs.
151.     * @param msg The message you would like logged.
152.     * @param tr An exception to log
153.     */ 
154.    public static int w(String tag, String msg, Throwable tr) {

155.        return println_native(LOG_ID_MAIN, WARN, tag, msg + '/n' + getStackTraceString(tr));

156.    } 
157.    /**

158.     * Checks to see whether or not a log for the specified tag is loggable at the specified level.
159.     *
160.     *  The default level of any tag is set to INFO. This means that any level above and including
161.     *  INFO will be logged. Before you make any calls to a logging method you should check to see
162.     *  if your tag should be logged. You can change the default level by setting a system property:
163.     *      'setprop log.tag.<YOUR_LOG_TAG> <LEVEL>'
164.     *  Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. SUPPRESS will
165.     *  turn off all logging for your tag. You can also create a local.prop file that with the
166.     *  following in it:
167.     *      'log.tag.<YOUR_LOG_TAG>=<LEVEL>'
168.     *  and place that in /data/local.prop.
169.     *
170.     * @param tag The tag to check.
171.     * @param level The level to check.
172.     * @return Whether or not that this is allowed to be logged.
173.     * @throws IllegalArgumentException is thrown if the tag.length() > 23.
174.     */ 
175.    public static native boolean isLoggable(String tag, int level);

176.    /*

177.     * Send a {@link #WARN} log message and log the exception.
178.     * @param tag Used to identify the source of a log message.  It usually identifies
179.     *        the class or activity where the log call occurs.
180.     * @param tr An exception to log
181.     */ 
182.    public static int w(String tag, Throwable tr) {

183.        return println_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));

184.    } 
185.    /** 186.     * Send an {@link #ERROR} log message.
187.     * @param tag Used to identify the source of a log message.  It usually identifies
188.     *        the class or activity where the log call occurs.
189.     * @param msg The message you would like logged.
190.     */ 
191.    public static int e(String tag, String msg) {

192.        return println_native(LOG_ID_MAIN, ERROR, tag, msg);

193.    } 
194.    /**

195.     * Send a {@link #ERROR} log message and log the exception.
196.     * @param tag Used to identify the source of a log message.  It usually identifies
197.     *        the class or activity where the log call occurs.
198.     * @param msg The message you would like logged.
199.     * @param tr An exception to log
200.     */ 
201.    public static int e(String tag, String msg, Throwable tr) {

202.        return println_native(LOG_ID_MAIN, ERROR, tag, msg + '/n' + getStackTraceString(tr));

203.    } 
204.    /**

205.     * What a Terrible Failure: Report a condition that should never happen.
206.     * The error will always be logged at level ASSERT with the call stack.
207.     * Depending on system configuration, a report may be added to the
208.     * {@link android.os.DropBoxManager} and/or the process may be terminated
209.     * immediately with an error dialog.
210.     * @param tag Used to identify the source of a log message.
211.     * @param msg The message you would like logged.
212.     */ 
213.    public static int wtf(String tag, String msg) {

214.        return wtf(tag, msg, null);

215.    } 
216.    /**

217.     * What a Terrible Failure: Report an exception that should never happen.
218.     * Similar to {@link #wtf(String, String)}, with an exception to log.
219.     * @param tag Used to identify the source of a log message.
220.     * @param tr An exception to log.
221.     */ 
222.    public static int wtf(String tag, Throwable tr) {

223.        return wtf(tag, tr.getMessage(), tr);

224.    } 
225.    /**

226.     * What a Terrible Failure: Report an exception that should never happen.
227.     * Similar to {@link #wtf(String, Throwable)}, with a message as well.
228.     * @param tag Used to identify the source of a log message.
229.     * @param msg The message you would like logged.
230.     * @param tr An exception to log.  May be null.
231.     */ 
232.    public static int wtf(String tag, String msg, Throwable tr) {

233.        tr = new TerribleFailure(msg, tr);

234.        int bytes = println_native(LOG_ID_MAIN, ASSERT, tag, getStackTraceString(tr));

235.        RuntimeInit.wtf(tag, tr); 
236.        return bytes;

237.    } 
238.    /**

239.     * Handy function to get a loggable stack trace from a Throwable
240.     * @param tr An exception to log
241.     */ 
242.    public static String getStackTraceString(Throwable tr) {

243.        if (tr == null) {

244.            return "";

245.        } 
246.        StringWriter sw = new StringWriter();

247.        PrintWriter pw = new PrintWriter(sw);

248.        tr.printStackTrace(pw); 
249.        return sw.toString();

250.    } 
251.    /**

252.     * Low-level logging call.
253.     * @param priority The priority/type of this log message
254.     * @param tag Used to identify the source of a log message.  It usually identifies
255.     *        the class or activity where the log call occurs.
256.     * @param msg The message you would like logged.
257.     * @return The number of bytes written.
258.     */ 
259.    public static int println(int priority, String tag, String msg) {

260.        return println_native(LOG_ID_MAIN, priority, tag, msg);

261.    } 
262.    /** @hide */ public static final int LOG_ID_MAIN = 0;

263.    /** @hide */ public static final int LOG_ID_RADIO = 1;

264.    /** @hide */ public static final int LOG_ID_EVENTS = 2;

265.    /** @hide */ public static final int LOG_ID_SYSTEM = 3;

266.    /** @hide */ public static native int println_native(int bufID,

267.            int priority, String tag, String msg);

268.}

我们看到所有代码都是调用public static native int println_native(int bufID,
            int priority, String tag, String msg);来实现输出的,这个函数的实现就是C++,调用的方式就是JNI

我们看一下对应的jni代码froyo/frameworks/base/core/jni/android_util_Log.cpp,最终调用的输出函数是

1./*
2. * In class android.util.Log:
3. *  public static native int println_native(int buffer, int priority, String tag, String msg)
4. */ 
5.static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,

6.        jint bufID, jint priority, jstring tagObj, jstring msgObj) 
7.{ 
8.    const char* tag = NULL;

9.    const char* msg = NULL;

10.    if (msgObj == NULL) {

11.        jclass npeClazz; 
12.        npeClazz = env->FindClass("java/lang/NullPointerException");

13.        assert(npeClazz != NULL);

14.        env->ThrowNew(npeClazz, "println needs a message");

15.        return -1;

16.    } 
17.    if (bufID < 0 || bufID >= LOG_ID_MAX) {

18.        jclass npeClazz; 
19.        npeClazz = env->FindClass("java/lang/NullPointerException");

20.        assert(npeClazz != NULL);

21.        env->ThrowNew(npeClazz, "bad bufID");

22.        return -1;

23.    } 
24.    if (tagObj != NULL)

25.        tag = env->GetStringUTFChars(tagObj, NULL); 
26.    msg = env->GetStringUTFChars(msgObj, NULL); 
27.    int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);

28.    if (tag != NULL)

29.        env->ReleaseStringUTFChars(tagObj, tag); 
30.    env->ReleaseStringUTFChars(msgObj, msg); 
31.    return res;

32.}

当然我们发现最终输出是

1.int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);

用力grep了一下代码,结果如下

./system/core/include/cutils/log.h:int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
./system/core/liblog/logd_write.c:int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
./system/core/liblog/logd_write.c:    return __android_log_buf_write(bufID, prio, tag, buf);

这个就是和android专用驱动进行通信的方式,这个分析下去就有点深了,后面分析。

以上三个小节分析了android的JAVA环境,我这里都是简单的抛砖引玉,希望能给大家一点大体的指引,其他修行靠大家了,能成为是一个android程序员是多么幸福的事情,各位已经在幸福中了,我什么时候也可以幸福一把??

本篇文章来源于 Linux公社网站(www.linuxidc.com)  原文链接:http://www.linuxidc.com/Linux/2011-10/44959p3.htm

Android 框架简介--Java环境(转)的更多相关文章

  1. 【读书笔记《Android游戏编程之从零开始》】1.Android 平台简介与环境搭建

    简单的记录下笔记,具体可百度! Android SDK (Software Development Kit)- Android 软件开发工具包,用于辅助Android 操作系统软件开发,是开发Andr ...

  2. [android开发篇]java环境配置

    http://www.runoob.com/java/java-environment-setup.html Java 开发环境配置 在本章节中我们将为大家介绍如何搭建Java开发环境. window ...

  3. Vue框架简介和环境搭建

    前言: 此篇随笔为个人学习前端框架Vue,js的技术笔记,主要记录一些自己在学习Vue框架的心得体会和技术总结,作为回顾和笔记使用. 这种写博客的方式,对刚开始学习Vue框架的我,也是一种激励,我相信 ...

  4. java、Android SDK、adb环境变量配置,以及JDK1.7换JDK1.8

    最近因项目需要使用将JDK1.7换成JDK1.8,故重新清晰地记录各种环境变量的配置: 这里更改的均是系统变量,不是用户变量 java环境变量配置: 变量名               变量值JAVA ...

  5. 配置java环境 ,安装Android Studio...(ps:用eclipse也不错,但as是趋势 自己凭爱好选择)

    to:青科大可爱的学弟学妹: 配置java环境 step1:下jdk 直接打开链接即可(ps:复制链接到迅雷下载更快哦) 64位的:http://download.oracle.com/otn-pub ...

  6. java Android SDK安装与环境变量配置以及开发第一个Android程序

    JAVA的安装与环境变量的配置 1.先下载JAVA,并且安装. 下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jdk-7u3 ...

  7. 【转】Ubuntu 14.04配置安装java环境和android开发环境(包括真机调试环境)

    原文网址:http://my.oschina.net/HalZf/blog/347351 总要记录下过程,不然老是会忘记掉-真老了.-_-! 一.配置安装ubuntu 64位java环境: 1.下载l ...

  8. android 之 java环境部署

    上甲骨文公司官网下载最新的jdk http://www.oracle.com/technetwork/cn/java/javase/downloads/jdk8-downloads-2133151-z ...

  9. Android RIL的java框架

    Android RIL的Java部分也被分为了两个模块,RIL模块与Phone模块.其中RIL模块负责进行请求以及相应的处理,它将直接与RIL的原声代码进行通信.而Phone模块则向应用程序开发者提供 ...

随机推荐

  1. 转 wince程序 中使用Listview显示图标问题 (C#) .

    思路: 1.窗体控件:lstaqgl [Listview控件名称]  imageList1[ImageList控件] 2.  图片路径添加到—imageList1——Listview显示图片从 ima ...

  2. PHP使用SOAP调用.net的WebService数据

    需要和一个.net系统进行数据交换,对方提供了一个WebService接口,使用PHP如何调用这个数据呢,下面就看看使用SOAP调用的方法吧 这个与一般的PHP POST或GET传值再查库拿数据的思路 ...

  3. http协议本身能获取客户端Mac地址问题

    http 位于网络应用程 应用层 会话层 表示层 传输层 网络层 数据链路层 物理层 数据在最高层开始传输 没经历下面一层加一层的头,然后传入目的电脑再进行一层层的解刨,所以http本来没有mac而接 ...

  4. (3)初次接触off

    boss布置任务了,要读入off文件,生成能显示出来的可执行文件,完成不了就要滚蛋 目前的东西还是不用保密的,到后面我就要设密码了 好,.off文件是什么? OFF,Object File Forma ...

  5. eq相等 ,ne、neq不相等 EL表达式

    eq相等,ne.neq不相等, gt大于, lt小于 gte.ge大于等于   lte.le 小于等于   not非   mod求模   is [not] div by是否能被某数整除   is [n ...

  6. CyclicBarrier、CountDownLatch与Semaphore的小记

    CyclicBarrier: 适合的业务场景,比如 1).,现有一大任务,需要得到全年的统计数据的,这个工作量是巨大的,那么可以将其分割为12个月的子任务,各个子任务相互独立,当所有子任务完成了,则就 ...

  7. iOS开发--xcode快捷键

    1. 文件CMD + N: 新文件CMD + SHIFT + N: 新项目CMD + O: 打开CMD + S: 保存CMD+OPt+S:保存所有文件CMD + SHIFT + S: 另存为CMD + ...

  8. 如何避免JSP页面自动生成session对象?为什么要这么做?

    JSP // 在默认情况下,在对一个JSP页面发出请求时,如果session还没有建立,JSP页面会自动为请求建立一个session对象,但是session是比较消耗资源的,如果没必要保持和使用ses ...

  9. MSBuild和Jenkins搭建持续集成环境

    http://www.2cto.com/os/201409/334323.html http://my.oschina.net/anxuyong/blog/353897 http://www.cnbl ...

  10. [c/c++]指针数组 pk 数组指针

    首先强调 指针数组归根结底是个数组:数组指针归根结底是个指针. 数组指针 以int (*int)[10]为例 ()的优先级大于[],因此首先它是一个指针,它指向一个数组,数组的维数是10.因此数组指针 ...