《Java基础》从入门到放弃系列 万字超详

Javase详细教程


文章目录


前言

Java SE(Java Standard Edition,Java 标准版)是Java技术的核心和基础,是Java ME和Java EE编程的基础 [1] 。Java SE是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台的总称。用Java实现的Hot Java浏览器(支持Java applet)显示了Java的魅力:跨平台、动态的Web、Internet计算。从此,Java被广泛接受并推动了Web的迅速发展,常用的浏览器均支持Java applet


一、Java语言概述

1.1开发环境的搭建

1.1.1 JDK下载与安装

JDK下载官方网站:
JDK19下载链接

注意:
需要注意下载对应不同操作系统版本的JDK

1.1.2 JDK、JRE、JVM的关系

JDK=JRE + 开发工具集(例如Javac编译工具)
JRE=JVM + JAVA SE标准类库

JRE:是Java程序的运行时环境,包含JVM和运行时所需要的核心类库;
JDK:是Java程序开发工具包,包含JRE和开发人员使用的工具;
我们想要运行一个已有的Java程序,只需要安装JRE即可;
我们想要开发一个全新的Java程序,那么必须安装JDK;

关系图

1.1.3 path环境变量的配置

path环境变量:windows操作系统执行命令时所要搜寻的路径
为什么要配置path:希望java的开发工具(javac.exe,java.exe)在任何的文件路径下都可以执行成功

1.2 注释和API文档的使用

1.2.1 注释(Comment)

类型格式
单行注释// 注释信息
多行注释/*注释信息 * /
文档注释/**注释信息 * /

作用:
① 对所写的程序进行解释说明,增强可读性。方便自己,方便别人
② 调试所写的代码

特点:
①单行注释和多行注释,注释了的内容不参与编译
② 注释内容可以被JDK提供的工具 javadoc 所解析,生成一套以网页文件形式体现的该程序的说明文档
③ 多行注释不可以嵌套使用

1.2.2 Java API 文档

API文档:针对于提供的类库如何使用,给的一个说明书(就如你去外面买的数码产品使用的说明书)
javaAPI文档入口

二、Java基本语法

2.1 关键字与标识符

2.1.1 关键字

定义:
被Java语言赋予了特殊含义,用做专门用途的字符串
特点:
关键字中所有的字母都是为小写

在这里插入图片描述
在这里插入图片描述

我们在命名的时候一定要避免与关键字进行冲突

2.1.2 标识符的使用

定义:就是给类、方法、变量等起名字的符号

标识符定义的规则:
1、由26个英文字母大小写、0-9、_或$组成
2、数字不可以开头
3、不可以使用关键字和保留字,但能包含关键字和保留字
4、严格区分大小写,长度没有限制
5、不能包含空格

包名:多单词组成时所有字母需要小写:aaabbbccc
类名、接口名:多单词组成时,所有单词的首字母大写:AaaBbbCcc
变量名:所有字母都大写,多单词时每个单词用下划线连接:AAA_BBB_CCC

我们在起名字的时候,最好就是要起的有意义,要做到“见名知意”的效果,这样子在我们写代码的时候能过提高阅读性

2.2 变量的使用

定义:
变量的组成:变量类型 变量名称 变量的值
取值格式:变量名称

变量定义格式:
数据类型 变量名称=变量值
例如:int a = 100

2.2.1 数据类型

请添加图片描述

变量的分类:自己要按照我们声明都位置不同
成员变量:在方法体外,类体内声明的变量
局部变量:在方法体内部声明的变量

请添加图片描述

数据类型内存占用和取值范围

类型范围
byte-128~127
short-32768-32767
int-2的31次方到2的31次方-1
long-2的63次方到2的63次方-1
float负数范围:-3.402823E+38到-1.401298E-45
正数范围 :1.401298E-45到3.402823E+38
double负数范围:-1.797693E+308到-4.9000000E-324
正数范围:4.9000000E到1.797693E+308
char0~65535
booleantrue、false

详细说明

整型:(byte、short、int、long)
①声明long型变量,必须以“l”或“L”结尾
②定义整型变量时,使用int型
③整型的常量,默认类型是int

浮点型:(float、double)
①浮点型,表示带小数点的数值
②float表示数值的范围比long大
③定义float类型变量时,变量要以“f”或“F”结尾
④定义浮点类型变量时,使用double型
⑤浮点型的常量,默认类型是double

布尔型:boolean
①只能取两个值:false/true
②一般使用在条件判断、循环结构中

字符型:char
①定义char型变量,通常使用一对 ’ ‘,内部只能写一个字符
②表示方式:1、声明一个字符 2、转义字符 3、直接使用Unicode值(统一码)来表示字符型常量

2.2.2 变量使用的注意点

①变量一般都是先声明,后使用
②变量都定义在其作用域内,在作用域内,它是有效的,反之,则不生效
③在同一个作用域内,不可以声明两个同名的变量

2.2.3 基本数据类型变量间的运算规则

自动类型转换

定义:
容量小的类型自动转换为容量大的数据类型

在这里插入图片描述

①byte、short、char之间不会相互转换,他们三者在计算时首先转换为int类型
②boolean类型不能与其他类型运算
③当把任何基本数据类型的值和字符串(String)进行连接运算时,基本数据类型的值将自动转化为字符串(String)类型

强制类型转换(不推荐使用)

①需要使用强转符:()
②强制类型转换,可能导致精度损失
③boolean类型不可以转换为其它的数据类型

String与8种基本数据类型之间的运算

①String属于引用数据类型,亦为字符串
②声明String类型变量时,使用一对" "
③String可以与8种基本数据类型变量做运算,运算时只能使用”+“
④任何数据类型和String类型结果+,结果依旧是String类型

2.3 运算符

运算符:对常量或者变量进行操作的符号
表达式:用运算符把常量或者变量连接起来符合
如:int a=0;
int b=1;
int c=a+b;

2.3.1 算术运算符

运算符运算
+正号
-负号
+
-
*
/
%取模
++自增前/后
自减前/后
+字符串连接

自增或自减就不详细介绍了,搞不懂的同学可以进入我的另一篇文章中算数运算符的相关内容,这里有介绍—>javascript基本语法

2.3.2 关系运算符

比较运算符的结果都是boolean型,也就是要么是true,要么是false

注意:
千万不要“==”误写成“=”,"“==是判断是否相等的关系,”="是赋值

运算符运算
==相等于
!=不等于
<小于
>大于
<=小于等于
>=大于等于
instanceof检查是否是类的对象

2.3.3 逻辑运算符

逻辑运算符把各个运算的关系表达式连接起来组成一个复杂的逻辑表达式,以判断程序中的表达式是否成立,判断的结果是 true 或 false

& — 逻辑与      | — 逻辑或     !— 逻辑非      && — 短路与     || — 短路或     ^—逻辑异或

在这里插入图片描述

2.3.4 位运算符

在这里插入图片描述

2.3.5 三元运算符

格式:
关系表达式 ? 表达式1 : 表达式2;

运算流程

  • 先对条件表达式求值判断
  • 如果判断结果为true,则执行语句1,并返回执行结果
  • 如果判断结果为false,则执行语句2,并返回执行结果

2.3.6 运算符的优先级

在这里插入图片描述

2.4 流程控制

顺序结构
程序从上到下逐行的执行,中间没有任何的判断和跳转

分支结构:
根据条件,选择性的执行某段代码
有if…else和switch-case两种分支语句

循环结构:
根据循环条件,重复性的执行某段代码
有while、do…while、for三种循环语句

2.4.1 if-else条件判断结构

结构一:

if(条件表达式){
	执行表达式
}

请添加图片描述

结构二:

if(条件表达式){
	执行表达式1
}else{
	执行表达式2
}

请添加图片描述

结构三:

if(条件表达式){
	执行表达式1
}else if(条件表达式){
	执行表达式2
}else if(条件表达式){
	执行表达式3
}
...
else{
	执行表达式n
}

请添加图片描述

说明:
1、else结构是可选的
2、针对于条件表达式:
①如果多个条件表达式之间是”互斥“关系,条件判断语句及执行语句间顺序无所谓
②当多个条件是“包含”关系时,“小上大下 / 子上父下”
③if-else语句结构,根据需要可以嵌套使用
④语句块只有一条执行语句时,一对{}可以省略,但建议保留
⑤条件表达式必须是布尔表达式(关系表达式或逻辑表达式)、布尔变量

public class AgeTest{
public static void main(String args[]){
int age = 95;
if (age< 0) {
System.out.println("不可能!");
} else if (age>250) {
System.out.println("我滴个姥姥,妖怪吧");
} else {
System.out.println(“老衲芳龄 " + age +" ");
} } }

2.4.2 switch-case结构

switch(表达式){
case 常量1:
	执行语句1;
	//break;
case 常量2:
	执行语句2;
	//break;
...
default:
	执行语句n;
	//break;
}
String season = "summer";
switch (season) {
case "spring":
System.out.println("春天");
break;
case "summer":
System.out.println("夏天");
break;
case "autumn":
System.out.println("秋天");
break;
case "winter":
System.out.println("冬天");
break;
default:
System.out.println("季节输入有误");
break; }

说明:
①switch(表达式)中表达式的值必须是下述几种类型之一:byte,short,char,int,枚举 (jdk 5.0),String (jdk 7.0)
②case子句中的值必须是常量,不能是变量名或不确定的表达式值
③同一个switch语句,所有case子句中的常量值互不相同
④break语句用来在执行完一个case分支后使程序跳出switch语句块;如果没有break,程序会顺序执行到switch结尾
⑤default子句是可任选的。同时,位置也是灵活的。当没有匹配的case时,执行default

switch和if语句之间的对比

①如果判断的具体数值不多,而且符合byte、short 、char、int、String、枚举等几种类型。虽然两个语句都可以使用,建议使用swtich语句。因为效率稍高
②对区间判断,对结果为boolean类型判断,使用if,if的使用范围更广。也就是说,使用switch-case的,都可以改写为if-else

2.4.3 for循环

语法格式

for (①初始化部分; ②循环条件部分; ④迭代部分){ 
		③循环体部分;

执行过程

①-②-③-④-②-③-④-②-③-④-…-②

说明:
②循环条件部分为boolean类型表达式,当值为false时,退出循环
①初始化部分可以声明多个变量,但必须是同一个类型,用逗号分隔
④可以有多个变量更新,用逗号分隔

public class ForLoop {
public static void main(String args[]) {
int num = 0;
for (int i = 1; i <= 100; i++) {
num += i; }
System.out.println("num=" + num);
} }

2.4.4 while循环

语法格式

①初始化部分
while(②循环条件部分){ 
③循环体部分; ④迭代部分; 
}

执行过程

①-②-③-④-②-③-④-②-③-④-…-②

说明:
①不要忘记声明④迭代部分。否则,循环将不能结束,变成死循环
②for循环和while循环可以相互转换

2.4.5 do-while循环

语法格式

①初始化部分;
do{
③循环体部分
④迭代部分
}while(②循环条件部分);

执行过程(与上述两个循环不一致)

①-③-④-②-③-④-②-③-④-…②

说明:
至少执行过一次循环

public class DoWhileLoop {
public static void main(String args[]) {
int result = 0, i = 1;
do {
result += i; i++;
} while (i <= 100);
System.out.println("result=" + result);
} }

2.4.6 特殊关键字的使用(break、contine)

break语句

break语句用于终止某个语句块的执行

public class BreakTest{
public static void main(String args[]){
for(int i = 0; i<10; i++){ 
if(i==6)
break;
System.out.println(" i =" + i);
}
System.out.println("执行结束!");
} }

continue 语句

①continue只能使用在循环结构中
②continue语句用于跳过其所在循环语句块的一次执行,继续下一次循环
③continue语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环

public class ContinueTest{
public static void main(String args[]){
for(int i = 0; i<10; i++){ 
if(i%2==0)
continue;
System.out.println(i);
		}
	}
}

说明:
①break只能用于switch语句和循环语句中
②continue 只能用于循环语句中
③二者功能类似,但continue是终止本次循环,break是终止本层循环
④break、continue之后不能有其他的语句,因为程序永远不会执行其后的语句

2.4.7 Scanner类的使用

我们从键盘中获取不同类型的变量,就需要使用到我们的Scanner类

步骤:
1、导包:import java.util.Scanner
2、Scanner的实例化:Scanner scan = new Scanner(System.in);
3.调用Scanner类的相关方法(next() / nextXxx()),来获取指定类型的变量

注意点:
需要根据相应的方法,来输入指定类型的值。如果输入的数据类型与要求的类型不匹配时,会报异常:InputMisMatchException导致程序终止

2.4.8 Random随机数

作用:用于产生一个随机数

1、导包:import java.util.Random(导包的动作必须出现在类定义上边)
2、创建对象:Random r = new Random(); (上边这个格式里面,r是变量名,可以变,其他的都不允许变)
3、获取随机数:int number = r.nextInt(10); (获取数据的范围:[0,10)包括0,不包括10上边这个格式里面,number是变量名,可以变,数字10可以变,其他都不可以变)

三、数组

数组(Array),是多个相同类型数据按一定顺序排列
的集合,并使用一个名字命名,并通过编号的方式
对这些数据进行统一管理

①数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型
②创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址
③确定了数组的长度就不能修改

3.1 一维数组的使用

声明方式:
type var[] 或 type[] var;

ege:
int a[];
int b[];
double c[];
String[] d;

注意:
我们在声明数组时不能指定其长度=>(int a[5])

3.1.1 一维数组初始化

①Java中的数组必须先初始化,然后才能使用;
②初始化是为了数组中的数组元素分配内存空间,并为每个数组元素赋值

动态初始化:
初始化时只指定数组长度,有系统为数组分配初始值

格式:
数据类型[] 变量名 = new 数据类型[数组长度]

int[] arr = new int[3];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;

String names[];
names = new String[3];
names[0] = “张三”;
names[1] = “李四”;
names[2] = “王五”;

静态初始化:
在定义数组的同时就为数组元素分配空间并赋值

格式:
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3,…};

int  arr[] = new int[]{ 3, 9, 8};
int[] arr = {3,9,8};
String names[] = {"张三","李四","王五" };
//创建基本数据类型的数组
public class Test{
public static void main(String args[]){
int[] a;
a = new int[10];//使用new来创建数组
for ( int i=0; i<10; i++ ) {
s[i] =2*i+1;
System.out.println(s[i]);
} } }

3.1.2 数组元素的访问

①访问的方式:数组名
②数组内部保存的数据的访问方式: 数组名[索引] //编号从0开始
③索引:索引是数组中数据的编号方式,作用就是用于访问数组中的数据,数组名[索引]等同于变量名,是一种特殊的变量名;索引从0开始,是连续的,逐一增加,每次加一

3.1.3 数组元素的分配

Java在运行时,需要分配内存空间,在空间中又进行了区域的划分,每一片区域都有特定的处理数据方式和内存管理方式,空间主要分为堆、栈、方法区等

3.1.4 数组的遍历

格式:数组名称.length(数组长度)

package com.gance.xyz;

/**
 * @author 杰仔正在努力
 * @create 2022-11-06 12:53
 */
