Java 面向对象 package/import/import static

本页面更新日期: 2016年07月23日

package 包

前面提到了这个概念.
什么是包?
由于非常多的人参与 Java 的开发, 这难免会遇到一个问题 – 类名冲突.
也就是说难免会遇到重名的情况.
所以 Java 引入了包这个机制.
提供了类的多层命名空间.
用于解决类的命名冲突 / 类文件管理等问题.

Java允许将一组功能相关的类放在同一个 package 下.
从而组成逻辑上的类库单元.
如果希望把一个类放在指定的包结构下,应该在Java源程序的第一个非注释行放置如下格式的代码:

package packageName;

一旦在Java源文件中使用了这个 package 语句.
就意味着该源文件里定义的所有类都属于这个包.
位于包中的每个类的完整类名都应该是包名和类名的组合.
如果其他人需要使用该包下的类, 也应该使用包名加类名的组合.
下面写个程序在 lee 包下定义了一个简单的Java类.

package lee;
public class Hello
{
    public static void main(String[] args)
    {
        System.out.println("Hello World!");
    }
}

上面第一行代码表明把 Hello 类放在 lee 包空间下.
然后把上面的源文件保存在任意位置, 使用如下命令来编译这个Java文件.

javac -d . Hello.java

编译中的 -d选项用于设置编译生成的 class 文件的保存位置.
这里指定将生成的 class 文件放在当前路径.( . 就代表当前路径)
使用该命令编译文件后,发现当前路径下并没有 Hello.class 文件.
而是多了一个名为 lee 的文件夹. 该文件夹下有一个 Hello.class 文件.

这是怎么回事呢?
这与Java的设计有关.
假设某个应用中包含两个 Hello 类.
Java通过引入包机制来区分两个不同的 Hello 类.
不仅如此,这两个 Hello 类还对应两个 Hello.class 文件.
它们在文件系统中也必需分开存放才不会引起冲突.
所以Java规定:
位于包中的类,在文件系统中也必需有与包名层次相同的目录结构.

对于上面的 Hello.class 它必需放在lee 文件夹下才是有效的.
当使用 -d 选项的 javac 命令来编译 Java源文件时, 改命令会自动建立对应的文件结构来存放相应的 class 文件.

如果直接使用 javac Hello.java 命令来编译文件.
将会在当前路径下生成一个 Hello.class 文件.
并不会生成 lee 文件夹.
也就是说, 如果不使用 -d 选项, 编译器不会为 java源文件生成相应的文件结构.
建议你以后使用编译命令时, 都加上 -d 选项.

下面, 进入编译器生成的 lee 文件夹所在路径(不是进入 lee 文件夹里面),执行如下命令.

java lee.Hello

然后看到程序正常输出.
然后我解释一下这其中的执行流程.

当虚拟机要装载 lee.Hello 类时, 他会依次搜索 CLASSPATH 环境变量所指定的系列路径.
查找这些路径下是否包含 lee 路径.
并在 lee 路径下查找是否包含 Hello.class 文件.
虚拟机在装载待包名的类时.
会先搜索 CLASSPATH 环境变量指定的目录.
然后在这些目录中按照与包层次对应的目录结构去查找 class 文件.

同一个包中的类不必位于相同的目录下.
例如有 lee.Person 和 lee.PersonTest 两个类.
它们完全可以一个位于 C 盘下某个位置, 一个位于 D 盘下某个位置.
只要让 CLASSPATH 环境变量里包含这两个路径即可.
虚拟机会自动搜索 CLASSPATH 下的子路径.
把它们当成同一个包下的类来处理.

不仅如此, 也可以把 Java源文件放在与包名一致的目录结构下.
与前面介绍的理由相似, 如果系统中存在两个 Hello 类.
通常也对应有两个 Hello.java 源文件.
如果把它们的源文件也放在对应的文件结构下.
就可以解决源文件在文件系统中的存储冲突.

