# Java 快速入门

# 2.1 Java 历史

# 2.2 搭建开发环境

# 2.3 Java 程序基础

  • Java程序基本结构
  • 变量和数据类型
  • 整数运算
  • 浮点数运算
  • 布尔运算
  • 字符和字符串
  • 数组类型

# 2.3.1 Java程序基本结构

我们先剖析一个完整的Java程序,它的基本结构是什么:

/**
 * 特殊的多行注释
 * 可以用来自动创建文档的注释
 */

// 类名必须以英文字母开头,后接字母,数字和下划线的组合
// 习惯以大写字母开头
// 注意到 public 是访问修饰符,表示该 class 是公开的
public class Demo {
    // 这里的方法名是main,返回值是void,表示没有任何返回值。
    public static void main(String[] args) {
        // 在方法内部,语句才是真正的执行代码。Java的每一行语句必须以分号结束
        // 向屏幕输出文本:
        System.out.println("Hello, world!"); 
        // 单行注释
        // 这是注释...

        // 多行注释
        /*
        这是注释
        blablabla...
        这也是注释
        */
    }
}

Java程序对格式没有明确的要求,多几个空格或者回车不影响程序的正确性,但是我们要养成良好的编程习惯,注意遵守Java社区约定的编码格式。

# 标识符

public class Demo01 {
    public static void main(String[] args) {
        // 所有的标识符都应该以 字母 $ _ 开始
        // 首字符之后可以是 字母 $ _ 数字
        // 注意标识符是大小写敏感的
        String hello = "Hello";
        String world = "World";
        String $hello = "Hello";
        String hello1 = "Hello";
        String hello_world = hello + world + "!";
        System.out.println(hello_world);
    }
}
  • 所有的标识符都应该以 字母 $ _ 开始
  • 首字符之后可以是 字母 $ _ 数字

# 2.3.2 变量和数据类型

# 变量

Java 是强类型语言,要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用

public static void main(String[] args) {
    String a;
    System.out.println(a); // 这里会报错
}

来看一个完整的定义变量,然后打印变量值的例子:

// 定义并打印变量
public class Main {
    public static void main(String[] args) {
        int x = 100; // 定义int类型变量x,并赋予初始值100
        System.out.println(x); // 打印该变量的值
    }
}

变量的一个重要特点是可以重新赋值。例如,对变量x,先赋值100,再赋值200

// 重新赋值变量
public class Main {
    public static void main(String[] args) {
        int x = 100; // 定义int类型变量x,并赋予初始值100
        System.out.println(x); // 打印该变量的值,观察是否为100
        x = 200; // 重新赋值为200
        System.out.println(x); // 打印该变量的值,观察是否为200
    }
}

Java 的数据类型分为两大类

  • 基本类型
  • 引用类型

# 基本数据类型

基本数据类型是CPU可以直接进行运算的类型。Java定义了以下几种基本数据类型

基本数据类型 具体类型 细节
数字 整数 byte 1 个字节 8 位二进制数
数字 整数 short 2 个字节 16 为二进制数
数字 整数 int 4 个字节 32 位数,可用来表示 10 位时间戳
数字 整数 long 8 个字节 64 位数,可用来表示 13 位时间戳
数字 浮点数 float 4 个字节
数字 浮点数 double 8 个字节
字符 char 2 个字节 表示单个字符
布尔值 boolean 1 个位 表示真/假 (是/否)
public static void basic() {
    // 整数
    byte b1 = 10;
    short s1 = 20;

    int num3 = 30;
    int i = 2147483647; // int 最常用
    int i2 = -2147483648; 
    int i3 = 2_000_000_000; // 加下划线更容易识别
    int i4 = 0xff0000; // 十六进制表示的16711680
    int i5 = 0b1000000000; // 二进制表示的512

    long num4 = 30L; // long 数字后面要加 L
    long n2 = 900; // 没有加L,此处900为int,但int类型可以赋值给long
    int i6 = 900L; // 错误:不能把long型赋值给int
    // 浮点数
    float f1 = 3.14f; // 数字后面要加 f
    float f2 = 3.14e38f; // 科学计数法表示的3.14x10^38
    float f3 = 1.0; // 错误:不带f结尾的是double类型,不能赋值给float

    double d = 1.79e308;
    double d2 = -1.79e308;
    double d3 = 4.9e-324; // 科学计数法表示的4.9x10^-324

    // 布尔值
    boolean b1 = true;
    boolean b2 = false;
    boolean isGreater = 5 > 3; // 计算结果为true
    int age = 12;
    boolean isAdult = age >= 18; // 计算结果为false
    /*
    Java语言对布尔类型的存储并没有做规定,
    因为理论上存储布尔类型只需要1 bit,
    但是通常JVM内部会把boolean表示为4字节整数。
    */
    // 字符
    char c1 = 'A'; // 字符要使用单引号
    char zh = '中';
}