public class LengthTest {
    public static void main(String[] args) {
        printArray(new int[]{2,4,6,5,7});
    }

    public static void  printArray(int[] array) {
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + " ");
        }
    }
}

3.1.5 一维数组练习

package com.gance.xyz;

import java.util.Scanner;

/**
 * @author 杰仔正在努力
 * @create 2022-11-06 13:08
 */
public class ArraysDemo1 {
    public static void main(String[] args) {
        //1、使用Scanner,读取学生的个数
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入学生的个数:");
        int number = scanner.nextInt();
        //2、创建数组,存储学生的成绩
        int[] scores = new int[number];
        //3、给数组元素赋值
        System.out.println("请输入"+number+"个学生的成绩");
        for(int i =0;i < scores.length;i++){
            scores[i] = scanner.nextInt();
        }
        //4、获取元素的最大值
        int maxScore = 0;
        for(int i = 0;i < scores.length;i++){
            if(maxScore < scores[i]){
                maxScore = scores[i];
            }
        }

        System.out.println("最高分的成绩为:"+maxScore);
    }
}

精简版

package com.gance.xyz;

import java.util.Scanner;

/**
 * @author 杰仔正在努力
 * @create 2022-11-06 13:08
 */
public class ArraysDemo1 {
    public static void main(String[] args) {
        //1、使用Scanner,读取学生的个数
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入学生的个数:");
        int number = scanner.nextInt();
        //2、创建数组,存储学生的成绩
        int[] scores = new int[number];
        //3、给数组元素赋值
        System.out.println("请输入"+number+"个学生的成绩");
        int maxScore = 0;
        for(int i =0;i < scores.length;i++){
            scores[i] = scanner.nextInt();
            //4、获取元素的最大值
            if(maxScore < scores[i]){
                maxScore = scores[i];
            }
        }
        System.out.println("最高分的成绩为:"+maxScore);
    }
}

3.2 多维数组的使用

格式1(动态初始化):int[][] arr = new int[3][2];
定义了名称为arr的二维数组
二维数组中有3个一维数组
每一个一维数组中有2个元素

格式2(动态初始化):int[][] arr = new int[3][];
二维数组中有3个一维数组。
每个一维数组都是默认初始化值null

格式3(静态初始化):int[][] arr = new int[][]{{3,8,2},{2,7},{9,0,1,6}};
定义一个名称为arr的二维数组,二维数组中有三个一维数组
每一个一维数组中具体元素也都已初始化
第一个一维数组 arr[0] = {3,8,2};
第二个一维数组 arr[1] = {2,7};
第三个一维数组 arr[2] = {9,0,1,6};

3.2.1 二维数组练习:杨辉三角

package com.gance.xyz;

