Java学习笔记

163 阅读13分钟

java Note

<> Data type

long数据类型后要加L

long tel = 13929068827L;

float数据类型后面要加f

float height = 183.1f;

<> Operator

x++:先执行操作再自增

++x:先自增再执行操作

public static void main(String[] args) {
    int x = 10;
    int y = x++;    // y = 10, x = 11
    int z = ++y;    // y = 11, z = 11

    System.out.println("x="+x);
    System.out.println("y="+y);
    System.out.println("z="+z);

    System.out.println("----------------------");

    int a = 3;
            // 4 + 4   + 5*10
    int b = (++a)+(a++)+(a*10);
    System.out.println("a="+a);
    System.out.println("b="+b);
}

赋值运算符

基本赋值运算符

  • =:将等号右侧数据赋值给左边的变量

拓展赋值运算符

  • +=:将符号左右两边的数据做加法运算,再将结果赋值给左边
  • -=
  • *=
  • /=
  • %=

:warning:拓展赋值运算符,内部自带强转效果。

/*
    short s = 1;
    s = (short)(S+1);
        <=>
    short s = 1;
    s += 1;
 */
public static void main(String[] args) {
    int num = 10;
    num += 20;      // num = num + 20
    System.out.println(num);

    System.out.println("-------------------");

    short s = 1;
    s += 1;     // s = (short)(s+1);
    System.out.println(s);

    System.out.println("-------------------");

    double a = 12.3;
    int b = 10;
    b += a;     // b = (int)(b+a);
    System.out.println(b);      // 22
}

逻辑运算符

  • 用于连接boolean类型的表达式或者值
  • 整合多个条件,作为一段整体的逻辑

分类

  • &:与
  • |:或
  • !:非
  • ^:异或,不同为true,相同为false

短路逻辑运算符

  • &:没有短路效果,无论左边true还是false,右边都要继续判断
  • &&:具有短路效果,如果左边为false,右边就不判断了;若果左边为true,右边要继续判断
  • ||:具有短路效果,如果左边为true,右边就不判断了;若果左边为false,右边要继续判断
public static void main(String[] args) {
    int x = 3;
    int y = 4;
                    // false & false
    boolean result = ++x > 5 & y-- < 4;

    System.out.println(x);      // 4
    System.out.println(y);      // 3
    System.out.println(result); // false

    System.out.println("--------------------");

    int x2 = 3;
    int y2 = 4;
                     //  false && 不用判断(执行)
    boolean result2 = ++x2 > 5 && y2-- < 4;

    System.out.println(x2);     // 4
    System.out.println(y2);     // 4
    System.out.println(result2);// false
}

运算符优先级

&&的优先级要大于||

三元运算符(三目运算符)

格式:

condition? value1 : value2;

执行流程:

  • 执行判断条件, 看其返回结果是true还是false
  • true的话返回value1
  • false的话返回value2
public static void main(String[] args) {
    int a = 10;
    int b = 20;

    int max = a > b ? a : b;

    System.out.println(max);
}

<> Scanner

import java.util.Scanner;

public class ScannerDemo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int age = sc.nextInt();
        System.out.println("Your input is " + age);
    }
}

Scanner的部分成员方法:

  • String next():遇到空格/tab就不再录入
  • String nextLine():遇到enter就不再录入

<> Type conversion

隐式转换

将取值范围小的数据或变量,给取值范围大的变量赋值,可以直接赋值。

范围从小到大:

byte -> short \
                -> int -> long -> float -> double
         char /

float虽然占用4个字节,但取值范围比8个字节的long更大。

  • 小数的二进制储存形式更加节省内存
public static void main(String[] args) {
    int a = 10;
    double b = a;

    System.out.println(a);  // 10
    System.out.println(b);  // 10.0

    System.out.println("-------------------");

    long num1 = 123L;
    float num2 = num1;
    System.out.println(num2);
}

强制转换

将取值范围大的数据或变量,给取值范围小的变量赋值,不允许直接赋值,需要加入强转。

:warning:强制转换有可能会出现精度损失

public static void main(String[] args) {
    double a = 12.3;
    int b = (int) a;
    System.out.println(b);  // 12

    System.out.println("------------------");

    int c = 10;
    byte d = (byte) c;
    System.out.println(d);  // 10

    System.out.println("------------------");

    int num1 = 130;
    byte num2 = (byte) num1;
    System.out.println(num2);   // -126, 由于2's complement的byte取值范围为-128~127, 130溢出到-126
}

常量优化机制

/*
    类型转换面试题:下列代码是否存在错误, 如果有, 请指出并改正.

    byte b1 = 3;
    byte b2 = 4;
    byte b3 = b1 + b2;

    错误原因:
        b1和b2是两个byte类型, 在运算的时候, 会提升为int类型,
        提升之后, 两个int类型运算结果还是int.
        将int类型的结果赋值给byte类型的变量属于大给小, 不能直接给.

    byte b1 = 3;
    byte b2 = 4;
    int b3 = b1+b2;
    or
    byte b3 = (byte)(b1+b2);

    System.out.println(b3);
    --------------------------------------------------------
    byte b = 3+4;

    Java存在常量优化机制:在编译的时候(javac)会将3和4这两个字面量进行计算.
        产生的字节码文件:byte b = 7;
 */

