Java语言基础(SE)-第二节 基础语法

语法须知

  1. 每一条语句都必须以分号 ; 结尾
  2. 程序的入口是 main 方法
    1. 没有 main 方法,Java 程序是无法启动的
    2. 方法必须包含在 class 内部,先有 class,再有方法
  3. public class 的名称(类的名称)须要和文件名保持一致
  4. 疑问:如果一个 Java 项目中有 2 个不同的 class,它们都有自己的 main 方法,那岂不是有 2 个 Java 程序入口?
    1. 只能选择其中一个入口开始执行程序
    2. 当运行的时候,会让选择执行哪一个入口
  5. Java 的注释有 3 种书写格式

     //这是单行注释
     /*
     这是多行注释
     */
     //自动生成文档注释,输入`/**`然后回车即可
     /**
      * 
      * @param a
      * @param b
      * @return
      */
    

数据类型

Java 的数据类型主要分为 2 大类

  1. 基本类型(Primitive Type)
```
byte:8-bit 的整数,取值范围是 [–128, 127]
short:16-bit 的整数,取值范围是 [–32768, 32767]
int:32-bit 的整数,取值范围是 [–231, 2 31– 1]
long:64-bit 的整数,取值范围是 [–263, 2 63– 1]
float:单精度 32-bit IEEE 754 浮点数,取值范围是 [1.40E–45F, 3.4028235E38F]
double:双精度 64-bit IEEE 754 浮点数,取值范围是 [4.9E-324, 1.7976931348623157E308]
boolean:布尔类型,有 true、false 两个取值
char:单个 16-bit 的 Unicode 字符
``` 2. 引用类型(Reference Type)    
1. 引用类型的值是对对象的引用

字面量(Literal)

//整数
//十进制
byte v1 = 123;
//二进制(或者0B11001)
short v2 = 0b11001;
//十六进制(或者0XF78A)
int v3 = 0xf78a;
//用L或者l结尾表示long类型(或者 1991)
long v4 = 199L;
	
//浮点数
//以F或者f结尾表示float类型(或者123.4f)
float v5 = 123.4F;
//以d或者D结尾表示double类型(或者123.4d)
double v6 = 123.4D;
//默认就是double类型
double v7 = 123.4;
//可以用科学计数法(E或者e)
float v8 = 1.234E2F;
double v9 = 1.234e2;
	
//字符、字符串
//用单引号表示字符
char v10 = 'A';
//用双引号表示字符串
String v11 = "ABCD";
	
//布尔
boolean v12 = true;
boolean v13 = false;
	
//空值
String string = null;

转义序列(Escape Sequences)

\b(退格,\u0008)
\t(制表符,\u0009)
\n(换行,\u000a)
\f(换页,\u000c)
\r(回车,\u000d)
\"(双引号,\u0022)
\'(单引号,\u0027)
\\(反斜杠,\u005c)

在数字中使用下划线

  1. 从 Java 7 开始,可以给数字添加下划线增强可读性

     int v1 = 1_000_000;
     int v2 = 0xff_ec_de_5e;
     int v3 = 0b11011101_11111111_00010010;
     double v4 = 1.23_45_67;
     long  v5 = 1___0000_0000;
    
  2. 下面的用法是错误的

     //不能在浮点数的小数点前后使用下划线
     double r1 = 1._23;
     double r2 = 1_.23;
     //不能在数字的前后使用下划线
     int r3 = _123;
     int r4 = 123_;
     //不能在特殊字母的前后使用下划线
     byte r5 = 0x_12;
     byte r6 = 0_b10010;
     float r7 = 1.23F_;
     long r8 = 189_L;
    

变量的初始化

  1. 任何变量在使用之前都必须要先初始化(赋值)
    1. 局部变量:需要程序员手动初始化
    2. 非局部变量(实例变量、类变量):编译器会自动给未初始化的变量设置一个初始值

       类型              初始默认值
              
       byte              0
       short             0
       int               0
       long              0L
       float             0.0F
       double            0.0D
       char              '\u0000'
       boolean           false
       对象(引用)        null
      