/**
 * @author 杰仔正在努力
 * @create 2022-11-06 21:12
 */
public class YangHuiTest {

    public static void main(String[] args) {
        //1、声明并初始化二维数组
        int[][] yangHui = new int[10][];

        //2、给数组的元素赋值
        for(int i = 0;i < yangHui.length;i++){
            yangHui[i] = new int[i + 1];
            //给首行和末行赋值
            yangHui[i][0] = yangHui[i][i] = 1;
            //给每行的非首末元素赋值
            if(i > 1){
                for(int j = 1;j < yangHui[i].length-1;j++){
                    yangHui[i][j] = yangHui[i-1][j-1] + yangHui[i-1][j];
                }
            }
        }

        //3、遍历二维数组
        for(int i = 0;i < yangHui.length;i++){
            for(int j = 0;j < yangHui[i].length;j++){
                System.out.print(yangHui[i][j] + " ");
            }
            System.out.println();
        }
    }
}

3.3 冒泡排序

冒泡排序的原理非常简单,它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来

排序思想:

  1. 比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数
  3. 针对所有的元素重复以上的步骤,除了最后一个
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较为止

原始版:

//具体过程:
//从第一个元素开始比较相邻的两个元素

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

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

        if(arr[j] > arr[j + 1]{
            int temp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = temp;
        }

}

升级版:

public class BubbleSort implements IArraySort {

    @Override
    public int[] sort(int[] sourceArray) throws Exception {
        // 对 arr 进行拷贝,不改变参数内容
        int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);

        for (int i = 1; i < arr.length; i++) {
            // 设定一个标记,若为true,则表示此次循环没有进行交换,也就是待排序列已经有序,排序已经完成。
            boolean flag = true;

            for (int j = 0; j < arr.length - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int tmp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = tmp;

                    flag = false;
                }
            }

            if (flag) {
                break;
            }
        }
        return arr;
    }
}

3.4 快速排序

快速排序的最坏运行情况是 O(n²),比如说顺序数列的快排。但它的平摊期望时间是 O(nlogn),且 O(nlogn) 记号中隐含的常数因子很小,比复杂度稳定等于 O(nlogn) 的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序

1、从数列中挑出一个元素,称为 “基准”(pivot);
2、重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
3、递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序

3.5 数组的反转

数组的复制:
String[] arr1 = new String[arr.length];
      for(int i = 0;i < arr1.length;i++) {
         arr1[i] = arr[i];
      }
数组的反转:

for(int i = 0;i < arr.length / 2;i++) {
         String temp = arr[i];
         arr[i] = arr[arr.length - i - 1];
         arr[arr.length - i - 1] = temp;
      }
//输出
for(int i = 0;i < arr.length;i++) {
         System.out.println(arr[i] + "\t");
      }

3.6 数组的线性查找

String dest = "BB";
      
      boolean isFlag = true;
      
      for(int i = 0;i < arr.length;i++) {
         
         if(dest.equals(arr[i])) {
            System.out.println("找到了指定的元素:" + i);
            isFlag = false;
            break;
         }
      }
      if(isFlag) {
         System.out.println("很遗憾,没找到哦!");
      }

3.7 数值型的数组

int[] arr = new int[10];
      
      for(int i = 0;i < arr.length;i++) {
         arr[i] = (int)(Math.random() * (99 - 10 + 1) + 10);
      }
      
      for(int i = 0;i < arr.length;i++) {
         System.out.println(arr[i] + "\t");
      }
      System.out.println();
      
    //最大值
      int maxValue = arr[0];
      for(int i = 1;i < arr.length;i++) {
         if(maxValue < arr[i]){
            maxValue = arr[i];
         }
      }
      System.out.println("最大值为:"+ maxValue);
      
    //最小值
      int minValue = arr[0];
      for(int i = 1;i < arr.length;i++) {
         if(minValue > arr[i]) {
            minValue = arr[i];
         }
      }
      System.out.println("最小值为:"+ minValue);
      
    //总和
      int sum = 0;
      for(int i = 0;i <arr.length;i++) {
         sum += arr[i];
      }
      System.out.println("总和为:"+ sum);
      
    //平均值
      int avgValue = sum / arr.length;
      System.out.println("平均数为:"+ avgValue);

3.8 二分法查找

int[] arr2 = new int[] {-98,-34,2,34,54,66,79,105,210,333};
      
      int dest1 = 626;
      int head = 0;
      int end = arr2.length -1;
      boolean isFlag = true;
      while(head <= end) {
         
         int middle = (head + end) /2;
         
         if(dest1 == arr2[middle]) {
            System.out.println("找到了指定元素,位置为:"+ middle);
            isFlag = false;
            break;
         }else if(arr2[middle] > dest1) {
            end = middle - 1;
         }else {
            head = middle +1;
         }
      }
      
      if(isFlag) {
         System.out.println("很遗憾,没有找到啦");
      }

3.9 Arrays工具类的使用

java.util.Arrays类即为操作数组的工具类,包含了用来操作数组(比如排序和搜索)的各种方法

语句作用
boolean equals(int[] a,int[] b)判断两个数组是否相等
String toString(int[] a)输出数组信息
void fill(int[] a,int val)将指定值填充到数组之中
void sort(int[] a)对数组进行排序
int binarySearch(int[] a,int key)对排序后的数组进行二分法检索指定的值

四、面向对象(上)

理解何为面向对象:
面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。 面向对象是相对于面向过程来讲的, 面向对象方法 ,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式

4.1 区分面向对象与面向过程

①面向过程强调的主要是功能行为,以函数为最小单位,考虑怎么做
②面向对象,具备功能的对象,以类或对象为最小单位,考虑谁来做

示意图

4.2 类和对象

概述:
类:是对一类事物的描述,是抽象的、概念上的定义,是对现实生活中的一类具有共同属性和行为的事物的对象
对象:是实际存在的该类事物的每个个体,因此也被称为实例

类的成员有:
属性:对应类中的成员变量
行为:对应类中的成员方法(函数)

属性 = 成员变量 = field = 域、字段
方法= 成员方法 = 函数 = method
创建类的对象 = 类的实例化 = 实例化类

示意图
在这里插入图片描述

package com.gance.xyz.day02;

/**
 * @author 杰仔正在努力
 * @create 2022-11-10 11:25
 */
public class AnimalParent {
    //属性,或成员变量
    private String name;
    private int age;

    //构造器
    public AnimalParent() {
    }


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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


}

