027_詹鸿诗_Java核心编程

Java核心编程实验笔记
第一次笔记:
第一个Java源程序:
public class HelloJava{
//这里是程序入口
public static void main(String args[]){
//输出字符串
Stytem.out.ptintln(“Hello Java”);
}
}

* 标识符由数字、字母、下划线(_)、及$组成 如:a12ghdg
* 注意:数字不能作为标识符的开始,如:1ac
*
* 关键字:具有特殊含义的标识符,例如:int、void、main、String…
* 用户自定义标识符:是由用户按标识符构成规则生成的非保留字的标识符, 如  abc、name 就是一个标识符。

* 命名规则:
* Java类的命名规则:类名首字母大写,如果由多个单词组合,则每个单词首字母大写(大驼峰命名法)
*        HelloWorld, Demo01
*  小驼峰命名法:首个单词字母小型,后面的单词首字母大写
*      如:helloWorld,dayMyYou
*
* 注意:java严格区分大小,如:name和Name表达的意思不一样

* 变量命名:
    语法:变量类型  变量名字  赋值符号  值;
         */
int age;  // 声明变量,不赋值
age = 32; // 声明变量之后赋值
String name = “大锤”;  // 声明变量,赋值

// 修改变量值(重新赋值)
  age = 56;
  name = “张三”;

//  int num;
//  num = “北京中关村”;

// int 2num;  // 非法命名

int n1, n2, n3, n4; // 批量命名(不推荐使用)
   n1 = 2;
   n2 = 3;
   n3 = 4;
   n4 = 5;

n1 = n2 = n3 = n4 = 56;

int num1 = 3, num2 = 4;

* 变量的作用域:
  *      全局变量:
  *          定义在方法(函数)和代码块之外的变量
  *      局部变量:
  *          定义在方法或者代码块之间的变量
// 定义全局变量
    int age; // 全局变量
    String name = “大锤”;

// 静态变量
    static int number;
    static double price = 1399.99;

public static void main(String[] args){
        // 定义局部变量
        int age;
        if (true) {
            String location;
        }

//        System.out.println(location);

// 成员常量
    final double PI = 3.14159;
    // 静态常量,使用 final static关键字修饰
    final static float PRICE = 99.99F;
//    Integer

* 常量命名规则:
     *     1、常量名字应该全部大写
     *      2、当常量名由多个单词组成时采用下划线分割,如:HTTP_CODE、HTTP_STATUS_CODE
     */
    final static int HTTP_CODE = 200;

// 成员常量和静态常量再定义同时必须初始化
    //final static long bigData;    
 //final long data; 
    public static void main(String[] args) {
        // 十进制
        int num = 42;
        // 八进制
        int num1 = 056;
        // 十六进制
        int num2 = 0x5d8e;

// 定义常量,使用关键字final
        final int PI = 3;
        // 常量一旦被定义赋值,则不可再被修改
//        pi = 6; Variable ‘name’ might already have been assigned to

// 局部常量
        final String NAME;
        NAME = “大锤”;

//name = “张三”; // Variable ‘name’ might already have been assigned to

final long N1;
//        final static long n2 = 3L; 错误写法

* Java中的数据类型:
         *      1、基本数据类型(八种)
         *          byte(字节型)、short(短整型)、int(整形)、long(长整型)、float(单精度浮点型)、double(双精度浮点型)
         *          char(字符型)、boolean(布尔型)
         *      2、引用数据类型
         *          除了基本数据类型,其他全部是引用数类型,如:String、数组等
         */
        // 字节型
        byte by = 127;
        // System.out.println((byte) (by + 1));
        // 短整型
        short sh = 56;
        // 整形
        int num = 78946;
        // 长整型,注意: 需要早长整型末尾添加L或者l
        long number = 56L;

// 单精度浮点型, 注意: 需要早长整型末尾添加F或者f
        float fl = 3.14F;
        float fl1 = 3.1415888888879874243246564564561129f; // 精度丢失
        System.out.println(fl1);

// 双精度浮点型,java中小数默认是double类型
        double db = 3.14159;

// 字符型, 字符型的值使用单引号引起来,当值为整形时不需要单引号
        char ch1 = 3;
        char ch2 = ‘a’;
        char ch3 = 97;
        System.out.println(ch1);
        System.out.println(ch3);

// 布尔值类型,注意:Java中布尔值类型只有true和false两个值
        boolean bool1 = true;
        boolean bool2 = false;

// null类型
        String str = null;

System.out.println(name);

//        int a = null; 报错

第二次笔记:
一、数据类型转换
数据类型的转换是在所赋值的数值类型和被变量接收的数据类型不一致时发生的,它需要从一种数据类型转换成另一种数据类型。数据类型的转换可以分为隐式转换(自动类型转换)和显式转换(强制类型转换)两种。
/**
         * 基本数据类型大小排行榜
         *      byte    1字节
         *      short   2字节
         *      char    2字节
         *      int     4字节
         *      long    8字节
         *      float   4字节
         *      double  8字节
         */
byte b1 = 25;
        // 小类型数据转为大类型数据(自动转换)
        short s1 = b1;
        // int age = “”;

short s2 = 654;
        // 大类型数据转为小类型数据时需要强制转换(类型强转)
        // 小类型  变量名  =  (需要转换的类型) 大类型;
        // 注意:大类型数据转为小类型数据有可能会造成数据进度丢失和溢出
        byte b2 = (byte) s2;
        System.out.println(b2);

/**
         * short类型与char类互相转化需要强制转换
         */
        short s3 = 97;
        char ch1 = (char) s3;
        System.out.println(ch1);

String str1 = “Hello”;

// 不能强转
        // int num1 = (int) str1;

int num2 = 56;
        // 不能转换
        //String str2 = (String) num2;

// 注意:两种数据类型彼此兼容,否则不能互相转换
        // 基本数据类型不能与引用数据类型转换

Date time = new Date();
        String s1 = time.toString();

Demo01 d1 = new Demo01();
        // d1 = (Demo01) time;
        Demo02 d2 = (Demo02) new Object();

一、一元运算符
/**
      *      -:取反
         *      ++:自增
         *      --:自减
         */
        int num1 = 56;
        int num2 = - num1;
        System.out.println(num2);

int num3 = 25;
        // num3 = num3 ++;
        num3 ++; // num3自增 + 1
        System.out.println(num3);

++ num3; // num3自增 + 1
        System.out.println(num3);// 27

int num4;
        num4 = num3 ++; // 先将 num3 赋值给num4,然后num3再自增 1
        System.out.println("num4 = " + num4 + ", num3 = " + num3);

int num5 = 25;
        int num6;
        num6 = ++ num5; // 先num5自增,然后再将自增之后的值赋值给 num6
        System.out.println("num5 = " + num5 + ", num6 = " + num6);

int num7 = 25;
        – num7;
        System.out.println(num7);
        num7 --;
        System.out.println(num7);
二、二元运算符
 /**
         * Java 语言中算术运算符的功能是进行算术运算,
         * 除了经常使用的加(+)、减(-)、乘(*)和除(\)外,
         * 还有取模运算(%)。加(+)、减(-)、乘(*)、除(\)
         * 和我们平常接触的数学运算具有相同的含义
         */
        int num1 = 2;
        int num2 = 7;

// 加法运算
        int num3 = num1 + num2;// 2 + 3 = 5
        System.out.println(num3);

// 减法运算
        num3 = num2 - num1; // 3 - 2 = 1
        System.out.println(num3);

// 乘法运算
        num3 = num1 * num2;
        System.out.println(num3);

// 除法运算
        num3 = num2 / num1; // 求商
        System.out.println(num3);

// 取余运算
        num3 = num2 % num1;
        System.out.println(num3)

三、赋值运算符

  • =:赋值符号
  • +=:如, num += 2; -----> 本质:num = num + 2;
  • -=: 如, num -= 2; -----> 本质:num = num - 2;
  • *=: 如, num *= 2; -----> 本质:num = num * 2;
  • /=: 如, num /= 2; -----> 本质:num = num / 2;
  • %=: 如, num %= 2; -----> 本质:num = num % 2;

四、逻辑运算符

  •  与、或、非
    
    •  &&(短路与):如:a && b, 如果ab全部为true则结果为true,否则为false
      
  •  ||(短路或):如:a || b, a或者b有一个为true,或者ab均为true,则为true,否则为false
    
  • !:a为true,则结果为false,a为false,则结果为true
    */
    注意:&& 与 & 区别:如果 a 为 false,则不计算 b(因为不论 b 为何值,结果都为 false)
    || 与 | 区别:如果 a 为 true,则不计算 b(因为不论 b 为何值,结果都为 true)

五、关系运算符
关系运算符(relational operators)也可以称为“比较运算符”,用于用来比较判断两个变量或常量的大小。关系运算符是二元运算符,运算结果是 boolean 型。当运算符对应的关系成立时,运算结果是 true,否则是 false。
注意点如下所示:
1、基本类型的变量、值不能和引用类型的变量、值使用 == 进行比较;boolean 类型的变量、值不能与其他任意类型的变量、值使用 == 进行比较;如果两个引用类型之间没有父子继承关系,那么它们的变量也不能使用 == 进行比较。
2、== 和 != 可以应用于基本数据类型和引用类型。当用于引用类型比较时,比较的是两个引用是否指向同一个对象,但当时实际开发过程多数情况下,只是比较对象的内容是否相当,不需要比较是否为同一个对象。
实例
public class Demo02 {
public static void main(String[] args) {
/**
* 当引用数据类型使用和!=做比较运算时的区别:
*
/
String s1 = “Hello”;
String s2 = “Hello”;
String s3 = new String(“Hello”);
System.out.println(s1 == s2);
System.out.println(s1 == s3);
/
*
* s1.equals(s3):比较s1与s3的内容是否相同
*/
System.out.println(s1.equals(s3));
关系运算符的优先级为:>、<、>=、<= 具有相同的优先级,并且高于具有相同优先级的 !=、
。关系运算符的优先级高于赋值运算符而低于算术运算符,结合方向是自左向右。
六、Scanner的基本使用
/**
         * java扫描器:用户从控制台输入数据,后台Java程序接收
         *
         */
        // 创建扫描器对象
        Scanner scan = new Scanner(System.in);
        //System.out.println(“请输入您的年龄:”);
        // 使用scan.nextInt()方法获取用户输入的年龄(整数)
        //int age = scan.nextInt();
        //System.out.println(age);
        // 获取用户输入的小数
       // System.out.println(“请输入商品价格:”);
        //System.out.println(scan.nextDouble());

// 获取用户输入的字符串
        //System.out.println(“请输入您的名字:”);
        System.out.println(“请您写一句诗:”);
        // System.out.println(scan.next());
        System.out.println(scan.nextLine());
        /**
         * next()与nextLine()方法的区别:
         *      1、当遇到空格或者回车的时候 next()方法停止读取
         *      2、当遇到回车的时候 nextLine()方法停止读取,读取整行数据
         */
八、位运算符
位运算符主要用来对操作数二进制的位进行运算。按位运算表示按每个二进制位(bit)进行计算,其操作数和运算结果都是整型值。
1、位逻辑运算符
位逻辑运算符包含 4 个:&(与)、|(或)、~(非)和 ^(异或)。除了 ~(即位取反)为单目运算符外,其余都为双目运算符。下表中列出了它们的基本用法。
运算符 含义 实例 结果
& 按位进行与运算(AND) 4 & 5 4
| 按位进行或运算(OR) 4 | 5 5
^ 按位进行异或运算(XOR) 4 ^ 5 1
~ 按位进行取反运算(NOT) ~ 4 -5
2、位与运算符
位与运算符为&,其运算规则是:参与运算的数字,低位对齐,高位不足的补零,如果对应的二进制位同时为 1,那么计算结果才为 1,否则为 0。因此,任何数与 0 进行按位与运算,其结果都为 0。
3、位或运算符

其运算规则是:参与运算的数字,低位对齐,高位不足的补零。如果对应的二进制位只要有一个为 1,那么结果就为 1;如果对应的二进制位都为 0,结果才为 0。
4、位异或运算符
位异或运算符为^,其运算规则是:参与运算的数字,低位对齐,高位不足的补零,如果对应的二进制位相同(同时为 0 或同时为 1)时,结果为 0;如果对应的二进制位不相同,结果则为 1。
位取反运算符
位取反运算符为~,其运算规则是:只对一个操作数进行运算,将操作数二进制中的 1 改为 0,0 改为 1。

第三次笔记:
while循环:
 语法:
  while (循环条件) {
   循环体
  }

do.while循环
 语法:
 do{
 循环体
  } while (循环条件);

while循环与do…while循环的区别:
1、while是先判断后执行,do…while循环是先执行然后再判断
2、do…while循环至少执行一次
3、while循环与do…while的特点:都是循环执行某一语句,循环次数素不固定

for循环:
 语法:
for (表达式1; 表达式2; 表达式3) {
循环体
}
特点:循环次数固定

foreach语法:
  for(迭代变量类型 变量的名字 :需要遍历(迭代)的对象){
 语句块;
    }

定义方法的语法:
 修饰符  返回值类型   方法名(参数1,参数2…) { 方法体… }

return关键字的作用:1、结束方法的执行。2、将方法的执行结果返回给调用者

方法(函数)的类型:
1、无参无返回值
修饰符  void  方法名(){ 方法体 }
2、无参有返回值
修饰符   返回值类型   方法名(){ 方法体}
3、有参无返回值
 修饰符   void   方法名(参数1, 参数2,…){ 方法体}
4、有参有返回值 
修饰符   返回值类型  方法名(参数1, 参数2,…){ 方法体}

比较两个数的大小,将大的值返回回去
@param num1
@param num2
@return 返回最大值
定义方法:
比较两个数大小,返回布尔值

方法调用
1、通过 对象.方法名字(参数)
2、类名.方法(参数)
3、方法(参数)

调用非static关键字修饰的方法,语法:对象.方法(参数)
调用被static修饰的方法,语法:类名.方法(参数)

方法重载:
            重载就是在一个类中,有相同的函数名称,但参数列表不相同的方法。

注意:
            方法重载只与方法名字和参数列表有关,与方法返回值类型无关

方法签名:方法名字 + 参数列表

什么是程序?
        答:程序 = 算法 + 数据结构

数组定义:
用来存放相同类型的一组数据
数组下标从0开始,对数组元素进行操作是通过数组的下标(索引)
  数组一旦被创建,则数组的长度不可被修改
  语法:
  静态创建数组
  数据类型[] 数组名 = {值1,值2…}
   数据类型 数组名[] = {值1,值2…}
 动态创建数组
数据类型[] 数组名 = new 数据类型[数组长度]
数据类型 数组名[] = new 数据类型[数组长度]
静态创建数组,特点:创建数组的同时给数组元素赋值
动态创建数组,特点创建数组时指定数组的长度
数组元素必须是相同类型的,不允许出现混合类型。
数组元素赋值:语法,数组名[索引] = 值
数组的长度获取方式,array.length

一、 什么是方法?
在java中,方法就是用来完成解决某件事情或实现某个功能的办法。方法实现的过程中,会包含很多条语句用于完成某些有意义的功能——通常是处理文本,控制输入或计算数值。

二、方法的定义和调用
修饰符:修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
返回值类型 :方法可能会返回值。returnValueType 是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType 是关键字void。
方法名:是方法的实际名称。方法名和参数表共同构成方法签名。
参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
方法体:方法体包含具体的语句,定义该方法的功能。
方法的作用及特点:
1、封装一段特定的业务逻辑功能
2、尽可能独立,一个方法只干一件事
3、方法可以被反复多次的调用
4、减少代码的重复,有利于代码的维护,有利于团队的协作

第三次笔记
二维数组:
java中使用 [][] 来定义二维数组,定义数组时也可同时初始化。
两种初始化形式:
格式1、动态初始化
数据类型 数组名[][] = new 数据类型[m][n]
数据类型[][] 数组名 = new 数据类型[m][n]
数据类型[] 数组名[] = new 数据类型[m][n]
举例:  * 二维数组:
         *      数据类型[][] 数组名字 = new 数据类型[m][n]
         *
         *      本质:数组的元素还是数组
          */
        int[][] arr = new int[2][3];
        System.out.println(arr.length);
静态初始化
数据类型[][]  数组名 = {{元素1,元素2…},{元素1,元素2…},{元素1,元素2…}…};
举例:int[][] arr = {{22, 15, 32, 20, 18}, {12, 21, 25, 19, 33}, {14, 58, 34, 24, 66}}。
3、遍历数组:
4、// 访问二维数组的元素,语法:arr[x][y]
5、        arr[0][0] = 10;
6、        arr[0][1] = 20;
7、        arr[0][2] = 30;
8、
9、        arr[1][0] = 22;
10、        arr[1][1] = 32;
11、        arr[1][2] = 42;
12、
13、        // 遍历二维数组
14、        for (int i = 0; i < arr.length; i++) {
15、            for (int j = 0; j < arr[i].length; j++) {
16、                System.out.print(arr[i][j] + “\t”);
17、            }
18、            System.out.println();
19、        }
20、    }
21、}
二、Arrays类;
由于数组对象本身并没有什么方法可以供我们调用,但是API中提供了一个根据类Arrays供我们使用,从而可以对数据对象进行一些基本操作。
Arrays类中的方法都是static修饰的静态方法,在使用的时候可以直接使用类名进行调用,而“不用”使用对象类调用(注意是“不用”,而不是“不能”)。
Arrays类具有以下常用的功能:
给数组赋值:通过调用fill方法。
对数组进行排序:通过sort方法。
比较数组:通过equals方法比较数组中元素的值是否相等。
查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找法操作。
将数组转为字符串输出:通过toString方法实现

1、
数组的复制:System.arraycopy(浅拷贝)
例子System.arraycopy(src, 1, dest, 0, 6);
*2、Arrays.copyOf(浅拷贝)
src为原数组,1为复制的起始位置,dest为目的数组,0为目的数组放置的起始位置,6为复制的长度
数组的复制:
         *      System.arraycopy(arr, start, dist, index, length)
         */
        int arr1[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};

// 案例:将arr1数组的 3-8的元素复制到arr2中去
        int arr2[] = new int[6];
        System.arraycopy(arr1, 2, arr2, 0, 6);
        for (int i : arr2) {
            System.out.print(i + “\t”);
        }

System.out.println();

/**
         * Arrays.copyOf(arr, length)
         /
        // 案例:将arr1数组进行复制,复制的范围下标为5之前的所有元素
        int arr3[] = Arrays.copyOf(arr1, 5);
        for (int j : arr3) {
            System.out.print(j + “\t”);
        }
    }
}
3、Arrays.copyOfRange
*
System.out.println();
        /**
         *  Arrays.copyOfRange(src, 1, 3);
         /
        // 案例:将arr1数组中的元素复制到arr4数组中,复制到范围为下标1开始,到下标6结束
        int[] arr4 = Arrays.copyOfRange(arr1, 1, 6);
        for (int i : arr4) {
            System.out.print(i + “\t”);
        }
4、数组扩容与缩容:
数组扩容与缩容的实质:就是创建一个新的数组,新数组的长度比原来的数组(大,扩容,小,缩容),然后将原来数组中的内容全部拷贝到新的数组中,最后将新数组重新赋给原来的数组。
举例:
 public static void main(String[] args) {
        /
*
         * 数组扩容与缩容的实质:就是创建一个新的数组,新数组的长度比原来的数组(大,扩容,小,缩容)
         */
        int arr[] = new int[10];
        // 创建随机数对象
        Random rand = new Random();
        for (int i = 0; i < 5; i++) {
            arr[i] = rand.nextInt(100);
        }

// 打印数组,Arrays.toString(arr)方法的作用是将数组以字符串的形式输出
        System.out.println(Arrays.toString(arr));

// 对数组进行缩容
        int arr1[] = Arrays.copyOf(arr, 5);
        System.out.println(Arrays.toString(arr1));

// 扩容,案例:将arr数组长度扩容到15
        int[] arr2 = Arrays.copyOf(arr, 15);
        System.out.println(Arrays.toString(arr2));

}
}
二、冒泡排序
冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。### 7.2.1、算法描述​ 1、比较相邻的元素。如果第一个比第二个大,就交换它们两个;​ 2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样在最后的元素应该会是最大的数;​ 3、针对所有的元素重复以上的步骤,除了最后一个;​ 4、重复步骤1~3,直到排序完成。
public static void main(String[] args) {
int arr[] = {6,9,3,5,2,8};
System.out.println(“排序前:”);
System.out.println(Arrays.toString(arr));
for(int i =0;i<arr.length-1;i++){
for(int j=0;j<arr.length-1-i;j++){
int tamp = 0;
if (arr[j]>arr[j+1]) {
tamp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tamp;
}
}
}
System.out.println(“排序后:”);
System.out.println(Arrays.toString(arr));
}
}