# 引用类型

引用数据类型 具体类型 细节
数字 整数 类 BigInteger 表示任意大小的整数
数字 浮点数 类 BigDecimal 表示一个任意大小且精度完全准确的浮点数
字符串 类 String 表示多个字符
String s = "hello";

# 常量

定义变量的时候,如果加上final修饰符,这个变量就变成了常量

final double PI = 3.14; // PI是一个常量
double r = 5.0;
double area = PI * r * r;
PI = 300; // compile error!

# 示例代码

public class Demo02 {
    public static void main(String[] args) {
        // Java 是强类型语言
        // 要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用
        /**
         * String a;
         * System.out.println(a); 这里会报错
         */
        number();
        reference();
    }

    public static void number() {
        // ====================
        System.out.println("====================进制");
        // ====================
        int i2 = 0b10; // 二进制的 10 表示十进制的 2
        int i10 = 10;
        int i8 = 010; // 八进制的 10 表示十进制的 8
        int i16 = 0x10; // 八进制的 10 表示十进制的 16
        System.out.println(i2);
        System.out.println(i10);
        System.out.println(i8);
        System.out.println(i16);
        // ====================
        System.out.println("====================浮点数的问题");
        // ====================
        // 浮点数的问题
        // 精度
        float f = 0.3f;
        double d1 = 0.1 + 0.2;
        double d2 = 0.3;
        System.out.println(f == d1); // false
        System.out.println(d1 == d2); // false
        // 溢出
        float f1 = 12345678910f;
        float f2 = f1 + 1;
        System.out.println(f1 == f2); // true
        // ====================
        System.out.println("====================强制转换");
        // ====================
        // 字符 转 Int 输出:字符对应的 Unicode 码
        // 字符的本质还是数字
        char c1 = '1';
        char c2 = 'a';
        char c3 = '中';
        char c4 = '\u0061'; // 16 进制的 61 表示 97 最终输入 a
        System.out.println(c1); // 1
        System.out.println((int)c1); // 49
        System.out.println((int)c2); // 97
        System.out.println((int)c3); // 20013
        System.out.println(c4); // a
    }

    public static void reference() {
        Integer num0 = 0;
        String Gauss = "Gauss"; // 字符串要使用双引号
        // ====================
        System.out.println("====================字符串常量池");
        // ====================
        // 字符串常量池
        // 为了提高性能并减少内存的开销,JVM在实例化字符串常量时进行了一系列的优化操作
        // 1.在JVM层面为字符串提供字符串常量池,可以理解为是一个缓存区
        // 2.创建字符串常量时,JVM会检查字符串常量池中是否存在这个字符串
        // 3.若字符串常量池中存在该字符串,则直接返回引用实例;若不存在,先实例化该字符串,并且,将该字符串放入字符串常量池中
        String sa = "abc";
        String sb = "abc";
        System.out.println(sa == sb); // true
        String sc = new String("abc");
        String sd = new String("abc");
        System.out.println(sc == sd); // false
    }
}