<> Method

一段具有独立功能的代码块,不调用就不执行。

Advantage:

  • 可以将原本挤在一起的臃肿代码按照功能做分类管理
  • 提高代码的复用性

定义格式:

public static void methodName (){
    method body (code);
}

调用格式:

methodName();

方法重载Overload

在同一个类中,定义多个同名的方法,但每个方法含有不同类型、个数或者顺序的参数,这些同名的方法构成重载关系。

:warning:识别方法之间是否重载关系,只看方法名和参数,和返回值以及返回值的类型无关

public class OverloadDemo {
    
    public static void main(String[] args) {

    }

  	public static void method(double a, double b) {

    }
  
    public static void method(int a, int b) {

    }

    public static void method(int a, int b, int c) {

    }
 
		public static void method(int a, double b) {

    }
  
  	public static void method(double a, int b) {

    }
}

<> Switch

switch语句格式:

switch(将要匹配的值){
    case value1:
        body1;
        break;
    case value2:
        body2;
        break;
    ...
    default:
        body_n+1;
        break;
}

:warning:

  • case后面的值不能重复
  • case后面的值只能是字面量,不能是变量
  • switch()中能接收的类型:
    • 基本数据类型:byte/short/char/int
    • 引用数据类型:jdk5版本开始可以是枚举jdk7版本开始可以是String
  • switch的穿透现象,见example2

example1 - switch实例

键盘输入一个整数,根据录入的数值,打印相应的星期。

public static void switchTest1() {
    Scanner sc = new Scanner(System.in);
    System.out.println("Please input an integer");
    int week = sc.nextInt();

    switch (week){
        case 1:
            System.out.println("Monday");
            break;
        case 2:
            System.out.println("Tuesday");
            break;
        case 3:
            System.out.println("Wednesday");
            break;
        case 4:
            System.out.println("Thursday");
            break;
        case 5:
            System.out.println("Friday");
            break;
        case 6:
            System.out.println("Saturday");
            break;
        case 7:
            System.out.println("Sunday");
            break;
        default:
            System.out.println("Error");
            break;
    }
}

example2 - switch的穿透现象

switch的穿透现象,在这个实例中,当case 1break省略后,程序会首先执行完case 1的代码,然后穿透到case 2,碰到break才停止运行。

public static void switchTest3() {
    int week = 1;

    switch (week) {
        case 1:
            System.out.println("Monday");
        case 2:
            System.out.println("Tuesday");
            break;
        case 3:
            System.out.println("Wednesday");
            break;
        default:
            System.out.println("Error");
            break;
    }
}

example3 - 利用穿透现象的优化

键盘录入一个数值,1~5输出工作日,6~7输出休息日。比较switchTest4_beforeswitchTest4_after,优化标准代码。

  • switchTest4_before
public static void switchTest4_before() {
    Scanner sc = new Scanner(System.in);
    System.out.println("Please input an integer");
    int week = sc.nextInt();

    switch (week) {
        case 1:
            System.out.println("Work day");
            break;
        case 2:
            System.out.println("Work day");
            break;
        case 3:
            System.out.println("Work day");
            break;
        case 4:
            System.out.println("Work day");
            break;
        case 5:
            System.out.println("Work day");
            break;
        case 6:
            System.out.println("Week-end");
            break;
        case 7:
            System.out.println("Week-end");
            break;
        default:
            System.out.println("Error");
            break;
    }
}
  • switchTest4_after
public static void switchTest4_after() {
    Scanner sc = new Scanner(System.in);
    System.out.println("Please input an integer");
    int week = sc.nextInt();

    switch (week) {
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
            System.out.println("Work day");
            break;
        case 6:
        case 7:
            System.out.println("Week-end");
            break;
        default:
            System.out.println("Error");
            break;
    }
}

jdk14以后的版本优化

jdk14开始,case后面允许编写多个数据,多个数据中间使用逗号分隔。

public static void switchTest5() {
    Scanner sc = new Scanner(System.in);
    System.out.println("Please input an integer");
    int week = sc.nextInt();

    switch (week) {
        case 1, 2, 3, 4, 5:
            System.out.println("Work day");
            break;
        case 6, 7:
            System.out.println("Week-end");
            break;
        default:
            System.out.println("Error");
            break;
    }
}

代码可以进一步优化,用符号->,并且把break删去。

public static void switchTest6() {
    Scanner sc = new Scanner(System.in);
    System.out.println("Please input an integer");
    int week = sc.nextInt();

    switch (week) {
        case 1, 2, 3, 4, 5 -> System.out.println("Work day");
        case 6, 7 -> System.out.println("Week-end");
        default -> System.out.println("Error");
    }
}

if-else if-else语句的比较

  • if语句:适用于范围性的判断
  • switch语句:适用于固定值的匹配