三、选择排序
选择排序(Selection-sort)是一种简单直观的排序算法。它的工作原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
(9.14)
一、面向对象
面向过程思想:
1、 步骤清晰简单,第一步要做什么,第二步要做什么……
2、 面向过程适合处理一些较为简单的问题
面向对象思想:
1、 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考,最后,才对某个分类 下的细节进行面向过程的思索。
2、 面向对象适合处理复杂的问题,适合处理需要多人协作的问题
面向过程的结构化程序设计:
结构化程序设计的弊端:
1、缺乏对数据的封装
2、数据与方法(操作数据)的分离

类是对象的抽象,对象都是类的属性.
2.什么是面向对象:
面向对象的本质就是:以类的方式组织代码,以对象的组织(封装)数据。
3、类中可以包含:
3.1、所有对象所共有的属性/特征------------成员变量
3.2、所有对象所共有的行为-----------------方法
4、一个类可以创建多个对象
同一类型所创建的对象,结构相同,数据不同
22、类是对象的模板,对象是类的具体的实例
23、面向对象的三大特征:封装、继承、多态
所谓的OOP就是指的面向对象编程.这是一种计算机编程架构.OOP的一条基本准则是计算机程序是由单个能够引

  • 起子程序作用的单元或对象组合而成.OOP达到了软件工程的三个主要目标:重用性,灵活性和扩展性.为了实现

  • 整体运算,每个对象都能够接收消息,处理数据和向其它对象发送消息.OOP主要有以下的概念和组件.

  • 组件: 数据和功能一起在运行着的计算机程序中形成的单元,组件在OOP计算机称重是模块和结构化的基础.

  • 抽象性: 程序有能力忽略正在处理中信息的某些方面,即对信息主要方面关注的能力

  • 封装: 也叫作信息封装:确保组件不会以不可预期的方式改变其它组件内部状态;只有在那些提供了内部状态改变方法的

  • 组建中,才可以访问其内部状态.每类组件都提供了一个与其它组件联系的接口.并规定了其它组件进行调用的方法.

  • 多态性: 组件的引用和类集会涉及到其它许多不同类型的组件,而且引用组件所产生的的结果得依据实际调用的类型.

  • 继承性: 允许在现存的组件基础上创建子类组件,着统一并强调了多态性和封装性.典型的来说就是用类来对组件进行分

  • 组,而且还可以定义新类为现存的类的扩展,这样就可以将类组织成树形或网状结构,这体现了动作的通用性.

  •  由于抽象性/封装性/重用性以及便于使用等方面的原因,以组件为基础的编程在脚本语言中已经变得特别
    
  • 流行.Python 和 Ruby 是最近才出现的语言,在开发时完全采用了 OOP 的思想,而流行的 Perl 脚本

  • 语言从版本5开始也慢慢地加入了新的面向对象的功能组件。用组件代替“现实”上的实体成为 JavaScript(ECMAScript)

  • 得以流行的原因,有论证表明对组件进行适当的组合就可以在英特网上代替 HTML 和 XML 的文档对象模型(DOM)。
    二、类与对象的创建
    /
    public class Student {
    // 内部类
    private class C{
    }
    }
    // 定义类A
    class A{
    }
    // 注意:一个java文件中只能有一个public修饰的Java类,并且这个被public修饰的Java类名必须与Java文件名字一致
    //public class B{
    //
    //}
    课堂实例:
    // 定义成员变量
        String name; // 姓名
        int age; // 年龄
        double height; // 身高
        // …
    // 定义方法
    public void run(){
    System.out.println(“人在跑”);
    }
    public void eat(){
    System.out.println(“人在吃饭”);
    }
    // 将数组排序
    public int[] sort(int[] arr){
    Arrays.sort(arr);
    return arr;
    }
    @Override
    public String toString() {
    return “Person{” +
    “name='” + name + ‘’’ +
    “, age=” + age +
    “, height=” + height +
    ‘}’;
    }
    }
    6.2创建对象:
    /
    *
    * 创建对象语法:
    * 数据类型 引用类型变量 指向(引用) new关键字 对象
    * Student zs = new Student();
    */
    // 案例:创建Person对象
    Person per = new Person(); // 实例化对象
    // 访问对象的成员变量和方法,语法:对像名.成员变量名字/方法名字, 能点出什么东西全看类有什么东西
    // 访问person类的成员变量
    per.name = “大锤”; // 访问name变量并且赋值
    // per.salary = 3000; 错误演示
    System.out.println(per.toString());
    per.age = 25;
    per.height = 177.777;
    System.out.println(per.toString());
    // 访问变量
    System.out.println(per.name);
    // 访问成员方法
    per.run();

     int[] ar = {1, 56, 0, 89, 78, 45};
     int[] arr = per.sort(ar);
     System.out.println(Arrays.toString(arr));
     // 实例化对象p2
     Person p2 = per; // 将per的值(对象地址信息)赋给p2,此时per和p2指向相同对象
     System.out.println(p2.toString());
    
     Person p3 = new Person();
     System.out.println(p3.toString());
    
    
     Person p4 = null;
     /**
      * Exception in thread "main" java.lang.NullPointerException
      * 空指针异常:
      *      造成空指针异常的原因:是因为对象为null,然后访问其对象变量或者方法
      */
     // System.out.println(p4.toString());
    

    }
    }
    二、面向对象分析产生三种模型
    1、对象模型:对用例模型进行分析,把系统分解成互相协作的分析类,通过类图\对象图描述对象\对象的属性\对象间的关系,是系统的静态模型
    2、动态模型:描述系统的动态行为,通过时序图/协作图/描述对象的交互,以揭示对象间如何协作来完成每个具体的用例。单个对象的状态变化/动态行为可以通过状态图来表示。
    3、功能模型(即用例模型à作为输入)
    第四次笔记:
    三、构造方法
    构造方法语法结构:
    构造方法是在类中定义的方法,不同于其他的方法,构造方法的定义有如下两点规则:
    (1)构造方法的名称必须与类名完全相同。
    (2)构造方法没有返回值,连void关键字有没有
    构造方法的语法:

    •          修饰符   类名(参数){
      
    •             方法体....
      
    •          }
      
    •  构造方法的作用:用于创建类的对象(实例化对象),还可以初始化成员比啊量的初始值
      
    •  注意:当我们手动添加构造器(构造方法)之后,编译器将不在为我们添加默认的无参构造器
      

