02.Java的语法

Java 语法

1. 注释,标识符,关键字。

  • 单行注释://
  • 多行注释: /* ... */
  • 文档注释:/** ....*/ 这个中间的每行之前都会自动生成*,并且用来跳转到说明文档。

可以从设置-->Editor-->Color Scheme-->Java->comment 去勾Inherit就可以更改颜色。

2. 数据类型: 强类型语言。

(VB,Javascript为弱类型语言)

  • 定义 数据类型 变量名=值 ;
  • 基本类型:primitive. 共8种: 4整,2小,1浮,1布。
  • 整型:
    • byte 8位: -128~127
    • short 16位:-32768-32767
    • int 32位: -21亿到正21亿
    • long 64位:10进制19位数. 值的表达方式应该是数字+"L". eg. long no4=33L;
      注意: Integer 这个是属于类,并不是基础类型关键字。
      整型数据值表达: 长整末尾加L, 8进制前面加0, 16进制前面加0x
  • 浮点:
    • float 4字节: 值的表达方式:数字后加F. eg. float no5=66.66F
    • double 8字节:
      数字值表达的时候,可以用下划线分割,系统会解析为注释,不起作用。
      eg. int money = 10_0000_0000, 就是10亿。
      注意:浮点型和双精型数据,如果用==进行比较,并不相等,只返回false
      注意:java 中虽然数值型变量有默认值0,但是不经过赋值,直接进行加减乘除,
      编译是无法通过的。
  • 字符:
    • char: 占两个字节,可以用来对应Unicode编码。
      可以用’反斜杠+u+ASCII‘码值来表达一个对应的字符。
      eg. char C1='\u0065' 这里需要用16进制
      转义字符: \n 回车。 \t。制表。println();与print("\n");效果一样。
      注意:print()语句参数,可以直接把数值和字符串连起来,并不需要%d这样的转义符,也不会 按值转ASCII. eg.
    System.out.print(j+"*"+i+"="+j*i+"\t"); 
    
    其中j,i是整数
    String: 这个不是关键字,也不是基本数据类型,所以首字母大写,它属于一个类。
    • 布尔:boolean: 取值只有true 和 false,计算机内部只占一个位。
  • 引用类型:reference
    • 类: eg. Integer; String; BigDecimal. Java类命名基本都是遵循匈牙利命名法。
    • 接口
    • 数组

3. 类型转换

​ 基础类型可以进行强行转换,格式为: (类型) 被转换值。
​ 例如(int) 字符值, 就会返回一个ASCII码值。
​ 正常自动转换,小位转大位,可以正常用,也不用使用强制类型符。
​ 正常转换会出现的问题是,如果被转换数是一个负数,那么转换后,高位将会用1补齐,形成一个很大的数。
​ 非正常转换,大位转小位,那么高位字节将会被截断,只保留低位字节内容。

注意:

  • boolean类型不能进行强制转换,前后都不行。
  • 对象类型不能转位完全不兼容类型。
  • 尽量避免不同精度的小数转换。
  • 两个int整型表达式相乘或相加数位溢出,仍然会返回一个int型,而不自动增位。
    eg.
int years=2000;
long total1 = money * years; //这种数据在赋值之前就已经溢出了,并不因为total1为long而保存
long total1 = money * (long)years; //正确写法,只要有一个数为long,整个表达式就为long.
          //同理两个整数相除,结果会是一个去余取整的整数,并不会产生小数。

4. 变量,常量