<> For

for循环语句格式:

for(initialisation; condition; control){
    loop body;
}

执行流程

  • 执行初始化语句,在整个循环过程中,只执行一次
  • 执行判断条件,看其返回结果是true/false
    • false:循环结束
    • true:执行:three:
  • 执行循环体语句
  • 执行条件控制语句
  • 回到:two:继续
public static void forTest1() {
        for (int i = 1; i <= 3; i++) {

        }
    }

:warning:

  • for循环{}中定义的变量,在每一轮循环结束后,都会从内存中释放
  • for循环()中定义的变量,在整个循环结束后,会从内存中释放
public static void forTest2() {
        for (int i = 0; i < 5; i++) {
            int num = 10;
            System.out.println("...");
        }

        System.out.println(num);    // 此处for中的num变量在循环结束后已经从内存中释放,程序将会报错
        System.out.println(i);      // 此处的i变量同样从内存中释放了,程序将会报错
}

<> While

while循环格式:

initialisation;
while(condition) {
    loop body;
    control;
}

<> Do...while

do...while循环格式:

initialisation;
do {
    loop body;
    control;
} while (condition);

<> Control

跳转控制:给循环起名,break可以直接对应到该名位置

public static void iniMenu() {
    Scanner sc = new Scanner(System.in);

    lo:     // 标号:给循环起名字,break可以选择直接跳到这一层
    while (true) {
        System.out.println("请输入您的选择:1. 添加学生 2. 删除学生 3. 修改学生 4. 查看学生 5. 退出");
        int choice = sc.nextInt();

        switch (choice) {
            case 1:
                System.out.println("添加学生逻辑执行...");
                break;
            case 2:
                System.out.println("删除学生逻辑执行...");
                break;
            case 3:
                System.out.println("修改学生逻辑执行...");
                break;
            case 4:
                System.out.println("查看学生逻辑执行...");
                break;
            case 5:
                System.out.println("感谢您的使用,再见");
                break lo;   // 跳转到lo位置
            default:
                System.out.println("Error");
                break;
        }
    }
}

<> Random

Random产生随机数,范围是0n10\backsim n-1

import java.util.Random;

public static void randomTest() {
    Random r = new Random();
    // 产生从20到80之间的随机数
    int num = r.nextInt(61)+20;
}

<> Array

数组声明

  • dataType[] arrName;or
  • dataType arrName[];
public static void arrayTest1() {
        int[] array;
    }

数组静态初始化

  • 完整格式:dataType[] arrName = new dataType[]{element1, element2, element3, ...};
  • 简化格式:dataType[] arrName = {element1, element2, element3, ...};

