精华内容
下载资源
问答
  • 深入理解Python的包机制

    千次阅读 2014-09-03 16:19:08
    最近在重构Python代码时,感觉代码只分割到文件有点不够用了,但以前对Python的包机制一直缺乏比较深入的理解,借此机会提升一下,彻底弄清楚Python的包机制,更好组织代码结构。后面逐渐把Python工具箱使用包组织...

         最近在重构Python代码时,感觉代码只分割到文件有点不够用了,但以前对Python的包机制一直缺乏比较深入的理解,借此机会提升一下,彻底弄清楚Python的包机制,更好组织代码结构。后面逐渐把Python工具箱使用包组织起来。

          Python中的Module是比较重要的概念。常见的情况是,事先写好一个.py文 件,在另一个文件中需要import时,将事先写好的.py文件拷贝 到当前目录,或者是在sys.path中增加事先写好的.py文件所在的目录,然后import。这样的做法,对于少数文件是可行的,但如果程序数目很多,层级很复杂,就很吃力了。

          有没有办法,像Java的Package一样,将多个.py文件组织起来,以便在外部统一调用,和在内部互相调用呢?答案是有的。
    主要是用到python的包的概念,python __init__.py在包里起一个比较重要的作用。要弄明白这个问题,首先要知道,python在执行import语句时,到底进行了什么操作,按照python的文档,它执行了如下操作:

    • 第1步,创建一个新的,空的module对象(它可能包含多个module);
    • 第2步,把这个module对象插入sys.module中
    • 第3步,装载module的代码(如果需要,首先必须编译)
    • 第4步,执行新的module中对应的代码。

            在执行第3步时,首先要找到module程序所在的位置,其原理为:

            如果需要导入的module的名字是m1,则解释器必须找到m1.py,它首先在当前目录查找,然后是在环境变量PYTHONPATH中查找。 PYTHONPATH可以视为系统的PATH变量一类的东西,其中包含若干个目录。如果PYTHONPATH没有设定,或者找不到m1.py,则继续搜索 与python的安装设置相关的默认路径,在Unix下,通常是/usr/local/lib/python。
    事实上,搜索的顺序是:当前路径 (以及从当前目录指定的sys.path),然后是PYTHONPATH,然后是python的安装设置相关的默认路径。正因为存在这样的顺序,如果当前 路径或PYTHONPATH中存在与标准module同样的module,则会覆盖标准module。也就是说,如果当前目录下存在xml.py,那么执 行import xml时,导入的是当前目录下的module,而不是系统标准的xml。

            了解了这些,我们就可以先构建一个package,以普通module的方式导入,就可以直接访问此package中的各个module了。

          Python中的package定义很简单,其层次结构与程序所在目录的层次结构相同,这一点与Java类似,唯一不同的地方在于,python中的package必须包含一个__init__.py的文件。
    例如,我们可以这样组织一个package:

    package1/
        __init__.py
        subPack1/
            __init__.py
            module_11.py
            module_12.py
            module_13.py
        subPack2/
            __init__.py
            module_21.py
            module_22.py
    ……

    __init__.py可以为空,只要它存在,就表明此目录应被作为一个package处理。当然,__init__.py中也可以设置相应的内容,下文详细介绍。

    好了,现在我们在module_11.py中定义一个函数:

    def funA():
         print "funcA in module_11"
         return

    在顶层目录(也就是package1所在的目录,当然也参考上面的介绍,将package1放在解释器能够搜索到的地方)运行python:

    >>>from package1.subPack1.module_11 import funcA
    >>>funcA()
    funcA in module_11

    这样,我们就按照package的层次关系,正确调用了module_11中的函数。

    细心的用户会发现,有时在import语句中会出现通配符*,导入某个module中的所有元素,这是怎么实现的呢?
    答案就在__init__.py中。我们在subPack1的__init__.py文件中写

    __all__ = ['module_13', 'module_12']

    然后进入python
    >>>from package1.subPack1 import *
    >>>module_11.funcA()
    Traceback (most recent call last):
    File "", line 1, in 
    ImportError: No module named module_11

    也就是说,以*导入时,package内的module是受__init__.py限制的。

    好了,最后来看看,如何在package内部互相调用。
    如果希望调用同一个package中的module,则直接import即可。也就是说,在module_12.py中,可以直接使用
    import module_11

    如果不在同一个package中,例如我们希望在module_21.py中调用module_11.py中的FuncA,则应该这样:
    from module_11包名.module_11 import funcA

    包机制
    # a.py
    def add_func(a,b):
    return a+b
    # b.py
    from a import add_func # Also can be : import a

    print ("Import add_func from module a")
    print ("Result of 1 plus 2 is: ")
    print (add_func(1,2)) # If using "import a" , then here should be "a.add_func"

    module可以定义在包里面.Python定义包的方式稍微有点古怪,假设我们有一个parent文件夹,该文件夹有一个child子文件夹.child中有一个module a.py . 如何让Python知道这个文件层次结构?很简单,每个目录都放一个名为_init_.py 的文件.该文件内容可以为空.这个层次结构如下所示:
    parent 
    --__init_.py
    --child
    -- __init_.py
    --a.py

    b.py
    那么Python如何找到我们定义的module?在标准包sys中,path属性记录了Python的包路径.你可以将之打印出来:
    import sys

    print(sys.path)
    通常我们可以将module的包路径放到环境变量PYTHONPATH中,该环境变量会自动添加到sys.path属性.另一种方便的方法是编程中直接指定我们的module路径到sys.path 中:
    import sys
    import os
    sys.path.append(os.getcwd()+'\\parent\\child')
    print(sys.path)
    from a import add_func
    print (sys.path)
    print ("Import add_func from module a")
    print ("Result of 1 plus 2 is: ")
    print (add_func(1,2))



    知识点:
    如何定义模块和包
    如何将模块路径添加到系统路径,以便python找到它们
    如何得到当前路径

    展开全文
  • 指的是Apk、jar和so文件等等,它们被加载到Android内存中,由一个转变成可执行的代码,这就需要一个机制来进行的加载、解析、管理等操作,这就是管理机制管理机制由许多类一起组成,其中核心为...

    本文首发于微信公众号「刘望舒」

    关联系列
    Android包管理机制系列

    前言

    包管理机制是Android中的重要机制,是应用开发和系统开发需要掌握的知识点之一。
    包指的是Apk、jar和so文件等等,它们被加载到Android内存中,由一个包转变成可执行的代码,这就需要一个机制来进行包的加载、解析、管理等操作,这就是包管理机制。包管理机制由许多类一起组成,其中核心为PackageManagerService(PMS),它负责对包进行管理,如果直接讲PMS会比较难以理解,因此我们需要一个切入点,这个切入点就是常见的APK的安装。
    讲到APK的安装之前,先了解下PackageManager、APK文件结构和安装方式。

    1.PackageManager简介

    与ActivityManager和AMS的关系类似,PMS也有一个对应的管理类PackageManager,用于向应用程序进程提供一些功能。PackageManager是一个抽象类,它的具体实现类为ApplicationPackageManager,ApplicationPackageManager中的方法会通过IPackageManager与AMS进行进程间通信,因此PackageManager所提供的功能最终是由PMS来实现的,这么设计的主要用意是为了避免系统服务PMS直接被访问。PackageManager提供了一些功能,主要有以下几点:

    1. 获取一个应用程序的所有信息(ApplicationInfo)。
    2. 获取四大组件的信息。
    3. 查询permission相关信息。
    4. 获取包的信息。
    5. 安装、卸载APK.

    2.APK文件结构和安装方式

    APK是AndroidPackage的缩写,即Android安装包,它实际上是zip格式的压缩文件,一般情况下,解压后的文件结构如下表所示。

    | 目录/文件| 描述|
    | :--------: |: --------?
    | assert| 存放的原生资源文件,通过AssetManager类访问。 |
    | lib| 存放库文件。 |
    | META-INF| 保存应用的签名信息,签名信息可以验证APK文件的完整性。 |
    | res| 存放资源文件。res中除了raw子目录,其他的子目录都参与编译,这些子目录下的资源是通过编译出的R类在代码中访问。 |
    |AndroidManifest.xml| 用来声明应用程序的包名称、版本、组件和权限等数据。 apk中的AndroidManifest.xml经过压缩,可以通过AXMLPrinter2工具解开。 |
    | classes.dex| Java源码编译后生成的Java字节码文件。 |
    | resources.arsc| 编译后的二进制资源文件。 |

    APK的安装场景主要有以下几种:

    • 通过adb命令安装:adb 命令包括adb push/install
    • 用户下载的Apk,通过系统安装器packageinstaller安装该Apk。packageinstaller是系统内置的应用程序,用于安装和卸载应用程序。
    • 系统开机时安装系统应用。
    • 电脑或者手机上的应用商店自动安装。

    这4种方式最终都是由PMS来进行处理,在此之前的调用链是不同的,本篇文章会介绍第二种方式,对于用户来说,这是比较常用的安装方式;对于开发者来说,这是调用链比较长的安装方式,能学到的更多。其他的安装场景会在本系列的后续文章进行讲解。

    3.寻找PackageInstaller入口

    在Android7.0之前我们可以通过如下代码安装指定路径中的APK。

    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setDataAndType(Uri.parse("file://" + path),"application/vnd.android.package-archive");
    context.startActivity(intent);
    

    但是Android7.0或更高版本再这么做,就会报FileUriExposedException异常。这是因为StrictMode API 政策禁止应用程序将file:// Uri暴露给另一个应用程序,如果包含file:// Uri的 intent 离开你的应用,就会报FileUriExposedException 异常。为了解决这个问题,谷歌提供了FileProvider,FileProvider继承自ContentProvider ,使用它可以将file://Uri替换为content://Uri,具体怎么使用FileProvider并不是本文的重点,只要知道无论是Android7.0之前还是Android7.0以及更高版本,都会调用如下代码:

    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(xxxxx, "application/vnd.android.package-archive");
    

    Intent的Action属性为ACTION_VIEW,Type属性指定Intent的数据类型为application/vnd.android.package-archive。
    能隐式匹配的Activity为InstallStart,需要注意的是,这里分析的源码基于Android8.0,7.0能隐式匹配的Activity为PackageInstallerActivity。
    packages/apps/PackageInstaller/AndroidManifest.xml

     <activity android:name=".InstallStart"
                    android:exported="true"
                    android:excludeFromRecents="true">
                <intent-filter android:priority="1">
                    <action android:name="android.intent.action.VIEW" />
                    <action android:name="android.intent.action.INSTALL_PACKAGE" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <data android:scheme="file" />
                    <data android:scheme="content" />
                    <data android:mimeType="application/vnd.android.package-archive" />
                </intent-filter>
             ...
            </activity>
    

    InstallStart是PackageInstaller中的入口Activity,其中PackageInstaller是系统内置的应用程序,用于安装和卸载应用。当我们调用PackageInstaller来安装应用时会跳转到InstallStart,并调用它的onCreate方法:
    packages/apps/PackageInstaller/src/com/android/packageinstaller/InstallStart.java

      @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
               if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {//1
                nextActivity.setClass(this, PackageInstallerActivity.class);
            } else {
                Uri packageUri = intent.getData();
                if (packageUri == null) {//2
                    Intent result = new Intent();
                    result.putExtra(Intent.EXTRA_INSTALL_RESULT,
                            PackageManager.INSTALL_FAILED_INVALID_URI);
                    setResult(RESULT_FIRST_USER, result);
                    nextActivity = null;
                } else {
                    if (packageUri.getScheme().equals(SCHEME_CONTENT)) {//3
                        nextActivity.setClass(this, InstallStaging.class);
                    } else {
                        nextActivity.setClass(this, PackageInstallerActivity.class);
                    }
                }
            }
            if (nextActivity != null) {
                startActivity(nextActivity);
            }
            finish();
        }
    

    注释1处判断Intent的Action是否为CONFIRM_PERMISSIONS,根据本文的应用情景显然不是,接着往下看,注释2处判断packageUri 是否为空也不成立,注释3处,判断Uri的Scheme协议是否是content,如果是就跳转到InstallStaging,如果不是就跳转到PackageInstallerActivity。本文的应用情景中,Android7.0以及更高版本我们会使用FileProvider来处理URI ,FileProvider会隐藏共享文件的真实路径,将路径转换成content://Uri路径,这样就会跳转到InstallStaging。InstallStaging的onResume方法如下所示。

    packages/apps/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java

      @Override
        protected void onResume() {
            super.onResume();
            if (mStagingTask == null) {
                if (mStagedFile == null) {
                    try {
                        mStagedFile = TemporaryFileManager.getStagedFile(this);//1
                    } catch (IOException e) {
                        showError();
                        return;
                    }
                }
                mStagingTask = new StagingAsyncTask();
                mStagingTask.execute(getIntent().getData());//2
            }
        }
    
    

    注释1处如果File类型的mStagedFile 为null,则创建mStagedFile ,mStagedFile用于存储临时数据。 注释2处启动StagingAsyncTask,并传入了content协议的Uri,如下所示。
    packages/apps/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java

     private final class StagingAsyncTask extends AsyncTask<Uri, Void, Boolean> {
            @Override
            protected Boolean doInBackground(Uri... params) {
                if (params == null || params.length <= 0) {
                    return false;
                }
                Uri packageUri = params[0];
                try (InputStream in = getContentResolver().openInputStream(packageUri)) {
                    if (in == null) {
                        return false;
                    }
                    try (OutputStream out = new FileOutputStream(mStagedFile)) {
                        byte[] buffer = new byte[4096];
                        int bytesRead;
                        while ((bytesRead = in.read(buffer)) >= 0) {
                            if (isCancelled()) {
                                return false;
                            }
                            out.write(buffer, 0, bytesRead);
                        }
                    }
                } catch (IOException | SecurityException e) {
                    Log.w(LOG_TAG, "Error staging apk from content URI", e);
                    return false;
                }
                return true;
            }
            @Override
            protected void onPostExecute(Boolean success) {
                if (success) {
                    Intent installIntent = new Intent(getIntent());
                    installIntent.setClass(InstallStaging.this, PackageInstallerActivity.class);
                    installIntent.setData(Uri.fromFile(mStagedFile));
                    installIntent
                            .setFlags(installIntent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT);
                    installIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
                    startActivityForResult(installIntent, 0);
                } else {
                    showError();
                }
            }
        }
    }
    

    doInBackground方法中将packageUri(content协议的Uri)的内容写入到mStagedFile中,如果写入成功,onPostExecute方法中会跳转到PackageInstallerActivity中,并将mStagedFile传进去。绕了一圈又回到了PackageInstallerActivity,这里可以看出InstallStaging主要起了转换的作用,将content协议的Uri转换为File协议,然后跳转到PackageInstallerActivity,这样就可以像此前版本(Android7.0之前)一样启动安装流程了。

    4.PackageInstallerActivity解析

    从功能上来说,PackageInstallerActivity才是应用安装器PackageInstaller真正的入口Activity,PackageInstallerActivity的onCreate方法如下所示。
    packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java

        @Override
        protected void onCreate(Bundle icicle) {
            super.onCreate(icicle);
            if (icicle != null) {
                mAllowUnknownSources = icicle.getBoolean(ALLOW_UNKNOWN_SOURCES_KEY);
            }
            mPm = getPackageManager();
            mIpm = AppGlobals.getPackageManager();
            mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
            mInstaller = mPm.getPackageInstaller();
            mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
            ...
            //根据Uri的Scheme进行预处理
            boolean wasSetUp = processPackageUri(packageUri);//1
            if (!wasSetUp) {
                return;
            }
            bindUi(R.layout.install_confirm, false);
            //判断是否是未知来源的应用,如果开启允许安装未知来源选项则直接初始化安装
            checkIfAllowedAndInitiateInstall();//2
        }
    

    首先初始话安装所需要的各种对象,比如PackageManager、IPackageManager、AppOpsManager和UserManager等等,它们的描述如下表所示。

    类名 描述
    PackageManager 用于向应用程序进程提供一些功能,最终的功能是由PMS来实现的
    IPackageManager 一个AIDL的接口,用于和PMS进行进程间通信
    AppOpsManager 用于权限动态检测,在Android4.3中被引入
    PackageInstaller 提供安装、升级和删除应用程序功能
    UserManager 用于多用户管理

    注释1处的processPackageUri方法如下所示。
    packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java

       private boolean processPackageUri(final Uri packageUri) {
            mPackageURI = packageUri;
            final String scheme = packageUri.getScheme();//1
            switch (scheme) {
                case SCHEME_PACKAGE: {
                    try {
                     ...
                } break;
                case SCHEME_FILE: {
                    File sourceFile = new File(packageUri.getPath());//1
                    //得到sourceFile的包信息
                    PackageParser.Package parsed = PackageUtil.getPackageInfo(this, sourceFile);//2
                    if (parsed == null) {
                        Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
                        showDialogInner(DLG_PACKAGE_ERROR);
                        setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
                        return false;
                    }
                    //对parsed进行进一步处理得到包信息PackageInfo
                    mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
                            PackageManager.GET_PERMISSIONS, 0, 0, null,
                            new PackageUserState());//3
                    mAppSnippet = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
                } break;
                default: {
                    Log.w(TAG, "Unsupported scheme " + scheme);
                    setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);
                    finish();
                    return false;
                }
            }
            return true;
        }
    

    首先在注释1处得到packageUri的Scheme协议,接着根据这个Scheme协议分别对package协议和file协议进行处理,如果不是这两个协议就会关闭PackageInstallerActivity并return false。我们主要来看file协议的处理,注释1处根据packageUri创建一个新的File。注释2处的内部会用PackageParser的parsePackage方法解析这个File(这个File其实是APK文件),得到APK的包信息Package ,Package包含了该APK的所有信息。注释3处会将Package根据uid、用户状态信息和PackageManager的配置等变量对包信息Package做进一步处理得到PackageInfo。
    回到PackageInstallerActivity的onCreate方法的注释2处,checkIfAllowedAndInitiateInstall方法如下所示。
    packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java

     private void checkIfAllowedAndInitiateInstall() {
            //判断如果允许安装未知来源或者根据Intent判断得出该APK不是未知来源
            if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {//1
                //初始化安装
                initiateInstall();//2
                return;
            }
            // 如果管理员限制来自未知源的安装, 就弹出提示Dialog或者跳转到设置界面
            if (isUnknownSourcesDisallowed()) {
                if ((mUserManager.getUserRestrictionSource(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
                        Process.myUserHandle()) & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {    
                    showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER);
                    return;
                } else {
                    startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
                    finish();
                }
            } else {
                handleUnknownSources();//3
            }
        }
    

    注释1处判断允许安装未知来源或者根据Intent判断得出该APK不是未知来源,就调用注释2处的initiateInstall方法来初始化安装。如果管理员限制来自未知源的安装, 就弹出提示Dialog或者跳转到设置界面,否则就调用注释3处的handleUnknownSources方法来处理未知来源的APK。注释2处的initiateInstall方法如下所示。
    packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java

      private void initiateInstall() {
            String pkgName = mPkgInfo.packageName;//1
            String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
            if (oldName != null && oldName.length > 0 && oldName[0] != null) {
                pkgName = oldName[0];
                mPkgInfo.packageName = pkgName;
                mPkgInfo.applicationInfo.packageName = pkgName;
            }
            try {
                //根据包名获取应用程序信息
                mAppInfo = mPm.getApplicationInfo(pkgName,
                        PackageManager.MATCH_UNINSTALLED_PACKAGES);//2
                if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
                    mAppInfo = null;
                }
            } catch (NameNotFoundException e) {
                mAppInfo = null;
            }
            //初始化安装确认界面
            startInstallConfirm();//3
        }
    

    注释1处得到包名,注释2处根据包名获取获取应用程序信息ApplicationInfo。注释3处的startInstallConfirm方法如下所示。
    packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java

       private void startInstallConfirm() {
           //省略初始化界面代码
            ...
            AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo);//1
            final int N = perms.getPermissionCount(AppSecurityPermissions.WHICH_ALL);
            if (mAppInfo != null) {
                msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
                        ? R.string.install_confirm_question_update_system
                        : R.string.install_confirm_question_update;
                mScrollView = new CaffeinatedScrollView(this);
                mScrollView.setFillViewport(true);
                boolean newPermissionsFound = false;
                if (!supportsRuntimePermissions) {
                    newPermissionsFound =
                            (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0);
                    if (newPermissionsFound) {
                        permVisible = true;
                        mScrollView.addView(perms.getPermissionsView(
                                AppSecurityPermissions.WHICH_NEW));//2
                    }
                }
            ...
        }
    

    startInstallConfirm方法中首先初始化安装确认界面,就是我们平常安装APK时出现的界面,界面上有确认和取消按钮并会列出安装该APK需要访问的系统权限。需要注意的是,不同厂商定制的Android系统会有不同的安装确认界面。
    注释1处会创建AppSecurityPermissions,它会提取出APK中权限信息并展示出来,这个负责展示的View是AppSecurityPermissions的内部类PermissionItemView。注释2处调用AppSecurityPermissions的getPermissionsView方法来获取PermissionItemView,并将PermissionItemView添加到CaffeinatedScrollView中,这样安装该APK需要访问的系统权限就可以全部的展示出来了,PackageInstaller的初始化工作就完成了。

    5.总结

    现在来总结下PackageInstaller初始化的过程:

    1. 根据Uri的Scheme协议不同,跳转到不同的界面,content协议跳转到InstallStart,其他的跳转到PackageInstallerActivity。本文应用场景中,如果是Android7.0以及更高版本会跳转到InstallStart。
    2. InstallStart将content协议的Uri转换为File协议,然后跳转到PackageInstallerActivity。
    3. PackageInstallerActivity会分别对package协议和file协议的Uri进行处理,如果是file协议会解析APK文件得到包信息PackageInfo。
    4. PackageInstallerActivity中会对未知来源进行处理,如果允许安装未知来源或者根据Intent判断得出该APK不是未知来源,就会初始化安装确认界面,如果管理员限制来自未知源的安装, 就弹出提示Dialog或者跳转到设置界面。

    PackageInstaller的初始化就讲到这,关于PackageInstaller的安装APK的过程会在本系列的下一篇文章进行讲解。

    参考资料
    应用程序安装流程


    这里不仅分享大前端、Android、Java等技术,还有程序员成长类文章。
    展开全文
  • 作用

    2018-12-09 20:55:32
    包机制是java中管理类的重要手段。开发中,我们会遇到大量同名的类,通过包我们很容易对解决类重名的问题,也可以实现对类的有效管理。包对于类相当于,文件夹对于文件的作用...

    包机制是java中管理类的重要手段。开发中,我们会遇到大量同名的类,通过包我们很容易对解决类重名的问题,也可以实现对类的有效管理。包对于类相当于,文件夹对于文件的作用

    展开全文
  • JAVA中的包机制

    千次阅读 2015-03-10 14:09:41
    是JAVA中文件的一种组织形式,例如:Windows操作系统的文件夹结构,在java当中,也相当于文件夹,实际上也起着这个作用,在开发比较大的java项目时,不可能只涉及到一个java文件,不可能把所有的代码都只写在

    包机制:

    搬家把同类物品装在一个大箱子里,就是打包封装,这样我们只看到包,就知道这个夏天衣服,那个装锅碗瓢盆。Java中也是这样的,把功能相关的类放置在一起,弄成一个大包裹。

    包是JAVA中文件的一种组织形式,例如:Windows操作系统的文件夹结构,在java当中,包也相当于文件夹,实际上也起着这个作用,在开发比较大的java项目时,不可能只涉及到一个java文件,不可能把所有的代码都只写在同一个java文件当中,可能要创建几十,甚至几百个java文件,这个时候我们就可以使用包,把相关的java文件放在一起,利用包来方便、快捷、有效的管理这些文件, 包的作用不仅仅是对类的封装管理,包的引用还可以避免命名冲突的问题,在一个庞大系统设计中,无论我们多小心的给类命名,但是设计到成千上万个类之后,对于类名的冲突就不可避免了,特别是我们使用简单的描述性的类名时,不同的程序员设计不同的模块,那么命名冲突更加明显,而在java程序中几乎没有命名冲突的问题,其最大的原因就是包的作用。

    如何创建包?

    包的创建使用package关键字来定义,package关键字后面跟着包名,也就是包的名字。这里大家一定要注意,使用package创建包的这条语句,必须放在java源程序的第一行,前面不能有任何可执行代码,当然注释除外。

    例如:Person类,在文件的第一句加入了package exec1;这样就创建了包exec1,并且Person类就被包含在包exec1当中,还有一种是这样的对于Windows文件夹,是不是可以创建多层文件夹呀?包呢,也是可以分层次的,不同的层次之间用点(.)隔开。创建多层包之间的语法是这样的,注意,包名之间使用“.”号隔开,包名都是小写的,现在创建两个包:com.pb.pack1在这个包下面有Person类,另外一个包:com.pb.pack2在这个包下面有PersonTest类。现在,我们要在PersonTest类当中用到Person类。那么Person类又不在pack2下面,这时怎么办呢?这时候我们就要导入包中的类。使用关键字:import。后面跟的是包名.类名。其实在以前就已经接触过包了,只是没注意,从键盘接收用户输入时,使用了Scanner类,咱们是不是需要导入这个包啊?

    首先,java.lang包,在这个包里,包含了java程序语言的基础类,在开发过程中么我们会经常使用到这个包,这个包不需要导入就可以使用其中的类,比如:声明字符串时使用的StringString类就是java.lang包下面的。第二包是java.util包,这个包里包含了各种各样的使用工具,也是一个非常重要的包。第三个是java.io包,包含了各种输入输出相关功能的类,还有就是java.sql包,这个包里包含了数据库操作的相关类。

    包的作用:主要是管理java文件,解决同名文件冲突,其实包实际上也是一种访问控制机制,通过包来限制,或者说约束类之间的访问关系。


    展开全文
  • JAVA反射机制作用是什么

    万次阅读 多人点赞 2015-10-30 21:10:39
    Java的反射机制是Java特性之一,反射机制是构建框架技术的基础所在。灵活掌握Java反射机制,对大家以后学习框架技术有很大的帮助。 那么什么是Java的反射呢?  大家都知道,要让Java程序能够运行,那么就得让Java...
  • 定义 反射机制是Java语言中一个非常重要的特性,它允许程序在运行时进行自我检查,同时也允许其对内部成员进行操作。由于反射机制能够实现在运行时对类进行装载,因此能够增加程序...反射机制作用: 1,反编译:.c...
  • Debian Linux管理机制

    千次阅读 2017-01-12 10:52:12
    需要注意的是这个文件的作用,从名字上看这个文件就是在安装完成之后做的事情(postinst = post install),实时上确实如此。 同样滴,postrm这个文件就是在remove之后执行的脚本文件,内容如下: 到此,我们...
  • 深入理解双亲委派机制作用

    千次阅读 多人点赞 2020-04-03 16:34:38
    java双亲委派机制作用 一、什么是双亲委派机制 当某个类加载器需要加载某个.class文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。 二、...
  • MyBatis各个jar作用

    千次阅读 2018-09-15 22:06:23
    字号 Spring jar官网下载地址:...Spring jar的描述:针对3.2.2以上版本 org.springframework spring-aop ——Spring的面向切面编程,提供AOP(面向切面编程)实现 org.springframework spring-a...
  • C# 反射机制作用

    千次阅读 2018-06-21 23:41:49
    第一件事就是:反射很慢,消耗性能。反射:可以通过程序集,类型,类型实例获取该程序集内【所有类型+类型所有字段+类型字段的...评价:很鸡肋的用法——如果你很懒,不想写反射机制的相关代码,完全可以用JsonMa...
  • 长连接和端连接 心跳包机制

    千次阅读 2017-08-15 22:45:29
    心跳包机制      跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是...
  • 心跳包机制(★firecat推荐★)

    千次阅读 2015-06-15 22:45:21
    心跳的发送,通常有两种技术 方法1:应用层自己实现的心跳  由应用程序自己发送心跳来检测连接是否正常,大致的方法是:服务器在一个 Timer事件中定时 向客户端发送一个短小精悍的数据包,然后启动一个低级别...
  • 程序管理包含三个部分内容:提供一个能够根据intent匹配到具体的Activity、Provider、Service。即当应用程序调用startActivity(intent)时,能够把参数中指定的intent转换成一个具体的包含了程序名称及具体...
  • Java 作用和定义

    万次阅读 2018-06-01 22:11:07
    是Java语言提供的一种...一、作用 1 把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。 2 如同文件夹一样,也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的...
  • 虚函数的作用及其底层实现机制

    万次阅读 多人点赞 2016-04-07 18:10:58
    动态联编C++中的虚函数的作用主要是实现了多态的机制。基类定义虚函数,子类可以重写该函数;在派生类中对基类定义的虚函数进行重写时,需要再派生类中声明该方法为虚方法。当子类重新定义了父类的虚函数后,当父类...
  • spring各个jar包作用

    千次阅读 2018-09-15 22:13:29
    Spring jar官网下载地址: http://repo.spring.io/release/org/springframework/spring/ Spring jar的描述:针对3.2.2以上版本 org.springframework spring-aop ——Spring的面向切面编程,提供AOP(面向切面...
  • 由应用程序自己发送心跳来检测连接是否正常,大致的方法是:服务器在一个 Timer事件中定时 向客户端发送一个短小精悍的数据包,然后启动一个低级别的线程,在该线程中不断检测客户端的回应, 如果在一定时
  • 浅谈HTTPS通信机制和Charles抓原理

    万次阅读 2018-06-17 16:44:57
    网络请求是应用开发的基础,在开发过程中经常需要通过抓来分析网络问题,了解HTTP基础知识和HTTPS通信机制对提高开发效率来说必不可少。在这篇文章里,我将介绍三部分的内容:1)HTTP基础知识:URL和报文结构;2)...
  • 位置编码在注意力机制中的作用

    千次阅读 2021-06-05 09:35:43
    有一种叫做注意机制的东西,但是你不需要知道注意力具体实现。 RNN/LSTM的不足。 A. Vaswani等人的《Attention Is All You Need》被认为是解决了众所周知的LSTM/RNN体系结构在深度学习空间中的局限性的突破之一。...
  • java 作用

    千次阅读 2009-04-08 09:18:00
    java作用--------------------------------------------J2EE常用Jar包含义activation.jar:与javaMail有关的jar,使用javaMail时应与mail.jar一起加入到lib中去,具体负责mail的数据源和类型等ajaxtags-1.2-...
  • 首先,我将Handler相关的原理机制形象的描述为以下情景: Handler:快递员 Message:包裹 MessageQueue:快递仓储空间 Looper:配送车 某天,你想给朋友寄一件礼物,首先你会包裹好,下单加了某家的快递员上门...
  • 游戏服务器心跳作用

    千次阅读 2014-12-25 20:16:24
    之前看代码没仔细,一直以为我们的心跳就是为了防止socket自动断开连接 直到同事刚刚讲,这个超时是我们自己设置的啊....socket本身就是长连接 accept(Socket) -> Ref = prim_inet:async_recy(Socket, 5, 600) ...
  • 什么是反射机制,有什么作用

    万次阅读 2017-01-05 17:34:42
    1.反射机制定义 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改其本身状态或行为的一种能力。 在Java环境中,反射机制允许程序在执行时获取某个类...2.反射机制作用 Java反射机制主要
  • Java反射机制的原理及作用

    千次阅读 2017-04-19 17:44:58
    反射机制是Java特性之一,反射机制是构建框架技术的基础所在。灵活掌握Java反射机制,对大家以后学习框架技术有很大的帮助。 那么什么是Java的反射呢?  大家都知道,要让Java程序能够运行,那么就得让Java类要被...
  • wireshark抓分析ARP协议 -------------------本文系个人知识理解总结,不一定标准,欢迎交流讨论--------------- 个人认为本实验的主要目的就是将理论实战化,具体看看一看真正的ARP在网络中的样子,重点在于...
  • 主要作用于对TCP/IP数据包的分包和包重组,常用于数据的流传输,是扩展的解码器。 目录结构如下:     2. 包中各类功能详解 (1) FrameDecoder 抽象类,将ChannelBuffers中的二进制数据转
  • AngularJS应用的任何一个部分,无论它渲染在哪个上下文中,都有父级作用域存在。对于 ng-app所处的层级来讲,它的父级作用...如果熟悉面向对象编程,对这个机制应该不会陌生。 默认情况下,AngularJS在当前作用域中无法找
  • Android心跳(一)——心跳机制

    万次阅读 2017-11-21 16:40:25
    在写之前,我们首先了解一下为什么android维护长连接需要心跳机制,首先我们知道,维护任何一个长连接都需要心跳机制,客户端发送一个心跳给 服务器,服务器给客户端一个心跳应答,这样就形成客户端服务器的一次...
  • struts2中各个jar包作用

    万次阅读 2014-02-24 14:30:20
    Struts2.3.4 所需的Jar及介绍 ...的作用 jar内包含的主要路径及主要类 依赖的自有jar名称 依赖的第三方jar名称 本jar是否为第三方包 Struts 2.3.4 的 核

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 680,831
精华内容 272,332
关键字:

包机制的作用