默认的构造方法:
​ 1)任何一个类都必须含有构造方法。
​ 2)如果源程序中没有定义构造方法,编译器在编译时会为其添加一个无参的构造方法(称为默认无参构造器)。
​ 3)当定义了构造方法之后,Java编译器不再添加默认的无参构造器。
构造方法的重载:
一个类定义多个构造方法,这些构造方法都有相同的名称,但是方法的参数列表不同
一个构造方法可以通过this关键字调用另外一个重载的构造方法
构造方法常用于实例化对象和对成员变量进行初始化
this关键字的使用:
​this关键字用在方法体中,用于指向调用该方法的当前对象,简单来说,那个对象调用方法,this就指的是那个对象,严格来讲在方法中需要通过this关键字指明当前对象。
实例:
int age;
String name;
double salary;

// 通过构造器初始化成员变量的值
public Demo01(){
    age = 23;
    name = "大锤";
    salary = 3000.0;
}


// 定义有参构造器
public Demo01(int age){
    System.out.println("我是有参构造器");
}

public Demo01(int age, String name, double salary){
    // this关键字,代表当前对象
    this.age = age;
    this.name = name;
    this.salary = salary;
}



@Override
public String toString() {
    return "Demo01{" +
            "age=" + age +
            ", name='" + name + '\'' +
            ", salary=" + salary +
            '}';//右击
}

}

Java内存分析
堆: new出来的对象(包括实例变量)
栈:局部变量(包括方法的参数)
方法区: .class字节码文件(包括方法、静态变量)

内存区域类型:
1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制;
​2. 堆:存放所有new出来的对象;
3. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(对象可能在常量池里)(字符串常量对象存放在常量池中。);
4. 静态域:存放静态成员(static定义的);
​5. 常量池:存放字符串常量和基本类型常量(public static final)。有时,在嵌入式系统中,常量本身会和其他部分分割离开(由于版权等其他原因),所以在这种情况下,可以选择将其放在ROM中 ;
​6. 非RAM存储:硬盘等永久存储空间

对于string的特殊解释
对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
对于通过new产生一个字符串(假设为”china”)时,会先去常量池中查找是否已经有了”china”对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此”china”对象的拷贝对象。
​ 这也就是有道面试题:String s = new String(“xyz”);产生几个对象?答:一个或两个,如果常量池中原来没有”xyz”,就是两个。
例如:

  1. 堆:
    1.1) 存储new出来的对象(包括实例变量)
    1.2) 垃圾: 没有任何引用所指向的对象
    垃圾回收器(GC)**不定时到内存中清理垃圾,
    回收过程是透明的(看不到的),不一定一发现垃圾就立刻回收,
    调用System.gc()可以建议虚拟机尽快调度GC来回收
    1.3) 内存泄漏: 不再使用的内存没有被及时的回收
    建议: 对象不再使用时及时将引用设置为null
    1.4) 实例变量的生命周期:
    在创建对象时存储在堆中,对象被回收时一并被回收
  2. 栈:
    2.1) 存储正在调用的方法中的所有局部变量(包括方法的参数)
    2.2) 调用方法时,会在栈中为该方法分配一块对应的栈帧,
    栈帧中存储方法中的局部变量(包括参数),
    方法调用结束时,栈帧被清除,局部变量一并被清除
    2.3) 局部变量的生命周期:
    方法被调用时存储在栈中,方法结束时与栈帧一并被清除
  3. 方法区:
    3.1) 存储.class字节码文件(包括静态变量、方法)
    3.2) 方法只有一份,通过this来区分具体的调用对象

对象数组
数组是对象:
​ 1、在Java中,数组属于引用数据类型。
​ 2、数组对象存储在堆中,数组变量属于引用类型,存储数组对象的地址信息,指向数组对象。
数组的元素可以看成数组对象的成员变量(只不过类型全部相同)
public class Demo02 {
public static void main(String[] args) {
// 定义一个数据类型,用于存放Student信息
Student[] stu = new Student[48];
// 创建student对象
Student zs = new Student(“张三”, 23, “202110107890”);
// 把张三对象装到数组中
stu[0] = zs;

    stu[1] = new Student("李四", 21, "202145678956");

    Demo01 d1 = new Demo01();

// stu[2] = d1; 报错,数据类型不匹配

    System.out.println(stu[0]);

    // 案例:定义一个数组,可以存放任意数据类型
    Object[] obj = new Object[3];
    obj[0] = 12;
    obj[1] = stu;
    obj[2] = "hello";

    Student[] students = {new Student(), new Student(), new Student()};

访问控制修饰符
private修饰的成员变量和方法仅仅只能在本类中访问调用。

​public修饰的成员变量和方法可以在任何地方调用,public修饰的内容是对外提供可以被调用的功能,需要相对稳定,private修饰的内容是对类实现的封装,如果“公开”会增加维护的成本。
protected和默认访问控制
​ 1)用protected修饰的成员变量和方法可以被子类及同一个包中的类使用。
​ 2)默认的访问控制即不书写任何访问修饰符,默认访问控制的成员变量和方法可以被同一个包中的类调用
package com.zpark.oop.day03;

public class Demo04 {
/**
* private:私有的
* 特点:凡是被private关键字修饰的属性和方法,只能在本类了当中访问,在其他类当中访问则没有权限
*
* public:关键字
* 特点:任何地方都可以访问
*/

public String nickname; // 昵称

private String name; // 姓名

protected int age;

double salary; // 当不添加任何修饰符时,则为默认访问修饰符default


public void a(){
    System.out.println("这是公共的方法");
}

private void b(){
    System.out.println("这是私有的方法");
}

public static void main(String[] args) {
    // 创建Demo04对象
    Demo04 d4 = new Demo04();
    // 访问d4对象的公有属性和方法
    d4.nickname = "大锤";
    System.out.println(d4.nickname);

    d4.a();

    // 访问d4对象的私有属性和方法
    d4.name = "张无忌";
    System.out.println(d4.name);
    d4.b();
}

}

public class Demo05 {
public static void main(String[] args) {
// 创建Demo04对象
Demo04 d4 = new Demo04();
// 访问d4对象的公有属性和方法
d4.nickname = “大锤”;
System.out.println(d4.nickname);

    d4.a();

    // 访问d4对象的私有属性和方法
    // d4.name = "张无忌"; 不能访问其他类中的私有属性
    // System.out.println(d4.name);
    // d4.b(); 不能访问其他类中的私有方法

    // 访问默认修饰符的属性
    d4.age = 23;
    // 访问默认修饰符的属性
    d4.salary = 5000.0;

    // 访问默认修饰符修饰的类
    A a = new A();
    System.out.println(a.name);

}

}

package com.zpark.oop.day03;

public class Student {
String name; // 姓名
int age; // 年龄
String number; // 学号

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

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

@Override
public String toString() {
    return "Student{" +
            "name='" + name + '\'' +
            ", age=" + age +
            ", number='" + number + '\'' +
            '}';
}

}

封装
封装,简单的说就是该露的露,该藏的藏。我们在设计程序是要追求“高内聚,低耦合”,其中,高内聚指的是类的内部数据操作细节由自己完成,不允许外部干涉。低耦合指的是仅暴露少量的方法给外部调用(使用get/set方法)。
​ 封装(对数据的隐藏),通常来说,应禁止直接访问应该对象中数据的实际表示,而是应该通过操作接口来访问,这种称为信息隐藏。
封装的意义:
​ 1、对外提供可调用的,稳定的功能。
​ 2、封装容易变化的,具体的细节,外界不可访问,这样封装的意义在于:
​ a. 降低代码出错的可能性,便于维护。
​ b. 当内部的实现细节改变时,只要保证对外的功能定义不变,其他的模块就不会因此而受到牵连。
封装的核心:属性私有化,行为(方法)公开化

继承

1、通过extends关键字可以实现类的继承。
2、子类可以继承父类的成员变量及成员方法,同时也可以定义自己的成员变量和成员方法。
3、Java语言不支持多重继承,一个类只能继承一个父类,但是一个父类可以有多个子类。
1、子类的构造方法中必须通过super关键字调用父类的构造方法,这样可以妥善的初始化继承自父类的成员变量。
2、如果子类的构造方法中没有调用父类的构造方法,Java编译器会自动的加入对父类的无参构造方法的调用(如果父类没有无参构造方法,则会有编译错误)。

多态
多态指的是同一方法可以根据发送对象的不同而采用多种不同的行为方式。
一个对象的实际类型是确定的,但是可以指向对象的引用的类型有很多。
多态存在的条件:
1、 有继承关系
2、 子类重写父类的方法
3、 父类引用指向子类对象
多态的意义:
1、行为的多态(所有抽象方法都是多态的)
2、对象的多态(所有对象都是多态的)
多态的表现形式:
1、重写:根据对象的不同来表现多态
2、重载:根据参数的不同来表现多态
注意:多态是方法的多态性,不是属性的多态性

super关键字
在java里面,对于super关键字通常有两种用法:**
​ 1. 用在子类的构造方法里(初始化用),主要是调用父类的默认构造方法,如果父类有不止一个构造方法,可以通过super指定具体的构造函数,比如 super(paras)。
​ 2. 用在子类里调用隐藏或重写的属性或行为,比如 super.onDestroy()等等。
​对于第1种需要注意,super表示当前类的父类对象,super()调用的是父类默认的构造方法,即这样可以对父类进行初始化。如果没有对父类进行初始化,当子类调用父类的方法时,便会从逻辑上出现错误,因为没对父类初始化,父类的方法和属性便没有内存空间。

关于super 与 this 关键字的对比(区别):**
​ 1. super(参数):调用基类中的某一个构造函数(应该位于子类构造函数中的第一条语句)。
​ 2. this(参数):调用本类中的构造函数(应该位于构造函数中的第一条语句)。
​ 3. super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)。
​ 4. this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
​ 5、调用super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。
​ 6、super()和this()类似,区别是,super()从子类中调用父类的构造方法,this()在同一类内调用其它构造方法。
​ 7、super()和this()均需放在构造方法内第一行。
​ 8、尽管可以用this调用一个构造器,但却不能调用两个。
​ 9、this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
​ 10、 this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
​ 11、 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。

