【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的拼接。

原文地址:https://www.cnblogs.com/-xk94/p/12341016.html