运算符(Operator)

运算符                     优先级
后缀                       expr++ expr--
一元(单目)                ++expr --expr +expr -expr ~ !
乘除模                     * / %
加减                       + -
位移                       << >> >>>
关系                       < > <= >= instanceof
等价                       == !=
按位与                     &
按位异或                   ^
按位或                     |
逻辑与                     &&
逻辑或                     ||
三元(三目)                ? :
赋值                      = += -= *= /= %= &= ^= |= <<= >>= >>>=
  1. 上面一行的优先级比下面一行高,同一行的优先级一样
  2. 当多个优先级一样的运算符一起使用时,按照结合性进行运算
    1. 只有赋值运算符的结合性是从右至左
    2. 其他运算符的结合性都是从左至右
  3. 为了保证运算符按照预期执行,尽量多使用小括号
    1. 比如 5 * ((a + b) / c)
  4. 算数表达式的结果必须被使用

字符串拼接

  1. 可以使用加号(+)进行字符串的拼接

     int age = 18;
     String name = "jack";
     double height = 1.78;
     System.out.println("my name is" + name + ", age is " + age + ", height is " + height);
    

位运算

  1. >>>>>
    1. >>(有符号右移):最左用符号位补齐
    2. >>>(无符号右移):最左用 0补齐
  2. &、|、^ 也能用在 boolean 类型上
    1. 对比 &&、||,&、| 少了短路功能
    2. 短路功能:&&左边是false右边不用算。||左边是true右边不用算

类型转换(Type Conversion)

  1. 拓宽基本类型转换(Widening Primitive Conversion)
    1. 数据范围小的转为数据范围大的(19种),可以自动转换(隐式转换)

       byte 转 short、int、long、 float、double 
       short 转 int、long、float、double 
       char 转 int、long、float、 double 
       int 转 long、float、double 
       long 转 float、double 
       float 转 double
      
    2. 举例

       byte b = 12;
       short s = b;
       int i = s;
       char c = 'A';
       int ix = c;
       long l = ix;
       float f = l;
       double d = f;
      
  2. 窄化基本类型转换(Narrowing Primitive Conversion)
    1. 数据范围大的转为数据范围小的(22种),可能会丢失精度和范围,需要强制转换

       short 转 byte、char 
       char 转 byte、short 
       int 转 byte、short、char 
       long 转 byte、short、char、 int 
       float 转 byte、short、char、int、long 
       double 转 byte、short、char、 int、 long、 float
      
    2. 举例:

       short s = 512;
       char c = (char)s;
       byte b = (byte) c;
       double d = 1.23;
       float f = (float)d;
       int i = (int)d;
      

数字提升

一元数字提升(Unary Numeric Promotion)

  1. 一元数字提升:将 byte、short、char 类型的一元数字自动提升为 int 类型(拓宽基本类型转换)
  2. 下面的情况会执行一元数字提升
    1. 数组的索引、创建数组时的数组长度
    2. 一元运算符 +
    3. 一元运算符 –
    4. 按位取反(~)
    5. 位移(«、»、»>)
     int []array = {11,22,33,4};
     byte index = 10;
     //会自动转化
     array[index] = 30;
     char c1 = 'A';
     System.out.println(c1); //A
     System.out.println(+c1); //65
     char c2 = +c1; //报错,int类型不能直接赋值给char类型
     char c3 = 65; //ok
    