例如,可以把上面的 Hello.java 文件也放在与包层次相同的文件夹下面.
即放在 lee 路径下.
如果将源文件和class文件统一存放,也可能造成混乱.
通常建议将源文件和class文件也分开存放.
以便管理.
例如,将上面定义的位于 lee 包下的 Hello.java 及其生成的 Hello.class 文件.
建议以下图的形式存放:

这里写图片描述

注意:
一些新手以为只要把生成的 class 文件放在某个目录下, 这个目录名就成了这个类的包名.
这是错误的.
不是有了目录结构.
就等于有了包名.
为 Java类添加包必需在 java源文件中通过 package 语句指定.
单靠目录名是没法指定的.
Java包机制必需满足两个条件:

  • 源文件里使用 package 语句指定包名;
  • class 文件必需存放在对应的路径下.

建议包名全部是小写字母.
而且是由一个或多个有意义的单词连缀而成.
实际开发中.
为了避免不同公司之间的类名的重复.
Java建议使用公司 Internet 域名倒过来写, 来作为包名.
例如公司的 Internet 域名是 baidu.com
则该公司的所有类都建议存放在 com.baidu 包及其子包下.

长姿势:
在实际企业开发中, 还会在 com.baidu 包下以项目名建立子包.
如果该项目足够大, 则还会在项目子包下以模块名来建立模块子包.
如果该模块下还包括多种类型的组建.
则还会建立对应的子包.
假设有一个 eLearning系统.
对于该系统下学生模块的 DAO 组件.
则通常会放在 com.baidu.elearning.student.dao 包下.
其中 elearning 是项目名.
student 是模块名.
dao 用于组织一类组件.

package 语句必需作为源文件的第一行非注释语句.
一个源文件只能指定一个包. 即只能包含一条 package 语句.
该源文件中可以定义多个类, 则这些类将全部位于该包下.
如果没有显式指定 package 语句, 则处于默认包下.
同一个包下的类可以自由访问.
例如下面的 HelloTest 类, 如果把它也放到 lee 包下.
则这个 HelloTest 类可以直接访问 Hello 类.
并且无须添加包前缀. 什么是包前缀? 后面会讲到.

package lee;
public class HelloTest
{
    public static void main(String[] args)
    {
        //直接访问相同包下的另一个类,无须使用包前缀
        Hello h = new Hello();
    }
}

下面代码在 lee 包下再定义一个 sub 子包, 并在该包下定义一个 Apple 空类.

package lee.sub;
public class Apple{}

对于上面的 lee.sub.Apple 类, 位于 lee.sub 包下.
与 lee.HelloTest 类 和 lee.Hello 类不再处于同一个包下.
因此使用 lee.sub.Apple 类时就需要使用该类的全名(即包名加类名).
必需使用 lee.sub.Apple 写法来使用该类.

虽然 lee.sub 包是 lee 包的子包.
但在 lee.Hello 或 lee.HelloTest 中使用 lee.sub.Apple 类时.
依然不能省略前面的 lee 包路径.
即在 lee.HelloTest 类 和 lee.Hello 类中使用该类时不可以写成 sub.Apple.
必需写成完整包名加类名: lee.sub.Apple 才可以呦

涨姿势:
父包和子包之间确实表示了某种内在的逻辑关系.
例如前面介绍的 com.baidu.elearnging 父包 和 com.baidu.elearning.student 子包.
确实可以表明后者是前者的一个模块.
但父包和子包在用法上则不存在任何关系.
如果父包中的类需要使用子包中的类.
则必需使用子包的全名, 而不能省略父包部分.

如果创建处于其他包下类的实例.
则在调用构造器时也需要使用包前缀.
例如在 lee.HelloTest 类中创建 lee.sub.Apple 类的对象.
则需要采用如下代码:

//调用构造器时需要在构造器前增加包前缀
lee.sub.Apple a = new lee.sub.Apple();

import 关键字

正如上面看到的, 如果需要使用不同包中的其它类时, 总是需要使用该类的全名.
但这是一件很蛋疼的事情. 怎么办呢?
Java当然为你着想, Java引入了 import 关键字.
import 可以向某个 Java文件中导入指定包层次下某个类或全部类.
import 语句应该出现在 package 语句(如果有的话)之后 、 类定义之前.
一个 Java源文件只能包含一个 package 语句, 但可以包含多个 import 语句.
多个 import 语句用于导入多个包层次下的类.
使用 import 语句导入单个类的用法如下:

import package.subpackage...ClassName;

上面语句用于直接导入指定的 Java类.
例如导入之前的 lee.sub.Apple 类.
应该使用如下的代码:

import lee.sub.Apple;

使用 import 语句导入指定包下啊全部类的语法如下:

import package.subpackage...*;

上面 import 语句中的 * 号只能代表类, 不能代表包.
因此使用 import lee.*; 语句时.
它表明导入 lee 包下的所有类. 即 Hello 类 和 HelloTest 类.
而 lee 包下 sub 子包内的类则不会被导入.
如需要导入 lee.sub.Apple 类.
则可以使用 import lee.sub.*; 语句来导入 lee.sub 包下的所有类.

一旦在 java 源文件中使用 import 语句来导入指定类.
在该源文件中使用这些类时就可以省略包前缀, 不再需要使用类全名.
修改上面的 HelloTest.java 文件.
在该文件中使用 import 语句来导入 lee.sub.Apple 类.


package lee;
//使用 import 导入 lee.sub.Apple 类
import lee.sub.Apple;

public class HelloTest
{
    public static void main(String[] args)
    {
        Hello h = new Hello();
        //使用类全名的写法
        lee.sub.Apple a = new lee.sub.Apple();
        //如果使用 improt 语句来导入 Apple 类, 就可以不再使用类全名了
        Apple aa = new Apple();
    }
}

注意:
Java默认为所有源文件导入 java.lang 包下的所有类.
因此前面我们使用 String / System 类时都无须使用 import 语句来导入这些类.
但对于前面介绍数组时提到的 Arrays 类.
其位于 java.util 包下, 则必需使用 import 语句来导入该类.

但是:
在一些极端的情况下, import 也帮不了我们.
此时只能在源文件中使用类全名.
例如, 需要在程序中使用 java.sql 包下的类, 也需要使用 java.util 包下的类.
则可以使用如下两行 import 语句:

import java.util.*;
import java.sql.*;

如果接下来程序中需要使用 Date 类, 则会引起编译错误如下:

HelloTest.java:25 对Date的引用不明确.
java.sql 中的类 java.sql.Date 和 java.util 中的类 java.util.Date 都匹配

上面的错误提示:
在 HelloTest.java 文件的第25行使用了 Date 类.
而import语句导入的 java.sql 和 java.util 包下都有 Date 类.
所以系统懵逼了. (提醒你, 不要让系统懵逼, 系统一懵逼绝对是你错了)
在这种情况下, 如果需要指定包下的类, 则只能使用类全名.

//为了让引用更加明确,即使使用了import语句,也还是需要使用类全名
java.sql.Date d = new java.sql.Date();

import static

import 语句可以简化编程.
可以导入指定包下的某个类或全部类.

JDK 1.5以后 (现在普遍都使用 JDK1.8或以上版本了 所以肯定支持)
Java增加了一种静态导入的语法.
它用于导入指定类的某个静态成员变量 / 方法 / 或全部静态成员变量 / 方法 .

静态导入使用 import static 语句.
静态导入也有两种语法.
分别导入指定的类的某个静态成员变量 / 方法 / 或全部静态成员变量 / 方法
其中导入指定类的单个静态成员变量 / 方法 的语法格式如下:

import static package.subpackage...className.fieldName | mathodName;

上面与法中, 导入 package.subpackage…ClassName 类中名为 fieldName 的静态成员变量 或名为 methodName 的静态方法.
例如, 可以使用 import static java.lang.System.out; 语句来导入 java.lang.System类的 out 静态成员变量.

导入指定类的全部静态成员变量 / 方法的语法格式如下:

import static package.subpackage...ClassName.*;

上面语法中的 * 号只能代表静态成员变量或方法名.
import static 语句也放在 java源文件的 package 语句(如果有的话)之后 / 类定义之前.
即放在与普通 import 语句相同的位置.
而且 import 语句和import static 语句之间没有任何顺序要求.