方法重写
方法的重写(Override):
1、发生在父子类中,方法名称相同,参数列表相同,方法体不同
2、重写方法被调用时,看对象的类型
3、遵循"两同两小一大"原则:------------了解
3.1、两同:
3.1.1、方法名称相同
3.1.2、参数列表相同
3.2、两小:
3.2.1、派生类方法的返回值类型小于或等于超类方法的
a、void时,必须相同
b、基本数据类型时,必须相同
c、引用数据类型时,小于或等于
3.2.2、派生类方法抛出的异常小于或等于超类方法的
3.3、一大:
3.3.1、派生类方法的访问权限大于或等于超类方法的
重写与重载的区别:
1、重写(Override):
1.1、发生在父子类中,方法名相同,参数列表相同,方法体不同
1.2、“运行期绑定”,看对象的类型绑定方法
2、重载(Overload):
2.1、发生在一个类中,方法名相同,参数列表不同,方法体不同
2.2、“编译期绑定”,看参数/引用的类型绑定方法
补充:
编译期:.java源文件,经过编译,生成.class字节码文件
运行期:JVM加载.class并运行.class
编译错误:只是检查语法
第五次笔记:
1、static修饰成员变量
2、1、用static修饰的成员变量不属于对象的数据结构,属于类的数据结构。
3、2、static变量是属于类的变量,通常可以通过类名来引用static成员。
4、3、static成员变量和类的信息一起存储在方法区,而不是在堆中,一个类的static变量只有一份,无论这个类创建了多少个对象。
5、
6、2、static修饰方法
7、1、通常的方法都会涉及到对具体对象的操作,这些方法在调用时需要隐式传递对象的引用(this)。
8、2、static修饰的方法则不需要针对某些对象进行操作,其运行结果仅仅与输入的参数有关,调用时直接用类名引用。
9、3、static在调用时没有具体的对象,因此在static方法中不能对非static成员进行访问,static方法的作用在于提供一些“工具方法”和“工厂方法”等。
10、
11、3、static静态块
12、Static块属于类的代码块,在类加载期间指向代码块,只执行一次,可以用来在软件中加载静态资源。
13、
14、4、final修饰变量
15、1、final关键字修饰成员变量,表示变量不可被改变。
16、2、final修饰成员变量的两种方式初始化:
17、a. 声明的同时初始化
18、            b. 构造函数中初始化
19、3、final关键字也可以修饰局部变量,使用之前初始化即可
20、
21、5、final修饰方法
22、1、final关键字修饰的方法不可被重写。
23、2、使一个方法不能被重写的意义在于:防止子类在定义新方法使造成“不间意”重写。
24、
25、6、final修饰类
26、1、final关键字修饰的类不可被继承。
27、2、 JDK中的一些基础类库被定义为final的,例如:String、Math、Integer、Double等。
28、3、使一个类不能继承的意义在于:可以保护类不被继承修改,可以控制滥用继承对系统造成的危害。
29、
30、7、static final常量
31、1、static final修饰的成员变量称为常量,必须声明同时初始化,不可被改变。
32、2、static final常量会在编译期被替换,
33、
34、抽象类描述:(在Java语言中使用abstract class来定义抽象类)
35、在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
36、抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。
父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。
在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。

抽象方法:
1、由abstract修饰
2、只有方法的定义,没有具体的实现(连{ }都没有)
如果一个方法使用 abstract 来修饰,则说明该方法是抽象方法,抽象方法只有声明没有实现。需要注意的是 abstract 关键字只能用于普通方法,不能用于 static 方法或者构造方法中。
抽象方法的 3 个特征如下:
1)抽象方法没有方法体
2)抽象方法必须存在于抽象类中
3)子类重写父类时,必须重写父类所有的抽象方法
注意:在使用 abstract 关键字修饰抽象方法时不能使用 private 修饰,因为抽象方法必须被子类重写,而如果使用了 private 声明,则子类是无法重写的。
抽象类:
1、由abstract修饰
2、包含抽象方法的类必须是抽象类
不包含抽象方法的类也可以声明为抽象类------我乐意
3、抽象类不能被实例化
4、抽象类是需要被继承的,派生类:
4.1、重写所有抽象方法--------常用
4.2、也声明为抽象类----------一般不这么做
5、抽象类的意义:
5.1、封装派生类所共有的属性和行为---------代码复用
5.2、给所有派生类提供统一的类型-----------向上造型
5.3、可以包含抽象方法,为所有派生类提供统一的入口
派生类的具体行为不同,但入口是一致的
设计规则:
1、将派生类所共有的属性和行为,抽到超类中--------抽共性
2、所有派生类的行为都一样,设计普通方法
所有派生类的行为都不一样,设计为抽象方法

接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过实现(implements)接口的方式,从而来实现接口的抽象方法。
接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
接口与类相似点:
1)一个接口可以有多个方法。
2)接口文件保存在 .java 结尾的文件中,文件名使用接口名。
3)接口的字节码文件保存在 .class 结尾的文件中。
4)接口相应的字节码文件必须在与包名称相匹配的目录结构中。
接口与类的区别:
1)接口不能用于实例化对象。
2)接口没有构造方法。
3)接口中所有的方法必须是抽象方法。
4)接口不能包含成员变量,除了 static 和 final 变量。
5)接口不是被类继承了,而是要被类实现。
6)接口支持多继承(接口不能继承类,接口只能继承接口)。
接口特性:
1)接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
2)接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
3)接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
抽象类和接口的区别:
1. 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
2. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
3. 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
注:JDK 1.8 以后,接口里可以有静态方法和方法体了。
十六、内部类
java内部类的几种类型:成员内部类,静态内部类,方法内部类,匿名内部类。
成员内部类:成员内部类是类内部的非静态类。成员内部类不能定义静态方法和变量(final修饰的除外)。这是因为成员内部类是非静态的,类初始化的时候先初始化静态成员,如果允许成员内部类定义静态变量,那么成员内部类的静态变量初始化顺序是有歧义的。
成员内部类的使用方法:
1、 Inner 类定义在 Outer 类的内部,相当于 Outer 类的一个成员变量的位置,Inner 类可以使用任意访问控制符,如 public 、 protected 、 private 等
2、 Inner 类中定义的 test() 方法可以直接访问 Outer 类中的数据,而不受访问控制符的影响,如直接访问 Outer 类中的私有属性a
3、 定义了成员内部类后,必须使用外部类对象来创建内部类对象,而不能直接去 new 一个内部类对象,即:内部类 对象名 = 外部类对象.new 内部类( );
静态内部类:
静态内部类是 static 修饰的内部类,这种内部类的特点是:
1、 静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问。
2、 如果外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员;如果外部类的静态成员与 内部类的成员名称不相同,则可通过“成员名”直接调用外部类的静态成员。
3、 创建静态内部类的对象时,不需要外部类的对象,可以直接创建 内部类 对象名= new 内部类();
方法内部类(局部内部类):
方法内部类就是内部类定义在外部类的方法中,方法内部类只在该方法的内部可见,即只在该方法内可以使用。
需要注意:由于方法内部类不能在外部类的方法以外的地方使用,因此方法内部类不能使用访问控制符和 static 修饰符。
匿名内部类:
匿名类是不能有名称的类,所以没办法引用他们。必须在创建时,作为new语句的一部分来声明他们。但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口。
这种形式的new语句声明一个 新的匿名类,他对一个给定的类进行扩展,或实现一个给定的接口。他还创建那个类的一个新实例,并把他作为语句的结果而返回。要扩展的类和要实现的接口是 new语句的操作数,后跟匿名类的主体。
注意匿名类的声明是在编译时进行的,实例化在运行时进行。这意味着 for循环中的一个new语句会创建相同匿名类的几个实例,而不是创建几个不同匿名类的一个实例。
从技术上说,匿名类可被视为非静态的内 部类,所以他们具备和方法内部声明的非静态内部类相同的权限和限制。
假如要执行的任务需要一个对象,但却不值得创建全新的对象(原因可能 是所需的类过于简单,或是由于他只在一个方法内部使用),匿名类就显得很有用。匿名类尤其适合在Swing应用程式中快速创建事件处理程式。
十七、枚举
枚举是一个被命名的整型常数的集合,用于声明一组带标识符的常数。枚举在曰常生活中很常见,例如一个人的性别只能是“男”或者“女”,一周的星期只能是 7 天中的一个等。类似这种当一个变量有几种固定可能的取值时,就可以将它定义为枚举类型。
在 JDK 1.5 之前没有枚举类型,那时候一般用接口常量来替代。而使用 Java 枚举类型 enum 可以更贴近地表示这种常量。
1、声明枚举
声明枚举时必须使用 enum 关键字,然后定义枚举的名称、可访问性、基础类型和成员等。
任意两个枚举成员不能具有相同的名称,且它的常数值必须在该枚举的基础类型的范围之内,多个枚举成员之间使用逗号分隔。
提示:如果没有显式地声明基础类型的枚举,那么意味着它所对应的基础类型是 int。

2、枚举类
Java 中的每一个枚举都继承自 java.lang.Enum 类。当定义一个枚举类型时,每一个枚举类型成员都可以看作是 Enum 类的实例,这些枚举成员默认都被 final、public, static 修饰,当使用枚举类型成员时,直接使用枚举名称调用成员即可。
所有枚举实例都可以调用 Enum 类的方法
3、为枚举添加方法
Java 为枚举类型提供了一些内置的方法,同时枚举常量也可以有自己的方法。此时要注意必须在枚举实例的最后一个成员后添加分号,而且必须先定义枚举实例。

分配一个新字符串,该字符串包含字符数组参数的子数组中的字符。

offset参数是子数组第一个字符的索引,count参数指定子数组的长度。

复制子数组的内容;字符数组的后续修改不会影响新创建的字符串。

分配一个新字符串,该字符串包含来自Unicode码点数组参数子数组的字符。

offset参数是子数组第一个编码点的索引,count参数指定子数组的长度。

子数组的内容被转换为字符;int数组的后续修改不会影响新创建的字符串。

将字符串转为int类型的值前提是字符内容必须是纯数字

使用包装类进行转换

使用concat方法进行字符串拼接
1、获取字符串长度
2、将字符串转大小写
3、去除字符串两端的空白

使用length()函数获取字符串长度

1、String字符串处理
一、Java定义字符串
二、1
三、字符串是Java中特殊的关,使用方法像一般的基本数据类型,被广泛应用在java编程中, java没有内置的字符串类型,而是在标准Java类库中提供了一个String关来创建和操作字符串。
四、在java中定义一个学特用品筒中的方法是用双引号把它包围起来。这种用双引号提出来的一串字符实际上都是String对象,如字符串“Hello”在端译后面成为String对象,因此也可以通过创建String类的实例来定义字符串。
1、直接定义字符串
2、血液定义字将单是物使用双引导的、物串中的内容,例如“Hello jaw”、“Java输配”物,具体方法是用字符串剂量直接切处化一个String对象,示例如下:
3、String str=“Hello 2ava”:
String(char[]value)
分配一个新的字符串,将参数中的字符数组元素全配交为字符串。该字符数组的内容已被复制,后续对字符数组的修改不会影响新创建的字符
sChar变革的值是字符串“Hello”。切便在创建字符串之后,对a数组中的第2个元素进行了修改,但未影响sChar的值。
4. String(char[]value. int offset, int count)
分配一个新的string,它包含来自 答数组参数一个子数组的字符。offset参数身子数组第一个字符的末引, count参数指定子数组的长度。该子数组的内容已被赋值。 “数组的修改不会影响新创建的字符串。例如:
char a□=(‘W’,‘e’,‘1’,‘T’,‘o’.
String scharenew String(a,1,4);
a[1]= 's ’ :
sChar变量的值是字符串"ellio"。该构造方法使用字符数组中的部分连接元素来创建字符串对象。offset参数指定起始末引角, count 指定载现元素的个数,创建字符串对象后,即使在后面修改了a数相中第2个元素的值,对sChar的值也没有任何影响。
二、String和int的相互转换
1、String转换为int
String 字符串转整型 int 有以下两种方式:

1、Integer.parseInt(str)
2、Integer.valueOf(str).intValue()
2、int转换为String
整型int转String字符串类型有以下3种方法:
1. Strings=String,valueOf(i);
2. Strings=Integer.toStringGi.
3. Strings=“”+"
使用第三种方法相对第一第二种耗时比较大。在使用第一种walueOf()方法时,注意valueOf括号中的值不能为空,否则会报空指针异常(NullPointerException)。
 toString()
toString()可以把一个引用类型转换为Suring字符串类型,是sun公司开发Java的时候为了方便所有类的字符串操作而特意加入的一个方法。
这里chars是存放字符的数组, startindex是字符数组中期望得到的子字符串的首字符下标,numChars指定子字符串的长度。2) parse()
parseXxx(String)这种形式,是指把字符串转换为数值型,其中Xxx对应不同的数据类型,然后转换为Xxx指定的类型,如int型和float型。
3) toString()
toString()可以把一个引用类型转换为Suring字符串类型,是sun公司开发Java的时候为了方便所有类的字符串操作而特意加入的一个方法。
三、字符串拼接(连接)
对于已经定义的字符串,可以对其进行各种操作。连接多个字符串是字符串操作中最简单的一种。通过字符串连接,可以将两个或多个字符串、字符、整数和浮点数等类型的数据连成一个更大的字符串。
String字符串虽然是不可变字符串,但也可以进行拼接只是会产生一个新的对象。String字符串拼接可以使用“+”运算符或String的concat(string str)方法。"+"运算符优势是可以连接任何类型数据拼接成为字符串,而concat方法只能拼接String类型字符串。
1、使用连接运算符“+”
与绝大多数的程序设计语言一样, Java语言允许使用“+”号连接(拼接)两个字符串。“+”远算符是最简单、最快捷,也是使用最多的字符串连接方式。在使用“+”运算符连接字符串和int型(或double型)数据时,“+”将int(或double)型数据自动转换成String类型。
2、使用 concat() 方法
在 Java 中,String 类的 concat() 方法实现了将一个字符串连接到另一个字符串的后面
格式:字符串 1.concat(字符串 2);
3、连接其他类型数据
前面介绍的例子都是字符串与字符串进行连接,其实字符串也可同其他基本数据类型进行连接。如果将字符串同这些数据类型数据进行连接,此时会将这些数据直接转换成字符串。
四、获取字符串长度(length())
1、要获取字符串的长度,可以使用 String 类的 length() 方法,其语法形式如下:
字符串名.length();
五、字符串大小写转换
String 类的 toLowerCase() 方法可以将字符串中的所有字符全部转换成小写,而非字母的字符不受影响。语法格式如下:
字符串名.toLowerCase() // 将字符串中的字母全部转换为小写,非字母不受影响
toUpperCase() 则将字符串中的所有字符全部转换成大写,而非字母的字符不受影响。语法格式如下:

