(笔记)Java快速入门

176 阅读8分钟

0 第一个Java程序

第一个Java程序 - 廖雪峰

Java程序基本结构 - 廖雪峰

了解基本结构

/**
 * 可以用来自动创建文档的注释
 * 
 * @auther liaoxuefeng
 */
// class的定义
public class Hello {
    // 方法的定义
    public static void main(String[] args) {
        System.out.println("Hello, world!"); // 向屏幕输出文本
    }
} 

目前,我们只需要知道,Java入口程序规定的方法必须是静态方法 static,方法名必须为 main

命名规则

  • 类名

    • 类名必须以英文字母开头,后接字母,数字和下划线的组合
    • 习惯以大写字母开头,如 Hello
  • 方法名

    • 命名和class一样,但是首字母小写,如 main

输出

  • System.out.println("Hello, world!"); // 向屏幕输出文本

1 数据类型

变量和数据类型 - 廖雪峰

1.1 基本数据类型

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

  • 整数类型:byte,short,int,long
  • 浮点数类型:float,double
  • 字符类型:char
  • 布尔类型:boolean
    • 只有truefalse两个值。

image-20200929213144715

1.2 引用类型

除了上述基本类型的变量,剩下的都是引用类型。例如,引用类型最常用的就是String字符串:

String s = "hello";

【√】引用类型的变量类似于C语言的指针,它内部存储一个“地址”,指向某个对象在内存的位置

1.3 常量

变量可重新赋值,等号是赋值语句,不是数学意义的等号。

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

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

常量在初始化后不可重新赋值,使用常量便于理解程序意图。

2 基本运算

2.1 整数运算

遵循四则运算规则

注意

整数的除法对于除数为0时运行时将报错,但编译不会报错。

两个整数相除只能得到结果的整数部分

溢出

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

2.2 浮点数运算

浮点数运算在除数为0时,不会报错,但会返回几个特殊值

  • NaN表示Not a Number
  • Infinity表示无穷大
  • -Infinity表示负无穷大
double d1 = 0.0 / 0; // NaN
double d2 = 1.0 / 0; // Infinity
double d3 = -1.0 / 0; // -Infinity

这三种特殊值在实际运算中很少碰到,我们只需要了解即可。

2.3 布尔运算

布尔运算的一个重要特点是短路运算。如果一个布尔运算的表达式能提前确定结果,则后续的计算不再执行,直接返回结果。运算和运算是短路运算。

Java还提供一个三元运算符 b ? x : y,它根据第一个布尔表达式的结果,分别返回后续两个表达式之一的计算结果

3 字符、字符串

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

3.1 字符类型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

3.2 字符串类型 String

char类型不同,字符串类型String是引用类型,我们用双引号"..."表示字符串。

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

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

如果用+连接字符串和其他数据类型,会将其他数据类型先自动转型为字符串:

public class Main {
    public static void main(String[] args) {
        int age = 25;
        String s = "age is " + age;
        System.out.println(s);
    }
}

从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);
    }
}

上述多行字符串实际上是5行,在最后一个DESC后面还有一个\n

4 数组

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

定义方式

// int数组
int[] ns1 = new int[5]; // 基本形式
int[] ns2 = new int[] { 68, 79, 91, 85, 62 }; // 不写大小,直接初始化
int[] ns3 = { 68, 79, 91, 85, 62 }; // 进一步简写

//字符串数组
String[] names = {
    "ABC", "XYZ", "zoo"
};

Java的数组有几个特点

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

5 流程控制

5.1 输出、输入

5.1.1 输出

基本方法

System.out.println("hello world"); // println是print line的缩写,表示输出并换行
System.out.print("a"); // 输出后不换行

Java还提供了格式化输出的功能

public class Main {
    public static void main(String[] args) {
        double d = 3.1415926;
        System.out.printf("%.2f\n", d); // 显示两位小数3.14
        System.out.printf("%.4f\n", d); // 显示4位小数3.1416
    }
}

5.1.2 输入

和输出相比,Java的输入就要复杂得多。

我们先看一个从控制台读取一个字符串和一个整数的例子:

import java.util.Scanner; //【√】

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in); // 创建Scanner对象【√】
        
        System.out.print("Input your name: "); // 打印提示
        String name = scanner.nextLine(); // 读取一行输入并获取字符串【√】
        
        System.out.print("Input your age: "); // 打印提示
        int age = scanner.nextInt(); // 读取一行输入并获取整数【√】
        
        System.out.printf("Hi, %s, you are %d\n", name, age); // 格式化输出
    }
}

直接使用System.in读取用户输入虽然是可以的,但需要更复杂的代码。

而通过Scanner就可以简化后续的代码,读取对应的类型可以使用:scanner.nextLine() / nextInt() / nextDouble() / ...

5.2 几种程序结构

和C很像耶

5.2.1 if 判断

// 从小到大依次判断:
if (n < 60) {
    // ...
} else if (n < 90) {
    // ...
} else {
    // ...
}

不推荐忽略花括号的写法

判断相等?

在Java中,判断值类型的变量是否相等,可以使用==运算符。