所谓静态成员变量 / 静态方法 其实就是前面介绍的 类变量 / 类方法.
它们都需要使用 static 来修饰.
而 static 在很多地方都被翻译为静态, 因此 import static 也就顺理成章被称为 静态导入.
其实完全可以抛开这个翻译, 用一句话来归纳 import 和 import static 的作用:

  • 使用 import 可以省略写包名;
  • 使用 import static 则可以连类名都省略.

下面程序使用 import static 语句来导入 java.lang.System 类下的全部静态成员变量. 从而可以将程序简化成如下形式:

import static java.lang.System.*;
import static java.lang.Math.*;

public class StaticImportTest
{
    public static void main(String[] args)
    {
        //out 是 java.lang.System 类的静态成员变量, 代表标准输出
        //PI 是 java.lang.Math 类的静态成员变量, 表示 π 常量
        out.println(PI);
        out.println(sqrt(256));
    }
}

从上面程序不难看出, import 和 import static 的功能非常相似.
只是它们导入的对象不一样而已.
import 语句 和 import static 语句的存在都是为了简化编程, 减少代码工作量.

Java 的常用包

java的核心类都放在 java 包以及其子包下, java 扩展的许多类都放在 javax 包以及其子包下.
这些实用类也就是前面所说的 API(应用程序接口).
这些类根据功能的不同分别放在不同包下.
下面几个包是 java语言中的常用包.

  • java.lang: 这个包下包含了 java语言的核心类, 如 String / Math / System / 和 Thread 类等, 使用这个包下的类无须使用 import 语句导入, 系统会自动导入这个包下的所有类.
  • java.util: 包含了 java大量工具类 / 接口 和集合框架类 / 接口. 例如 Arrays 和 List / Set 等.
  • java.net: 包含了一些java网络编程相关的类 / 接口
  • java.io: 包含了一些java 输入/输出 相关的类/ 接口
  • java.text: 包含了一些java格式化相关的类.
  • java.sql: 包含了一些java进行JDBC数据库编程的相关 类 / 接口
  • java.awt: 包含了抽象窗口工具集的相关类 / 接口.这些类主要用于构建图形用户界面(GUI)程序.
  • java.swing: 包含了Swing图形用户界面编程的相关类 / 接口, 这些类可用于构建平台无关的 GUI 程序.

暂时各位客官对这些类有个大概的印象即可, 以后我们会慢慢逐渐熟悉这些包下各类和接口的用法.