二元数字提升(Binary Numeric Promotion)

  1. 二元数字提升:提升一个或者两个数字(拓宽基本类型转换)
    1. 如果任意一个数字是 double 类型,那么另一个就会被转换为 double 类型
    2. 否则,如果任意一个数字是 float 类型,那么另一个就会被转换为 float 类型
    3. 否则,如果任意一个数字是 long 类型,那么另一个就会被转换为 long 类型
    4. 否则,两个数字都被转换为 int 类型
  2. 下面的情况会执行二元数字提升
    1. 乘(*)、除(/)、取余(%)
    2. 加法(+)、减法(–)
    3. 比较(<、<=、>、>=)
    4. 判等(==、!=)
    5. 位运算(&、^、
    6. 三目(? :)
     byte v1 = 1;
     byte v2 = 1;
     byte v3 = v1 + v2; //报错,结果是int,不能直接赋值给byte
     byte v4 = v1 + 2; //报错,同上
     byte v5 = 1 + v2; //报错,同上
     byte v6 = 1 + 2; //ok
    		
     byte v7 = 1;
     v7 = v7 + 2; //error
     v1 += 2; //ok 复合赋值运算自带转换
    

关键字(Keyword)

  1. 关键字,也叫做保留字(reserved word)
  2. Java 的关键字如下所示

     abstract、continue、 for、new、 switch、assert、default、goto、package、synchronized 
     boolean、do、if、private、 this、 break、 double、 implements、protected、throw 
     byte、else、import、 public、 throws、case、enum、instanceof、 return、transient 
     catch、extends、 int、short、 try、char、 final、interface、static、void 
     class、finally、 long、 strictfp、volatile、const、float、 native、super、 while
    
  3. 虽然 goto、const 未被使用,但也属于关键字
  4. true、false、null 不是关键字,是字面量

标识符(Identifier)

  1. 标识符:变量名、方法名、类名等,命名规则如下
    1. 不限长度的 Java 字母、Java 数字序列,但必须以 Java 字母开头(区分大小写)
    2. 不能使用关键字
    3. 不能使用字面量 true、false、null
  2. Java 字母
    1. Character.isJavaIdentifierStart 方法返回 true 的字符
    2. 包括 ASCII 中的 A~Z、a~z,美元符($),下划线(_),中文,韩文,日文等字符
  3. Java 数字
    1. Character.isJavaIdentifierPart 方法返回 true 的字符,即该方法返回值为true,说明要么是Java字母,要么是Java数字
    2. Java 数字 包括 ASCII 中的 0~9
  4. 命名建议
    1. 变量名、方法名:小驼峰,比如 myNameAndAge
    2. 类名:大驼峰,比如 MyNameAndAge
    3. 常量:比如 MY_NAME_AND_AGE

数组

  1. 数组的创建
    1. 注意: 在Java中,字符数组 != 字符串
      1. 字符数组:char[]
      2. 字符串:String
    2. 推荐使用 char[] arr 格式定义数组,不推荐使用 char arr[] 格式定义数组
     int[] arr1;
     int[] arr2 = {}; //空数组
     int arr3[] = {}; //空数组
        	
     //定义的时候指定数组元素
     int[] arr4 = new int[] { 1, 2, 3, 4};
     //上面的简化,省略了new int
     int[] arr5 = { 1, 2, 3, 4 };
        	
     //定义的时候指定数组长度
     int[] arr6 = new int[4];
     arr6[0] = 1;
     arr6[1] = 2;
     arr6[2] = 3;
     arr6[3] = 4;
        	
     //多维数组
     int[][][] arr7;
     int[] arr8[][];
    
  2. 数组的内存
    1. Java 的数组属于引用类型,即对象
      1. 数组元素存储在堆空间(Heap)
      2. 举例:
         public static void main(String[] args) {
             int[] arr = new int[] { 11, 22, 33};
         }
        
        1. arr是一个引用类型,在main函数中是一个局部变量,因此放在了栈中,占用8个字节,内部存储的是元素存放堆空间的首字节地址
        2. 数组的元素放在堆空间,分配12个字节存放11、22、33这三个元素
      3. 注意:Java的数组元素都是放在堆空间

         //下面2者等价
         int[] arr = new int[] { 11, 22, 33};
         int[] arr = { 11, 22, 33};
        
    2. Java 的堆内存申请会自动进行初始化

       //元素在堆空间中统一初始化为0
       int[] arr6 = new int[4];
       //元素在堆空间中统一初始化为null
       String[] arr6 = new String[4];
      
  3. 数组的遍历

     //遍历数组
     int[] arr = {11,22,33,44};
     for(int i =0; i<arr.length;i++) {
         System.out.println(arr[i]);
     }
     //直接遍历每个元素
     for (int ele : arr) {
         System.out.println(ele);
     }
    

方法(Method)

  1. 方法(Method)
    1. Java 中的方法,其实就是其他编程语言中的函数(Function)
  2. 方法的书写格式

     修饰符 返回值类型 方法名(参数列表) { 
         方法体
     }
    
  3. 可变参数( Variable Argument)
    1. 可变参数必须是方法中的最后一个参数
    2. 举例:JDK自带的 System.out.printf 方法使用了可变参数
      1. 格式字符串参考API文档的 java.util.Formatter 类

         //格式化打印
         String name = "Jack";
         int age = 20;
         System.out.printf("name is %s,age is %d %n",name,age);
                    
         //查看printf系统源码如下
         public PrintStream printf(String format, Object ... args) {
             return format(format, args);
         }
        
    3. 举例使用

       //调用
       sum(1,2,3);
       public static int sum(int... numbers) {
           int result = 0;
           for (int i : numbers) {
               result += i;
           }
           return result;
       }
       public static int sum1(int... numbers , int name) {} //错误,可变参数必须放最后面
      
      1. numbers就相当一个数组,存储着传递过来的实参,如果调用时不传任何值,numbers默认就是空数组{};
  4. 参数传递
    1. 基本类型作为参数是值传递
      1. 基本类型作为返回值,返回的是值
    2. 引用类型作为参数是引用传递(地址传递)
      1. 引用类型作为返回值,返回的是引用(地址)
  5. 方法签名(Method Signature)
    1. 方法签名由 2 部分组成:方法名、参数类型
    2. 下面方法的方法签名是:sum(int, long, double)

       public static double sum(int i,long l,double d) {
           return i + l + d;
       }
      
    3. 在同一个类中,不能定义2个方法签名一样的方法
  6. 方法的重载(Overload)
    1. Java 的方法支持重载:方法名相同,方法签名不同
      1. 参数个数不同
      2. 参数类型不同
    2. 重载与返回值类型、参数名称无关
     public static int summary(int a, int b) {
         return a+b;
     }
        	
     public static double summary(double a, double b) {
         return a+b;
     }
     //重载跟返回值无关
     //	public static char summary(double a, double b) {
     //		return a+b;
     //	}
     public static int summary(String a, int... b) {
         return 5;
     }
    
  7. 栈帧(Frame)
    1. 栈帧随着方法的调用而创建,随着方法结束而销毁,存储了方法的局部变量信息
    2. 每个函数调用都会创建一个栈帧,当调用完毕销毁函数栈
    3. C++中详细分析过
  8. 递归调用
    1. 如果递归调用没有终止,将会一直消耗栈空间
      1. 最终导致栈内存溢出(Stack Overflow)
    2. 所以必需要有一个明确的结束递归的条件
      1. 也叫作边界条件、递归基
     public static void main(String[] args) {
         sumx(100);
     }
     public static int sumx(int n) {
         if(n<1) return n;
         return n + sumx(n-1);
     }
    

注意事项

  1. Java中不存在直接获取变量内存地址的方法
  2. Java不建议程序员去关注内存地址

官方文档

  1. Java 语言规范
    1. https://docs.oracle.com/javase/specs/index.html
    2. https://docs.oracle.com/javase/specs/jls/se13/html/index.html
    3. 最常用JAVA8:https://docs.oracle.com/javase/specs/jls/se8/html/index.html
  2. Java 虚拟机规范
    1. https://docs.oracle.com/javase/specs/jvms/se13/html/index.html
    2. https://docs.oracle.com/javase/specs/jvms/se8/html/index.html
  3. Java 教程
    1. https://docs.oracle.com/javase/tutorial/java/index.html
  4. Java API 文档
    1. https://docs.oracle.com/en/java/javase/13/docs/api/index.html
    2. https://docs.oracle.com/javase/8/docs/api/
  5. JAVA语言、虚拟机、API 离线中英文 文档,详见 网盘资料01[官方文档]压缩包
Table of Contents