type varName [=value][{,varname[=value]}]; //变量定义时也可以省略赋值,并可以用多个逗号分开定义多个变量。
注意变量的作用域,一般会分为类变量,实例变量,以及局部变量。

  • 类变量: 类变量跟实例变量都同样定义在类的根范围内。类变量需要加static进行修饰。
  • 实例变量:实例变量不用static,默认为实例。
    注意: 类变量随类的生存期产生,并分配空间。可以用类名.类变量名来调用,也可以用实例.类变量名来调用,所指的是同一个值地址,等于共用。 而实例变量,只有对实例进行New分配的时候,才会有对应变量空间,而且不同实例之间的实例变量是独立的,互不影响。
  • 局部变量:方法内,或者一个范围{}内。
  • 常量: final [数据类型] 常量名=值; 相当于Delphi中的const.
    对于默认类变量的值: 数值为0, 字符为空操作ASCII0 ,布尔型为false; 而用类定义变量都是默认为Null
    在一个java类中 final 关键字的含义是:变量一旦赋值就不能修改,且必须在 “声明时 / 构造方法中 / 初始化块中” 完成赋值。
    所以,常常会使用构造方法传参进行赋值,eg.
    private final StoreOutService service;
    public StoreOutController(StoreOutService service) {
    this.service = service;
    }
  • 命名机制:
    • 类成员变量,局部变量:驼峰原则,第一个单词首字母小写,其他大写。
    • 常量命名: 通常约定,常量名用大写字母,多个单次下划线隔开。
    • 类名: 首字母大写,标准匈牙利命名法。

5. 运算符

  1. 算术运算符: + , -, *, /, %, ++, --
    百分号为求余运算,等于delphi中mod.
    a++,表示给a自增,并返回a增加前的值。 ++a,表示给a自增,然后返回自增后的值。
    对于String类,加号可以当作连接,但是符号char数据没办法相加变成连接,只会机械的将ASCII码值相加并返回整型。
  2. 赋值运算符:=
    给String赋值char需要用到类方法valueof : str=String.Valueof(charVar);
  3. 关系运算符:>, <, >=, <=, , !=, instanceof
    instanceof 是对象是否属于类的判断,相当于Delphi中的is.
    字符串的相等判断,需要用String的实例方法equals,而不能用

    判断数组元素是否相等同样要用到Arrays.equals(数组1,数组2);
  4. 逻辑运算符:&&, ||, !
  5. 位运算符: &, |, ^, ~,>>,<<, >>>
    ^为位异或, ~为位非。 同样的,非是单操作数运算。
    数值>>移位数,和数值<<移位数,相当于把数值除以或乘以2的移位数幂。
    当使用右位移时,正数高位会用0补齐,负数高位会用1补齐。
    >>>是无符号右移运算,负数右移一样用0补齐,这个运算符号使用在特殊场景。
  6. 条件运算符: ?...: 问号和冒号。 a ? b : c 返回值,如果a为true返回b,如果a为false 返回b。
    相当于Delphi中的iif.
  7. 扩展赋值运算符: +=, -=, *=, /=, <<=, >>=, >>>=
  • Java运算符的优先级顺序
    1.括号 ()‌:最高优先级,用于明确指定运算顺序。‌‌
    2.单目运算符‌:包括正负号 +、-、自增 ++、自减 --、逻辑非 ! 等。‌‌
    3.算术运算符‌:乘法 *、除法 /、取余 % 优先级相同,高于加法 + 和减法 -。‌‌
    4.移位运算符‌:左移 <<、右移 >>、无符号右移 >>>。‌‌
    5.关系运算符‌:小于 <、大于 >、小于等于 <=、大于等于 >=。‌‌
    6.相等性运算符‌:等于 ==、不等于 !=。‌‌
    7.位运算符‌:按位与 &、按位异或 ^、按位或 |(优先级依次降低)。‌‌
    8.逻辑运算符‌:逻辑与 && 高于逻辑或 ||。‌‌
    9.条件运算符‌:三元运算符 ?:。‌‌
    10.赋值运算符‌:包括 =、+=、-= 等,优先级最低。‌‌

结合优先一般遵从从左到右,个别单目运算从右到左。

6. 包机制,JavaDoc