字符串名.toUpperCase()    // 将字符串中的字母全部转换为大写,非字母不受影响

六、去除字符串中的空格(trim())
字符串中存在的首尾空格一般情况下都没有任何意义,如字符串“ Hello ”,但是这些空格会影响到字符串的操作,如连接字符串或比较字符串等,所以应该去掉字符串中的首尾空格,这需要使用 String 类提供的 trim() 方法。
trim() 方法的语法形式如下:

字符串名.trim()
使用 trim() 方法的示例如下:
String str = " hello ";
System.out.println(str.length());    // 输出 7
System.out.println(str.trim().length());    // 输出 5
	如果不确定要操作的字符串首尾是否有空格,最好在操作之前调用该字符串的 trim() 方法去除首尾空格,然后再对其进行操作。
trim() 只能去掉字符串中前后的半角空格(英文空格),而无法去掉全角空格(中文空格)。可用以下代码将全角空格替换为半角空格再进行操作,其中替换是 String 类的 replace() 方法。
```java
str = str.replace((char) 12288, ' ');    // 将中文空格替换为英文空格
str = str.trim();
其中,12288 是中文全角空格的 unicode 编码。
七、截取(提取)子字符串(substring())
		在 String 中提供了两个截取字符串的方法,一个是从指定位置截取到字符串结尾,另一个是截取指定范围的内容。下面对这两种方法分别进行介绍。
1substring(int beginIndex) 形式
		此方式用于提取从索引位置开始至结尾处的字符串部分。调用时,括号中是需要提取字符串的开始位置,方法的返回值是提取的字符串。例如:
String str = "Hello Java";
String result = str.substring(3);
System.out.println(result);    // 输出:lo Java
2substring(int begin,int end) 形式
		此方法中的 begin 表示截取的起始索引,截取的字符串中包括起始索引对应的字符;end 表示结束索引,截取的字符串中不包括结束索引对应的字符,如果不指定 end,则表示截取到目标字符串末尾。该方法用于提取位置 begin 和位置 end 位置之间的字符串部分。
		这里需要特别注意的是, 对于开始位置 begin, Java 是基于字符串的首字符索引为 0 处理的,但是对于结束位置 end,Java 是基于字符串的首字符索引为 1 来处理的,如下图所示。
		注意:substring() 方法是按字符截取,而不是按字节截取

课堂实例:
public class Demo {
    public static void main(String[] args) {
        /**
         * 字符串截取
         * substring(int start): 从指定位置开始截取,start表示开始位置下标
         * substring(int start, int end):截取指定范围内的字符串,含前不含尾
         */
        String number = "522226199999999998";

        String substring = number.substring(14);
        System.out.println(substring);

        System.out.println(number.substring(6, 14));

    }
}
public class Demo01 {
    public static void main(String[] args) {
        /**
         * 将字符数组转为字符串
         */
        char[] ch = new char[]{'H', 'e', 'l', 'l', 'o'};
        // 创建建字符串
        String str = new String(ch);
        System.out.println(str);

        /**
         * 分配一个新字符串,该字符串包含字符数组参数的子数组中的字符。
         * offset参数是子数组第一个字符的索引,count参数指定子数组的长度。
         * 复制子数组的内容;字符数组的后续修改不会影响新创建的字符串。
         */
        char[] ch1 = new char[]{'H', 'e', 'l', 'l', 'o', ',', 'w', 'o', 'r', 'l', 'd'};
        String str1 = new String(ch1, 2, 8);
        System.out.println(str1);

        /**
         * 分配一个新字符串,该字符串包含来自Unicode码点数组参数子数组的字符。
         * offset参数是子数组第一个编码点的索引,count参数指定子数组的长度。
         * 子数组的内容被转换为字符;int数组的后续修改不会影响新创建的字符串。
         */
        int[] arr = new int[]{65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75};
        String str2 = new String(arr, 0, 5);
        System.out.println(str2);
    }
}


public class Demo02 {
    public static void main(String[] args) {
        /**
         * 将字符串转为int类型数据
         *
         * 注意:
         *      将字符串转为int类型的值前提是字符内容必须是纯数字
         */
        // 使用包装类进行转换
        String str1 = "56";

        int num1 = Integer.parseInt(str1);
        System.out.println(num1 + 1);


        int num2 = Integer.valueOf(str1).intValue();
        System.out.println(num2 + 1);

        String str2 = "Hello56";
        String str3 = "12World"; //

        // int num3 = Integer.parseInt(str2); // java.lang.NumberFormatException: For input string: "Hello56"
        int num4 = Integer.parseInt(str3); // java.lang.NumberFormatException: For input string: "12World"

    }
}
public class Demo03 {
    public static void main(String[] args) {
        /**
         * 将int类型数据转为String类型
         */
        // 第一种方式
        int num1 = 56;
        String str = num1 + "";
        System.out.println(str + 1);// 561

        // String s = String.valueOf(i);
        String str2 = String.valueOf(89);
        System.out.println(str2 + 1); // 891

        // String s = Integer.toString(i);
        String str3 = Integer.toString(90);
        System.out.println(str3 + 1); //901

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

        String str = "Hello";
        String s1 = "world";
        /**
         * 字符串+运算
         */
        // 获取系统时间戳
        long start = System.currentTimeMillis();

        for (int i = 0; i < 10000; i++) {
            str += s1;
        }

        long end = System.currentTimeMillis();
        System.out.println(end - start);

        // 使用concat方法进行字符串拼接
        String s2 = "张三";
        String s3 = "李四";
        String s4 = s2.concat(s3);
        System.out.println(s4);

    }
}

public class Demo05 {
    public static void main(String[] args) {
        /**
         * 1、获取字符串长度
         * 2、将字符串转大小写
         * 3、去除字符串两端的空白
         */
        String str = "Hello Java";
        // 使用length()函数获取字符串长度
        System.out.println(str.length());

        // 将字符串转为大写
        System.out.println(str.toUpperCase());

        // 将字符串转小写
        System.out.println(str.toLowerCase());


        String str1 = "              hello                     ";
        System.out.println(str1.length());
        // 取出字符串两端空白
        String str2 = str1.trim();
        System.out.println(str2.length());

    }
}
public class Demo05Test {
    public static void main(String[] args) {
        /**
         * 要求:
         *      用户从控制台输入应该长度为4的验证码,验证码的内容为字符或者数字
         *      后台接收到用户输入内容之后统一将其转为大写和小写
         */
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入长度为4的验证码: ");

        // 接收用户输入的值
        String val = scan.nextLine();
        // 取出val两端的空白
        val = val.trim();
        // 验证长度
        if (val.length() == 4) {
            // 长度为4,则进行转大小写
            System.out.println(val.toUpperCase());
            System.out.println(val.toLowerCase());
        }else{
            System.out.println("您输入的长度有误");
        }
    }
}
补、字符串的分割和截取
八、分割字符串(spilt())
tring 类的 split() 方法可以按指定的分割符对目标字符串进行分割,分割后的内容存放在字符串数组中。该方法主要有如下两种重载形式:

```java
str.split(String sign)
str.split(String sign,int limit)
其中它们的含义如下:
**str:**为需要分割的目标字符串。
**sign:**为指定的分割符,可以是任意字符串。
**limit:**表示分割后生成的字符串的限制个数,如果不指定,则表示不限制,直到将整个目标字符串完全分割为止。
使用分隔符注意如下:
1)“.”和“|”都是转义字符,必须得加“\\”。
如果用“.”作为分隔的话,必须写成`String.split("\\.")`,这样才能正确的分隔开,不能用`String.split(".")`。
如果用“|”作为分隔的话,必须写成`String.split("\\|")`,这样才能正确的分隔开,不能用`String.split("|")`。

2)如果在一个字符串中有多个分隔符,可以用“|”作为连字符,比如:“acount=? and uu =? or n=?”,把三个都分隔出来,可以		用`String.split("and|or")`。

九、案例:截取新闻标题
		在新闻网站中通常以列表的形式显示最新新闻的动态标题。一般情况下,一行显示一条新闻标题,而新闻标题往往比较长,因此需要对它进行截取,将超出部分显示成一个省略号“…”。
public class Demo07 {
    public static void main(String[] args) {
        // 定义存储新闻标题的数组
        String[] news = new String[] { "如何快速掌握Java", "听老王剖析Java中的运算符",
                "学习Java的十大忠告", "你所不知道的java网络编程技巧大全", "Java面试题大全" };

        for (int i = 0; i < news.length; i++) {
            if(news[i].length() > 10) {
                // 截取新闻标题
                System.out.println(news[i].substring(0, 10) + "....");
            }else{
                // 长度不够,不截取
                System.out.println(news[i]);
            }
        }

    }
}
在该程序中,首先定义了存储新闻标题的数组,元素类型为 String 类型,然后循环遍历该数组,在循环体中,判断数组中的元素长度是否大于 10,如果大于,则使用 String 类的 substring() 方法截取前 10 个字符并输出,否则将数组中的元素输出即可。
十、字符串的替换
		因为要截取的是新闻标题中的前 10 个字符,因此,起始位置从 0 开始,结束位置为 10(索引从 1 开始),即使用 substring(0,10) 就完成了新闻标题的截取操作。
1replace() 方法
		replace() 方法用于将目标字符串中的指定字符(串)替换成新的字符(串),其语法格式如下:
字符串.replace(String oldChar, String newChar)
		其中,oldChar 表示被替换的字符串;newChar 表示用于替换的字符串。replace() 方法会将字符串中所有 oldChar 替换成 newChar。
public class Demo08 {
    public static void main(String[] args) {
        /**
         * 字符串替换
         *      replace("o", "v")
         */
        String str = "Hello Jaoa";
        String replace = str.replace("o", "v");
        System.out.println(replace);
        /**
         * 替换敏感字符
         */
        String s = "你个DSB,TMD会不会玩,你就是应该DJB,去NMD";
        s = s.replace("DSB", "*");
        s = s.replace("TMD", "*");
        s = s.replace("DJB", "*");
        s = s.replace("NMD", "*");
        System.out.println(s);
    }
}
1replace() 方法
		replace() 方法用于将目标字符串中的指定字符(串)替换成新的字符(串),其语法格式如下:
字符串.replace(String oldChar, String newChar)
		其中,oldChar 表示被替换的字符串;newChar 表示用于替换的字符串。replace() 方法会将字符串中所有 oldChar 替换成 newChar。
例 1
		创建一个字符串,对它使用 replace() 方法进行字符串替换并输出结果。代码如下:
public static void main(String[] args) {
   String words = "hello java,hello php";
   
   System.out.println("原始字符串是'"+words+"'");
   System.out.println("replace(\"l\",\"D\")结果:"+words.replace("l","D"));
   System.out.println("replace(\"hello\",\"你好\")结果:"+words.replace("hello","你好 "));
   
   words = "hr's dog";
   
   System.out.println("原始字符串是'"+words+"'");
   System.out.println("replace(\"r's\",\"is\")结果:"+words.replace("r's","is"));
}
		输出结果如下所示:
原始字符串是'hello java,hello php'
replace("l","D")结果:heDDo java,heDDo php
replace("hello","你好")结果:你好 java,你好 php
原始字符串是'hr's dog'
replace("r's","is")结果:his dog
2replaceFirst() 方法
		replaceFirst() 方法用于将目标字符串中匹配某正则表达式的第一个子字符串替换成新的字符串,其语法形式如下:
字符串.replaceFirst(String regex, String replacement)
		其中,regex 表示正则表达式;replacement 表示用于替换的字符串。例如:
String words = "hello java,hello php";
String newStr = words.replaceFirst("hello","你好 ");
System.out.println(newStr);    // 输出:你好 java,hello php
3replaceAll() 方法
		replaceAll() 方法用于将目标字符串中匹配某正则表达式的所有子字符串替换成新的字符串,其语法形式如下:
字符串.replaceAll(String regex, String replacement)
		其中,regex 表示正则表达式,replacement 表示用于替换的字符串。例如:
String words = "hello java,hello php";
String newStr = words.replaceAll("hello","你好 ");
System.out.println(newStr);    // 输出:你好 java,你好 php
十一、案例:替换敏感字符
假设有一段文本里面有很多敏感词汇。现在使用 Java 中的字符串替换方法对它进行批量修改和纠正,就可以用到 String 类的 replace() 方法、replaceFirst() 方法和 replaceAll() 方法。
public class Demo08 {
    public static void main(String[] args) {
        /**
         * 字符串替换
         *      replace("o", "v")
         */
        String str = "Hello Jaoa";

        String replace = str.replace("o", "v");
        System.out.println(replace);

        /**
         * 替换敏感字符
         */
        String s = "你个DSB,TMD会不会玩,你就是应该DJB,去NMD";

        s = s.replace("DSB", "*");
        s = s.replace("TMD", "*");
        s = s.replace("DJB", "*");
        s = s.replace("NMD", "*");

        System.out.println(s);

    }
}
# 十二、字符串比较

​		字符串比较是常见的操作,包括比较相等、比较大小、比较前缀和后缀串等。在 Java 中,比较字符串的常用方法有 3 个:equals() 方法、equalsIgnoreCase() 方法、 compareTo() 方法。

## 1equals() 方法

​		equals() 方法将逐个地比较两个字符串的每个字符是否相同。如果两个字符串具有相同的字符和长度,它返回 true,否则返回 false。对于字符的大小写,也在检查的范围之内。equals() 方法的语法格式如下:

```java
str1.equals(str2);
​		str1 和 str2 可以是字符串变量, 也可以是字符串字面量。 例如, 下列表达式是合法的:
```java
"Hello".equals(greeting)
下面的代码说明了 equals() 方法的使用:
java
String str1 = "abc";
String str2 = new String("abc");
String str3 = "ABC";
System.out.println(str1.equals(str2)); // 输出 true
System.out.println(str1.equals(str3)); // 输出 false

public class Demo09 {
public static void main(String[] args) {
/**
* 字符串的比较
* 1、==
* 2、equals()
* 3、equalsIgnoreCase(s2)
*/
String s1 = “java”;
String s2 = “JAVA”;

    System.out.println(s1 == s2);
    System.out.println(s1.equals(s2));
    System.out.println(s1.equalsIgnoreCase(s2));
}

}

2、equalsIgnoreCase() 方法
equalsIgnoreCase() 方法的作用和语法与 equals() 方法完全相同,唯一不同的是 equalsIgnoreCase() 比较时不区分大小写。当比较两个字符串时,它会认为 A-Z 和 a-z 是一样的。
下面的代码说明了 equalsIgnoreCase() 的使用:
java
String str1 = “abc”;
String str2 = “ABC”;
System.out.println(str1.equalsIgnoreCase(str2)); // 输出 true

3、equals()与==的比较

理解 equals() 方法和==运算符执行的是两个不同的操作是重要的。如同刚才解释的那样,equals() 方法比较字符串对象中的字符。而==运算符比较两个对象引用看它们是否引用相同的实例。

​ 下面的程序说明了两个不同的字符串(String)对象是如何能够包含相同字符的,但同时这些对象引用是不相等的:

String s1 = "Hello";
String s2 = new String(s1);
System.out.println(s1.equals(s2)); // 输出true
System.out.println(s1 == s2); // 输出false
变量 s1 指向由“Hello”创建的字符串实例。s2 所指的的对象是以 s1 作为初始化而创建的。因此这两个字符串对象的内容是一样的。但它们是不同的对象,这就意味着 s1 和 s2 没有指向同一的对象,因此它们是不`==`的。
因此,千万不要使用`==`运算符测试字符串的相等性,以免在程序中出现糟糕的 bug。从表面上看,这种 bug 很像随机产生的间歇性错误。
# 十三、字符串查找
在给定的字符串中查找字符或字符串是比较常见的操作。字符串查找分为两种形式:一种是在字符串中获取匹配字符(串)的索引值,另一种是在字符串中获取指定索引位置的字符。
## 1、根据字符查找
String 类的 indexOf() 方法和 lastlndexOf() 方法用于在字符串中获取匹配字符(串)的索引值。
### 1.1indexOf() 方法
indexOf() 方法用于返回字符(串)在指定字符串中首次出现的索引位置,如果能找到,则返回索引值,否则返回 -1。该方法主要有两种重载形式:
`java
str.indexOf(value)
str.indexOf(value,int fromIndex)
其中,str 表示指定字符串;value 表示待查找的字符(串);fromIndex 表示查找时的起始索引,如果不指定 fromIndex,则默认从指定字符串中的开始位置(即 fromIndex 默认为 0)开始查找。
例如,下列代码在字符串“Hello Java”中查找字母 v 的索引位置。
`java
String s = "Hello Java";int size = s.indexOf('v');    // size的结果为8
上述代码执行后 size 的结果为 8, 
### 1.2lastlndexOf() 方法