下面的实例中arr1输出结果为[I@4617c264,其中:

  • @:分隔符
  • [:当前内存空间为数组类型
  • I:当前数组类型为int
  • 4617c264:数组内存地址
public static void arrayTest2() {
    int[] arr1 = new int[]{11,22,33};
    double[] arr2 = {11.1,22.2,33.3};

    System.out.println(arr1);   // [I@4617c264
    System.out.println(arr2);   // [D@36baf30c
}

数组元素访问

访问数组中某一个元素:arr[index]

public static void arrayTest() {
    int[] arr = {11,22,33,44,55};

    // 取出元素22
    System.out.println(arr[1]);

    // 修改数组中第三个元素为66
    arr[2] = 66;
    System.out.println(arr[2]);
}

数组长度

arrName.length表示数组长度。

数组遍历

数组的for遍历快捷键:arrName.fori

public static void arrayTest2() {
    int[] arr = {1,2,3,4,5,6,7,8};
    System.out.println(arr.length);

    for (int i = 0; i < arr.length; i++) {

    }
}

数组动态初始化

数组动态初始化:在初始化时,只需要指定数组的长度,系统会自动分配初始值。

格式:dataType[] arrName = new dataType[length]

默认值分类:

  • int:0

  • double:0.0

  • booleanfalse

  • char'\u0000'(unicode字符都以\u开头,后接四位十六进制,这里的0000表示空白字符)

  • 引用数据类型(数组/类/接口):null

public static void arrayTest() {
    int[] arr1 = new int[3];
    for (int i = 0; i < arr1.length; i++) {
        System.out.println(arr1[i]);    // 输出:0
                                        //      0
                                        //      0
    }

  	// String是字符串类,属于引用数据类型,默认值为null
    String[] arr2 = new String[3];
    for (int i = 0; i < arr2.length; i++) {		// 输出:null
        System.out.println(arr2[i]);					//			null
    }																					//			null
}

<> 2D Array

二维数组静态初始化

格式:

  • 标准:dataType[][] arrName = new dataType[][]{ {element1,element2}, {element1,element2} };

  • 简化:dataType[][] arrName = { {element1,element2}, {element1,element2} };

:warning::二维数组存储的是一维数组的地址值。

public static void main(String[] args) {
    // 二维数组静态初始化
    // dataType[][] arrName = new dataType[][]{ {element1,element2}, {element1,element2} };
    // dataType[][] arrName = { {element1,element2}, {element1,element2} };
    int[][] arr = {
        {1,2,3},
        {4,5,6}
    };

    System.out.println(arr);    // [[I@4617c264

    System.out.println(arr[0]); // [I@36baf30c
    System.out.println(arr[1]); // [I@7a81197d

    // 二维数组元素访问
    System.out.println(arr[0][1]);  // 2
    System.out.println(arr[1][2]);  // 6
}

二维数组遍历

  • 第一层快捷键:arr.fori

  • 第二层快捷键:arr[i].fori,再将遍历索引i改成j

public static void main(String[] args) {
    int[][] arr = {
        {1,2,3},
        {4,5,6}
    };

    /*
        二维数组遍历
        第一层快捷键arr.fori
        第二层快捷键arr[i].fori,再将i改成j
     */
    for (int i = 0; i < arr.length; i++) {
        for (int j = 0; j < arr[i].length; j++) {
            System.out.println(arr[i][j]);
        }
    }
}

二维数组动态初始化

格式:dataType[][] arrName = new dataType[length_row][length_col];

private static void arrayTest1() {
    int[][] arr = new int[2][3];

    for (int i = 0; i < arr.length; i++) {
        for (int j = 0; j < arr[i].length; j++) {
            System.out.println(arr[i][j]);
        }
    }
}

:warning::可以将提前创建好的一维数组直接存入二维数组。

public static void main(String[] args) {
    int[] arr1 = {11,22,33};
    int[] arr2 = {44,55,66};

    // 将提前创建好的一维数组直接存入二维数组
    int[][] arr = new int[2][3];
    arr[0] = arr1;
    arr[1] = arr2;

    for (int i = 0; i < arr.length; i++) {
        for (int j = 0; j < arr[i].length; j++) {
            System.out.println(arr[i][j]);
        }
    }
}

<> StringTokenizer

StringTokenizer属于java.util包,用于分隔字符串。

常用方法

  • boolean hasMoreTokens()返回是否还有分隔符

  • String nextToken返回从当前位置到下一个分隔符的字符串

<> Exception

空指针异常 NullPointerException

当引用数据类型变量被赋值为null后,其跟堆内存的连接被切断,此时想根据地址去访问堆内存的数据,就会出现空指针异常。

public static void main(String[] args) {
    int[] arr = {1,2,3};
    arr = null;
    System.out.println(arr[0]);
}

Output:

Exception in thread "main" java.lang.NullPointerException: Cannot load from int array because "arr" is null
	at exception.NullPointerExceptionDemo.main(NullPointerExceptionDemo.java:13)

<> Object Oriented Programming (OOP)

类Class

  • class:一组相关属性和行为的集合,是对象object的设计图

  • 对象object:根据设计图(类),创建出来的实体

类的组成:

  • 属性:成员变量

  • 行为:成员方法,需要去掉static关键字

public class Student {

    // 属性
    String name = "albert";
    int age = 24;

    // 行为(方法)
    public void study() {
        System.out.println("Studying...");
    }

    public void eat() {
        System.out.println("Eating...");
    }
}

对象Object

  • 创建对象的格式:className objectName = new className();

  • 使用对象的成员变量:objectName.memberVar

  • 使用对象的成员方法:objectName.memberMethod

:warning::打印对象名,可以看到对象的内存地址(全类名=包名.类名)

:warning::成员变量就算没有赋值,也可以直接使用,使用的是变量的默认值

public static void main(String[] args) {
    Student stu1 = new Student();

    System.out.println(stu1);   // oop.Student@36baf30c
  															// 包名.类名@内存地址

    System.out.println(stu1.name);
    System.out.println(stu1.age);

    stu1.study();
    stu1.eat();

    System.out.println("---------------------");

    Student stu2 = new Student();

    System.out.println(stu2);   // oop.Student@7a81197d

    System.out.println(stu2.name);
    System.out.println(stu2.age);

    stu2.study();
    stu2.eat();
}

This

当成员变量与局部变量重名时,java采用就近原则。如果一定要使用成员变量的情况,需要使用this关键字进行区分。

this关键字的作用:

  • 调用本类成员变量:this.memberVar

  • 调用本类成员方法:this.memberMethod

this关键字省略规则:

  • 对于本类成员变量:如果该方法中没有重名变量,this.才可以省略

  • 对于本类成员方法:没有前提条件,this.可以直接省略

this本质:代表当前类对象的引用(地址)

一个对象的this代表的就是该对象的地址。

public class Student {

    String name;

    public void sayHello(String name) {
        System.out.println("local variable: "+name);         // local variable: Betty
        System.out.println("member variable: "+this.name);    // member variable: Albert

        this.method();
    }

    public void method() {
        System.out.println("method...");
    }

    public void print() {
        System.out.println("print keyword this: "+this);    // mthis.Student@7a81197d
    }
}
public static void main(String[] args) {
    Student stu1 = new Student();
    stu1.name = "Albert";
    stu1.sayHello("Betty");

    System.out.println("-----------------");

    System.out.println(stu1);   // mthis.Student@7a81197d
    stu1.print();               // print keyword this: mthis.Student@7a81197d

    Student stu2 = new Student();
    System.out.println(stu2);   // mthis.Student@5ca881b5
    stu2.print();               // print keyword this: mthis.Student@5ca881b5
}

Constructor

构造器:创建对象时要执行的方法,标准形式包括一个有参构造和无参构造。

格式:

  • 方法名与类名相同,大小写一致

  • 没有返回值类型,没有void

  • 没有具体的返回值,不能有return语句

public class Student {

    String name;
    int age;

  	// 有参构造
    public Student(String name, int age) {
        System.out.println("this is constructor of class Student");

        this.name = name;
        this.age = age;
    }

  	// 无参构造
    public Student() {
        
    }
}

constructor的执行时机:

  • 在创建对象的时候,被调用执行

  • 每创建一次对象,就会执行一次构造方法

constructor的作用:

  • 本质作用:创建对象

  • 结合执行时机:在创建对象的时候,给对象中的数据(成员对象)初始化,类似python__init__()

:warning:

  • 一个类中,如果没有编写构造方法,系统将会提供一个默认的且无参数的构造方法
  • 一个类中,如果手动编写了构造方法,系统将不会提供默认的无参构造
    • 建议:编写类的时候,无参构造,有参构造都手动给出
  • 构造方法不允许手动调用
    • 如:stu3.Student();
public static void main(String[] args) {
    Student stu1 = new Student("Albert",24);
    Student stu2 = new Student("Betty",23);
    Student stu3 = new Student("Cat",22);
}

Permissions

权限修饰符:

  • private:同一个类中

  • (default):默认权限,同一个类中,同一个包中

  • protected:同一个类中,同一个包中,不同包的子类

  • public:任意位置访问

public class Student {

    private int age;
//    int age;

    public void show() {
        System.out.println("show...");
    }
}
public static void main(String[] args) {
    Student stu = new Student();
    stu.age = 23;	// 由于age在Student内是private,类的外部无法访问,此句将报错
}

Encapsulation

封装:

  • 将成员变量私有化private(保证数据的安全性)

  • 针对私有的成员变量,提供对应的setXXXgetXXX方法,中间加入数据合理性判断

  • 设计规范:合理隐藏,合理暴露

public class Student {

    private int age;

    public void setAge(int age) {
        if (age >= 1 && age <= 120) {
            this.age = age;
        } else {
            System.out.println("the age input is out of range");
        }
    }

    public int getAge() {
        return this.age;
    }
}
public static void main(String[] args) {
    Student stu = new Student();
    stu.setAge(23);
    stu.setAge(-23);

    System.out.println(stu.getAge());
}

javabean

  • 成员变量私有化

  • 无参,带参构造方法

  • 对于私有成员变量,提供对应的setXXXgetXXX方法

:warning::实体类只负责数据的存取,对数据的处理交由其他类来完成,以实现数据和数据业务处理相分离。

生成器:

generator:快捷键command+N,选择constructor/setter and getter/toString

Ptg plugin:快捷键command+shift+,,一键生成constructor+setter+getter+toString

public class Student {

    private String name;
    private int age;


    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}

实例

在该实例中,实体类只负责数据的存取,对数据的处理交由其他类来完成,实现了数据和数据业务处理相分离。

package domain;

public class Movie {

    private int id;
    private String title;
    private String time;
    private double score;
    private String region;
    private String genre;
    private String director;
    private String starring;


    public Movie() {
    }

    public Movie(int id, String title, String time, double score, String region, String genre, String director, String starring) {
        this.id = id;
        this.title = title;
        this.time = time;
        this.score = score;
        this.region = region;
        this.genre = genre;
        this.director = director;
        this.starring = starring;
    }

    /**
     * 获取
     * @return id
     */
    public int getId() {
        return id;
    }

    /**
     * 设置
     * @param id
     */
    public void setId(int id) {
        this.id = id;
    }

    /**
     * 获取
     * @return title
     */
    public String getTitle() {
        return title;
    }

    /**
     * 设置
     * @param title
     */
    public void setTitle(String title) {
        this.title = title;
    }

    /**
     * 获取
     * @return time
     */
    public String getTime() {
        return time;
    }

    /**
     * 设置
     * @param time
     */
    public void setTime(String time) {
        this.time = time;
    }

    /**
     * 获取
     * @return score
     */
    public double getScore() {
        return score;
    }

    /**
     * 设置
     * @param score
     */
    public void setScore(double score) {
        this.score = score;
    }

    /**
     * 获取
     * @return region
     */
    public String getRegion() {
        return region;
    }

    /**
     * 设置
     * @param region
     */
    public void setRegion(String region) {
        this.region = region;
    }

    /**
     * 获取
     * @return genre
     */
    public String getGenre() {
        return genre;
    }

    /**
     * 设置
     * @param genre
     */
    public void setGenre(String genre) {
        this.genre = genre;
    }

    /**
     * 获取
     * @return director
     */
    public String getDirector() {
        return director;
    }

    /**
     * 设置
     * @param director
     */
    public void setDirector(String director) {
        this.director = director;
    }

    /**
     * 获取
     * @return starring
     */
    public String getStarring() {
        return starring;
    }

    /**
     * 设置
     * @param starring
     */
    public void setStarring(String starring) {
        this.starring = starring;
    }

}
package service;

import domain.Movie;

import java.util.Scanner;

public class MovieService {

    private Movie[] movies;
    private Scanner sc = new Scanner(System.in);
    public MovieService(Movie[] movies) {
        this.movies = movies;
    }

    /**
     * 启动电影信息管理系统
     */
    public void start() {

        lo:
        while (true) {
            System.out.println("----------Movie Info System----------");
            System.out.println("Please input your choice:");
            System.out.println("1: enquire all movie info");
            System.out.println("2: enquire movie info via id");
            System.out.println("3: exit");

            int choice = sc.nextInt();

            switch (choice) {
                case 1:
                    queryMovieInfos();
                    break;
                case 2:
                    queryMovieInfoById();
                    break;
                case 3:
                    System.out.println("Exit");
                    break lo;
                default:
                    System.out.println("Error, please check your input");
                    break;
            }
        }
    }

    /**
     * 根据电影编号,查询电影详情信息
     */
    private void queryMovieInfoById() {
        // 1. 键盘录入用户输入的编号
        System.out.println("Please input the query movie id:");
        int id = sc.nextInt();
        // 2. 遍历数组,从数组中查询电影信息
        for (int i = 0; i < movies.length; i++) {
            Movie movie = movies[i];
            if (id == movie.getId()) {
                // 3. 将找到的电影信息,打印在控制台
                System.out.println(movie.getId()+"---"+movie.getTitle()+"---"+movie.getTime()
                        +"---"+movie.getScore()+"---"+movie.getRegion()+"---"+movie.getGenre()
                        +"---"+movie.getDirector()+"---"+movie.getStarring());
                return;
            }
        }

        // 代码如果走到这里,说明没找到
        System.out.println("The input id does not exist, please check.");
    }

    /**
     * 展示系统中全部的电影(名称,评分)
     */
    private void queryMovieInfos() {
        // 1. 遍历数组,取出每一个电影对象
        for (int i = 0; i < movies.length; i++) {
            Movie movie = movies[i];
            // System.out.println(movie);   打印对象名,会看到内存地址
            // 2. 通过电影对象,调用内部getXXX方法,获取信息并打印
            System.out.println(movie.getTitle()+"---"+movie.getScore());
        }
    }
}
package service;

import domain.Movie;

public class Test {
    public static void main(String[] args) {

        Movie movie1 = new Movie(1, "Love letter", "1995", 7.9, "Japan", "Drama", "Shunji Iwai", "Miho Nakayama");
        Movie movie2 = new Movie(2, "Inception", "2010", 8.8, "US", "Sci-Fi", "Christopher Nolan", "Leonardo DiCaprio");
        Movie movie3 = new Movie(3, "The legend of 1900", "1998", 8.0, "Italy", "Music", "Giuseppe Tornatore", "Tim Roth");

        Movie[] movies = {movie1,movie2,movie3};

        MovieService movieService = new MovieService(movies);
        movieService.start();
    }
}

<> String类

String类的特点

  • Java中所有双引号字符串,都是String这个类的对象
  • 字符串一旦被创建,就不可更改。如果想要更改,只能使用新的对象,来替换,而旧的String对象本身并没有发生改变。
  • String字符串虽然不可改变,但可以共享
    • 字符串常量池StringTable:当使用双引号创建字符串对象时,会检查常量池中是否存在该数据
      • 不存在:创建
      • 存在:复用
    • 字符串常量池所处位置:
      • jdk7版本之前:在方法区
      • jdk7版本开始:被挪到了堆内存中
public static void main(String[] args) {
    String s = "abc";
    System.out.println(s.toUpperCase());
    System.out.println("helloworld".toUpperCase());

    System.out.println("-----------------------------");

    String s1 = "abc";
    s1 = "def";
    System.out.println(s1);

    System.out.println("-----------------------------");

    String s2 = "abc";
    String s3 = "abc";
    System.out.println(s2 == s3);   // true
}

构造方法

String类常见构造方法:

  • public String():创建一个空白字符串,里面不含任何内容
  • public String(char[] chs):根据传入的字符数组,创建字符串对象
  • public String(String original):根据传入字符串来创建字符串对象
public static void main(String[] args) {
    // public String():创建一个空白字符串,里面不含任何内容
    String s1 = new String();
    System.out.println(s1);

    // public String(char[] chs):根据传入的字符数组,创建字符串对象
    char[] chs = {'a','b','c'};
    String s2 = new String(chs);
    System.out.println(s2);     // abc

    // public String(String original):根据传入字符串来创建字符串对象
    String s3 = new String("abc");
    System.out.println(s3);     // abc
}

String所处地址1

s1s2共用StringTable内的"abc",地址相同。

public static void main(String[] args) {
    String s1 = "abc";
    String s2 = "abc";
    System.out.println(s1 == s2);   // true
}

String所处地址2

  • s1用双引号直接创建,记录StringTable"abc"的地址
  • s2通过new对象创建,记录的是堆内存中对象的地址,该过程创建了两个字符串对象
  • 两者内存中的位置不同
public static void main(String[] args) {
    String s1 = "abc";
    String s2 = new String("abc");

    System.out.println(s1 == s2);   // false
}

String所处地址3

字符串的加法会在堆内存创建一个StringBuilder对象,完成"ab""c"的拼接,再通过成员方法toString(),将其转换成堆内存中一个String对象,内容是"abc"s3记录该对象地址,因此和s1地址不同。

public static void main(String[] args) {
    String s1 = "abc";
    String s2 = "ab";
    String s3 = s2 + "c";

    System.out.println(s1 == s3);   // false
}

String所处地址4

s2是三个字符串常量拼接,java有常量优化机制,在字节码文件中已经完成拼接,因此s2也记录StringTable内的"abc"地址,和s1相同。

public static void main(String[] args) {
    String s1 = "abc";
    String s2 = "a" + "b" + "c";

    System.out.println(s1 == s2);   // true
}

equals/equalsIgnoreCase

String类中用于比较的方法:

  • public boolean equals(Object anObject)将此字符串与指定对象比较

  • public boolean equalsIgnoreCase(String anotherString)将此String与另一个String比较,不考虑大小写

public static void main(String[] args) {
    String s1 = "abc";
    String s2 = new String("abc");

    System.out.println(s1 == s2);       // false
    System.out.println(s1.equals(s2));  // true

    System.out.println("-------------------------");

    String s3 = "abc";
    String s4 = "ABC";

    System.out.println(s3.equals(s4));              // false
    System.out.println(s3.equalsIgnoreCase(s4));    // true
}

toCharArray/charAt/length

String类用于遍历的方法:

  • public char[] toCharArray()将此字符串转换为一个新的字符数组

  • public char charAt(int index)返回指定索引处的char值

  • public int length()返回此字符串的长度

/**
 * 字符串的第一种遍历方式,比第二种效率更高
 */
private static void print1() {
    String s = "helloworld";

    char[] chars = s.toCharArray();

    for (int i = 0; i < chars.length; i++) {
        System.out.println(chars[i]);
    }
}
/**
 * 字符串的第二种遍历方式
 */
private static void print2() {
    String s = "helloworld";

    char c = s.charAt(2);

    System.out.println(c);

    for (int i = 0; i < s.length(); i++) {
        System.out.println(s.charAt(i));
    }
}

substring

String类的切片方法:

  • public String substring(int beginIndex)根据传入的索引开始做切片,截取到字符串的末尾

  • public String substring(int beginIndex, int endIndex)根据传入的开始和结束索引,截取字符串,包含头不包含尾

:warning::截取出来的内容作为新的字符串返回,不要忘记找变量接收

private static void slide1() {
    String s = "helloworld";

    System.out.println(s.substring(5));
}
private static void slide2() {
    String s = "helloworld";

    System.out.println(s.substring(0,5));
}

replace

String类的替换方法:

  • public String replace(CharSequence target, CharSequence replacement)
    • target:旧值
    • replacement:新值
public static void main(String[] args) {
    String s = "helloworld";

    String result = s.replace("hello", "goodbye");

    System.out.println(result);     // goodbyeworld
}

split

String类的切割方法:

  • public String[] split(String regex):根据传入的字符串作为规则,切割当前字符串

:warning::建议先正常指定切割规则,后来发现没有得到自己要的效果,就可以尝试在规则前面加上"\\"

public static void main(String[] args) {
    String s = "192,168,1,1";

    String[] sArr = s.split(",");

    for (int i = 0; i < sArr.length; i++) {
        System.out.println(sArr[i]);
    }

    System.out.println("----------------------");

    String s1 = "192.168.1.1";

    // "."可以代表任意字符,用该规则进行切割得不到正确的结果,需要变成"\\."
    String[] sArr1 = s1.split(".");
    System.out.println(sArr1.length);
}

<> StringBuilder类

StringBuilder作用

StringBuilder的作用:提高字符串的操作效率

public static void main(String[] args) {
    long start = System.currentTimeMillis();

    StringBuilder sb = new StringBuilder();

    for (int i = 1; i <= 100000; i++) {
        sb.append(i);
    }

    System.out.println(sb);

    long end = System.currentTimeMillis();

    System.out.println(end - start);    // 7 ms
}

private static void method1() {
    // 获取1970年1月1日0时0分0秒到现在所经历过的毫秒值
    long start = System.currentTimeMillis();

    String s = "";

    for (int i = 1; i <= 100000; i++) {
        s += i;
    }

    System.out.println(s);

    long end = System.currentTimeMillis();

    System.out.println(end - start);    // 1292 ms
}

StringBuilder介绍

  • 一个可变的字符序列
  • StringBuilder是字符串缓冲区,相当于一个容器,可以存储任意数据类型,但进入容器后,这些数据都变成字符串

StringBuilder的构造方法

  • public StringBuilder():创建一个空白的字符串缓冲区,其初始容量为16个字符,容量不够时会自动扩容
  • public StringBuilder(String str):创建一个字符串缓冲区,容器创建好后初始化为参数的内容
public static void main(String[] args) {
    StringBuilder sb = new StringBuilder();

    sb.append(100);
    sb.append(45.6);
    sb.append(false);
    sb.append('中');
    sb.append("helloworld");

    System.out.println(sb);     // 10045.6false中helloworld

    System.out.println("---------------------");

    StringBuilder sb1 = new StringBuilder("abc");
    System.out.println(sb1);    // abc
}

append/reverse/length/toString

StringBuilder常用成员方法:

  • public StringBuilder append(any):添加数据并返回对象自己

  • public StringBuilder reverse():将缓冲区的内容进行反转

  • public int length():返回长度

  • public String toString():将缓冲区的内容,以String字符串类型返回

public static void main(String[] args) {
    StringBuilder sb = new StringBuilder();

    // 链式编程:调用的方法,如返回的结果是对象,就可以继续向下调用方法
    sb.append(1).append(2).append(3);

    System.out.println(sb);

    System.out.println("------------------");

    sb.reverse();

    System.out.println(sb);

    System.out.println("------------------");

    System.out.println(sb.length());

    System.out.println("------------------");

    String s = sb.toString();

    System.out.println(s);
}

Summary

/*
String ---> StringBuilder
    String s = "abc";
    StringBuilder sb = new StringBuilder(s);

StringBuilder ---> String
    String s = sb.toString();
 */

<> ArrayList列表

构造方法

  • ArrayList list = new ArrayList();

    • 可以添加任意类型的数据
    • 但数据不够严谨
  • ArrayList<String> list = new ArrayList<>();

    • <>是泛型,指定了ArrayList里面能装的数据类型,从jdk7开始,new后面的<>会自动匹配前面所指定的数据类型
    • 泛型中不允许编写基本数据类型,解决方案是使用基本数据类型所对应的包装类
      • byte ---> Byte
      • short ---> Short
      • int ---> Integer ***
      • long ---> Long
      • float ---> Float
      • double ---> Double
      • boolean ---> Boolean
      • char ---> Character ***
public static void main(String[] args) {
    ArrayList list = new ArrayList();

    list.add(100);
    list.add(45.6);
    list.add(false);
    list.add('a');
    list.add("abc");

    System.out.println(list);       // [100, 45.6, false, a, abc]

    System.out.println("------------------");

    ArrayList<Double> list1 = new ArrayList<>();

    list1.add(11.1);
    list1.add(22.2);
    list1.add(33.3);

    System.out.println(list1);      // [11.1, 22.2, 33.3]
}

add

  • public boolean add(E e):将指定的元素添加到此列表的尾部,add返回boolean类型,固定返回true

  • public void add(int index, E element):在指定索引位置,添加对应的元素(插队)

private static void addMethod() {
    ArrayList<String> list = new ArrayList<>();

    boolean b1 = list.add("1");
    boolean b2 = list.add("2");
    boolean b3 = list.add("3");

    System.out.println(b1);     // true代表添加成功
    System.out.println(b2);     // true
    System.out.println(b3);     // true

    System.out.println(list);   // ["1", "2", "3"]

    System.out.println("---------------------");

    list.add(0, "0");

    System.out.println(list);   // ["0", "1", "2", "3"]
}

remove

  • public E remove(int index):根据索引做删除,返回被删除掉掉元素

  • public boolean remove(Object o):根据元素做删除,返回是否删除成功的状态

private static void removeMethod() {
    ArrayList<String> list = new ArrayList<>();

    list.add("1");
    list.add("2");
    list.add("3");

    String result = list.remove(1);

    System.out.println(result);     // 2
    System.out.println(list);       // [1, 3]

    System.out.println("-----------------------");

    boolean flag1 = list.remove("1");
    boolean flag2 = list.remove("4");

    System.out.println(flag1);      // true
    System.out.println(flag2);      // false

    System.out.println(list);       // [3]
}

set

public E set(int index, E element):修改指定索引位置为对应的元素,返回被覆盖掉的元素

private static void updateMethod() {
    ArrayList<String> list = new ArrayList<>();

    list.add("1");
    list.add("2");
    list.add("3");

    String res = list.set(1, "4");

    System.out.println(res);        // 2 被覆盖的值

    System.out.println(list);       // [1, 4, 3]
}

attention

:warning::以上方法的返回值通常不做接收

get

  • public E get(int index):根据索引获取集合中的元素

  • public int size():返回集合中元素的个数,即列表的长度

private static void searchMethod() {
    ArrayList<String> list = new ArrayList<>();

    list.add("1");
    list.add("2");
    list.add("3");

    String s = list.get(2);             // "3"
    System.out.println(s);              // 3
    System.out.println(list.size());    // 3
}