# 2.3.3 整数运算

Java的整数运算遵循四则运算规则,可以使用任意嵌套的小括号。四则运算规则和初等数学一致。例如:

// 四则运算
public class Main {
    public static void main(String[] args) {
        int i = (100 + 200) * (99 - 88); // 3300
        int n = 7 * (5 + (i - 9)); // 23072
        int x = 12345 / 67; // 184
        int y = 12345 % 67; // 12345÷67的余数是17
        System.out.println(i);
        System.out.println(n);
        System.out.println(x);
        System.out.println(y);
    }
}

整数的数值表示不但是精确的,而且整数运算永远是精确的,即使是除法也是精确的,因为两个整数相除只能得到结果的整数部分

# 溢出

要特别注意,整数由于存在范围限制,如果计算结果超出了范围,就会产生溢出,而溢出不会出错,却会得到一个奇怪的结果

// 运算溢出
public class Main {
    public static void main(String[] args) {
        int x = 2147483640;
        int y = 15;
        int sum = x + y;
        System.out.println(sum); // -2147483641
        long sum = x + y;
        System.out.println(sum); // 2147483655
    }
}

# 自增/自减

Java还提供了++运算和--运算,它们可以对一个整数进行加1和减1的操作

// 自增/自减运算
public class Main {
    public static void main(String[] args) {
        int n = 3300;
        n++; // 3301, 相当于 n = n + 1;
        n--; // 3300, 相当于 n = n - 1;
        int y = 100 + (++n); // 不要这么写
        System.out.println(y);
    }
}

# 移位运算

在计算机中,整数总是以二进制的形式表示。例如,int类型的整数7使用4字节表示的二进制如下:

00000000 0000000 0000000 00000111

可以对整数进行移位运算。对整数7左移1位将得到整数14,左移两位将得到整数28:

int n = 7;       // 00000000 00000000 00000000 00000111 = 7
int a = n << 1;  // 00000000 00000000 00000000 00001110 = 14
int b = n << 2;  // 00000000 00000000 00000000 00011100 = 28

# 位运算

对两个整数进行位运算,实际上就是按位对齐,然后依次对每一位进行运算。例如:

// 位运算
public class Main {
    public static void main(String[] args) {
        int i = 167776589; // 00001010 00000000 00010001 01001101
        int n = 167776512; // 00001010 00000000 00010001 00000000
        System.out.println(i & n); // 167776512
    }
}

# 运算优先级

在Java的计算表达式中,存在运算优先级,一般来说乘除优先于加减。

记不住也没关系,只需要加括号就可以保证运算的优先级正确。

# 类型转换

public class Demo05 {
    public static void main(String[] args) {
        /**
         * 注意点
         * 1. 不能对布尔值进行转换
         * 2. 不能把对对象类型转换位不相干类型
         * 3. 高容量到低容量需要强制转换
         * 4. 转换的时候可能存在内存溢出或者丢失精度
         */

        // 强制转换  高到低
        int i = 128;
        byte b = (byte) i;
        System.out.println(b); // - 128
        float f = 61.8f;
        double d = 61.8;
        System.out.println((int) f); // 61
        System.out.println((int) d); // 61
        // 自动转换  低到高
        long l = (long) i;
        System.out.println(l); // 128
        char c = 'a';
        System.out.println(c + 1); // 98
    }
}

# 整数运算小结

整数运算的结果永远是精确的;

运算结果会自动提升;

可以强制转型,但超出范围的强制转型会得到错误的结果;

应该选择合适范围的整型(intlong),没有必要为了节省内存而使用byteshort进行整数运算。

# 2.3.4 浮点数运算

# 2.3.5 布尔运算

# 2.3.6 字符和字符串

在Java中,字符和字符串是两个不同的类型。

# 字符类型

字符类型char是基本数据类型,它是character的缩写。一个char保存一个Unicode字符:

char c1 = 'A';
char c2 = '中';

因为Java在内存中总是使用Unicode表示字符,所以,一个英文字符和一个中文字符都用一个char类型表示,它们都占用两个字节。要显示一个字符的Unicode编码,只需将char类型直接赋值给int类型即可:

int n1 = 'A'; // 字母“A”的Unicodde编码是65
int n2 = '中'; // 汉字“中”的Unicode编码是20013

# 字符串类型

和char类型不同,字符串类型String是引用类型,我们用双引号"..."表示字符串。一个字符串可以存储0个到任意个字符:

String s = ""; // 空字符串,包含0个字符
String s1 = "A"; // 包含一个字符
String s2 = "ABC"; // 包含3个字符
String s3 = "中文 ABC"; // 包含6个字符,其中有一个空格

# 字符串连接

Java的编译器对字符串做了特殊照顾,可以使用+连接任意字符串和其他数据类型,这样极大地方便了字符串的处理。例如:

// 字符串连接
public class Main {
    public static void main(String[] args) {
        String s1 = "Hello";
        String s2 = "world";
        String s = s1 + " " + s2 + "!";
        System.out.println(s); // Hello world!
    }
}

# 多行字符串

从Java 13开始,字符串可以用"""..."""表示多行字符串(Text Blocks)了。举个例子:

// 多行字符串
public class Main {
    public static void main(String[] args) {
        String s = """
                   SELECT * FROM
                     users
                   WHERE id > 100
                   ORDER BY name DESC
                   """;
        System.out.println(s);
    }
}

# 不可变特性

Java的字符串除了是一个引用类型外,还有个重要特点,就是字符串不可变。考察以下代码:

// 字符串不可变
public class Main {
    public static void main(String[] args) {
        String s = "hello";
        System.out.println(s); // 显示 hello
        s = "world";
        System.out.println(s); // 显示 world
    }
}

执行String s = "hello";时,JVM虚拟机先创建字符串"hello",然后,把字符串变量s指向它:

          s
          │
          ▼
┌───┬───────────┬───┐
│   │  "hello"  │   │
└───┴───────────┴───┘

紧接着,执行s = "world";时,JVM虚拟机先创建字符串"world",然后,把字符串变量s指向它:

 s ───────────────────┐
                      │
                      ▼
┌───┬───────────┬───┬───────────┬───┐
│   │  "hello"  │   │  "world"  │   │
└───┴───────────┴───┴───────────┴───┘

# 字符与字符串小结

Java的字符类型char是基本类型,字符串类型String是引用类型;

基本类型的变量是“持有”某个数值,引用类型的变量是“指向”某个对象;

引用类型的变量可以是空值null;

要区分空值null和空字符串""。

# 2.3.7 数组类型

如果我们有一组类型相同的变量,例如,5位同学的成绩,可以这么写:

public class Main {
    public static void main(String[] args) {
        // 5位同学的成绩:
        int n1 = 68;
        int n2 = 79;
        int n3 = 91;
        int n4 = 85;
        int n5 = 62;
    }
}

但其实没有必要定义5个int变量。可以使用数组来表示“一组”int类型。代码如下:

// 数组
public class Main {
    public static void main(String[] args) {
        // 5位同学的成绩:
        int[] ns = new int[5];
        ns[0] = 68;
        ns[1] = 79;
        ns[2] = 91;
        ns[3] = 85;
        ns[4] = 62;
    }
}

Java的数组有几个特点:

  • 数组所有元素初始化为默认值,整型都是0,浮点型是0.0,布尔型是false;
  • 数组一旦创建后,大小就不可改变。

# 字符串数组

# 数组类型小结

数组是同一数据类型的集合,数组一旦创建后,大小就不可变;

可以通过索引访问数组元素,但索引超出范围将报错;

数组元素可以是值类型(如int)或引用类型(如String),但数组本身是引用类型;

# 2.4 Java 流程控制

# 2.5 Java 数组操作