lastIndexOf() 方法用于返回字符(串)在指定字符串中最后一次出现的索引位置,如果能找到则返回索引值,否则返回 -1。该方法也有两种重载形式:
java
str.lastIndexOf(value)str.lastlndexOf(value, int fromIndex)
**注意:**lastIndexOf() 方法的查找策略是从右往左查找,如果不指定起始索引,则默认从字符串的末尾开始查找。
## 2、根据索引查找
String 类的 charAt() 方法可以在字符串内根据指定的索引查找字符,该方法的语法形式如下:
`java
**提示:**字符串本质上是字符数组,因此它也有索引,索引从零开始。
public class Demo10 {
    public static void main(String[] args) {
        /**
         * indexOf() 方法用于返回字符(串)在指定字符串中首次出现的索引位置,
         * 如果能找到,则返回索引值,否则返回 -1
         */
        String str = "indexOf() 方法用于返回字符(串)在指定字符串中首次出现的索引位置,如果能找到,则返回索引值,否则返回 -1";
        // 查找 ”字符“
        System.out.println(str.indexOf("字符"));
        System.out.println(str.indexOf("大锤"));
        // 从指定位置开始查找
        System.out.println(str.indexOf('字', 17));

        /**
         * lastIndexOf() 方法用于返回字符(串)在指定字符串中最后一次出现的索引位置,
         * 如果能找到则返回索引值,否则返回 -1。
         */
        String  s = "lastIndexOf() 方法用于返回字符(串)在指定字符串中最后一次出现的索引位置,如果能找到则返回索引值,否则返回 -1。";
        System.out.println(s.lastIndexOf("索引值"));

        /**
         * 案例:用户给定文件名字(完整名字),程序判断文件类型
         */
        Scanner scan = new Scanner(System.in);
        System.out.println("请输入完整的文件名字(包括文件后缀): ");
        String fileName = scan.nextLine();

        // 处理用户输入的内容
        fileName = fileName.toLowerCase();
        fileName = fileName.trim();

        // 获取文件的后缀 a.txt  b.a.exe
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
        System.out.println(suffix);

        // 判断文件的类型
        switch (suffix) {
            case "txt":
                System.out.println("文本文件");
                break;
            case "exe":
                System.out.println("win可执行程序");
                break;
            case "word":
                System.out.println("word文档");
                break;
            case "html":
                System.out.println("网页的文件");
                break;
            default:
                System.out.println("未知的文件");
                break;
        }
    }
}
# 十四、StringBuffer 类
在 Java 中,除了通过 String 类创建和处理字符串之外,还可以使用 StringBuffer 类来处理字符串。StringBuffer 类可以比 String 类更高效地处理字符串。

因为 StringBuffer 类是可变字符串类,创建 StringBuffer 类的对象后可以随意修改字符串的内容。每个 StringBuffer 类的对象都能够存储指定容量的字符串,如果字符串的长度超过了 StringBuffer 类对象的容量,则该对象的容量会自动扩大。

## 1、创建 StringBufferStringBuffer 类提供了 3 个构造方法来创建一个字符串,如下所示:
1StringBuffer() 构造一个空的字符串缓冲区,并且初始化为 16 个字符的容量。
2StringBuffer(int length) 创建一个空的字符串缓冲区,并且初始化为指定长度 length 的容量。
3StringBuffer(String str) 创建一个字符串缓冲区,并将其内容初始化为指定的字符串内容 str,字符串缓冲区的初始容量为 		16 加上字符串 str 的长度。
## 2、追加字符串
StringBuffer 类的 append() 方法用于向原有 StringBuffer 对象中追加字符串。该方法的语法格式如下:
java
StringBuffer 对象.append(String str)
该方法的作用是追加内容到当前 StringBuffer 对象的末尾,类似于字符串的连接
## 3、替换字符
StringBuffer 类的 setCharAt() 方法用于在字符串的指定索引位置替换一个字符。该方法的语法格式如下:
java
StringBuffer 对象.setCharAt(int index, char ch);
该方法的作用是修改对象中索引值为 index 位置的字符为新的字符 ch
public class Demo11 {
    public static void main(String[] args) {
        String str = "hello java";

        // 查找字符
        System.out.println(str.charAt(3));
    }
}
4、反转字符串
		StringBuffer 类中的 reverse() 方法用于将字符串序列用其反转的形式取代。该方法的语法格式如下:
StringBuffer 对象.reverse();
		使用 StringBuffer 类中的 reverse() 方法对字符串进行反转的示例如下:
StringBuffer sb = new StringBuffer("java");
sb.reverse();
System.out.println(sb);    // 输出:avaj
5、删除字符串
StringBuffer 类提供了 deleteCharAt()delete() 两个删除字符串的方法,下面详细介绍。
1deleteCharAt() 方法
deleteCharAt() 方法用于移除序列中指定位置的字符,该方法的语法格式如下:
StringBuffer 对象.deleteCharAt(int index);
deleteCharAt() 方法的作用是删除指定位置的字符,然后将剩余的内容形成一个新的字符串。例如:
StringBuffer sb = new StringBuffer("She");
sb.deleteCharAt(2);
System.out.println(sb);    // 输出:Sh
执行该段代码,将字符串 sb 中索引值为 2 的字符删除,剩余的内容组成一个新的字符串,因此对象 sb 的值为 Sh2delete() 方法
delete() 方法用于移除序列中子字符串的字符,该方法的语法格式如下:
StringBuffer 对象.delete(int start,int end);
其中,start 表示要删除字符的起始索引值(包括索引值所对应的字符),end 表示要删除字符串的结束索引值(不包括索引值所对应的字符)。该方法的作用是删除指定区域以内的所有字符,例如:
StringBuffer sb = new StringBuffer("hello jack");
sb.delete(2,5);
System.out.println(sb);    // 输出:he jack
sb.delete(2,5);
System.out.println(sb);    // 输出:heck
执行该段代码,将字符串“hello jack”索引值为 2(包括)到索引值为 5(不包括)之间的所有字符删除,因此输出的新的字符串的值为“he jack”。
# 十五、StringStringBufferStringBuilder区别

在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。String 类是不可变类,即一旦一个 String 对象被创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁。

Java 提供了两个可变字符串类 StringBufferStringBuilder,中文翻译为“字符串缓冲区”。

StringBuilder 类是 JDK 1.5 新增的类,它也代表可变字符串对象。实际上,StringBuilderStringBuffer 功能基本相似,方法也差不多。不同的是,StringBuffer 是线程安全的,而 StringBuilder 则没有实现线程安全功能,所以性能略高。因此在通常情况下,如果需要创建一个内容可变的字符串对象,则应该优先考虑使用 StringBuilder 类。

StringBufferStringBuilderString 中都实现了 CharSequence 接口。CharSequence 是一个定义字符串操作的接口,它只包括 length()charAt(int index)subSequence(int start, int end) 这几个 API。

StringBufferStringBuilderStringCharSequence 接口的实现过程不一样,如下图 1 所示:

<img src="01-String 字符串处理.assets\image-20220929165136354.png" alt="image-20220929165136354" style="zoom:80%;" />

可见,String 直接实现了 CharSequence 接口,StringBuilderStringBuffer 都是可变的字符序列,它们都继承于 AbstractStringBuilder,实现了 CharSequence 接口。
public class Demo01 {
    public static void main(String[] args) {
        // 创建StringBuffer对象
        StringBuffer sb = new StringBuffer();
        System.out.println(sb.length());

        StringBuffer sb2 = new StringBuffer(32);
        System.out.println(sb2.length());

        StringBuffer sb3 = new StringBuffer("Hello Java");
        System.out.println(sb3.length());

        /*
         *输出字符串的容量大小
         *capacity()方法返回字符串的容量大小
         */
        System.out.println(sb.capacity());
        System.out.println(sb2.capacity());
        System.out.println(sb3.capacity());
    }
}
public class Demo02 {
    public static void main(String[] args) {
        String str = "java";
        StringBuffer sb = new StringBuffer("java");

        // String类的拼接
        long s1 = System.currentTimeMillis();

        for (int i = 0; i < 100000; i++) {
            str = str + "Hello";
        }

        long end1 = System.currentTimeMillis();
        System.out.println(end1 - s1);

        // append方法拼接字符串
        long s2 = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            sb.append("Hello");
        }
        long end2 = System.currentTimeMillis();
        System.out.println(end2 - s2);

        System.out.println(str.equalsIgnoreCase(sb.toString()));

    }
}
public class Demo03 {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("Hello java");

        // 替换字符setCharAt(int index, char ch)
        sb.setCharAt(4, 'O');
        System.out.println(sb.toString());


    }
}

public class Demo04 {
    public static void main(String[] args) {
        /**
         * 字符串反转
         */
        String str = "Hello java";

        StringBuffer sb = new StringBuffer("Hello Java");
        StringBuffer reverse = sb.reverse();
        System.out.println(reverse.toString());

        // 判断回文
        // 上海自来水来自海上
        StringBuffer sb1 = new StringBuffer("上海自来水来自海上");
        // 将sb1反转
        StringBuffer sb2 = sb1.reverse();
        System.out.println(sb1.equals(sb2));

        System.out.println(sb1.toString());

        /**
         * deleteCharAt() 方法用于移除序列中指定位置的字符
         */
        sb1.deleteCharAt(1);
        System.out.println(sb1.toString());

        /**
         * delete() 方法用于移除序列中子字符串的字符
         */
        sb1.delete(1, 4);
        System.out.println(sb1.toString());

        System.out.println("******************************************");
        /**
         * insert()方法插入字符串
         */
        StringBuffer sb3 = new StringBuffer();
        sb3.append("Hello");
        System.out.println(sb3);
        sb3.insert(1, new char[]{'5','A'});
        System.out.println(sb3);

    }
}
String Buliderpublic class Demo01 {
    public static void main(String[] args) {
        /**
         * StringBuilder类
         */
        StringBuffer sf = new StringBuffer("java");
        StringBuilder sl = new StringBuilder("java");

        long sf1 = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            sf.append("Python");
        }
        long sf2 = System.currentTimeMillis();
        System.out.println(sf2-sf1);


        long sl1 = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            sl.append("Python");
        }
        long sl2 = System.currentTimeMillis();
        System.out.println(sl2-sl1);


    }

}

02数字和日期处理
一、Math类的常用方法
Java 中的 +-*/% 等基本算术运算符不能进行更复杂的数学运算,例如,三角函数、对数运算、指数运算等。于是 Java 提供了 Math 工具类来完成这些复杂的运算。
在 JavaMath 类封装了常用的数学运算,提供了基本的数学操作,如指数、对数、平方根和三角函数等。Math 类位于 java.lang 包,它的构造方法是 private 的,因此无法创建 Math 类的对象,并且 Math 类中的所有方法都是类方法,可以直接通过类名来调用它们。
1、静态常量
Math 类中包含 E 和 PI 两个静态常量,正如它们名字所暗示的,它们的值分别等于 e(自然对数)和 π(圆周率)。
例 1
调用 Math 类的 E 和 PI 两个常量,并将结果输出。代码如下:
System.out.println("E 常量的值:" + Math.E);
System.out.println("PI 常量的值:" + Math.PI);
2、求最大值、最小值和绝对值
在程序中常见的就是求最大值、最小值和绝对值问题,如果使用 Math 类提供的方法可以很容易实现。这些方法的说明如下表所示。
方法	说明
static int abs(int a)	返回 a 的绝对值
static long abs(long a)	返回 a 的绝对值
static float abs(float a)	返回 a 的绝对值
static double abs(double a)	返回 a 的绝对值
static int max(int x,int y)	返回 x 和 y 中的最大值
static double max(double x,double y)	返回 x 和 y 中的最大值
static long max(long x,long y)	返回 x 和 y 中的最大值
static float max(float x,float y)	返回 x 和 y 中的最大值
static int min(int x,int y)	返回 x 和 y 中的最小值
static long min(long x,long y)	返回 x 和 y 中的最小值
static double min(double x,double y)	返回 x 和 y 中的最小值
static float min(float x,float y)	返回 x 和 y 中的最小值
## 3、求整运算
Math 类的求整方法有很多,详细说明如下表所示。
| 方法                          | 说明                                                         |
| ----------------------------- | ------------------------------------------------------------ |
| static double ceil(double a)  | 返回大于或等于 a 的最小整数                                  
| static double floor(double a) | 返回小于或等于 a 的最大整数                                  
| static double rint(double a)  | 返回最接近 a 的整数值,如果有两个同样接近的整数,则结果取偶数 |
| static int round(float a)     | 将参数加上 1/2 后返回与参数最近的整数                        
| static long round(double a)   | 将参数加上 1/2 后返回与参数最近的整数,然后强制转换为长整型  |
## 5、指数运算
指数的运算包括求方根、取对数及其求 n 次方的运算。在 Math 类中定义的指数运算方法及其说明如下表所示。
| 方法                                 | 说明                               |
| ------------------------------------ | ---------------------------------- |
| static double exp(double a)          | 返回 e 的 a 次幂                   |
| static double pow(double a,double b) | 返回以 a 为底数,以 b 为指数的幂值 |
| static double sqrt(double a)         | 返回 a 的平方根                    |
| static double cbrt(double a)         | 返回 a 的立方根                    |
| static double log(double a)          | 返回 a 的自然对数,即 lna 的值     |
| static double log10(double a)        | 返回以 10 为底 a 的对数            |

二、生成随机数(random()Random类)

在 Java 中要生成一个指定范围之内的随机数字有两种方法:一种是调用 Math 类的 random() 方法,一种是使用 Random 类。
Random 类提供了丰富的随机数生成方法,可以产生 booleanintlongfloatbyte 数组以及 double 类型的随机数,这是它与 random() 方法最大的不同之处。random() 方法只能产生 double 类型的 0~1 的随机数。
Random 类位于 java.util 包中,该类常用的有如下两个构造方法。
**Random()**该构造方法使用一个和当前系统时间对应的数字作为种子数,然后使用这个种子数构造 Random 对象。
**Random(long seed)**使用单个 long 类型的参数创建一个新的随机数生成器。
Random 类提供的所有方法生成的随机数字都是均匀分布的,也就是说区间内部的数字生成的概率是均等的,在表 1 中列出了 Random 类中常用的方法。
| 方法                    | 说明                                                         |
| ----------------------- | ------------------------------------------------------------ |
| boolean nextBoolean()   | 生成一个随机的 boolean 值,生成 truefalse 的值概率相等   |
| double nextDouble()     | 生成一个随机的 double 值,数值介于 [0,1.0),含 0 而不包含 1.0 |
| int nextlnt()           | 生成一个随机的 int 值,该值介于 int 的区间,也就是 -231~231-1。如果 需要生成指定区间的 int 值,则需要进行一定的数学变换 |
| int nextlnt(int n)      | 生成一个随机的 int 值,该值介于 [0,n),包含 0 而不包含 n。如果想生成 指定区间的 int 值,也需要进行一定的数学变换 |
| void setSeed(long seed) | 重新设置 Random 对象中的种子数。设置完种子数以后的 Random 对象 和相同种子数使用 new 关键字创建出的 Random 对象相同 |
| long nextLong()         | 返回一个随机长整型数字                                       |
| boolean nextBoolean()   | 返回一个随机布尔型值                                         |
| float nextFloat()       | 返回一个随机浮点型数字                                       |
| double nextDouble()     | 返回一个随机双精度值                                         |
课堂实例:
public class Demo02 {
    public static void main(String[] args) {
        /**
         * Random 类提供了丰富的随机数生成方法,可以产生 boolean、int、long、float、byte
         * 数组以及 double 类型的随机数,这是它与 Math.random() 方法最大的不同之处。random()
         * 方法只能产生 double 类型的 0~1 的随机数。
         */
        // 第一种生成随机数的方法,Math.random()
        for (int i = 0; i < 10; i++) {
            // System.out.println(Math.random());
            // 生成10以内的随机数
            // System.out.println((int) (Math.random() * 10));
            // 生成10-20之间的随机数
            // System.out.println(10 + (int) (Math.random() * 10));
            // 生成50以内的随机数
            System.out.println((int) (Math.random() * 50));
        }

        System.out.println("*****************************************");
        // 第二种方式生成随机数,Random rand = new Random(); rand.nextXXX()
        // 创建随机数Random对象
        Random rand = new Random();
        for (int i = 0; i < 10; i++) {
            // System.out.println(rand.nextInt(10));
            System.out.println(rand.nextDouble());
        }


    }
}



数字格式化


代码:
package com.zpark.math;

import java.text.DecimalFormat;

public class Demo03 {
    public static void main(String[] args) {
        /**
         * 数字格式化
         */
        // 实例化数字格式化对象,并且指定格式
        DecimalFormat df1 = new DecimalFormat("0.0");
        DecimalFormat df2 = new DecimalFormat("#.#");
        DecimalFormat df3 = new DecimalFormat("000.000");
        DecimalFormat df4 = new DecimalFormat("###.###");

        // 格式化 3789.14159
        double d1 = 3789.14159;
        System.out.println(df1.format(d1));
        System.out.println(df2.format(d1));
        System.out.println(df3.format(d1));
        System.out.println(df4.format(d1));

        // 格式化1999
        int d2 = 1999;
        System.out.println(df1.format(d2));
        System.out.println(df2.format(d2));
        System.out.println(df3.format(d2));
        System.out.println(df4.format(d2));

    }
}

java大数字运算

	在 Java 中提供了用于大数字运算的类,即 java.math.BigInteger 类和 java.math.BigDecimal 类。这两个类用于高精度计算,其中 BigInteger 类是针对整型大数字的处理类,而 BigDecimal 类是针对大小数的处理类。
代码:
package com.zpark.math;

import java.math.BigDecimal;

public class Demo04 {
    public static void main(String[] args) {
        /**
         * java大数字运算
         */
        BigDecimal bd = new BigDecimal(3.14159263578461259445);
        bd = bd.add(new BigDecimal(3.14159263578461259445));
        System.out.println(bd);

    }
}


Java时间日期的处理

DateDate 类表示系统特定的时间戳,可以精确到毫秒。Date 对象表示时间的默认顺序是星期、月、日、小时、分、秒、年。

代码:
package com.zpark.data;

import java.util.Date;

public class Demo01 {
    public static void main(String[] args) {
        /**
         * date类简介
         */
        // 获取系统当前时间
        Date date = new Date();
        System.out.println(date);

        // 创建date对象,并且指定时间
        Date d1 = new Date(60000);
        System.out.println(d1);

        //判断此日期是否在指定日期之后
        boolean after = date.after(d1);
        System.out.println(after);

        // 判断此日期是否在指定日期之前
        boolean before = date.before(d1);
        System.out.println(before);

        // 比较两个日期的顺序 返回1表示date在d1之后,0表示相等(同一时刻), -1表示之前
        int i = date.compareTo(d1);
        System.out.println(i);

        // 获取毫秒值
        System.out.println(date.getTime());
        System.out.println(System.currentTimeMillis());

        System.out.println(date.getHours());
    }
}

Calendar 类

代码:
package com.zpark.date;

import java.util.Calendar;

public class Demo02 {
    public static void main(String[] args) {
        /**
         * Calendar 类
         */
        // Calendar 类对象
        Calendar cl = Calendar.getInstance();
        // 获取一星期的第一天。根据不同的国家地区,返回不同的值
        System.out.println(cl.getFirstDayOfWeek());

        int year = cl.get(Calendar.YEAR); // 获取当前年份
        System.out.println("现在是" + year + "年");


    }
}

日期格式化

代码:
package com.zpark.date;

import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;

public class Demo03 {
    public static void main(String[] args) throws ParseException {
        /**
         * 日期格式化
         */
        DateFormat df = DateFormat.getDateInstance();
        // 将 Date 格式化日期/时间字符串
        System.out.println(df.format(new Date()));

        DateFormat sf1 = DateFormat.getDateTimeInstance();
        System.out.println(sf1.format(new Date()));

        String time = "2022-10-19 16:08:28";
        Date d1 = DateFormat.getTimeInstance().parse(time);
        System.out.println(d1);

    }
}

DateFormatDateFormat 是日期/时间格式化子类的抽象类,它以与语言无关的方式格式化并解析日期或时间。日期/时间格式化子类(如 SimpleDateFormat)允许进行格式化(也就是日期→文本)、解析(文本→日期)和标准化日期。
代码:
package com.zpark.date;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class Demo04 {
    public static void main(String[] args) {
        /**
         * 如果使用 DateFormat 类格式化日期/时间并不能满足要求,
         * 那么就需要使用 DateFormat 类的子类——SimpleDateFormat。
         */
        Date date = new Date();
        // 格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 这是今年第D天 HH时mm分ss秒SSS毫秒 今天是星期E",
                Locale.CHINA);

        // 格式化日期
        String format = sdf.format(date);
        System.out.println(format);

        // 格式化日期
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
        System.out.println(sdf1.format(new Date()));
    }
}


三、内置类及包装类

包装类、装箱和拆箱

包装类
Java 的设计中提倡一种思想,即一切皆对象。但是从数据类型的划分中,我们知道 Java 中的数据类型分为基本数据类型和引用数据类型,但是基本数据类型怎么能够称为对象呢?于是 Java 为每种基本数据类型分别设计了对应的类,称之为包装类(Wrapper Classes),也有地方称为外覆类或数据类型类。


装箱和拆箱
基本数据类型转换为包装类的过程称为装箱,例如把 int 包装成 Integer 类的对象;包装类变为基本数据类型的过程称为拆箱,例如把 Integer 类的对象重新简化为 int。

代码:
package com.zpark.内置类和包装类;

public class Demo01 {
    public static void main(String[] args) {
        /**
         * 拆箱与装箱:
         *      拆箱:将包装类转为基本数据类型
         *      装箱:将基本数据类型转为包装类
         */
        int num = 1919;
        Integer i1 = num;// 装箱
        int number = i1;// 拆箱

    }

}

ObjectObjectJava 类库中的一个特殊类,也是所有类的父类。也就是说,Java 允许把任何类型的对象赋给 Object 类型的变量。当一个类被定义后,如果没有指定继承的父类,那么默认父类就是 Object 类

代码:
package com.zpark.内置类和包装类;

import java.io.Serializable;
import java.util.Objects;

public class Demo02 implements Serializable {
    private Integer num = 3;
    public static void main(String[] args) {
        /**
         * object类:
         */
        Demo02 d1 = new Demo02();
        System.out.println(d1.toString());

        Demo02 d2 = new Demo02();
        System.out.println(d2.hashCode() + ": " + d1.hashCode());

        d2.equals(d1);
        String s1 = "Hello";
//        s1.equals()

        Demo02 d3 = new Demo02();
        // 获取字节码对象
        Class<? extends Demo02> aClass = d3.getClass();
        System.out.println(aClass.getName());
        System.out.println(aClass.getPackage());

        // 获取父类的名字
        System.out.println(aClass.getSuperclass().getName());
        // 获取父类的包名
        System.out.println(aClass.getSuperclass().getPackage());

        // 获取实现的接口信息
        Class<?>[] interfaces = aClass.getInterfaces();
        for (int i = 0; i < interfaces.length; i++) {
            System.out.println(interfaces[i]);
        }

        // 接收任意数据类型
        int num = 3;
        Object o1 = num;
        Object o2 = d3;
        Object o3 = "";

    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Demo02)) return false;
        Demo02 demo02 = (Demo02) o;
        return Objects.equals(num, demo02.num);
    }

    @Override
    public int hashCode() {
        return Objects.hash(num);
    }

    @Override
    public String toString() {
        return "Demo02{" +
                "num=" + num +
                '}';
    }
}

IntegerInteger 类在对象中包装了一个基本类型 int 的值。Integer 类对象包含一个 int 类型的字段。此外,该类提供了多个方法,能在 int 类型和 String 类型之间互相转换,还提供了处理 int 类型时非常有用的其他一些常量和方法。

代码:
package com.zpark.内置类和包装类;

public class Demo03 {
    public static void main(String[] args) {
        /**
         * integer类
          */
        Integer intg1 = new Integer("798");
        // 以 int 类型返回该 Integer 的值
        System.out.println(intg1.intValue() + 1);

        // 返回保存指定的 String 值的 Integer 对象
        Integer value = Integer.valueOf("10000");

        // 获取最大值和最小值
        System.out.println(Integer.MAX_VALUE);
        System.out.println(Integer.MIN_VALUE);

        System.out.println(Integer.SIZE);
        System.out.println(Integer.TYPE);


    }
}


SystemSystem 类位于 java.lang 包,代表当前 Java 程序的运行平台,系统级的很多属性和控制方法都放置在该类的内部。由于该类的构造方法是 private 的,所以无法创建该类的对象,也就是无法实例化该类。

代码:
package com.zpark.内置类和包装类;

import java.util.Enumeration;
import java.util.Properties;

public class Demo04 {
    public static void main(String[] args) {
        /**
         * System类
         */
        System.out.println(12);
        // System.in.
        System.err.println(12);

        // 调用垃圾回收器
        System.gc();

        // 获取properties对象
        Properties properties = System.getProperties();
        Enumeration<Object> keys = properties.keys();
        // 循环取数据
        while (keys.hasMoreElements()) {
            // 有下一个元素,取元素
            String key = (String) keys.nextElement();
            String value = properties.getProperty(key);

            System.err.println(key + "------" + value);
        }

        // 退出程序
        System.exit(0);

        System.out.println("程序还未退出");
    }
}


JDK自带记录日志类

代码:
package com.zpark.内置类和包装类;

import java.util.logging.Level;
import java.util.logging.Logger;

public class Demo05 {
    public static void main(String[] args) {
        /**
         * Java自带日志信息类
         */
        Logger.getGlobal().info("打印日志信息");

        int num = 32;
        Logger.getGlobal().info("定义了int类型的num变量,值为:" + num);

        Logger.getGlobal().log(Level.WARNING, "这是警告信息");

        Logger.getGlobal().severe("这是严重的情况");
    }
}


异常处理

计算机程序的编写也需要考虑处理这些异常情况。异常(exception)是在运行程序时产生的一种异常情况,已经成为了衡量一门语言是否成熟的标准之一。目前的主流编程语言,如 C++、c#、RubyPython 等大都提供了异常处理机制。

Java 中的异常又称为例外,是一个在程序执行期间发生的事件,它中断正在执行程序的正常指令流。为了能够及时有效地处理程序中的运行错误,必须使用异常类,这可以让程序具有极好的容错性且更加健壮。

              在 Java 中一个异常的产生,主要有如下三种原因:

                            1Java 内部错误发生异常,Java 虚拟机产生的异常。

                            2、编写的程序代码中的错误所产生的异常,例如空指针异常、数组越界异常等。

                            3、通过 throw 语句手动生成的异常,一般用来告知该方法的调用者一些必要信息。

              Java 通过面向对象的方法来处理异常。在一个方法的运行过程中,如果发生了异常,则这个方法会产生代表该异常的一个对象,并把它交给运行时的系统,运行时系统寻找相应的代码来处理这一异常。

              我们把生成异常对象,并把它提交给运行时系统的过程称为拋出(throw)异常。运行时系统在方法的调用栈中查找,直到找到能够处理该类型异常的对象,这一个过程称为捕获(catch)异常。

为了能够及时有效地处理程序中的运行错误,Java 专门引入了异常类。

Error(错误)和 Exception(异常)都是 java.lang.Throwable 类的子类,在 Java 代码中只有继承了 Throwable 类的实例才能被 throw 或者 catchExceptionError 体现了 Java 平台设计者对不同异常情况的分类,Exception 是程序正常运行过程中可以预料到的意外情况,并且应该被开发者捕获,进行相应的处理。Error 是指正常情况下不大可能出现的情况,绝大部分的 Error 都会导致程序处于非正常、不可恢复状态。所以不需要被开发者捕获。

              Error 错误是任何处理技术都无法恢复的情况,肯定会导致程序非正常终止。并且 Error 错误属于未检查类型,大多数发生在运行时。Exception 又分为可检查(checked)异常和不检查(unchecked)异常,可检查异常在源码里必须显示的进行捕获处理,这里是编译期检查的一部分。不检查异常就是所谓的运行时异常,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译器强制要求。

              如下是常见的 ErrorException1)运行时异常(RuntimeException): ​                            NullPropagation:空指针异常; ​                       ClassCastException:类型强制转换异常 ​                          IllegalArgumentException:传递非法参数异常 ​                       IndexOutOfBoundsException:下标越界异常 ​                        NumberFormatException:数字格式异常

              2)非运行时异常: ​                        ClassNotFoundException:找不到指定 class 的异常 ​                           IOException:IO 操作异常

              3)错误(Error): ​                         NoClassDefFoundError:找不到 class 定义异常 ​                          StackOverflowError:深递归导致栈被耗尽而抛出的异常 ​                       OutOfMemoryError:内存溢出异常

Java 的异常处理通过 5 个关键字来实现:trycatchthrowthrowsfinallytry catch 语句用于捕获并处理异常,finally 语句用于在任何情况下(除特殊情况外)都必须执行的代码,throw 语句用于拋出异常,throws 语句用于声明可能会出现的异常。

              Java 的异常处理机制提供了一种结构性和控制性的方式来处理程序执行期间发生的事件。异常处理的机制如下: ​                          1、在方法中用 try catch 语句捕获并处理异常,catch 语句可以有多个,用来匹配多个异常。 ​                          2、对于处理不了的异常或者要转型的异常,在方法的声明处通过 throws 语句拋出异常,即由上层的调用方法来处理。

try catchJava 的异常处理通过 5 个关键字来实现:trycatchthrowthrowsfinallytry catch 语句用于捕获并处理异常,finally 语句用于在任何情况下(除特殊情况外)都必须执行的代码,throw 语句用于拋出异常,throws 语句用于声明可能会出现的异常。

​在 Java 中通常采用 try catch 语句来捕获异常并处理。

注意:try...catchif...else 不一样,try 后面的花括号{ }不可以省略,即使 try 块里只有一行代码,也不可省略这个花括号。与之类似的是,catch 块后的花括号{ }也不可以省略。另外,try 块里声明的变量只是代码块内的局部变量,它只在 try 块内有效,其它地方不能访问该变量。

多重catch语句

如果 try 代码块中有很多语句会发生异常,而且发生的异常种类又很多。那么可以在 try 后面跟有多个 catch 代码块。

在多个 catch 代码块的情况下,当一个 catch 代码块捕获到一个异常时,其它的 catch 代码块就不再进行匹配。

              注意:当捕获的多个异常类之间存在父子关系时,捕获异常时一般先捕获子类,再捕获父类。所以子类异常必须在父类异常的前面,否则子类捕获不到。

try catch finally语句

在实际开发中,根据 try catch 语句的执行过程,try 语句块和 catch 语句块有可能不被完全执行,而有些处理代码则要求必须执行。

使用 try-catch-finally 语句时需注意以下几点: ​                     

1、异常处理语法结构中只有 try 块是必需的,也就是说,如果没有 try 块,则不能有后面的 catch 块和 finally 块; ​                        

2catch 块和 finally 块都是可选的,但 catch 块和 finally 块至少出现其中之一,也可以同时出现; ​                         

3、可以有多个 catch 块,捕获父类异常的 catch 块必须位于捕获子类异常的后面; ​

4、不能只有 try 块,既没有 catch 块,也没有 finally 块; ​                     

5、多个 catch 块必须位于 try 块之后,finally 块必须位于所有的 catch 块之后。 ​ 

6finallytry 语句块匹配的语法格式,此种情况会导致异常丢失,所以不常见。

       一般情况下,无论是否有异常拋出,都会执行 finally 语句块中的语句

throws 声明异常

            当一个方法产生一个它不处理的异常时,那么就需要在该方法的头部声明这个异常,以便将该异常传递到方法的外部进行处理。使用 throws 声明的方法表示此方法不处理异常。

使用 throws 声明抛出异常的思路是,当前方法不知道如何处理这种类型的异常,该异常应该由向上一级的调用者处理;如果 main 方法也不知道如何处理这种类型的异常,也可以使用 throws 声明抛出异常,该异常将交给 JVM 处理。JVM 对异常的处理方法是,打印异常的跟踪栈信息,并中止程序运行,这就是前面程序在遇到异常后自动结束的原因。

方法重写时声明抛出异常的限制

              使用 throws 声明抛出异常时有一个限制,是方法重写中的一条规则:子类方法声明抛出的异常类型应该是父类方法声明抛出的异常类型的子类或相同,子类方法声明抛出的异常不允许比父类方法声明抛出的异常多。

throw 拋出异常

       与 throws 不同的是,throw 语句用来直接拋出一个异常,后接一个可拋出的异常类对象

       其中,ExceptionObject 必须是 Throwable 类或其子类的对象。如果是自定义异常类,也必须是 Throwable 的直接或间接子类

当 throw 语句执行时,它后面的语句将不执行,此时程序转向调用者程序,寻找与之相匹配的 catch 语句,执行相应的异常处理程序。如果没有找到相匹配的 catch 语句,则再转向上一层的调用程序。这样逐层向上,直到最外层的异常处理程序终止程序并打印出调用栈情况。

throws 关键字和 throw 关键字在使用上的几点区别如下:            1throws 用来声明一个方法可能抛出的所有异常信息,表示出现异常的一种可能性,但并不一定会发生这些异常;throw 则是指拋出的一个具体的异常类型,执行 throw 则一定抛出了某种异常对象。 通常在一个方法(类)的声明处通过 throws 声明方法(类)可能拋出的异常信息,而在方法(类)内部通过 throw 声明一个具体的异常信息。           2throws 通常不用显示地捕获异常,可由系统自动将所有捕获的异常信息抛给上级方法; throw 则需要用户自己捕获相关的异常,而后再对其进行相关包装,最后将包装后的异常信息抛出。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值