但是,判断引用类型的变量是否相等==表示“引用是否相等”,或者说,是否指向同一个对象。

要判断引用类型的变量内容是否相等,必须使用equals()方法:

public class Main {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "HELLO".toLowerCase();
        if (s1.equals(s2)) {
            System.out.println("s1 equals s2");
        } else {
            System.out.println("s1 not equals s2");
        }
    }
}

注意:执行语句s1.equals(s2)时,如果变量s1null,会报NullPointerException;要避免NullPointerException错误,可以利用短路运算符&&

public class Main {
    public static void main(String[] args) {
        String s1 = null;
        if (s1 != null && s1.equals("hello")) {
            System.out.println("hello");
        }
    }
}

5.2.2 switch多重选择

对于多个==判断的情况,使用switch结构更加清晰。

public class Main {
    public static void main(String[] args) {
        int option = 99;
        switch (option) {
        case 1:
            System.out.println("Selected 1");
            break; // 记得别漏写【√】
        case 2:
            System.out.println("Selected 2");
            break;
        case 3:
            System.out.println("Selected 3");
            break;
        default:
            System.out.println("Not selected");
            break;
        }
    }
}

5.2.3 while循环

while (条件表达式) {
    循环语句
}
// 继续执行后续代码

5.2.4 do while循环

do {
    执行循环语句
} while (条件表达式);

可见,do while循环会至少循环一次。

5.2.5 for循环

for (初始条件; 循环检测条件; 循环后更新计数器) {
    // 执行语句
}

使用for循环时,千万不要在循环体内修改计数器!在循环体中修改计数器常常导致莫名其妙的逻辑错误。

for循环还可以缺少初始化语句、循环条件和每次循环更新语句,通常不推荐这样写,但是,某些情况下,是可以省略for循环的某些语句的。

Java还提供了另一种for each循环,它可以更简单地遍历数组:

public class Main {
    public static void main(String[] args) {
        int[] ns = { 1, 4, 9, 16, 25 };
        for (int n : ns) { // 【√】
            System.out.println(n);
        }
    }
}

5.2.6 break和continue

  • break语句可以跳出当前循环;

    • break语句通常配合if,在满足条件时提前结束整个循环;
    • break语句总是跳出最近的一层循环;
  • continue语句可以提前结束本次循环;

    • continue语句通常配合if,在满足条件时提前结束本次循环。

6 数组操作

6.1 遍历数组

法1:for

public class Main {
    public static void main(String[] args) {
        int[] ns = { 1, 4, 9, 16, 25 };
        for (int i=0; i<ns.length; i++) {
            int n = ns[i];
            System.out.println(n);
        }
    }
}

法2:for each

public class Main {
    public static void main(String[] args) {
        int[] ns = { 1, 4, 9, 16, 25 };
        for (int n : ns) {
            System.out.println(n);
        }
    }
}

注意:在for (int n : ns)循环中,变量n直接拿到ns数组的元素,而不是索引。

显然for each循环更加简洁。但是,for each循环无法拿到数组的索引,因此,到底用哪一种for循环,取决于我们的需要。

快速打印数组内容

Arrays.toString()

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] ns = { 1, 1, 2, 3, 5, 8 };
        System.out.println(Arrays.toString(ns)); // 【√】
    }
}

6.2 数组排序

对数组进行排序是程序中非常基本的需求。

常用的排序算法有冒泡排序、插入排序和快速排序等。

冒泡排序的特点是,每一轮循环后,最大的一个数被交换到末尾,因此,下一轮循环就可以“刨除”最后的数,每一轮循环都比上一轮循环的结束位置靠前一位。

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
        // 排序前:
        System.out.println(Arrays.toString(ns));
        // 冒泡排序
        for (int i = 0; i < ns.length - 1; i++) { // 循环
            for (int j = 0; j < ns.length - i - 1; j++) { // 把最大的一个数交换到末尾
                if (ns[j] > ns[j+1]) {
                    // 交换ns[j]和ns[j+1]:
                    int tmp = ns[j];
                    ns[j] = ns[j+1];
                    ns[j+1] = tmp;
                }
            }
        }
        // 排序后:
        System.out.println(Arrays.toString(ns));
    }
}

实际上,Java的标准库已经内置了排序功能,我们只需要调用JDK提供的Arrays.sort()就可以排序:

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
        Arrays.sort(ns); // 【√】
        System.out.println(Arrays.toString(ns));
    }
}

必须注意,对数组排序实际上修改了数组本身。

6.3 多维数组

最常见的多维数组是二维数组

int[][] ns = {
            { 1, 2, 3, 4 },
            { 5, 6, 7, 8 },
            { 9, 10, 11, 12 }
        };

image-20200929225252873

访问二维数组的某个元素需要使用array[row][col],例如:

System.out.println(ns[1][2]); // 7

要打印一个二维数组,可以使用两层嵌套的for循环:

for (int[] arr : ns) {
    for (int n : arr) {
        System.out.print(n);
        System.out.print(', ');
    }
    System.out.println();
}

或者使用Java标准库的Arrays.deepToString()

System.out.println(Arrays.deepToString(ns));