本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。
目录: APP项目如何与插件化无缝结合(一)  APP项目如何与插件化无缝结合(二)  APP项目如何与插件化无缝结合(三)  搬砖码字不易,转载请注明转自: http://blog.csdn.net/u011176685/article/details/52006474 上面一篇主要介绍了Small的原理,相信大家应该现在心里有个大概的了解。好,我们接下来继续开始! 一、Small的使用 关于Small的使用, Small的使用 这里讲的很详细,关于这里提下我当时遇到的问题和解决办法。 1.Small作
在Windows下试了试用Ionic开发Android应用,试通了。记录了过程。列在下面,供参考。 1. JDK 我用的jdk8,这里下载: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 。我老早下载的,8u66,i586(32位的),现在是8u102: http://download.oracle.com/otn-pub/java/jdk/8u102-b14/jdk-8u102-wi
最近写的项目中有用到数据库,写了不少蛋疼的sql语句,每次都是好几行代码,而且每次都是重复的没有一点技术含量的代码,虽然也有不少基于sqlite的封装,不过用起来还是感觉不够面向对象! 为了不再写重复的代码,花了几天时间,基于SQLite3简单封装了下,实现了一行代码解决增删改查等常用的功能!并没有太过高深的知识,主要用了runtime和KVC: 首先我们创建个大家都熟悉的Person类,并声明两个属性,下面将以类此展开分析 @interface Person : NSObject @property (

以太网帧格式 - 2016-07-24 18:07:25

浅谈以太网帧格式                                       一、Ethernet帧格式的发展 1980 DEC,Intel,Xerox制订了Ethernet I的标准 1982 DEC,Intel,Xerox又制订了Ehternet II的标准 1982 IEEE开始研究Ethernet的国际标准802.3  1983 迫不及待的Novell基于IEEE的802.3的原始版开发了专用的Ethernet帧格式 1985 IEEE推出IEEE 802.3规范,后来为解决Eth
  谷歌改良了ndk的开发流程,对于Windows环境下NDK的开发,如果使用的NDK是r7之前的版本,必须要安装Cygwin才能使用NDK。而在NDKr7开始,Google的Windows版的NDK提供了一个ndk-build.cmd的脚本,这样,就可以直接利用这个脚本编译,而不需要使用Cygwin了。只需要为Eclipse Android工程添加一个Builders,而为Eclipse配置的builder,其实就是在执行Cygwin,然后传递ndk-build作为参数,这样就能让Eclipse自动编译
文章系列 视频驱动V4L2子系统驱动架构 - 驱动框架 视频驱动V4L2子系统驱动架构 - ioctl 基于linux4.6.3,最后会附上一张ioctl调用总图,分析代码还是要用图来说明,这样更清晰一点,我就是这么分析的,不过平时分析的图很随便,而且很大,所以就不能在这里呈现,我在这里会贴出一个简略图 ioctl详解 进入ioctl都是从cdev-ops-ioctl进入的,一般的驱动cdev都是驱动自己初始化的,在v4l2架构中,cdev都已经初始化完成,不需要驱动开发者来初始化,下面是v4l2的cde
杂谈 最近在研究gradle ,插件化~自己碰到的坑很多.今天先总结一下 以下这三个都研究过,原理都是一样的,区别就在于用哪个更方便. 在这里我会讲述一下,这里面的原理和自己爬的坑,以便大家理解,还有少爬坑~~ 原理是需要懂得~ 不然,你遇到错误不会解决,并且你始终会是初级工程师~ 首先,按照顺序,介绍下目前三种热修复的方式: 1.Nuwa (基于gradle写的脚本,操作起来比较麻烦,需要拷贝和运行命令行~) https://github.com/jasonross/Nuwa 2.andfix (看过~
题记——  难过了,悄悄走一走;         伤心了,默默睡一觉;         优雅不是训练出来的,而是一种阅历;         淡然不是伪装出来的,而是一种沉淀;         时间飞逝,老去的只是我们的容颜;         时间仿佛一颗灵魂,越来越动人; 1、简述:     在多线程的世界中,是那么的神奇 与 高效以及合理; 2、创建线程池实例     官方推荐使用Executors类工厂方法来创建线程池管理,Executors类是官方提供的一个工厂类,里面封装了好多功能不一样的线程池,
书接上回,我们已经了解了一些关于适配的一些相关概念,接下来我们会了解一下,在设置布局时我们应该注意的地方。 尽量不去设定具体的尺寸值。 为了确保布局适应各种尺寸的屏幕,在保证功能实现的前提下,最好不要写死一些尺寸,这样的硬编码,我们最好使用“match_parent”,”wrap_content”,”weight”这些不用指定具体的尺寸值的参数,这样视图就会根据自身需要的空间去充填。这样就可以让布局去适应各种屏幕的尺寸,当屏幕有旋转时也不会受到影响。 这里我们重点说一下“weight”,用过 LiearL

艺术般的波浪点击反馈效果 - 2016-07-24 17:07:27

Material Design之Rippledrawable 使用与简单封装(向下兼容至selector) 前言 Android 5.0问世以来,谷歌所推崇的Material Design得到业界的一致好评,其良好的UI规范与交互确实让界面交互友好和漂亮了不少,Rippledrawable便是其中之一,本博客今天着重讲如何将它运用到我们自己的项目中,并且封装得简单易用。 我们都知道,我们在之前做按钮或者布局的反馈效果,一般都用selector来实现,分别指定按下或正常状态的两种颜色即可,我们点击的效果也本