• 【Java】 入门 — —(五)


       这一章讲的是,包,类的引入之类的,开发都离不开引入,所以挺重要的(修正一下,非常重要);

      因为编程语言中,这些涉及到 目录结构,开发时候不懂它的意思,就根本理解不了为什么要这样做,博主未正规学习时候去搭建 Java 项目时候,看得一头雾水。

       

      1、包(package):

         A、Java 中允许使用 package 将类组织起来。

         B、使用包,可以方便组织自己的代码,同时方便清晰管理自己的代码和别人提供的代码。

           C、* 使用包的主要原因是为了确保类名的唯一性,例如:A包 和 B包 下面都存在一个叫 Employee 的类,这样就不会产生冲突了。

         D、实际上为了确保 包名 的唯一性,Sun 公司建议将公司的因特网域名以 逆序的形式作为包名,

            例如:

             · Java 的核心技术 的作者之一的注册域名为 horstmann.com, 逆序形式就是 com.horstmann。

             · 上面说的,还可以进行进一步划分成子包,如:com.horstmann.corejava。

         E、标准的 Java 类库,分布在多个包中。

               F、标准的 Java 包具有一个层次结构;如同硬盘的目录嵌套一样,也可以使用嵌套层次组织包。

           G、所有标准的 Java 包都处于 Java 和 Java小包层次中。

         H、从编译器的角度来看,嵌套包直接没有任何关系,例如:java.util 包 和 java.util.jar 包 毫无关系;每一个都拥有独立的类集合。


      

      2、类的导入:

        Ps: 一个类可以使用所属包中的所有类,以及其他包中的公有类(public class)

        A、访问另一个包中的公共类有下面两种方法:

          1.  在每个类名之前添加完整的包名,如:java.time.LocalDate today = new java.time.LocalDate.now();

          2. 使用 import 方法,使用了 import 方法后,就不需要把包名也带上了。

            Ps: import 导入特定的类,或者 整个包中所有的类: 

              · 特定的类 ---- import java.time.LocalDate;

                · 包中所有的类 ---- import java.util.*;(这种写法是比较简单的,但是不明确导入的类有哪些)    

        B、上面导入包中所有类的写法,* 号写法,只能导入一个包,而不能通过 java.*.* 来进行导入所有 java 前缀的包。

        C、要是使用 * 号来导入两个包,刚刚包中有重复名字的类,这个时候会报错,例如:

    /// java.util 和 java.sql 都有 名字为 Date 的类
    import java.util.*;
    import java.sql.*;
    
    /// 上面的导入,会导致编译器不知道你要的是那个包下的 Date 类
    /// 我们在下面增加一条 特定指向导入的类来解决错误。
    import java.util.Date;
    
    /// 解决错误后,但是我们实际上,两个包中的 Date 类都要用到。
    /// 解决方法是 第一种使用 包中公共类的写法,写全包名。
    java.util.Date deadline = new java.util.Date();
    java.sql.Date today = new java.sql.Date(...);

         D、在包中定位类时编译器(compiler)的工作,也就是说,把 .java 文件编译成 .class 文件的时候,编译器会完整的带上包名,存放在字节码中,相当于 语法糖 的作用。


      

      3、静态导入:

        A、import 除了能导入类外,还有导入 静态方法 和 静态域的功能。

    /// 在源文件顶部添加一条命令。
    /// 这样的写法会添加类中的 所有 静态方法 和 静态域。
    /// 这里都是针对 public 类的。
    import static java.lang.Math.*;
    
    class StaticImport
    {
      public static void main(String[] args)
      {
        /// pow 是 静态方法
        double a = pow(10, 2);
        System.out.println("pow = " + a);
        /// PI 是 静态域
        System.out.println(PI);
      }
    }    

       


      

      4、将类放入包中:

        A、要想把类放入包中,就必须将 包 的名字放在源代码的开头

    package 包名;
    
    public class Employee
    {
        ...
    }

        B、如果源文件没有放置 package 语句,这个源文件中的 类就被放置在一个 默认包(default package)中。

         C、默认包是没有名字的。

         D、* 将包中的文件放到与完整的 包名 匹配的子目录中:

          例如:com.horstmann.corejava 包中的所有 源文件(即 .java 后缀的文件)应该放在 com/horstmann/corejava 目录下。

         E、编译器会将类文件(.class)也放在相同的目录结构中:

          也就是说,我们把 Employee 类,放在 com.horstmann.corejava 中个包中,源文件 Employee.java 是在 com/horstmann/corejava 目录下;

      编译器 编译后 生成的 Employee.class 文件也会在 com/horstmann/corejava 目录下。

        F、编译生成:

    /*
        目录结构:
        |— TestImportMain.java
        |— importclass/
            |— ImportClass.java
            |— NotImportClass.java
    */
    
    TestImportMain.java 文件,下面是它的全部内容
    ----
    /// 这里 使用了了 ImportClass;
    import importclass.ImportClass;
    class TestImportMain
    {
      public static void main(String[] args)
      {
        System.out.println(ImportClass.name);
      }
    }
    ----

    ImportClass.java 文件,下面是它的全部内容
    NotImoportClass.java 文件 也是一样的内容,只是 名字不同,name 的值不同。

    ----
    package importclass;

    public class ImportClass
     {
      public static String name = "引入或使用了的 包中 类";
      ImportClass(){}
     }
     ----
    
    /// 我们只需要执行 在根目录下 执行 javac TestImportClass.java 去编译,就能生成下面的目录结构:
    /// 因为 NotImportClass 没有在 TestImportClass 中使用,所以编译不会去编译它。
    /*
        目录结构:
        |— TestImportMain.java
        |— TestImportMain.class
        |— importclass/
            |— ImportClass.java
            |— ImportClass.class
            |— NotImportClass.java
    */

        G、编译器在编译源文件的时候,不检查目录结构,意思是有下面的情况:

    我回退过头没了,心态炸了,不写了。有人说不明白 这句话 再说吧。

         H、第 F 点说的入口文件编译,是在 default package 包下面的, 要是我们的入口文件不在默认包中,如下:

    /*
    .(基目录)/// 也就是 终端打开目录
      |— com/
         |— horstmann/
         |       |— corejava/
         |               |— Employee.java
         |- myapp/
              |- App.java /// 入口函数 Main 所在的 main 
    */
    /// 编译时候要从 基目录编译 和运行类,即包含 com 目录:
    /// 编译:javac com/myapp/App.java
    /// 运行:java com.myapp.App
    
    Ps:
        1、编译器(就是上面命令行中的 javac)对文件(带文件分隔符 和 扩展名 .java 的文件)进行操作。
        2. java 解析器(就是上面命令行中的 java) 加载类(带 . 分隔符)

     


      

      5、包的作用域:

          A、被 public 修饰的类,可以被 任意类(不在同一个包里面的类也是可以的) 使用。

          B、被 private 修饰的类,只能被定义它的类中 使用。

          C、如果 一个 类 它没有被任何其他类包含着,只用使用 public/公共的、abstract/抽象的、final/最终的 这三个关键字是被允许去修饰它的。

            否则会报:Illegal modifier for the class PrivateClass; only public, abstract & final are permitted

          D、如果一个包中的类,没有被 public 修饰,那么它只能被 同一个包中的类的所有方法访问。

          E、类 被 public 修饰后,构造器也要被 public 修饰,否则 类的构造器 同样只能在同一个包中(这个同一个包中,只要源文件上面的 package 包名; 都是相同的,就是同一个包,哪怕分成多个源文件,并不影响)使用。

          F、同一个包中,分成多个源文件,不同源文件中都可以重复 类名,

            Ps:

              · 编译器会先找到同一个源文件中的 类,如果同一个源文件中 没有该类,往包的其他源文件中 查找,同一个包中的 不需要 import。

              · 因为上面这点,编写一个包的时候,注意 类名 的重复

          G、注意:一个包中,类的 域(实例域 或者 静态域)没有被 public 或者 private 关键字修饰的话,类的域 也是可以被同一个包中其他所有的方法 获取到,所以 变量 这里不适宜 省略掉 private 或者 public 修饰词。

      PS:

        我们看了上面那个多 包 的解说,可以看到:

          · 默认情况下,包不是一个封闭的实体,也就是说,任何人都可以往包里添加更多的类 或 修改包的代码。

          · 默认情况下,1.2的JDK开始 类加载器 明确地禁止 加载用户自定义的 包名以 "java." 开始的类。

          · 上面保护的方法,无法保护 用户自定义的类,解决这个问题,通过 包密封(package sealing)机制来解决各种包混杂在一起的问题。

          · 将一个包密封起来,就不能再向这个包添加类了。制作包含密封包的 JAR 文件(也就是 .jar 文件了,终于知道这个后缀是什么鬼了),后面再说。

          · JAR 文件使用 ZIP 格式组织文件和子目录;可以使用所有 ZIP 实用程序查看内部 的 rt.jar 以及其他的JAR 文件


     

      6、类路径( class path)[这个鬼东西,就是window 安装 Java 时候,好多教程都有教到的设置 window 环境变量中的 CLASSPATH ]:

          A、类的路径 必须 与 包名 匹配;类路径是包含类文件的路径的集合

          B、window 中使用(;)分隔,Linux 中使用(:)分隔.

          C、Java SE 6 开始,JAR 的文件目录中可以用 * 通配符,这个通配符,值匹配 .jar文件(注意 Unix 系统不允许这样做,但 Linux 也是允许的)

              · window:  c:classdir;.;c:archives*

              · Linux: /home/user/classdir:.:/home/user/archives/'*'

          D、javac 编译器总是在当前目录中查找文件,但 Java 虚拟机仅在类路径中有 ( . ) 目录的时候才查看当前目录。

          E、如果没有设置类路径,默认的类路径包含了 . 目录。

          F、设置了类路径,但忘记写上 . 目录,会导致编译没问题,但是运行不了。

          G、设置类路径:

    # 最好采用 -classpath(或 -cp)选项指定类路径
    # Linux 或者 Mac
    $ java -classpath /home/user/classdir....
    
    # window
    $ java -classpath c:classdir...
    
    
    # 整个命令要写在一行,太长的话,可以写在 shell 脚本 或者 批处理中然后执行。
    # 上面的是首选,但是,我们同样可以设置 环境变量 CLASSPATH.
    # window 设置环境变量就不用说了(点击设置哪些)
    
    # 命令行设置
    # Linux 依赖的是 export 
    $ export CLASSPATH=/home/user/classdir....
    
    # window shell 如下:
    $ set CLASSPATH=c:classdir...
    
    # 上面命令行设置,知道 shell 退出之前,都有效,shell 推出后就失效了。
    # 适合临时设置的,要是一直用到,把它写在环境变量配置中

      文件分隔符:

        参考:https://www.cnblogs.com/hellowhy/p/6526114.html

          我直接复制粘贴过来了,写的挺好的,如果认为侵权删除,请联系我。

    一、linux系统和windows系统中的文件路径:

    Linux系统:

    Windows系统:

    可以看到Linux系统中,路径中的文件名分隔符是"/",而Windows中是""

    二、linux系统和windows系统中的path路径:

    Linux系统:

    .:%JAVA_HOME%lib:%JAVA_HOME%lib	ools.jar:%JAVA_HOME%jrelib
    t.jar:

    Windows系统:

    .;%JAVA_HOME%lib;%JAVA_HOME%lib	ools.jar;%JAVA_HOME%jrelib
    t.jar;

    同样,可以看到Linux系统中,path间的分隔符是":"(冒号),而Windows中是";"(分号)

    因为分隔符的不同,我们在编程时就不能硬性制定文件路径或path之间的分隔符,因为这会导致跨平台时出现找不到文件或路径的错误,

    在java中是这样解决的,jdk中有对应的方法,可以根据当前系统类型动态地获取文件或path的分隔符,下面是使用方法及源码中的相关描述:

    一、获取文件路径中的文件名分隔符:

    File.separator;

     下面开始追踪源码:

    第一步:

    系统相关的默认名称分隔符。为了方便它被表示为一个字符串,该字符串只包含一个字符,即separatorChar

    第二步:

    系统相关的默认名称分隔符,这个字段被初始化为包含系统属性file.separator值的第一个字符,在UNIX系统中是”/”,在Windows系统中是””

    第三步:

    FileSystem对象表示当前平台的本地文件系统

    第四步:

    返回本地文件系统的名称分隔符

    二、获取path中的分隔符:

    File.pathSeparator

    第一步:

    系统相关的路径分隔符,为了方便被表示为一个字符串,这个字符串是一个单独的字符,即pathSeparatorChar

    第二步:

    系统相关的路径分隔符。这个字段被初始化为系统属性path.separator值的第一个字符,这个字符被用来分隔以列表形式给定的文件序列的文件名称,

    在UNIX系统中是冒号(:),在Windows系统中是分号(;)

    第三步:

    FileSystem对象表示当前平台的本地文件系统

    第四步:

    返回本地文件系统的路径分隔符

    所以在java编程中,遇到文件和path等操作时,为了跨平台时不引起因分隔符导致的错误,就要调用这两个方法来进行文件路径或path的拼接。

  • 相关阅读:
    CSS选择器的权重与优先规则
    excel上传--phpExcel读取xls、xlsx
    反射与代理设计模式
    Map集合
    接口实际应用-工厂代理模式
    代码模型:对象比较
    Stream数据流
    集合输出接口-Iterator迭代输出-古老枚举输出:Enumeration
    Set集合接口-HashSet_TreeSet理解
    List类集接口-ArrayList
  • 原文地址:https://www.cnblogs.com/-xk94/p/12341016.html
Copyright © 2020-2023  润新知