语法格式:
修饰符 class 类名{
属性声明;
方法声明:

public class Person{
private int age ; //声明私有变量 age
public void showAge(int i) { //声明方法showAge( )
age = i; 
	}
 }

创建Java自定义类的步骤:
1、定义类(考虑修饰符、类名)
2、编写类的属性(考虑修饰符、属性类型、属性名、初始化值)
3、编写类的方法(考虑修饰符、返回值类型、方法名、形参等)

4.3 创建并使用对象

4.3.1 创建使用对象

//创建对象的步骤
1、创建对象
格式:类名 对象名 = new 类名();
ege : Dog dog = new Dog();

2、使用对象
2.1、使用成员变量
格式:对象名称.变量
ege:dog.name="二哈";

2.2、使用成员方法
格式:对象名称.方法名
ege: dog.lookDoor();

案例题

package com.gance.xyz.day02;

/**
 * @author 杰仔正在努力
 * @create 2022-11-10 22:19
 */
 //学生类
public class Student {
    private String name;
    private int age;
    private String major;
    private String interest;

    public Student() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getMajor() {
        return major;
    }

    public void setMajor(String major) {
        this.major = major;
    }

    public String getInterest() {
        return interest;
    }

    public void setInterest(String interest) {
        this.interest = interest;
    }

    public void say(){
        System.out.println("返回学生的个人信息");
    }
}

package com.gance.xyz.day02;

/**
 * @author 杰仔正在努力
 * @create 2022-11-10 22:20
 */
//老师类
public class Teacher {
    private String name;
    private int age;
    private int teachage;
    private String interest;

    public Teacher() {
    }

    public Teacher(String name, int age, int teachage, String interest) {
        this.name = name;
        this.age = age;
        this.teachage = teachage;
        this.interest = interest;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getTeachage() {
        return teachage;
    }

    public void setTeachage(int teachage) {
        this.teachage = teachage;
    }

    public String getInterest() {
        return interest;
    }

    public void setInterest(String interest) {
        this.interest = interest;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                ", teachage=" + teachage +
                ", interest='" + interest + '\'' +
                '}';
    }

    public void say(){
        System.out.println("输出教师的个人信息");
    }
}
package com.gance.xyz.day02;

/**
 * @author 杰仔正在努力
 * @create 2022-11-10 22:33
 */
 //测试类
public class ParentTest {
    public static void main(String[] args) {
        Student student = new Student();
        student.setAge(18);
        student.setInterest("打游戏");
        student.setMajor("计算机");
        student.setName("小明");
        student.say();
        System.out.println(student.getName()+"今年"+student.getAge()+"专业是"+student.getMajor()+"兴趣是"+student.getInterest());
        System.out.println("---------------------------------------");

        Teacher teacher = new Teacher();
        teacher.setName("张伟");
        teacher.setAge(50);
        teacher.setTeachage(28);
        teacher.setInterest("打球");
        teacher.say();
        System.out.println(teacher.getName()+"今年"+teacher.getAge()+"教龄"+teacher.getTeachage()+"兴趣是"+teacher.getInterest());
    }
}

4.3.2 匿名对象

1、匿名对象就是没有明确的给出名字的对象,是对象的一种简写形式
2、一般匿名对象只使用一次,而且匿名对象只在堆内存中开辟空间,而不存在栈内存的引用
3、我们经常将匿名对象作为实参传递给一个方法调用

public class Person {
    public String name; // 姓名
    public int age; // 年龄

    // 定义构造方法,为属性初始化
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 获取信息的方法
    public void tell() {
        System.out.println("姓名:" + name + ",年龄:" + age);
    }

    public static void main(String[] args) {
        new Person("张三", 28).tell(); // 匿名对象
    }
}

4.4 类的成员—属性(field)

语法格式:
修饰符 数据类型 属性名 = 初始化值

权限修饰符含义
private私有
default默认
protected受保护的
public公开的
public class Person {
	private int age;
	public String name =  "二哈";
	}

属性(成员变量)vs 局部变量
相同点:
1、定义变量格式相同:数据类型 变量名 = 变量值
2、先声明,后使用
3、变量都有对应的作用域

不同点:
1、声明的位置不同:
①成员变量:直接定义在类的一对{}内
②局部变量:声明在方法内,方法形参,代码块,构造器形参,构造器内部的变量
2、内存中位置不同:
①成员变量:堆内存
②局部变量:栈内存
3、生命周期不同:
①成员变量:随着对象的存在而存在
②局部变量:随着方法调用存在而存在,随方法结束消失而消失
4、初始化值不同:
①成员变量:有默认的初始化值
②局部变量:没有默认的初始化值,必须先定义赋值后再使用

4.5 类的成员—方法(method)

何为方法:
1、方法是解决一类问题的步骤的有序组合,用来完成某个功能操作
2、方法包含于类或对象中,不能独立存在
3、使用方法的目的是为了实现代码的重用,简化代码

//格式
方法的声明:权限修饰符 返回值类型 方法名(形参列表){
                            方法体
                        }
举例:
public void eat(){}
public void sleep(int hour){}
public String getName(){}
public String getNation(String nation){}

请添加图片描述

注意:
1、方法被调用一次的话,就会被执行一次
2、没有具体的返回值,返回值类型用关键字void表示,通常,没有返回值的方法中,就不能使用return,但是,如果使用的话,只能"return"表示结束此方法的意思
3、方法中只能调用方法或属性,不可以在方法内部定义方法
4、定义方法时,方法的结果应该返回给调用者,交由调用者处理

案例

/**
 * @author 杰仔正在努力
 * @create 2022-11-11 11:23
 */
public class Person {
    String name;
    int age;
    String set;

    public void study() {
        System.out.println("studying");
    }
    public void showAge() {
        System.out.println("age" + age);
    }
    public int addAge(int i) {
        age += i;
        return age;
    }

}
/**
 * @author 杰仔正在努力
 * @create 2022-11-11 11:31
 */
public class PersonTest {
    public static void main(String[] args) {
        Person p = new Person();
        p.name = "Tom";
        p.age = 18;
        p.set = "男";

        p.study();

        p.showAge();

       int newAge = p.addAge(2);
        System.out.println("新的年龄为" + newAge);
    }
}
package com.gance.xyz.day04;

//定义类Student,包含三个属性:学号number(int),年级state(int),成绩
//score(int)。 创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
//问题一:打印出3年级(state值为3)的学生信息。
//问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息
/**
 * @author 杰仔正在努力
 * @create 2022-11-11 13:44
 */
public class StudentTest {
    public static void main(String[] args) {
        //声明一个student类型的数组
        Student[] stu = new Student[20]; //String[] s = new String[20];

        //循环
        for(int i = 0;i < stu.length;i++){
            stu[i] = new Student();
            //给student对象的属性赋值
            stu[i].number = (i+1);
            stu[i].state = (int) (Math.random() * (6-1+1) + 1);//强转
            stu[i].score = (int)  (Math.random() * (100 - 0 + 1));
        }

        //遍历学生数组
        for(int i = 0;i < stu.length;i++){
            System.out.println(stu[i].info());
        }
        System.out.println("-----------------------------------------");
        //问题一
        for (int i = 0;i < stu.length;i++){
            if(stu[i].state == 3){
                System.out.println(stu[i].info());
            }
        }
        System.out.println("-----------------------------------------");
        //问题二
        for (int i = 0;i < stu.length-1;i++){
            for(int j = 0;j < stu.length-1;j++){
                if(stu[j].score > stu[j + 1].score){
                    Student temp = stu[j];
                    stu[j] = stu[j + 1];
                    stu[j + 1] = temp;
                }
            }
        }
        for(int i = 0;i < stu.length;i++){
            System.out.println(stu[i].info());
        }
    }

}
class Student{
    int number;
    int state;
    int score;

    public String info(){
        return "学号:" + number + "," + "年级:"+ state+ "," + "成绩:" + score;
    }
}

4.6 方法的重载(overload)

重载的概念:
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可

定义:
两同一不同:同一个类、同一个方法名
参数列表不同,参数个数不同,参数类型不同

4.7 可变个数的形参

  1. 可变个数形参的格式:数据类型 . . . 变量名
  2. 当调用可变个数形参的方法时,传入的的参数个数可以是:0个,1个,2个…
  3. 可变个数的形参方法与本类中方法名相同,形参不同的方法之间构成重载
  4. 可变个数的形参方法与本类中方法名相同,形参类型相同的数组之间不构成重载
  5. 可变个数形参在方法形参中,必须声明在末尾
  6. 变个数形参在方法形参中,最多只能声明一个可变形参
public void test(String[] msg){
System.out.println(“含字符串数组参数的test方法 ");
}
public void test1(String book){
System.out.println(****与可变形参方法构成重载的test1方法****");
}
public void test1(String ... books){
System.out.println("****形参长度可变的test1方法****");
}
public static void main(String[] args){
TestOverload to = new TestOverload();
//下面两次调用将执行第二个test方法
to.test1();
to.test1("aa" , "bb");
//下面将执行第一个test方法
to.test(new String[]{"aa"});
}

4.8 方法参数传递和递归

形参:方法定义时,声明在小括号内的参数
实参:方法调用时,实际传递给形参的数据

Java中方法的参数传递方式是通过值传递进行的,就是将实际参数值的副本传入方法内,而参数本身则是不受影响的
①形参是基本数据类型:将实参基本数据类型变量的“数据值”传递给形参
②形参是引用数据类型:将实参引用数据类型变量的“地址值”传递给形参

//该程序创建一个方法,该方法用于交换两个变量
public class TestPassByValue {
  public static void main(String[] args) {
    int num1 = 1;
    int num2 = 2;
 
    System.out.println("交换前 num1 的值为:" +
                        num1 + " ,num2 的值为:" + num2);
 
    // 调用swap方法
    swap(num1, num2);
    System.out.println("交换后 num1 的值为:" +
                       num1 + " ,num2 的值为:" + num2);
  }
  /** 交换两个变量的方法 */
  public static void swap(int n1, int n2) {
    System.out.println("\t进入 swap 方法");
    System.out.println("\t\t交换前 n1 的值为:" + n1
                         + ",n2 的值:" + n2);
    // 交换 n1 与 n2的值
    int temp = n1;
    n1 = n2;
    n2 = temp;
 
    System.out.println("\t\t交换后 n1 的值为 " + n1
                         + ",n2 的值:" + n2);
  }
}

理解递归:
①方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制
②递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环

// 例1:计算1-n之间所自然数的和
	public int getSum(int n) {// 3

		if (n == 1) {
			return 1;
		} else {
			return n + getSum(n - 1);
		}

	}

	// 例2:计算1-n之间所自然数的乘积:n!
	public int getSum1(int n) {

		if (n == 1) {
			return 1;
		} else {
			return n * getSum1(n - 1);
		}

	}

	//例3:已知一个数列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),
	//其中n是大于0的整数,求f(10)的值。
	public int f(int n){
		if(n == 0){
			return 1;
		}else if(n == 1){
			return 4;
		}else{
//			return f(n + 2) - 2 * f(n + 1);
			return 2*f(n - 1) + f(n - 2);
		}
	}

4.9 面向对象的特征—封装

何为封装?
封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏

作用:
隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性

封装性的体现:
①我们将类的属性私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值
②不对外暴露的私有的方法

封装的实现:
1.修改属性私有(设为private)
2.创建getter/setter方法(设为public用于属性的读写)
3.在getter/setter方法中加入属性控制语句(对属性的合法性进行判断)

package com.gance.xyz.day04;

/**
 * @author 杰仔正在努力
 * @create 2022-11-11 23:58
 */
public class Encapsulate {
    private int age;

    public Encapsulate() {
    }

    public Encapsulate(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age < 0 || age > 150){
            System.out.println("输入的数据非法");
            return;
        }
        this.age = age;
    }
}
package com.gance.xyz.day04;

/**
 * @author 杰仔正在努力
 * @create 2022-11-11 23:59
 */
public class EncapsulateTest {
    public static void main(String[] args) {
        Encapsulate e  = new Encapsulate();
        e.setAge(80);
        System.out.println("这个人的年龄为" + e.getAge());
    }
}

4.10 构造器

构造器的特征:
①具有与类相同的名称
②不声明返回值类型
③不能被static、final、synchronized、abstract、native修饰,不能有
return语句返回值

作用:
1、创建对象
2、初始化对象的属性(信息)

语法格式:
修饰符 类名(参数列表){
初始化语句;
}

public class Parent{
	private int age;
	
	public Parent(){
	age = 18;
	}
	
	public void setAge(int i){
		age = i;
		}

	public int getAge(){
		return age;
		}
}

说明:
1、如果没有显示的定义类的构造器的话,则系统默认提供一个空参的构造器
2、一个类中定义多个构造器,彼此构成重载
3、一旦我们显示的定义了类的构造器之后,系统就不再提供默认的空参构造器
4、一个类中至少会有一个构造器

属性赋值的先后顺序:
①默认初始化
②显示初始化
③构造器中初始化
④通过“对象.方法”或“对象.属性”的方式,赋值

4.11 this关键字

理解this关键字:
①它在方法内部使用,即这个方法所属对象的引用
②它在构造器内部使用,表示该构造器正在初始化的对象

何时使用?
当在方法内需要用到该方法的对象时,就用this,我们可以使用this来区分属性和局部变量

package com.gance.xyz.day04;

/**
 * @author 杰仔正在努力
 * @create 2022-11-12 0:27
 */
public class Boy {
    private String name;
    private int age;

    public Boy() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

4.12 package、import的使用

package语句作为Java源文件的第一条语句,指明该文件中定义的类所在的包

包(package):就是文件夹
作用:对类进行分类管理
包的定义格式
格式:package 包名 (多级包用.分开)
范例:com.gance.abc

包对应于文件系统的目录,package语句中,用 “.” 来指明包(目录)的层次
包通常用小写单词标识。通常使用所在公司域名的倒置:com.xxx.xxx

package关键字的使用:
1、为了更好的实现项目中类的管理,提供包的概念
2、使用package声明类或接口所属的包,声明在源文件的首行
3、包,属于标识符,遵守标识符的命名规则、规范(xxxyyyzzz)、”见名知意“
4、每"."一次就代表一层文件目录

注意:
同一个包下,不能命名同名的接口、类
不同的包下,可以命名同名的接口、类

import关键字的使用
import:导入
1、在源文件中显示的使用imort结构导入指定包下的类、接口
2、声明在包的声明和类的声明之间
3、如果需要导入多个结构,则并列写出即可
4、可以使用"xxx."的方式,表示导入xxx’包下的所有结构
5、如果使用的类或接口是Java.lang包下定义的,则可以省略import
6、如果使用的类或接口是本包定义下的,则可以省略import结构
7、如果在源文件中使用不同包下中同名的类,则必须至少有一个使用全类名的方式显示
8、如果使用"xxx.
"方式表明可以调用xxx的包下的所有结构,但是如果使用的是xxx子包下的结构,则仍然需要显示导入
9、import.static:导入指定类或接口中的静态结构:属性、结构或方法

五、面向对象(中)

5.1 面向对象特征—继承(extends)

何为继承?
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为

作用:
①继承的出现减少了代码冗余,提高了代码的复用性
②继承的出现,更有利于功能的扩展
③继承的出现让类与类之间产生了关系,提供了多态的前提

规则:
子类不能直接访问父类中的私有的变量和方法

注意:
1.java中类只支持单继承,不支持多继承(一个子类不能有两个父类)
2.java中类支持多层继承

案例:
猪和猫继承动物类

package com.gance.xyz.day05;

/**
 * @author 杰仔正在努力
 * @create 2022-11-12 10:52
 */
public class Animal {
    private String name;
    private int age;

    public Animal() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
package com.gance.xyz.day05;

/**
 * @author 杰仔正在努力
 * @create 2022-11-12 23:20
 */
public class Pig extends Animal{
    public Pig() {
    }

    public Pig(String name, int age) {
        super(name, age);
    }

    public void eat() {
        System.out.println("猪吃饭");
    }
}
package com.gance.xyz.day05;

/**
 * @author 杰仔正在努力
 * @create 2022-11-12 10:53
 */
public class Cat extends Animal{
    public Cat() {
    }

    public Cat(String name, int age) {
        super(name, age);
    }

    public void catchMouse() {
        System.out.println("猫抓老鼠");
    }
}
package com.gance.xyz.day05;

/**
 * @author 杰仔正在努力
 * @create 2022-11-12 10:56
 */
public class AnimalTest {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.setAge(1);
        cat.setName("大猫");
        cat.catchMouse();
        System.out.println(cat.getName() + "," + cat.getAge());

        Pig pig = new Pig();
        pig.setAge(5);
        pig.setName("猪八戒");
        pig.eat();
        System.out.println(pig.getName() + "," + pig.getAge());

    }
}

5.2 方法的重写(@Override)

重写的含义:
子类继承父类之后,可以对父类中同名同参数的方法,进行覆盖操作

重写的作用:
重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法

重写的规定:
方法的声明:权限修饰符 返回值类型 方法名(形参列表)throws 异常的类型{
//方法体
}

重写的要求:
①子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
②返回值类型:
>父类被重写的方法的返回值类型是void,则子类重写的返回值类型只能是void
>父类被重写的方法的返回值类型是A类型,则子类重写的返回值类型可以是A类或A类的子类
>父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的返回值类型必须是相同的基本数据类型(必须是double)
③子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
④声明为 static 的方法不能被重写,但是能够被再次声明
⑤构造方法不能被重写

注意:
1、父类中私有方法,子类不能被继承(私有的方法不能被重写)
2、子类方法访问权限不能比父类低(public>默认>私有的)

案例

class Animal{
   public void move(){
      System.out.println("动物可以移动");
   }
}
 
class Dog extends Animal{
   public void move(){
      System.out.println("狗可以跑和走");
   }
}
 
public class TestDog{
   public static void main(String args[]){
      Animal a = new Animal(); // Animal 对象
      Animal b = new Dog(); // Dog 对象
 
      a.move();// 执行 Animal 类的方法
 
      b.move();//执行 Dog 类的方法
   }
}

5.3 super关键字

作用:
可以调用父类的属性方法、构造器

super的使用:
1、我们可以在子类的方法或构造器中,通过使用”super.方法“的方式,显示的调用父类中声明的属性或方法,但是,通常情况下,我们习惯省略”super.“
2、当子类和父类定义了同名的属性时,我们想要在子类中调用父类中声明的属性,则必须显示的使用”super.属性“的方式,表明调用的是父类声明的属性
3、当子类重写了父类中的方法之后,我们想在子类的方法调用父类中被重写的方法时则必须显示的使用”super.方法“的方式,表明调用的是父类中被重写的方法

super调用构造器:
1、我们可以在子类的构造器中显示的使用“super(形参列表)”的方式,调用父类中声明的指定的构造器
2、“super(形参列表)”的使用,必须声明在子类构造器的首行
3、我们在类的构造器中,针对于“this(形参列表)”或“super(形参列表)”只能二选一,不能同时出现
4、在构造器的首行,没有显示的声明this(形参列表)”或“super(形参列表)”,则默认调用的是父类中空参的构造器
5、在类的多个构造器中,至少有一个类的构造器中使用了“super(形参列表)”,调用了父类的构造器

class Animal{
   public void move(){
      System.out.println("动物可以移动");
   }
}
 
class Dog extends Animal{
   public void move(){
      super.move(); // 应用super类的方法
      System.out.println("狗可以跑和走");
   }
}
 
public class TestDog{
   public static void main(String args[]){
 
      Animal b = new Dog(); // Dog 对象
      b.move(); //执行 Dog类的方法
 
   }
}

5.4 面向对象特征—多态

多态是同一个行为具有多个不同表现形式或形态的能力

对象的多态性:父类的引用指向子类的对象(可以应用在抽象类和接口上)

Java引用变量的时候有两个类型:编译时类型运行时类型,编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。简称:编译时,看左边;运行时,看右边

成员变量:编译看左边,执行看左边;
成员方法:编译看左边,执行看右边;

多态的优点:

  1. 消除类型之间的耦合关系
  2. 可替换性
  3. 可扩充性
  4. 接口性
  5. 灵活性
  6. 简化性

多态的缺点:
不能使用子类的特有功能

多态存在的三个必要条件
1、继承
2、重写
3、父类指向子类:Parent p = new Son();

示例图
在这里插入图片描述

class Animal() {
	void eat() {}
}
class Dog extends Animal{
    void eat() {
        System.out.println("Dog.draw()");
    }
}
 
class Cat extends Animal{
    void eat() {
        System.out.println("Cat.draw()");
    }
}
 
class Pig extends Animal{
    void eat() {
        System.out.println("Pig.draw()");
    }
}

多态中的的转型:
1.向上转型(多态)
从子到父
父类引用指向子类对象
2.向下转型
从父到子
父类引用转为子类对象

instanceof操作符:
作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型

a instanceof A:判断对象a时候是类A的实例,如果是,返回true,如果不是,返回false
如果a instanceof A返回true,则a instanceof B也返回true;其中类B是类A的父类

使用情境:为了避免在向下转型出现ClassCastException的异常,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法,子类特有的属性和方法不能调用

public class Test {
    public static void main(String[] args) {
      show(new Cat());  // 以 Cat 对象调用 show 方法
      show(new Dog());  // 以 Dog 对象调用 show 方法
                
      Animal a = new Cat();  // 向上转型  
      a.eat();               // 调用的是 Cat 的 eat
      Cat c = (Cat)a;        // 向下转型  
      c.work();        // 调用的是 Cat 的 work
  }  
            
    public static void show(Animal a)  {
      a.eat();  
        // 类型判断
        if (a instanceof Cat)  {  // 猫做的事情 
            Cat c = (Cat)a;  
            c.work();  
        } else if (a instanceof Dog) { // 狗做的事情 
            Dog c = (Dog)a;  
            c.work();  
        }  
    }  
}
 
abstract class Animal {  
    abstract void eat();  
}  
  
class Cat extends Animal {  
    public void eat() {  
        System.out.println("吃鱼");  
    }  
    public void work() {  
        System.out.println("抓老鼠");  
    }  
}  
  
class Dog extends Animal {  
    public void eat() {  
        System.out.println("吃骨头");  
    }  
    public void work() {  
        System.out.println("看家");  
    }  
}

5.5 Object 类的使用

1、Object类是所有Java类的根父类
2、如果在类的声明中未使用extends关键字指明其父类,则默认父类 为java.lang.Object类

5.5.1 ==操作符

基本类型比较值:只要两个变量的值相等,即为true

int a = 5;
int b = 4;
if(a>b){...}

引用类型比较引用(是否指向同一个对象):只有指向同一个对象时,==才返回true

Person p1=new Person();
Person p2=new Person();
if (p1==p2){}

5.5.2 equals方法

equals():所有类都继承了Object,也就获得了equals()方法,还可以重写

只能比较引用类型,其作用与“==”相同,比较是否指向同一个对象

 格式:obj1.equals(obj2)
class User{
        String name;
        int age;

    public boolean equals(Object obj){
            if (obj == this){
                    return true;
    }
            //判断是否当前类的实例
            if(obj instanceof User){
            //强转
            User u = (User)obj;
            return this.age == u.age && this.name.equals(u.name);
    }

        return false;
    }
    }

说明:
1、Object类中定义的equals()和==的作用是相同的,比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体
2、像String、Date、File、包装类等的都重写Object类中的equals()方法,重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的“实体内容”是否相同
3、通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象”实体内容“是否相同,那么我们就需要对Object类中的equals()进行重写
4、重写的原则:比较两个对象的实体内容是否相同

5.5.3 toString() 方法

1、toString() 方法用于返回以一个字符串表示的 Number 对象值
2、如果方法使用了原生的数据类型作为参数,返回原生数据类型的 String 对象值
3、如果方法有两个参数, 返回用第二个参数指定基数表示的第一个参数的字符串表示形式

public class Test{
    public static void main(String args[]){
        Integer x = 5;

        System.out.println(x.toString());  //返回表示 Integer 值的 String 对象  结果为:5
        System.out.println(Integer.toString(12)); //返回表示指定 int 的 String 对象  结果为:12
    }
}

案例

/**
*一个登录界面 有账号和密码两个属性 分别自定义给他们赋值
*创建Scanner 获取用户输入的值
*对比自定义和创建的属性 
*只有三次机会
*/
package com.gance.xyz.day10;

import java.util.Scanner;

/**
 * @author 杰仔正在努力
 * @create 2022-11-19 14:16
 */
public class Login {
    public static void main(String[] args) {
        //用户名
        String username = "admin";
        //密码
        String password = "123456";

        Scanner scanner = new Scanner(System.in);

        //用户输入次数
        int pwdCount = 3;
        for (int i = 1;i <= pwdCount;i++){
            System.out.println("请输入账号");
            String user = scanner.nextLine();

            System.out.println("请输入密码");
            String pwd = scanner.nextLine();

            if (username.equals(user)&&password.equals(pwd)){
                System.out.println("账号密码正确,登录成功");
                break;
            }else{
                if(i==pwdCount){
                    System.out.println("错误次数较多,账号今天无法登录");
                    return;
                }
                System.out.println("账号密码错误,登录失败 剩下次数:" + (pwdCount - i));
            }
        }

    }
}

5.6 包装类的使用

Java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征

基本数据类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean
charCharacter

基本数据类型 -->包装类 :调用包装类的构造器
int num1 = 10;
Integer in1 = new Integer(num1);

包装类 -->基本数据类型:调用包装类的xxxValue()
Integer in1 = new Integer(12);
int i1 = in1.intValue();
System.out.println(i1 + 1);

int转换为String类型
1、第一种方法:
通过空字符串与int类型+

int a = 4;
String b = "" + a;

2、使用String.
valueOf

String b = String valueOf(a);

String类型转换为int类型

package com.gance.xyz.day11;

/**
 * @author 杰仔正在努力
 * @create 2022-11-22 10:20
 */
public class Test06 {
    public static void main(String[] args) {
        String str = "123";
        //第一种方法
        Integer integer = Integer.valueOf(str)
        // inValue不是静态方法 先new对象 integer就是new出来的对象
        int i = integer.intValue();
        System.out.println(i); //123

        System.out.println("----------------------");
        //第二种方法(推荐使用)
        int i1 = Integer.parseInt(str);
        System.out.println(i1); //123
    }
}

6、面向对象(下)

6.1 static关键字

static翻译中文的意思是“静态”,可以用来修饰成员方法和成员变量

static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响

非静态成员方法
1、能够访问静态的成员变量
2、能够访问非静态的成员变量
3、能够访问静态的成员方法
4、能够访问非静态的成员方法
静态的成员方法
1、能够访问静态成员变量,但是不能够直接访问非静态成员变量
2、能够访问静态的成员方法,但是不能够直接访问非静态成员方法

/**
 * @author 杰仔正在努力
 * @create 2022-11-16 16:38
 */
public class Student {
    //成员属性和方法
    //非静态成员属性
    private int age;
    //静态成员属性(static修饰)
    public static int staticAge;

    /**
     * 非静态方法
     */
    public void a() {
        /**
         * 非静态的成员方法 可以访问到 非静态的成员属性 和 静态的成员属性
         * 非静态的成员方法 可以调用静态的成员方法 也可以调用非静态的
         */
        System.out.println(staticAge);
        System.out.println(age);
        staticB();
        staticC();
    }

    /**
     * static 关键字修饰
     * 静态方法
     */
    public static void staticB() {
        /**
         * 特点:
         * 1、静态方法中 不能访问 非静态方法 可以访问静态方法
         * 2、静态方法中 不能直接访问 静态成员属性 可以访问静态成员属性
         *
         */
        staticC();
        System.out.println(staticAge);
    }

    /**
     * 静态方法
     */
    public static void staticC() {

    }

    /**
     * 非静态方法
     */
    public void D() {

    }
}

静态代码块

1、静态代码块类似于一个方法,但它不可以存在于任何方法体中
2、静态代码块可以置于类中的任何地方,类中可以有多个静态初始化块。
3、Java 虚拟机在加载类时执行静态代码块,所以很多时候会将一些只需要进行一次的初始化操作都放在 static 代码块中进行
4、如果类中包含多个静态代码块,则 Java 虚拟机将按它们在类中出现的顺序依次执行它们,每个静态代码块只会被执行一次
5、静态代码块与静态方法一样,不能直接访问类的实例变量和实例方法,而需要通过类的实例对象来访问

public class StaticCode {
    public static int count = 0;
    {
        count++;
        System.out.println("非静态代码块 count=" + count);
    }
    static {
        count++;
        System.out.println("静态代码块1 count=" + count);
    }
    static {
        count++;
        System.out.println("静态代码块2 count=" + count);
    }

    public static void main(String[] args) {
        System.out.println("*************** StaticCode1 执行 ***************");
        StaticCode sct1 = new StaticCode();
        System.out.println("*************** StaticCode2 执行 ***************");
        StaticCode sct2 = new StaticCode();
    }
}

6.2 main方法

Java方法是语句的集合,它们在一起执行一个功能
1、方法是解决一类问题的步骤的有序组合
2、方法包含于类或对象中
3、方法在程序中被创建,在其他地方被引用

优点:

  1. 使程序变得更简短而清晰
  2. 有利于程序维护
  3. 可以提高程序开发的效率
  4. 提高了代码的重用性

命名规则:
1.方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:addPerson
2.下划线可能出现在 JUnit 测试方法名称中用以分隔名称的逻辑组件。一个典型的模式是:test< MethodUnderTest >_< state >,例如 testPop_emptyStack

修饰符 返回值类型 方法名(参数类型 参数名){
    ...
    方法体
    ...
    return 返回值;
}

6.3 final关键字

在Java中声明类、变量和方法时,我们可以使用final关键字来修饰,表示“最终的”

注意:
①被final关键字标记的类不难被继承
②final标记的方法不能被子类重写

1、final关键字修饰一个引用

1、如果引用为基本数据类型,则该引用为常量,该值无法修改
2、如果引用时类的成员变量,则必须当场赋值,否则编译会报错

/**
 * @author 杰仔正在努力
 * @create 2022-11-17 20:48
 */

    final class Person {
        String name = "哈士奇";
        final int age = 5;
    }

	public class Demo {
    public static void main(String[] args) {
        final int i = 5;
//        i = 15;   //基本数据类型为常量,不可以被修改

        Person p = new Person();
        p.name = "金毛";

//        p.age = 3; //age被final标记,不可修改

        final int[] arr = {1,3,5,4,6};   //数组被final标记,不可修改
        arr[3] = 34;
//        arr = new int[]{3,6,5,7};
//        arr[3] = 45;
//        System.out.println(arr[3]);
    }
}

final修饰一个方法

当使用final修饰方法时,这个方法将成为最终方法,无法被子类重写。但是,该方法仍然可以被继承

/**
 * @author 杰仔正在努力
 * @create 2022-11-17 21:12
 */
public class Person {
    public  void eat() {
        System.out.println("我是final修饰的吃方法。。。");
    }
    public final void swim() {
        System.out.println("我是final修饰的游泳方法。。。");
    }
}
public class Animal extends Person {
    @Override
    public void eat() {
        System.out.println("我重写了父类的吃方法");
    }

    // final修饰的方法不能被重写,但是方法依旧被继承
//    public void swim() {
//        System.out.println("我重写了父类的游泳方法");
//    }
}
public class Test {
    public static void main(String[] args) {
        Animal animal = new Animal();
        animal.swim();
        animal.eat();
    }
}

fianl修饰类

当用final修改类时,该类成为最终类,无法被继承

 final class Person {}
//    class Person extends Person2 {}
//    class Person extends Person3 {}

public class Person4 {}

6.4 抽象类和抽象方法(abstract)

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类

声明:
1、 抽象类不能被实例化,如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象
2、抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类
3、抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能
4、构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法
5、 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类

package com.gance.xyz.day08;

/**
 * 编写一个Employee类,声明为抽象类
 * 包含如下三个属性:name,id,salary
 * 提供必要的构造器和抽象方法:work()
 * 对于Manager类来说,他既是员工,还具有奖金(bonus)的属性
 */

/**
 * @author 杰仔正在努力
 * @create 2022-11-17 21:37
 */
public abstract class Employee {   //定义抽象类
    String name; //名字
    int id;   //工号
    double salary;  //工资

    public Employee() {    //无参构造方法
    }

    public Employee(String name, int id, double salary) {   //有参构造方法
        this.name = name;
        this.id = id;
        this.salary = salary;
    }

    public abstract void work();   //定义抽象方法
}

public class Manager extends Employee{

    private double bonus;//奖金

    public Manager(double bonus) {
        this.bonus = bonus;
    }

    public Manager(String name, int id, double salary, double bonus) {
        super(name, id, salary);
        this.bonus = bonus;
    }

    public double getBonus() {
        return bonus;
    }

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }

    @Override                   //重写父类抽象方法
    public void work() {
        System.out.println("我的工作是管理");
    }
}

public class CommonEmployee extends Employee{

    public CommonEmployee() {
    }

    public CommonEmployee(String name, int id, double salary) {
        super(name, id, salary);
    }

    @Override
    public void work() {
        System.out.println("我的工作是生产");
    }
}
public class Demo01 {
    public static void main(String[] args) {

        //多态
        Employee employee = new Manager("张三",1,5000,3000);
        //强转
        Manager manager = (Manager) employee;
        employee.work();
        System.out.println(employee.name + "工号为:" + employee.id + "工资为:" + employee.salary + "奖金是:" + manager.getBonus());

        Employee commonEmployee = new CommonEmployee("李四",4,3000);
        commonEmployee.work();
        System.out.println(commonEmployee.name + "工号为:" + commonEmployee.id + "工资为:" + commonEmployee.salary);
    }
}

6.5 接口(interface)

接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法

接口的使用:
1、接口使用interface来定义
2、Java中,接口和类是并列的两个结构
3、如何定义接口,定义接口中的成员

接口的特性:
1、接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract
2、接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量
3、接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法

抽象类和接口的区别:

  1. 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行
  2. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的
  3. 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法
  4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口
1.接口 用关键字interface 修饰
public interface 接口名{}

2.类实现接口用 implements 表示
public classimplements 接口 {}
package com.gance.xyz.day09;

/**
 * @author 杰仔正在努力
 * @create 2022-11-18 11:24
 */
public abstract class Animal implements JumpInterface {
    String name;
    int age;

    public Animal() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void eat() {

    }
}

package com.gance.xyz.day09;

/**
 * @author 杰仔正在努力
 * @create 2022-11-18 11:28
 */
//定义跳高接口
public interface JumpInterface {
    //跳高方法
    void jump();
}
package com.gance.xyz.day09;

/**
 * @author 杰仔正在努力
 * @create 2022-11-18 11:30
 */
public class Cat extends Animal {

    @Override
    public void jump() {
        System.out.println("我是猫 我可以跳高");
    }

    public Cat() {
    }

    public Cat(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("我是猫 我可以吃猫粮");
    }
}

package com.gance.xyz.day09;

/**
 * @author 杰仔正在努力
 * @create 2022-11-18 11:34
 */
public class Dog extends Animal{

    @Override
    public void jump() {
        System.out.println("我是狗类 我可以跳高");
    }

    public Dog() {
    }

    public Dog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("我是狗 我可以吃大骨头");

    }
}

package com.gance.xyz.day09;

/**
 * @author 杰仔正在努力
 * @create 2022-11-18 11:35
 */
public class Test {
    public static void main(String[] args) {
        //  我们可以用接口来接收也是可以的
        // 编译看左边,执行看右边 JumpInterface中没有这个eat方法,无法调用
        JumpInterface cat1 = new Cat("大猫", 2);
        cat1.jump();

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

        //我们使用多态方式接收
        Animal cat2 = new Cat("小猫", 1);
        cat2.eat();
        cat2.jump();
        System.out.println(cat2.getName() + cat2.getAge());
    }
}

6.6 内部类

Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B就是外部类

内部类的分类:成员内部类(静态、非静态) vs 局部内部类(方法内、代码块内、构造器内)

成员内部类

成员内部类是最普通的内部类,它的定义为位于另一个类的内部

class Circle {
    double radius = 0;
     
    public Circle(double radius) {
        this.radius = radius;
    }
     
    class Draw {     //内部类
        public void drawSahpe() {
            System.out.println("drawshape");
        }
    }
}

成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)

class Circle {
    private double radius = 0;
    public static int count =1;
    public Circle(double radius) {
        this.radius = radius;
    }
     
    class Draw {     //内部类
        public void drawSahpe() {
            System.out.println(radius);  //外部类的private成员
            System.out.println(count);   //外部类的静态成员
        }
    }
}

外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问

class Circle {
    private double radius = 0;
 
    public Circle(double radius) {
        this.radius = radius;
        getDrawInstance().drawSahpe();   //必须先创建成员内部类的对象,再进行访问
    }
     
    private Draw getDrawInstance() {
        return new Draw();
    }
     
    class Draw {     //内部类
        public void drawSahpe() {
            System.out.println(radius);  //外部类的private成员
        }
    }
}

总结:
成员内部类:
一方面:作为外部类的成员:
①调用外部类的结构
②可以被static修饰
③可以被4种不同的权限修饰


另一方面:作为一个类:
①类内可以定义属性、方法、构造器等
②可以被final修饰,表示此类不能被继承,言外之意,不用final就可以被继承
③可以被abstract修饰

匿名内部类

匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类

格式:
new 父类构造器(实参列表)|实现接口(){
//匿名内部类的类体部分
}

特点:
①匿名内部类必须继承父类或实现接口
② 匿名内部类只能有一个对象
③ 匿名内部类对象只能使用多态形式引用

6.7 String类的使用

6.7.1 String 遍历字符串

package com.gance.xyz.day11;

import java.util.Scanner;

/**
 * @author 杰仔正在努力
 * @create 2022-11-21 10:35
 */
public class Test01 {
    public static void main(String[] args) {
        /**
         * 实现字符串的遍历
         * String底层基于char 类型数组的实现
         * char value[]
         * 获取 String char value[]
         * charAt 根据 char value[根据index 下标获取对应的] 字符
         */

//        String str = "apple";
//        System.out.println(str.charAt(0));
//        System.out.println(str.charAt(1));
//        System.out.println(str.charAt(2));
//        System.out.println(str.charAt(3));
//        System.out.println(str.charAt(4));

        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入内容");
        String str = scanner.nextLine();
        //获取字符串的长度 底层就是获取到 char类型数组的长度
        for (int i = 0; i < str.length(); i++){
            System.out.println(str.charAt(i));
        }
    }
}

6.7.2 String替换方法

package com.gance.xyz.day11;

/**
 * @author 杰仔正在努力
 * @create 2022-11-21 11:03
 */
public class Test02 {
    public static void main(String[] args) {
        //replaceFirst 替换第一个
        //replace  替换所有
        //replaceAll 替换全部
        
        //定义一个字符串 需要将字符串里面的内容中的12345 替换为apple
        String str1 = "stringtest12345";
        /**
         * replace参数1 需要替换的字符串内容 12345 替换为 apple
         */
        String newStr1 = str1.replace("12345", "apple");
        System.out.println(newStr1);

        //定义一个字符串"stringtest12345string12345" 需要将字符串里面的内容中的第1个12345 替换为apple
        String str2 = "stringtest12345string12345";

        String newStr2 = str2.replaceFirst("12345", "apple");
        System.out.println(newStr2);

        String str3 = "stringtest12345string12345";

        String newStr3 = str3.replaceAll("12345","apple");
        System.out.println(newStr3);

    }
}

6.7.3 String分割方法

split() 方法根据匹配给定的正则表达式来拆分字符串

注意: . 、 $、 | 和 * 等转义字符,必须得加 \。

注意:多个分隔符,可以用 | 作为连字符。

package com.gance.xyz.day11;

/**
 * @author 杰仔正在努力
 * @create 2022-11-21 11:17
 */
public class Test03 {
    public static void main(String[] args) {
        String str = "猪|狗|猫|兔|鼠";

        String[] s = str.split("\\|");
        System.out.println(s[0]);
        System.out.println(s[1]);
        System.out.println(s[2]);
        System.out.println(s[3]);
        System.out.println(s[4]);
    }
}

6.7.4 indexOf

package com.gance.xyz.day11;

/**
 * @author 杰仔正在努力
 * @create 2022-11-21 11:46
 */
public class Test04 {
    public static void main(String[] args) {
        String str = "helloword";

        //长度从1开始计算
        System.out.println("helloword".length()); //9

        //indexOf返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1
        //索引从0开始计算
        System.out.println(str.indexOf("word")); //5

        String str1 = "hellowordhelloword";
        //返回从 fromIndex 位置开始查找指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1
        System.out.println(str1.indexOf("hello",5));
    }
}

6.8 Math类

package com.gance.xyz.day11;

/**
 * @author 杰仔正在努力
 * @create 2022-11-21 16:54
 */
public class Test05 {
    public static void main(String[] args) {
        //Math.abs()返回绝对值
        System.out.println(Math.abs(99)); //-99
        System.out.println(Math.abs(-99)); //99

        System.out.println("-------------------------");
        //Math.ceil()返回大于或等于参数的最小double值,等于一个整数
        System.out.println(Math.ceil(10.11)); //11.0
        System.out.println(Math.ceil(10.67)); //11.0
        System.out.println(Math.ceil(10.00)); //10.0

        System.out.println("--------------------------");
        //Math.floor()返回小于或等于参数的最大double值,等于一个整数
        System.out.println(Math.floor(13.55)); //13.0
        System.out.println(Math.floor(13.43)); //13.0
        System.out.println(Math.floor(13.00)); //13.0

        System.out.println("--------------------------");
        //Math.round()按照四舍五入返回一个int值
        System.out.println(Math.round(12.67)); //13
        System.out.println(Math.round(12.34)); //12
        System.out.println(Math.round(12.00)); //12

        System.out.println("--------------------------");
        //Math.max()返回两者之间的最大值
        int a = 3;
        int b = 2;
        System.out.println(Math.max(a,b)); //3
        //Math.min()返回两者之间的最小值
        System.out.println(Math.min(a,b)); //2

        System.out.println("---------------------------");
        //Math.pow()返回a的b次幂
        System.out.println(Math.pow(3,3));

        System.out.println("---------------------------");
        //Math.radom()随机数 [0.0,1.0)  Math.random()*100 //0-99
        System.out.println(Math.random()*100);
    }
}

七、异常处理

7.1 异常概述

异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的

1、检查性异常: 最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
2、运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
3、错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

7.2 常见的异常

java.lang.Throwable
        -----java.lang.Error:一般不写针对性的代码进行处理
        -----java.lang.Exception:可以进行异常处理
            -----编译时异常(checked)
                ------IOException
            -----运行时异常(unchecked)
                ------NullPointerException(空指针异常)
                ------ArrayIndexOutOfBoundsException(数组角标越界)
                ------ClassCastException(类型转换异常)
                ------NumberFormatException(数值转换异常)
                ------InputMismatchException(输入不匹配异常)
                ------ArithmeticException(算数异常)

7.3 异常处理方式

7.3.1 try-catch-finally

使用 try 和 catch 关键字可以捕获异常,try/catch 代码块放在异常可能发生的地方

try{
        //可以出现异常的代码
}catch(异常类型1    变量名1{
    //处理异常的方式1
}catch(异常类型2    变量名2{
    //处理异常的方式2
}catch(异常类型3    变量名3{
    //处理异常的方式3
}
..........
finally{
    //一定会执行的代码
}

Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try 后面的 catch 块就会被检查
如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样

不论在try代码块中是否发生了异常事件,catch语句是否执
行,catch语句是否有异常,catch语句中是否有return,
finally块中的语句都会被执行

说明:
1、finally是可选的
2、使用try将可能出现的代码包装起来,执行过程中如果出现异常,就会生成一个对应的异常类,根据此对象的类型,去catch中进行匹配
3、一旦try的异常对象匹配到某一个catch时,就进入了catch中进行异常的处理,一旦处理完成,就跳出当前的try-catch结构(在没有写finally情况下),继续执行其后的代码
4、catch中的异常类型如果没有子父类关系,则谁声明在上,都无所谓
catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面,否则报错
5、常用的异常对象处理的方式:①String getMassage() ②printStackTrace()
6、在try结构中声明的变量,再出try结构以后,不能再被调用
7、try-catch-finally可以嵌套

import java.io.*;
public class ExcepTest{
 
   public static void main(String args[]){
      try{
         int a[] = new int[2];
         System.out.println("Access element three :" + a[3]);
      }catch(ArrayIndexOutOfBoundsException e){
         System.out.println("Exception thrown  :" + e);
      }
      System.out.println("Out of the block");
   }
}

7.3.2 throws

如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理

import java.io.*;
public class className
{
  public void deposit(double amount) throws RemoteException
  {
    // Method implementation
    throw new RemoteException();
  }
  //Remainder of class definition
}

一个方法可以声明抛出多个异常,多个异常之间用逗号隔开

import java.io.*;
public class className
{
   public void withdraw(double amount) throws RemoteException,
                              InsufficientFundsException
   {
       // Method implementation
   }
   //Remainder of class definition
}

开发中如何选择try-catch-finally 还是使用throws?
1、如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中有异常,必须使用try-catch-finally方式处理
2、执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的,我们建议这几个方法使用throws的方式进行处理,而执行的方法a可以考虑使用try-catch-finally方式进行处理

7.4 自定义异常

在 Java 中你可以自定义异常。编写自己的异常类时需要记住下面的几点:
1、所有异常都必须是 Throwable 的子类
2、如果希望写一个检查性异常类,则需要继承 Exception 类
3、如果你想写一个运行时异常类,那么需要继承RuntimeException 类

public class MyException extends Exception {
    public MyException() {
        super();
    }
    public MyException(String str) {
        super(str);
    }
}
import java.util.InputMismatchException;
import java.util.Scanner;
public class Test07 {
    public static void main(String[] args) {
        int age;
        Scanner input = new Scanner(System.in);
        System.out.println("请输入您的年龄:");
        try {
            age = input.nextInt();    // 获取年龄
            if(age < 0) {
                throw new MyException("您输入的年龄为负数!输入有误!");
            } else if(age > 100) {
                throw new MyException("您输入的年龄大于100!输入有误!");
            } else {
                System.out.println("您的年龄为:"+age);
            }
        } catch(InputMismatchException e1) {
            System.out.println("输入的年龄不是数字!");
        } catch(MyException e2) {
            System.out.println(e2.getMessage());
        }
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值