在Src里面可以用New->package新建包。 然后可以用Shift工程拖动到包里,选择refactor,然后下面点击Do Refactor.
通常的包命名约定: 会用对应的公司倒置作为包名,eg.com.baidu.www。用Ctrl+鼠标点包名,可以跳转到包细节。

      import 包名,可以引用外面的包。语法如下:
      package pkg1[.pkg2[.pkg3...];
      ...
      import package1[.package2...]. (classname|*); 这里可以用.*来导入对应包通用的类。
      JavaDoc 命令可以生成说明文档包.
      /**
       * @author 作者名MurphyYu
       * @param 参数说明
       * @return  返回值说明
       * @throws Exception 异常说明
       * @version 版本号
       * @since 1.8 需要的最早JDK版本。
       */
       IDEA界面可以用Tools-->Generate JavaDoc-->Generate来实现。
       非Windows系统,最下面Locale应该增加:zh_CN, 
       Command line arguments 这里写: encoding UTF-8 charset UTF-8
    
       命令示例:JavaDoc -encoding UTF-8 -charset UTF-8 Demo.java.
       可以通过右键点击IDEA树型目录-->Open In-->Terminal调出终端界面。

示例: 新建空项目,可以添加Module,选择项目。 还需要在空项目上,File->Project Structure->Project
更改项目的SDK 和 languag Level到对应的版本。


7. Java流程控制

  • Scanner类
    next() 获得一个用户输入内容,遇空格或者回车结束。
    nextLine() 获得除next()外的用户输入内容,遇回车结束。也可以不使用next()直接获得整行数据。
    hasNext() 对应判断。
    hasNextLine() 对应判断。
    同理,可以用hasNextByte, hasNextDouble, hasNextFloat, hasNextLong……来判断接收的数据类型。
    数据判断也有兼容效果,当输入整数的时候,hasNextDouble也同样生效。
    如果不用hasNext..()判断对应数据,而直接取值,会报异常。

  • 选择结构:

    1. 标准if
      if (布尔表达式){
      执行体
      }
      单判断if后面的花括号可以省略,但编译器会建议增加。

    2. 双选if.
      if(布尔表达式){
      执行体1
      }else{
      执行体2
      }

    3. 多选if
      if(布尔表达式){
      执行体1
      } else if(布尔表达式){
      执行体2
      }...无限else if(布尔表达式)
      {} else {
      执行体N
      }
      注意else后面的花括号可以省略,但编译器会建议增加。

    4. 分值选择switch..case.. 相当于Delphi中的case 语句,但没有case when强大,只能判断变量相等。不过从JDK7以后,这个变量支持String比较了。这里的实际执行语句是判断: str变.hashCode().
      switch(变量){
      case 值1
      语句块;
      [break];
      case 值2
      语句块;
      [break];
      ...
      Default:
      语句块N;
      }
      如果各个分值中的break没有加,那么一旦进入了某个分支,就会顺序执行到下个break直至末尾,
      不会再次进行case匹配判断。

      注意: 可以查找到对应的class文件,然后拷贝到java文件目录中,再点击IDEA树结构上新出现的.class
      文件实现对.class文件的反编译。

  • 循环结构
    1.while循环.
    while (布尔表达式){
    循环体
    }

    1. do .. while 循环,与while循环不同之处在于至少执行一次循环体,第一次是不判断的。
      do {
      循环体
      } while(布尔表达式);
    2. for 循环. 特点是循环前就可以确定循环次数。
      for([初始化循环变量];[布尔表达式];[更新循环变量]){
      循环体
      }
      增强for循环, 声明的变量,必须与数组元素类型匹配,表达式的返回值应该是一个数组名。
      这种循环用来遍历数组或者集合,循环次数等于元素个数。这里不能得到数组循环的当前下标。
      for(声明语句 : 表达式)
      {
      循环体
      }
    3. 循环控制: break; continue;
      break用来跳出循环;
      continue 结束本次循环,直接执行下次循环。
      Java不支持goto语句,但是却保留了goto关键字,并且启用了标签Label.
      标签用来控制在嵌套循环中break和continue的跳出层数。 语法为:
      alabel : for (){... continue alabel;...};
      从使用上来看,比C和Delphi强多了。C的break默认是跳出所有循环的,而continue只能跳出一层。
    4. forEach 是 Java 8+ 中 Collection 集合(List、Set 等)的遍历方法,替代了传统的 for 循环,
      结合 Lambda 表达式可以简化遍历代码。
      eg. operationInfo.getOperationInfoDetailList().forEach(item -> {
      item.setPid(operationInfo.getId());
      }); //这个是让从表获取主表ID.

8. Java的方法:

概述

  1. Java的方法只有函数,没有过程,可以用void定义一个无返回值的函数。 并且,所有方法都必须属于类或对象。不存在全局方法。
  2. main方法是执行代码中,最底层的方法。main方法的String args[]是命令行的参数。可 以用java 文件名 参数列表(空格隔开) 在命令行传输主参数。
  3. 方法的语法格式:
   public/private [static] 返回类型 方法名() {
       方法体...;
       return 返回类型表达式; //注意,这里不是Result;
   }     
   //static 用来定义类方法。并没有类似Self的语法来引用类本身,不过可以在实例方法中使用this来引用实例,用来区分同名类变量/方法 和 成员变量/方法。
  1. 方法的重载: 必须相同的方法名,不同的参数列表。 Java里不用增加overload关键字。
    但是一个用static 修饰,一个不用,这样的两个方法并不是重载,而是独立的类方法和成员方法。
  2. 可以在参数列表的最后位置用 元素类型...数组名 的形式,形成一个可变数量的形参。但这些参数都必须是
    符合元素类型的同类型参数。
    在传递实参时,即可以传送一个用逗号隔开数据列表,也可以传送花括号括起来的数字,或者直接传数组名。
    数组名作为参数,其实是一个指针,在方法中对任何数组元素的值操作,都会直接影响到实参的元素数据。
  3. 递归,严格说递归不算一种语法,只能算一种算法,不过需要语法的支持。
    单方法递归,一般分递归头和递归体,递归用来结束调用。而递归体就包含回调函数本身。需要在递归体中控制
    流程可以走到递归头。

9. 数组:

1.数组的概述
一种数据结构,严格说这里的数组不是结构体,而是对象。哪怕全是基础数据类型,也需要空间申请。
数组空间一旦被分配,数据类型及长度就不可改变。不能定义混合类型数组。
数组元素类型多种多样,即可以是基本数据类型,也可以是引用(类)数据类型。
2.数组的声明及创建
声明方法:

         dataType[] arrayRefver;  //首选方法。
         dataType arrayRefver[];  //非首选方法,兼容C语法。

变量初始化:

         datatype[] arrayRefVar = new dataType[arraySize];  //动态初始化,其实也会有初始值,全部都为0

还有静态初始化:

         int[] a ={1,2,3};  //花括号,带数据组,就代表一个数据
         clss1[] temps = {new clss1(1,2), new clss1(3,4)};     
  1. 数组使用
    数组的使用下标从0开始到.length-1;
    ArrayIndexOutOfBoundsException : 数组下标超范围异常。
    循环的IDEA简化:数组名.for,会自动带出增强循环格式。
  2. 多维数组
    数组的数组,以数组为元素的数组。常量表达为:
 int [][] arry={{1,2},{2,3},{4,5,6}}; //这个同C语言一样,常量表达时,子数组是允许不等长的。

多维数组的真正长度是:arry[].length*arry.length;
5. Arrays类,对数组的应用。java.util.Arrays

- sort 排序
- binarySearch 二分查找法,参数数组必须是已经排序好的。
- fill 填充,这个不仅仅可以做全部填充,也可以做部分填充,参数为4个fill(数组名,范围下标始,范围下标终,填充值);
- copyof 复制数组
- asList 将数组转换成集合
- toString 将数组元素转换成字串
- equals[数组1,数组2]判断数组元素是否相等。
6. 稀疏数组,这个并不是一种语法,而是一种存取数据的方法和思维。
当矩阵中大部分数据都相同时,可以用到稀疏数组,只记录其不同的数据即可。
稀疏数组的记录模式: {{行总数,列总数,异常元素总数},{行位置1,列位置1,异常值1},{行位置2,列位置2,异常值2}..}
也就是说稀疏数组除了第一个元素记录总的行列数,异常点数,后面只记录每个异常点信息即可。

10. 面向对象:封装,继承,多态

  1. 面相对象的方法。return代表着方法的结束,后面的语句不会再执行。return可以不带任何数值,对应void.
  2. 不需要在每个类定义中都使用main方法,整个程序只需要有一个main方法即可。
  3. 每个对象都是由成员和方法组成。每个类都是属性和方法组成。类名首字母大写。
  4. 对象的初始化,会有默认值和 类构造器(构造方法)的调用。类定义中,可以用this指代对象,用来使用对象成员或方法。
  5. 同一个包中的java文件,可以直接互相调用其类,不需要用import引用。

6.类的构造器(构造方法): 一般用来初始化成员信息,常用this来实现。
java public 类名(){ //这里方法名跟类名相同,既没有static修饰,也没有 返回值类型,这就是构造方法语法。 }
默认都是无参构造,不过如果使用了有参数的构造方法定义,那么使用new时就必须带参数,除非显式重载无参构造方法。
alt+insert热键,可以生成构造函数语法框架。MacOS系统是用Command+N。
子类的构造方法,默认会先执行父类的构造方法,相当于Delphi中inherited省略。如果父类是有参构造,子类构造必须显示调用父类有参构造,否则无法编译。

  1. 封装:高内聚,低耦合。 通常应该禁止直接访问一个对象中数据的实际表示,而应该通过操作接口来访问,这即为信息隐藏。
    设计时,可以用属性值私有(private); 然后用公用方法get和set进行存取。
    意义: 我们可以在设计期对set方法进行检查,确定输入数据的合法性。隐藏代码的实现细节。增强了系统的可维护性。

  2. 继承:语法为定义的时候增加extends 类名,即可实现。java语法跟delphi是一样的,只能单继承。但是类之间还可以有:依赖,组合,聚合关系。
    public class 子类名 extends 父类名{

    }

    • 继承权限: public; protected; default; private; Ctrl+H 可以显示当前类的继承关系层。
    • Object是java中的万物之王,相当于Delphi中的TObject.追踪Object的定义,可以看到其具备的基本对象方法:
    • equals : public boolean equals(Object obj)
    • clone : protected native Object clone() throws CloneNotSupportedException.
    • toString : public String toString()
    • wait :
    • finalize : protected void finalize() throws Throwable { } //析构函数

注意:子类和父类中出现的同名方法,属性都不会被覆盖,可以用this 和 super来区分和调用。
this(),super()可以用来调用构造方法。
注意:super只能调用public和protected修饰的属性和方法。被final修饰的类,即便是public也无法被继承。

相对于delphi中的动态方法和虚方法(dynamic/virtual),java也有对应的实现模式.一般无任何关键字标识的都是java的动态方法,可以
在子类中随意覆盖.而在delphi中无标识的普通静态方法,java则需要用相应的修饰符来进行控制: private/final/static,这三种修饰符
控制的方法,是不能在子类中重写的.

而对于delphi中的inherited关键字,java可以用super.同名方法()来实现. 对于构造方法中的inherited create; java的实现方法是子类
构造方法中,第一行写上:super(); 即可.

  1. 多态:用重写方法来实现多态。
    注意: 类方法需要用static保持一致。在子类中重写父类的类方法,其实是独立的,不存在多态或覆盖。
    多态主要用作对象方法的重写。
    用同样在同样的方法名,参数中,内容中利用super.方法名();就实现了继承主方法体。
    我们可以用父类的一个变量 去指向子类的new实例,这是合法的,只不过不能直接调用子类新增的部分。
    这样的父类变量,对应的成员和方法,其实都是子类中初始化的。
    但是,我们不能用子类变量去指向一个父类实例,这样会报错。因为子类变量的新增空间无法被初始化。
    子类变量和父类变量可以互相转换,报异常:ClassCastException

    ???继承和多态过程中,修饰范围可以被扩大,不能被缩小。 而异常的抛出,可以被缩小,但不能被扩大。

构造继承多态,可以用alt+insert(Windows) 或 Command+N(MacOs)来实现框架格式。对应Constructor和Override.

instanceof 用来判断一个对象数据是否完全包含一个类,但是前提是这个对象的类是判断类的父类,否则编译会报错。
如果是某个类的父类,则可以用(子类名)+对象名,强行转换为子类,从而使用子类的新开辟方法或属性。
语法中也允许子类转换为父类,这个其实是默认转换,不存在强制,会丢失一些子类新开辟的方法或属性。
instanceof 结合 (子类名)+对象名 的转换,相当于 Delphi中的 对象 is 类,对象 as 类。

  1. 静态代码块与匿名代码块。这两种块都应该处于某个类的根下。
    static {
    代码块;
    }
    静态代码块,默认代码中所有代码都会自动在构造方法之前执行。但是不管开辟多少对象,这里的代码只执行一次。
    去掉static只保留花括号,就是匿名代码块。
    开辟对象空间的时候,默认执行顺序为:静态代码块>匿名代码块>构造方法。 这个顺序跟代码块书写位置无关。

  2. 抽象类与抽象方法:增加abstract修饰的类和方法。
    抽象类特点: 不能使用New来创建,必须要用子类实现才能使用。但可以定义一个抽象类变量,赋值子类实例。
    抽象方法特点: 只有声明,没有阐述。子类必须实现抽象方法,除非子类也是抽象类。
    拥有抽象方法的类,必须是抽象类; 但是,抽象类不一定必须包含抽象方法。

  3. 接口:定义关键字: interface
    普通类:声明,阐述;具体实现。
    抽象类:具体实现 和 抽象方法声明。

    • 接口: 只有声明。无具体实现。 实现软件中约束和实现分离。

    • 接口的本质就是契约规范,代表的意义是“如果你是……则必须能……”。 这种规范,所有涉及到接口的内容都必须遵守。

    • 接口中所有的方法都是public abstract属性的,并且在代码声明的时候可以省略这两个关键字。

    • 接口中只能定义常量。定义时默认为是public static final,不过一般很少在接口中定义常量。
      语法:返回值类型 方法名(参数列表);

    • 接口调用: public class 类名 implements 接口名列表(逗号隔开); //并且在类中必须实现接口中所有的方法。

    • 接口是不能实例化的,不具备构造方法。

  4. 内部类:

    • 如果内部类不是static ,就必须使用外部类的实例来开辟内部类的实例,语法为:

    • 外部类.内部类 变量名 =外部类实例.new 内部类名;

    • 如果内部类是static的,并且成员和方法也是静态的,那就可以用:外部类.内部类.静态方法 的模式来访问。

    • 如果内部类是static,但是内部类的方法不是静态的,依旧需要定义两层实例来访问方法。

    • 内部类static以后,是无法访问外部类的实例变量和方法的,因为它的生存期早于它们。

      注意:一个java文件中,只有有一个public 类,但允许有许多定义的class平级类,可以叫局部类,相当于私有类。

      直接使用new 类名().方法(); 这种不用变量保存实例到变量,而直接使用方法的语句叫匿名类,例如调用局部类方法。
      实现接口方法时,也常常用new 接口 { 方法实现 };的语句,同样是匿名。

11. 异常机制 Exception

程序运行过程中,出现超乎于程序处理方式的情况。
1,检查性异常。 2,运行时异常。 3,错误: 编译检查不到,内存错误。

Throwable Error     VirtulMachineError  StackOverFlowError   //栈溢出
                                        OutofMemoryError     //内存
                    AWTError                                 //图形化
          Exception IOException         EOFException                     
                                        FileNotFoundException
                    RuntimeException    ArithmeticException  //算术异常  
                                        MissingResourceException //资源丢失
                                        ClassNotFoundException //找不到类
                                        NullPointerException //空指针
                                        IllegalArgumentException //非法参数
                                        ArrayIndexOutOfBoundsException //数组越界
                                        UnkownTypeException

Error是无法被控制处理的,而Exception是可以捕获和处理的。
- 异常的处理: try, catch, finally, throw, throws
try{ 监视区}
catch(异常类型1 e){异常处理……}
catch(异常类型2 e){异常处理……}
... //多catch后面,尽量加catch(Exception)防止遗漏的异常。
finally{ 善后 };
- 方法中如果有处理不了的异常,可以抛出: if (异常条件) { throw new ArithmeticException(); }
- 自定义异常:
public class MyException extends Exception{ 异常体,通常要包含构造方法 };
- 异常的抛出:
方法名(参数) throws MyException{ 参数判断……throw new MyException(参数) );
这里参数一般都是要传到异常构造函数的参数。
- 调用方法时捕获:try {抛异常的方法} catch(MyException e){...}……
尽量在catch块增加一些代码处理,让异常数据变正常。

12. 泛型与迭代器:

我们可以用ArrayList 泛型变量,来定义一个泛型,也就是相当于指针数组。
然后通过迭代器Iterator来访问泛型的每一个元素。
eg.

       ArrayList<Point> points;        //定义一个泛型变量points.
       points = new ArrayList();
       ...
       points.add(New Point(x,y)); //通过循环在points中添加无数点,这里能不能添加不同类还未得知。
       ...
       Iterator iterator = points.iterator();   // 得到泛型的迭代器。
       while(iterator.hasNext()){      //利用迭代器遍历泛型
            Point point=(Point).iterator.next();  //强行转换迭代器元素。
            ...
       }   

javabean 的核心规范:

  1. 必须具备无参构造!
  2. 成员变量必须私有(private),通过getXxx()/setXxx()间接访问成员变量(boolean的 get可用is)。
    3.Serializable 接口,支持序列化。即:类具有implements Serializable修饰。以保证对象可以转换为字节序列,并可以进行持久化存储。

用途:早期用于Swing等桌面可视化, 现在更多用于后端业务组件,适配各种框架,如:
Spring , MyBatis, Struts等。

13. Jar包与War包的结构:

  • Jar包结构无严格规范,核心是META-INF/MANIFEST.MF 清单文件:
    xxx.jar
    META-INF
    MANIFEST.MF 这里可以指定Main-Class,决定可执行包
    com 业务类包
    demo
    Utils.class
    config 自定义配置包
    application.properties
    lib 依赖第三方JAR,Spring Boot常用。
    可执行JAR包,需要指定Main-Class:com.demo.Main. 然后通过 java -jar xxx.jar运行。
    非可执行类库,可以作为依赖引入,通过classpath加载。命令:javac -cp xxx.jar Demo.java

  • War包需要具有严格的目录结构,复合Servlet标准,Web容器。
    xxx.war
    WEB-INF/ #核心目录(容器保护,外部无法直接访问)
    classes/ #编译后的Java类,等同于JAR的class文件
    lib/ #Web应用依赖的第三方JAR包(容器自动加载)
    web.xml #Servlet配置文件,3.0版本后可用注解代替
    META-INF/ #清单文件,部署描述符等。
    index.html #静态页面,根目录直接访问的入口
    css/ #静态资源
    js/ #javascript文件。
    WAR包运行,需要部署到Web容器
    将WAR包放入容器的webapps目录; 启动容器后会自动解压WAR包,并解析WEB-INF
    通过http://域名:端口/包名/ 即可访问。
    也可以将WAR包转换为可执行JAR。

关系:
Spring boot默认打包为JAR,如需要部署外部Tomcat也可打包为WAR。
一个WAR包可以包含多个JAR包, JAR包无法直接转换为WAR包,需补充Web目录结构配置。
EAR包,企业级应用宝,可包含多个WAR/JAR包,用于EJB容器。

posted @ 2026-06-23 08:56  莫霏  阅读(15)  评论(0)    收藏  举报