01 JAVA语言概述

应用程序=算法+数据结构

常用的DOS命令:

java语言的特点

面向对象性:两个基本概念:类、对象;三大特性:封装、继承、多态

健壮性:吸收了C/C++语言的优点,但去掉了其影响程序健壮性的部分(如指针、内存的申请与释放等),提供了一个相对安全的内存管理和访问机制

跨平台性:通过Java语言编写的应用程序在不同的系统平台上都可以运行。“Write once, Run Anywhere”

第一个Java程序

java规范的三种注释方式:单行注释多行注释文档注释(java特有)


/*
1. java规范的三种注释方式:
单行注释
多行注释
文档注释(java特有)2.
单行注释和多行注释的作用:
① 对所写的程序进行解释说明,增强可读性。方便自己,方便别人
② 调试所写的代码3. 特点:单行注释和多行注释,注释了的内容不参与编译。换句话说,编译以后生成的.class结尾的字节码文件中不包含注释掉的信息4. 文档注释的使用:注释内容可以被JDK提供的工具 javadoc 所解析,生成一套以网页文件形式体现的该程序的说明文档。5. 多行注释不可以嵌套使用*//**
文档注释
@author shkstart
@version v1.0
这是我的第一个java程序!非常的开森!*/
public class HelloJava{/*多行注释:如下的main方法是程序的入口!main的格式是固定的!*//**如下的方式是main(),作用:程序的入口。*/public static void main(String[] args){//单行注释:如下的语句表示输出到控制台//System.out.println("Hello World!")System.out.println("Hello World!");}
}

总结

对第一个java程序进行总结

  • 一、java程序编写-编译-运行的过程

  • 编写:我们将编写的java代码保存在以".java"结尾的源文件中

  • 编译:使用javac.exe命令编译我们的java源文件。格式:javac 源文件名.java

  • 运行:使用java.exe命令解释运行我们的字节码文件。 格式:java 类名

  • 二、

  • 在一个java源文件中可以声明多个class。但是,只能最多有一个类声明为public的。

  • 而且要求声明为public的类的类名必须与源文件名相同。

  • 程序的入口是main()方法。格式是固定的。

  • 输出语句:

  1. System.out.println():先输出数据,然后换行

  1. System.out.print():只输出数据

  • 每一行执行语句都以";"结束。

  • 编译的过程:编译以后,会生成一个或多个字节码文件。字节码文件的文件名与java源文件中的类名相同。

/*
对第一个java程序进行总结
1. java程序编写-编译-运行的过程
编写:我们将编写的java代码保存在以".java"结尾的源文件中
编译:使用javac.exe命令编译我们的java源文件。格式:javac 源文件名.java
运行:使用java.exe命令解释运行我们的字节码文件。 格式:java 类名2.
在一个java源文件中可以声明多个class。但是,只能最多有一个类声明为public的。
而且要求声明为public的类的类名必须与源文件名相同。3. 程序的入口是main()方法。格式是固定的。4. 输出语句:
System.out.println():先输出数据,然后换行
System.out.print():只输出数据5.每一行执行语句都以";"结束。6.编译的过程:编译以后,会生成一个或多个字节码文件。字节码文件的文件名与java源文件中的类名相同。*/
public class Hello {public static void main(String[] args) {//public static void main(String a[]) {//arguments:参数System.out.print("Hello World!");System.out.println();//换行System.out.println("Hello World!");}
}class Person{}class Animal{}

重点问题

1.JDK,JRE,JVM三者之间的关系,以及JDK、JRE包含的主要结构有哪些

JDK = JRE + Java的开发工具(javac.exe,java.exe,javadoc.exe)

JRD = JVM + Java核心类库

2.为什么要配置path环境变量?如何配置?

希望在任何路径下都可以执行Java的开发工具

JAVA_HOME = bin的上一层目录

path = %JAVA_HOME%\bin

3.常用的几个命令行操作都有哪些?(至少4个)

cd

md

rd

del

cd..

cd/

**4.创建如下的类,使得运行的话可以输出:**创建java文件:ChairMan.javapublic class ChairMan{public static void main(String[] args){System.out.println("姓名:习大大\n");//[//System.out.println](//System.out.println)();System.out.println("性别:男");System.out.println("家庭住址:北京中南海");}}5.编译和运行上述代码的指令编译:javac ChairMan.java运行:java ChairMan

02 JAVA基础语法

关键字和保留字

关键字

保留字

goto 、 const

标识符(命名)

标识符的使用

1.标识符:凡是自己可以起名字的地方都叫标识符。

比如:类名、变量名、方法名、接口名、包名...

2.标识符的命名规则:

--> 如果不遵守如下的规则,编译不通过!需要大家严格遵守

1.由26个英文字母大小写,0-9 ,_或 $ 组成

2.数字不可以开头。

3.不可以使用关键字和保留字,但能包含关键字和保留字。

4.Java中严格区分大小写,长度无限制。

5.标识符不能包含空格。

  1. Java中的名称命名规范:

** **--->如果不遵守如下的规范,编译可以通过!建议大家遵守

包名:多单词组成时所有字母都小写:xxxyyyzzz

类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz

变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz

常量名:所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ

注意1:在起名字时,为了提高阅读性,要尽量有意义,“见名知意”。

注意2:java采用unicode字符集,因此标识符也可以使用汉字声明,但是不建议使用。

变量

变量的使用

  1. java定义变量的格式:数据类型 变量名 = 变量值;

  1. 说明:

① 变量必须先声明,后使用

② 变量都定义在其作用域内。在作用域内,它是有效的。换句话说,出了作用域,就失效了

③ 同一个作用域内,不可以声明两个同名的变量

基本数据类型(八种)

Java定义的数据类型

一、变量按照数据类型来分

基本数据类型:

**整型:**byte \ short \ int \ long(用int就行了)//1. 整型:byte(1字节=8bit) \ short(2字节) \ int(4字节) \ long(8字节)![](https://secure2.wostatic.cn/static/d2D2hBmyJg37wigopUrEuz/image.png?auth_key=1673847590-vDuiTR9FmsSrdqaRkdEZnY-0-bfb7b69b534067b7cedec26cb945dad3)**浮点型:**float \ double(用double就行了)![](https://secure2.wostatic.cn/static/e5khpWvVhVrq9JRVLN3ZEd/image.png?auth_key=1673847590-797Vu5WdH4cGDRE4pGisud-0-743485e818667293c74a01289047fe8b)**字符型:**char(1字符=2字节)1、通常使用一对单引号'',内部只能写一个字符,要写多个要使用字符串(后面会讲)2、转义字符 '\n';//换行符'\t';//制表符3、直接使用 Unicode 值来表示字符型常量**布尔型:**boolean//① 只能取两个值之一:true 、 false//② 常常在条件判断、循环结构中使用

引用数据类型:

类(class)接口(interface)数组(array)

二、变量在类中声明的位置:

成员变量 vs 局部变量

基本数据类型间转换

1.自动类型转换

**结论:**当容量小的数据类型的变量与容量大的数据类型的变量做运算时,结果自动提升为容量大的数据类型。

byte 、char 、short --> int --> long --> float --> double

说明:此时的容量大小指的是,表示数的范围的大和小。比如:float容量要大于long的容量

特别的:当byte、char、short三种类型的变量做运算时,结果为int型

2.强制类型转换

自动类型提升运算的逆运算。1.需要使用强转符:()

2.注意点:强制类型转换,可能导致精度损失。

class VariableTest3 {public static void main(String[] args) {double d1 = 12.9;//精度损失举例1int i1 = (int)d1;//截断操作System.out.println(i1);//没有精度损失long l1 = 123;short s2 = (short)l1;//精度损失举例2int i2 = 128;byte b = (byte)i2;System.out.println(b);//-128(二进制层面的问题)}
}

数据型与String间转换

String类型变量的使用

  1. String属于引用数据类型,翻译为:字符串

  1. 声明String类型变量时,使用一对""

  1. String可以和8种基本数据类型变量做运算,且运算只能是连接运算:+

  1. 运算的结果仍然是String类型

  //***********************//练习1char c = 'a';//97   A:65int num = 10;String str = "hello";System.out.println(c + num + str);//107helloSystem.out.println(c + str + num);//ahello10System.out.println(c + (num + str));//a10helloSystem.out.println((c + num) + str);//107helloSystem.out.println(str + num + c);//hello10a//练习2//*  *System.out.println("*  *");System.out.println('*' + '\t' + '*');System.out.println('*' + "\t" + '*');System.out.println('*' + '\t' + "*");System.out.println('*' + ('\t' + "*"));//***********************//String str1 = 123;//编译不通过String str1 = 123 + "";System.out.println(str1);//"123"//int num1 = str1;//int num1 = (int)str1;//"123"//字符串转化成整型的方式int num1 = Integer.parseInt(str1);System.out.println(num1);//123

二进制十进制转换

反推过程

运算符

算术运算符

赋值运算符

运算符之二:赋值运算符= += -= *= /= %=

结论:不会改变变量本身的数据类型

class SetValueTest {public static void main(String[] args) {//赋值符号:=int i1 = 10;int j1 = 10;int i2,j2;//连续赋值i2 = j2 = 10;int i3 = 10,j3 = 20;//*********************int num1 = 10;num1 += 2;//num1 = num1 + 2;System.out.println(num1);//12int num2 = 12;num2 %= 5;//num2 = num2 % 5;System.out.println(num2);short s1 = 10;//s1 = s1 + 2;//编译失败s1 += 2;//结论:不会改变变量本身的数据类型System.out.println(s1);//开发中,如果希望变量实现+2的操作,有几种方法?(前提:int num = 10;)//方式一:num = num + 2;//方式二:num += 2; (推荐)//开发中,如果希望变量实现+1的操作,有几种方法?(前提:int num = 10;)//方式一:num = num + 1;//方式二:num += 1; //方式三:num++; (推荐)//练习1int i = 1;i *= 0.1;System.out.println(i);//0i++;System.out.println(i);//1//练习2int m = 2;int n = 3;n *= m++; //n = n * m++;  System.out.println("m=" + m);//3System.out.println("n=" + n);//6//练习3int n1 = 10;n1 += (n1++) + (++n1);//n1 = n1 + (n1++) + (++n1);System.out.println(n1);//32}}

比较运算符(关系运算符)

逻辑运算符

操作的都是布尔类型的变量


//区分& 与 &&

//相同点1:& 与 && 的运算结果相同

//相同点2:当符号左边是true时,二者都会执行符号右边的运算

//不同点:当符号左边是false时,&继续执行符号右边的运算。&&不再执行符号右边的运算。

//开发中,推荐使用&&


// 区分:| 与 ||

//相同点1:| 与 || 的运算结果相同

//相同点2:当符号左边是false时,二者都会执行符号右边的运算

//不同点3:当符号左边是true时,|继续执行符号右边的运算,而||不再执行符号右边的运算

//开发中,推荐使用||


位运算符

(这个位运算符很少用到)

运算符之五:位运算符 (了解)

结论:

  1. 位运算符操作的都是整型的数据

  1. << :在一定范围内,每向左移1位,相当于 * 2

:在一定范围内,每向右移1位,相当于 / 2

面试题:最高效方式的计算2 * 8 ? 2 << 3 或 8 << 1

三元运算符

1.结构:(条件表达式)? 表达式1 : 表达式2

  1. 说明

① 条件表达式的结果为boolean类型

② 根据条件表达式真或假,决定执行表达式1,还是表达式2.

如果表达式为true,则执行表达式1。

如果表达式为false,则执行表达式2。

③ 表达式1 和表达式2要求是一致的。

④ 三元运算符可以嵌套使用

凡是可以使用三元运算符的地方,都可以改写为if-else

反之,不成立。

4**.**如果程序既可以使用三元运算符,又可以使用if-else结构,那么优先选择三元运算符。原因:简洁、执行效率高。

class SanYuanTest {public static void main(String[] args) {//获取两个整数的较大值int m = 12;int n = 5;int max = (m > n)? m : n;System.out.println(max);double num = (m > n)? 2 : 1.0;//(m > n)? 2 : "n大";//编译错误(需要可以统一数据类型)//**************************n = 12;String maxStr = (m > n)? "m大" : ((m == n)? "m和n相等" : "n大");System.out.println(maxStr);//*****************************//获取三个数的最大值int x=14,d=90,k=-34;int max=(x>d)? x:d;int en=(max>k)? max:k;System.out.println("三个数中最大的是: "+en);//改写成if-else:if(m > n){System.out.println(m);}else{System.out.println(n);}}
}

运算符优先级

一个()走天下

流程控制

顺序结构

分支结构

if—else

/*
分支结构中的if-else(条件判断结构)一、三种结构第一种:
if(条件表达式){执行表达式
}第二种:二选一
if(条件表达式){执行表达式1
}else{执行表达式2
}第三种:n选一
if(条件表达式){执行表达式1
}else if(条件表达式){执行表达式2
}else if(条件表达式){执行表达式3
}
...
else{执行表达式n
}
*/
class IfTest {public static void main(String[] args) {//举例1int heartBeats = 79;if(heartBeats < 60 || heartBeats > 100){System.out.println("需要做进一步检查");}System.out.println("检查结束");//举例2int age = 23;if(age < 18){System.out.println("你还可以看动画片");}else{System.out.println("你可以看成人电影了");}//举例3if(age < 0){System.out.println("您输入的数据非法");}else if(age < 18){System.out.println("青少年时期");}else if(age < 35){System.out.println("青壮年时期");}else if(age < 60){System.out.println("中年时期");}else if(age < 120){System.out.println("老年时期");}else{System.out.println("你是要成仙啊~~");}}
}

说明:

  1. else 结构是可选的。

  1. 针对于条件表达式:

如果多个条件表达式之间是“互斥”关系(或没有交集的关系),哪个判断和执行语句声明在上面还是下面,无所谓。如果多个条件表达式之间有交集的关系,需要根据实际情况,考虑清楚应该将哪个结构声明在上面。如果多个条件表达式之间有包含的关系,通常情况下,需要将范围小的声明在范围大的上面。否则,范围小的就没机会执行了。

例题1

/*
岳小鹏参加Java考试,他和父亲岳不群达成承诺:
如果:
成绩为100分时,奖励一辆BMW;
成绩为(80,99]时,奖励一台iphone xs max;
当成绩为[60,80]时,奖励一个 iPad;
其它时,什么奖励也没有。
请从键盘输入岳小鹏的期末成绩,并加以判断说明:
1. else 结构是可选的。
2. 针对于条件表达式:> 如果多个条件表达式之间是“互斥”关系(或没有交集的关系),哪个判断和执行语句声明在上面还是下面,无所谓。> 如果多个条件表达式之间有交集的关系,需要根据实际情况,考虑清楚应该将哪个结构声明在上面。> 如果多个条件表达式之间有包含的关系,通常情况下,需要将范围小的声明在范围大的上面。否则,范围小的就没机会执行了。
*/import java.util.Scanner;
class IfTest {public static void main(String[] args) {Scanner scan = new Scanner(System.in);System.out.println("请输入岳小鹏期末成绩:(0-100)");int score = scan.nextInt();if(score == 100){System.out.println("奖励一辆BMW");//be my wife!  BMW <---> MSN}else if(score > 80 &&  score <= 99){System.out.println("奖励一台iphone xs max");}else if(score >= 60 && score <= 80){System.out.println("奖励一个 iPad");}else{System.out.println("什么奖励也没有");}}
}

如何从键盘中输入char的方法

    //对于char型的获取,Scanner没有提供相关的方法。只能获取一个字符串System.out.println("请输入你的性别:(男/女)");String gender = scan.next();//"男"char genderChar = gender.charAt(0);//获取索引为0位置上的字符System.out.println(genderChar);

例题2

/*
编写程序:由键盘输入三个整数分别存入变量num1、num2、num3,
对它们进行排序(使用 if-else if-else),并且从小到大输出。说明:
1. if-else结构是可以相互嵌套的。
2. 如果if-else结构中的执行语句只有一行时,对应的一对{}可以省略的。但是,不建议大家省略。
*/
/*
编写程序:由键盘输入三个整数分别存入变量num1、num2、num3,
对它们进行排序(使用 if-else if-else),并且从小到大输出。
*/import java.util.Scanner;class IfTest
{public static void main(String[] args){//实例化Scanner scan = new Scanner(System.in);System.out.println("请输入第一个数字:");double num1 = scan.nextDouble();System.out.println("请输入第二个数字:");double num2 = scan.nextDouble();System.out.println("请输入第三个数字:");double num3 = scan.nextDouble();System.out.println("输入的三个数为:"+num1+","+num2+","+num3);//进行判断if (num1>num2){if (num1>num3){if (num2>num3){System.out.println("从大到小排序为:"+num1+","+num2+","+num3);}else{System.out.println("从大到小排序为:"+num1+","+num3+","+num2);}}else{System.out.println("从大到小排序为:"+num3+","+num1+","+num2);}//num2>num1}else {if (num2>num3){if(num1>num3){System.out.println("从大到小排序为:"+num2+","+num1+","+num3);}else{System.out.println("从大到小排序为:"+num2+","+num3+","+num1);}}else{System.out.println("从大到小排序为:"+num3+","+num2+","+num1);}}}
}

方法二:

import java.util.Scanner;class IfTest
{public static void main(String[] args){//实例化Scanner scan = new Scanner(System.in);System.out.println("请输入第一个数字:");double num1 = scan.nextDouble();System.out.println("请输入第二个数字:");double num2 = scan.nextDouble();System.out.println("请输入第三个数字:");double num3 = scan.nextDouble();System.out.println("输入的三个数为:"+num1+","+num2+","+num3);//进行判断if(num1 >= num2){//比大的还大if(num3 >= num1){System.out.println("从小到大排序为:"+num2 + "," + num1 + "," + num3);}//比小的还小else if(num3 <= num2){System.out.println("从小到大排序为:"+num3 + "," + num2 + "," + num1);}else{System.out.println("从小到大排序为:"+num2 + "," + num3 + "," + num1);}}else{if(num3 >= num2){System.out.println("从小到大排序为:"+num1 + "," + num2 + "," + num3);}else if(num3 <= num1){System.out.println("从小到大排序为:"+num3 + "," + num1 + "," + num2);}else{System.out.println("从小到大排序为:"+num1 + "," + num3 + "," + num2);}}}
}

例题3

/*
计算你家的狗几岁了?
我家的狗5岁了,5岁的狗相当于人类多大呢?其实,狗前两年每一年相当于人类的10.5岁,
之后每增加一年就增加四岁。那么5岁的狗相当于人类多大呢?
应该是:10.5*2+(n-2)*4=y
33岁
*/
import java.util.Scanner;
class DogAge
{public static void main(String[] args){Scanner scan = new Scanner(System.in);System.out.println("请输入你家狗狗的狗龄:");double age = scan.nextDouble();if(age<=2){System.out.println("相当于人的"+(10.5*age)+"岁");}else{System.out.println("相当于人的"+(10.5*2+4*(age-(double)2))+"岁");}}
}

例子4:

生成指定区间

例如:随机产生六个红球数值范围在[1-33]

a=(int)(Math.random()*33 + 1); 输出一个数

[a,b]

int a=(int)(Math.random()*b + a);

/*
模拟福利彩票开奖
抽奖规则:红球六个在1-33中选择六个不相同的数篮球在1-16中选择1个中奖规则:一等奖:7个号码完全相符(6个红球和1个蓝球)最高奖金为一千万元;
二等奖:6个红球相符,浮动奖金;
三等奖:5个红球和1个蓝球相符,固定奖金每注3000元;
*四等奖:5个红球或4个红球和1个蓝球号码相符,固定奖金每注200元;
*五等奖:4个红球或3个红球+1个蓝球号码相符,固定奖金每注10元;
六等奖:1个蓝球号码相符(有无红球号码相符均可),固定奖金每注5元。*/
import java.util.Scanner;
class CaiPiao
{public static void main(String[] args){Scanner input = new Scanner(System.in);System.out.println("\n请输入红球第一个数值:[1—33]");int number1 = input.nextInt();System.out.println("\n请输入红球第二个数值:[1—33](不可与前面重复)");int number2 = input.nextInt();System.out.println("\n请输入红球第三个数值:[1—33](不可与前面重复)");int number3 = input.nextInt();System.out.println("\n请输入红球第四个数值:[1—33](不可与前面重复)");int number4 = input.nextInt();System.out.println("\n请输入红球第五个数值:[1—33](不可与前面重复)");int number5 = input.nextInt();System.out.println("\n请输入红球第六个数值:[1—33](不可与前面重复)");int number6 = input.nextInt();System.out.println("\n请输入蓝球数值:[1—16]");int number7 = input.nextInt();//1、随机产生六个红球数值范围在[1-33]int[] red=new int[6];//生成随机数for (int i=0;i<red.length;i++){red[i] = (int)(Math.random()*33 + 1);//得到[1,33],即[1,34)}//如有重复的重新赋值(这个不会解决)//打印System.out.println("六个红球数值分别为:");for (int i=0;i<red.length;i++){System.out.println(red[i]);}//1、随机产生蓝球数值范围在[1-16]int[] bule=new int[1];//生成随机数for (int i=0;i<bule.length;i++){bule[i] = (int)(Math.random()*16 + 1);//得到[1,16]}//打印System.out.println("蓝球数值为:");for (int i=0;i<bule.length;i++){System.out.println(bule[i]);}//中奖情况System.out.println("中奖情况:");//一等奖if(number1==red[0]&&number2==red[1]&&number3==red[2]&&number4==red[3]&&number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:一等奖(奖金一千万)");}//二等奖else if(number1==red[0]&&number2==red[1]&&number3==red[2]&&number4==red[3]&&number5==red[4]&&number6==red[5]){System.out.println("中奖了:二等奖(奖金五十万)");}//三等奖else if(number1!=red[0]&&number2==red[1]&&number3==red[2]&&number4==red[3]&&number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:三等奖(奖金3000元)");}else if(number1==red[0]&&number2!=red[1]&&number3==red[2]&&number4==red[3]&&number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:三等奖(奖金3000元)");}else if(number1==red[0]&&number2==red[1]&&number3!=red[2]&&number4==red[3]&&number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:三等奖(奖金3000元)");}else if(number1==red[0]&&number2==red[1]&&number3==red[2]&&number4!=red[3]&&number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:三等奖(奖金3000元)");}else if(number1==red[0]&&number2==red[1]&&number3==red[2]&&number4==red[3]&&number5!=red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:三等奖(奖金3000元)");}else if(number1==red[0]&&number2==red[1]&&number3==red[2]&&number4==red[3]&&number5==red[4]&&number6!=red[5]&&number7==bule[0]){System.out.println("中奖了:三等奖(奖金3000元)");}//四等奖:5个红球或4个红球和1个蓝球号码相符else if(number1!=red[0]&&number2==red[1]&&number3==red[2]&&number4==red[3]&&number5==red[4]&&number6==red[5]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number1==red[0]&&number2!=red[1]&&number3==red[2]&&number4==red[3]&&number5==red[4]&&number6==red[5]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number1==red[0]&&number2==red[1]&&number3!=red[2]&&number4==red[3]&&number5==red[4]&&number6==red[5]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number1==red[0]&&number2==red[1]&&number3==red[2]&&number4!=red[3]&&number5==red[4]&&number6==red[5]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number1==red[0]&&number2==red[1]&&number3==red[2]&&number4==red[3]&&number5!=red[4]&&number6==red[5]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number1==red[0]&&number2==red[1]&&number3==red[2]&&number4==red[3]&&number5==red[4]&&number6!=red[5]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number1!=red[0]&&number2==red[1]||number3==red[2]&&number4==red[3]&&number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number1!=red[0]&&number2==red[1]&&number3==red[2]||number4==red[3]&&number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number1!=red[0]&&number2==red[1]&&number3==red[2]&&number4==red[3]||number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number1!=red[0]&&number2==red[1]&&number3==red[2]&&number4==red[3]&&number5==red[4]||number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number2!=red[1]&&number1==red[0]||number3==red[2]&&number4==red[3]&&number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number2!=red[1]&&number1==red[0]&&number3==red[2]||number4==red[3]&&number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number2!=red[1]&&number1==red[0]&&number3==red[2]&&number4==red[3]||number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number2!=red[1]&&number1==red[0]&&number3==red[2]&&number4==red[3]&&number5==red[4]||number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number3!=red[2]&&number2==red[1]||number1==red[0]&&number4==red[3]&&number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number3!=red[2]&&number2==red[1]&&number1==red[0]||number4==red[3]&&number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number3!=red[2]&&number1==red[1]&&number1==red[0]&&number4==red[3]||number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number3!=red[2]&&number2==red[1]&&number1==red[0]&&number4==red[3]&&number5==red[4]||number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number4!=red[3]&&number2==red[1]||number3==red[2]&&number1==red[0]&&number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number4!=red[3]&&number2==red[1]&&number3==red[2]||number1==red[0]&&number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number4!=red[3]&&number2==red[1]&&number3==red[2]&&number1==red[0]||number5==red[4]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number4!=red[3]&&number2==red[1]&&number3==red[2]&&number1==red[0]&&number5==red[4]||number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number5!=red[4]&&number2==red[1]||number3==red[2]&&number4==red[3]&&number1==red[0]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number5!=red[4]&&number2==red[1]&&number3==red[2]||number4==red[3]&&number1==red[0]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number5!=red[4]&&number2==red[1]&&number3==red[2]&&number4==red[3]||number1==red[0]&&number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}else if(number5!=red[4]&&number2==red[1]&&number3==red[2]&&number4==red[3]&&number1==red[0]||number6==red[5]&&number7==bule[0]){System.out.println("中奖了:四等奖(奖金200元)");}//五等奖//...else if(number7==bule[0]){System.out.println("中奖了:六等奖(奖金5元)");}else{System.out.println("很遗憾,你没中奖,再来一次喂!");}}
}

switch—case

分支结构之二:switch-case1.格式
switch(表达式){
case 常量1:执行语句1;break;case 常量2:执行语句2;break;...default:执行语句n;break;}

说明:

  • ① 根据switch表达式中的值,依次匹配各个case中的常量。一旦匹配成功,则进入相应case结构中,调用其执行语句。

当调用完执行语句以后,则仍然继续向下执行其他case结构中的执行语句,直到遇到break关键字或此switch-case结构

末尾结束为止。

  • ② break,可以使用在switch-case结构中,表示一旦执行到此关键字,就跳出switch-case结构

  • ③ switch结构中的表达式,只能是如下的6种数据类型之一:

byte 、short、char、int、枚举类型(JDK5.0新增)、String类型(JDK7.0新增)

  • ④ case 之后只能声明常量。不能声明范围。

  • ⑤ break关键字是可选的。

  • ⑥ default:相当于if-else结构中的else.

default结构是可选的,而且位置是灵活的。

class SwitchCaseTest {public static void main(String[] args) {int number = 5;switch(number){case 0:System.out.println("zero");break;case 1:System.out.println("one");break;case 2:System.out.println("two");break;case 3:System.out.println("three");break;default:System.out.println("other");//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;}//**************如下的两种情况都编译不通过*********************//情况一/*boolean isHandsome = true;switch(isHandsome){case true:System.out.println("我好帅啊~~~");break;case false:System.out.println("我好丑啊~~~");break;default:System.out.println("输入有误~~~");}//情况二int age = 10;switch(age){case age > 18:System.out.println("成年了");break;default:System.out.println("未成年");}*/}
}

例题2

/*
用swith——case来写这个及格问题
*/
import java.util.Scanner;
class GreadTest
{public static void main(String[] args){Scanner scan = new Scanner(System.in);System.out.println("请输入你的成绩:");int gread = scan.nextInt();switch (gread/60){case 1:System.out.println("及格");break;case 0:System.out.println("不及格");break;}}
}方式二:
int score = 78;switch(score / 10){case 0:case 1:case 2:case 3:case 4:case 5:System.out.println("不及格");break;case 6:case 7:case 8:case 9:case 10:System.out.println("及格");break;}

例题3

循环结构

For循环结构

For循环结构的使用

一、循环结构的4个要素

① 初始化条件

② 循环条件 --->是boolean类型

③ 循环体

④ 迭代条件

二、for循环的结构

for(初始化条件;循环条件;迭代条件){

循环体

}

执行过程:① - ② - ③ - ④ - ② - ③ - ④ - ... - ②

练习1

class ForTest
{public static void main(String[] args){//遍历0-100的偶数,输出所有偶数的和/*int i=0;int sum=0;int count=0;for (i=0 ; i<=100 ; i++){if (i%2==0){System.out.println(i);sum +=i;count +=1; //设置计数器的思想}}System.out.println("所有偶数的和为:"+sum);System.out.println("所有偶数的个数为:"+count);*//*
编写程序从1循环到150,并在每行打印一个值,
另外在每个3的倍数行上打印出“foo”,
在每个5的倍数行上打印“biz”,
在每个7的倍数行上打印输出“baz”。*/int i=1;for (i=1; i<=150 ; i++ ){System.out.print(i+" ");if (i%3==0){System.out.print(" foo ");}if (i%5==0){System.out.print(" biz ");}if (i%7==0){System.out.println(" baz ");}else{System.out.println(" ");}}}
}

break关键字的使用

例题:

/*
题目:输入两个正整数m和n,求其最大公约数和最小公倍数。
比如:12和20的最大公约数是4,最小公倍数是60。说明:break关键字的使用:一旦在循环中执行到break,就跳出循环*/import java.util.Scanner;class ForTest{public static void main(String[] args){Scanner input = new Scanner(System.in);System.out.println("请输入正整数m: ");int  m = input.nextInt();System.out.println("请输入正整数n: ");int  n = input.nextInt();//最大公约数//获取两个数之中的最小值int min = (m<=n)? m:n;for (int i=min ; i>=1 ; i-- ){if (m%i==0&&n%i==0){System.out.println("最大公约数为:\n"+i);break;}}//最小公倍数//获取两个数最大的int max = (m>=n)? m:n;for (int i = max ; i<=m*n ; i++ ){if (i%m==0 && i%n==0){System.out.println("最小公倍数为:\n"+i);break;}}}
}

while循环结构

While 循环的使用

一、循环结构的4个要素

① 初始化条件

② 循环条件 --->是boolean类型

③ 循环体

④ 迭代条件

二、while循环的结构

初始化条件

while(循环条件){

循环体;

迭代条件;

}

执行过程:① - ② - ③ - ④ - ② - ③ - ④ - ... - ②

说明:

1.写while循环千万小心不要丢了迭代条件。一旦丢了,就可能导致死循环!

2.我们写程序,要避免出现死循环。

3.for循环和while循环是可以相互转换的!

区别:for循环和while循环的初始化条件部分的作用范围不同。

算法:有限性。

class  WhileTest{public static void main(String[] args) {//遍历100以内的所有偶数int i = 1;while(i <= 100){if(i % 2 == 0){System.out.println(i);}i++;}//出了while循环以后,仍可以调用。System.out.println(i);//101}
}

do—while循环结构

do-while循环的使用

一、循环结构的4个要素

① 初始化条件

② 循环条件 --->是boolean类型

③ 循环体

④ 迭代条件

二、do-while循环结构:

初始化条件

do{

循环体;

迭代条件;

}while(循环条件);

执行过程:① - ③ - ④ - ② - ③ - ④ - ... - ②

说明:

1.do-while循环至少会执行一次循环体!

2.开发中,使用for和while更多一些。较少使用do-while

class DoWhileTest {public static void main(String[] args) {//遍历100以内的偶数,并计算所有偶数的和及偶数的个数int num = 1;int sum = 0;//记录总和int count = 0;//记录个数do{if(num % 2 == 0){System.out.println(num);sum += num;count++;}num++;}while(num <= 100);System.out.println("总和为:" + sum);System.out.println("个数为:" + count);//*************体会do-while至少执行一次循环体***************int number1 = 10;while(number1 > 10){System.out.println("hello:while");number1--;}int number2 = 10;do{System.out.println("hello:do-while");number2--;}while(number2 > 10);}
}

综合例题:

/*
题目:
从键盘读入个数不确定的整数,并判断读入的正数和负数的个数,输入为0时结束程序。**说明:
1. 不在循环条件部分限制次数的结构:for(;;) 或 while(true)
2. 结束循环有几种方式?方式一:循环条件部分返回false方式二:在循环体中,执行break**
*/
import java.util.Scanner;
class ForTest{public static void main(String[] args){Scanner scan = new Scanner(System.in);System.out.println("请输入.....");int count_zheng = 0;//计数int count_fu = 0;//计数while(true){int number = scan.nextInt();if (number>0){count_zheng +=1;}else if (number<0){count_fu +=1;}else{break;}}System.out.println("正数个数为:"+count_zheng+"    负数个数为:"+count_fu);}}

嵌套循环

嵌套循环的使用

1.嵌套循环:将一个循环结构A声明在另一个循环结构B的循环体中,就构成了嵌套循环

外层循环:循环结构B

内层循环:循环结构A

  1. 说明

① 内层循环结构遍历一遍,只相当于外层循环循环体执行了一次

② 假设外层循环需要执行m次,内层循环需要执行n次。此时内层循环的循环体一共执行了m * n次

  1. 技巧:

外层循环控制行数,内层循环控制列数

//画星星
class ForForTest {public static void main(String[] args) {//******//System.out.println("******");for(int i = 1;i <= 6;i++){System.out.print('*');}System.out.println("\n");/**************************/for(int j = 1;j <= 4;j++ ){for(int i = 1;i <= 6;i++){System.out.print('*');}System.out.println();}/*      i(行号)    j(*的个数)*      1      1**      2      2***      3      3****    4      4*****    5      5*/for(int i = 1;i <= 5;i++){//控制行数for(int j = 1;j <= i;j++){//控制列数System.out.print("*");}System.out.println();}/*      i(行号)    j(*的个数)   规律:i + j = 5 换句话说:j = 5 - i;****    1      4***      2      3**      3      2*      4      1*/  for(int i = 1;i <= 4;i++){for(int j = 1;j <= 5 - i;j++){System.out.print("*");  }System.out.println();}/***************************///略上面两个相加就行/*----* ---* * --* * * -* * * * * * * * * * * * * * * * * * * *///上半部分for (int i=1 ; i<=5 ; i++ ){for (int j=1; j<=5-i ;j++ ){System.out.print(" ");}for (int k=1; k<=i ; k++ ){System.out.print("* ");}System.out.println();}//下半部分for (int i=1; i<=4 ; i++ ){for (int j=1; j<=i ; j++ ){System.out.print(" ");}for (int k=1; k<=5-i ; k++ ){System.out.print("* ");}System.out.println();}}
}

九九乘法表

/*
嵌套循环的应用1:九九乘法表
1 * 1 = 1
2 * 1 = 2  2 * 2 = 4
。。。
9 * 1 = 9 。。。 9 * 9 = 81*/class ForTest{public static void main(String[] args){for (int i=1; i<=9 ; i++ ){for (int j=1; j<=i ; j++ ){System.out.print(i+"*"+j+"="+(i*j)+"\t");}System.out.println();}}
}

一百以内所有的质数

/*
100以内的所有质数的输出。
质数:素数,只能被1和它本身整除的自然数。-->从2开始,到这个数-1结束为止,都不能被这个数本身整除。最小的质数是:2
*/
class PrimeNumberTest {public static void main(String[] args) {boolean isFlag = true;//标识i是否被j除尽,一旦除尽,修改其值for(int i = 2;i <= 100;i++){//遍历100以内的自然数for(int j = 2;j < i;j++){//j:被i去除if(i % j == 0){ //i被j除尽isFlag = false;}}//if(isFlag == true){System.out.println(i);}//重置isFlagisFlag = true;}}
}

优化

/*
100000以内的所有质数的输出。实现方式一
质数:素数,只能被1和它本身整除的自然数。-->从2开始,到这个数-1结束为止,都不能被这个数本身整除。对PrimeNumberTest.java文件中质数输出问题的优化
*/
class PrimeNumberTest1 {public static void main(String[] args) {boolean isFlag = true;//标识i是否被j除尽,一旦除尽,修改其值int count = 0;//记录质数的个数//获取当前时间距离1970-01-01 00:00:00 的毫秒数long start = System.currentTimeMillis();for(int i = 2;i <= 100000;i++){//遍历100000以内的自然数//优化二:对本身是质数的自然数是有效的。//for(int j = 2;j < i;j++){for(int j = 2;j <= Math.sqrt(i);j++){//j:被i去除(开方)if(i % j == 0){ //i被j除尽(只要有一个被除尽这个数就不是质数了直接break)isFlag = false;break;//优化一:只对本身非质数的自然数是有效的。}}//if(isFlag == true){System.out.println(i);count++;}//重置isFlagisFlag = true;}//获取当前时间距离1970-01-01 00:00:00 的毫秒数long end = System.currentTimeMillis();System.out.println("质数的个数为:" + count);System.out.println("所花费的时间为:" + (end - start));//17110 - 优化一:break:1546 - 优化二:13}
}

写法二:

/*
100以内的所有质数的输出。
质数:素数,只能被1和它本身整除的自然数。-->从2开始,到这个数-1结束为止,都不能被这个数本身整除。最小的质数是:2
*/
class ForTest{public static void main(String[] args){int count=0;label:for (int i=2 ; i<=100 ; i++ ){for (int j=2 ; j<=Math.sqrt(i) ; j++ ){if (i%j==0){continue label;}}System.out.println(i);count+=1;}System.out.println(count);}
}

break与continue关键字的使用

使用范围 循环中使用的作用(不同点) 相同点

break: switch-case

             循环结构中      结束当前循环          关键字后面不能声明执行语句  

continue: 循环结构中 结束当次循环 关键字后面不能声明执行语句

class BreakContinueTest {public static void main(String[] args) {for(int i = 1;i <= 10;i++){if(i % 4 == 0){break;//123//continue;//123567910//System.out.println("今晚迪丽热巴要约我!!!");}System.out.print(i);}System.out.println("\n");//******************************label:for(int i = 1;i <= 4;i++){for(int j = 1;j <= 10;j++){if(j % 4 == 0){//break;//默认跳出包裹此关键字最近的一层循环。//continue;//break label;//结束指定标识的一层循环结构continue label;//结束指定标识的一层循环结构当次循环(可任意命名)}System.out.print(j);}System.out.println();}}
}

03 Eclipse的使用

快捷键

  • *1.补全代码的声明:alt + /

  • 2.快速修复: ctrl + 1

  • 3.批量导包:ctrl + shift + o

  • 4.使用单行注释:ctrl + /

  • 5.使用多行注释: ctrl + shift + /

  • 6.取消多行注释:ctrl + shift + \

  • 7.复制指定行的代码:ctrl + alt + down 或 ctrl + alt + up

  • 8.删除指定行的代码:ctrl + d

  • 9.上下移动代码:alt + up 或 alt + down

  • 10.切换到下一行代码空位:shift + enter

  • 11.切换到上一行代码空位:ctrl + shift + enter

  • 12.如何查看源码:ctrl + 选中指定的结构 或 ctrl + shift + t

  • 13.退回到前一个编辑的页面:alt + left

  • 14.进入到下一个编辑的页面(针对于上面那条来说的):alt + right

  • 15.光标选中指定的类,查看继承树结构:ctrl + t

  • 16.复制代码: ctrl + c

  • 17.撤销: ctrl + z

  • 18.反撤销: ctrl + y

  • 19.剪切:ctrl + x

  • 20.粘贴:ctrl + v

  • 21.保存: ctrl + s

  • 22.全选:ctrl + a

  • 23.格式化代码: ctrl + shift + f

  • 24.选中数行,整体往后移动:tab

  • 25.选中数行,整体往前移动:shift + tab

  • 26.在当前类中,显示类结构,并支持搜索指定的方法、属性等:ctrl + o

  • 27.批量修改指定的变量名、方法名、类名等:alt + shift + r

  • 28.选中的结构的大小写的切换:变成大写: ctrl + shift + x

  • 29.选中的结构的大小写的切换:变成小写:ctrl + shift + y

  • 30.调出生成 getter/setter/构造器等结构: alt + shift + s

  • 31.显示当前选择资源(工程 or 文件)的属性:alt + enter

  • 32.快速查找:参照选中的 Word 快速定位到下一个 :ctrl + k

  • 33.关闭当前窗口:ctrl + w

  • 34.关闭所有的窗口:ctrl + shift + w

  • 35.查看指定的结构使用过的地方:ctrl + alt + g

  • 36.查找与替换:ctrl + f

  • 37.最大化当前的 View:ctrl + m

  • 38.直接定位到当前行的首位:home

  • 39.直接定位到当前行的末位:end

04 数 组

  • 一、数组的概述

  • 1.数组的理解:数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,

  • 并通过编号的方式对这些数据进行统一管理。

  • 2.数组相关的概念:

  • 数组名

  • 元素

  • 角标、下标、索引

  • 数组的长度:元素的个数

  • 3.数组的特点:

  • 1)数组是有序排列的

  • 2)数组属于引用数据类型的变量。数组的元素,既可以是基本数据类型,也可以是引用数据类型

  • 3)创建数组对象会在内存中开辟一整块连续的空间

  • 4)数组的长度一旦确定,就不能修改。

  • 4. 数组的分类:

  • ① 按照维数:一维数组、二维数组、。。。

  • ② 按照数组元素的类型:基本数据类型元素的数组、引用数据类型元素的数组

  • 5. 一维数组的使用

  • ① 一维数组的声明和初始化

  • ② 如何调用数组的指定位置的元素

  • ③ 如何获取数组的长度

  • ④ 如何遍历数组

  • ⑤ 数组元素的默认初始化值

  • ⑥ 数组的内存解析

public class ArrayTest {public static void main(String[] args) {//1. 一维数组的声明和初始化int num;//声明num = 10;//初始化int id = 1001;//声明 + 初始化int[] ids;//声明//1.1 静态初始化:数组的初始化和数组元素的赋值操作同时进行ids = new int[]{1001,1002,1003,1004};//1.2动态初始化:数组的初始化和数组元素的赋值操作分开进行String[] names = new String[5];//也是正确的写法:int[] arr4 = {1,2,3,4,5};//类型推断//总结:数组一旦初始化完成,其长度就确定了。//2.如何调用数组的指定位置的元素:通过角标的方式调用。//数组的角标(或索引)从0开始的,到数组的长度-1结束。names[0] = "王铭";names[1] = "王赫";names[2] = "张学良";names[3] = "孙居龙";names[4] = "王宏志";//charAt(0)
//    names[5] = "周扬";//3.如何获取数组的长度。//属性:lengthSystem.out.println(names.length);//5System.out.println(ids.length);//4.如何遍历数组/*System.out.println(names[0]);System.out.println(names[1]);System.out.println(names[2]);System.out.println(names[3]);System.out.println(names[4]);*/for(int i = 0;i < names.length;i++){System.out.println(names[i]);}}}

**⑤ 数组元素的默认初始化值 **

  • > 数组元素是整型:0

  • > 数组元素是浮点型:0.0

  • > 数组元素是char型:0或'\u0000',而非'0'

  • > 数组元素是boolean型:false

  • > 数组元素是引用数据类型:null

package com.atguigu.java;
/** ⑤ 数组元素的默认初始化值*     > 数组元素是整型:0*     > 数组元素是浮点型:0.0*     > 数组元素是char型:0或'\u0000',而非'0'*     > 数组元素是boolean型:false* *     > 数组元素是引用数据类型:null*  *  ⑥ 数组的内存解析*/
public class ArrayTest1 {public static void main(String[] args) {//5.数组元素的默认初始化值int[] arr = new int[4];for(int i = 0;i < arr.length;i++){System.out.println(arr[i]);}System.out.println("**********");short[] arr1 = new short[4];for(int i = 0;i < arr1.length;i++){System.out.println(arr1[i]);}System.out.println("**********");float[] arr2 = new float[5];for(int i = 0;i < arr2.length;i++){System.out.println(arr2[i]);}System.out.println("**********");char[] arr3 = new char[4];for(int i = 0;i < arr3.length;i++){System.out.println("----" + arr3[i] + "****");}if(arr3[0] == 0){System.out.println("你好!");}System.out.println("**********");boolean[] arr4 = new boolean[5];System.out.println(arr4[0]);System.out.println("**********");String[] arr5 = new String[5];System.out.println(arr5[0]);if(arr5[0] == null){System.out.println("北京天气不错!");}}}

⑥ 数组的内存解析

放在方法中得变量都叫及局部变量,放在栈中

数组练习2

package com.java.exer;import java.util.Scanner;/** 2. 从键盘读入学生成绩,找出最高分,并输出学生成绩等级。成绩>=最高分-10    等级为’A’   成绩>=最高分-20    等级为’B’成绩>=最高分-30    等级为’C’   其余                               等级为’D’提示:先读入学生人数,根据人数创建int数组,存放学生成绩。* */public class LianXi {public static void main(String[] args) {//1.使用Scanner,读取学生个数Scanner scan = new Scanner(System.in);System.out.println("请输入学生个数:");int m=scan.nextInt();//创建数组,存储学生成绩,动态初始化int[] arr = new int[m];//给数组元素赋值System.out.println("请输入学生成绩:");for (int i=0;i<m;i++){int sroce=scan.nextInt();arr[i]=sroce;}//找出数组元素中的最大值(最高分)int maxsroce=0;System.out.println("\n");for (int i=0;i<arr.length;i++){if(arr[i]>maxsroce){maxsroce=arr[i];}  }System.out.println("最高分为:"+maxsroce+"\n");//根据每个学生的分数差值,得到每个小学生的等级String level="";for (int i=0;i<arr.length;i++){if(arr[i]>=maxsroce-10){level="A";}else if(arr[i]>=maxsroce-20){level="B";}else if(arr[i]>=maxsroce-30){level="C";}else{level="D";}System.out.println("第"+(i+1)+"个学生的成绩为:"+arr[i]+"    该学生的成绩等级为:"+level);}  }}

二维数组的使用

  • 如果说可以把一维数组当成几何中的线性图形,那么二维数组就相当于是一个表格,像右图Excel中的表格一样。

  • 对于二维数组的理解,我们可以看成是一维数组array1又作为另一个一维数组array2的元素而存在。其实,从数组底层的运行机制来看,其实没有多维数组。

  • 2. 二维数组的使用:

  • ① 二维数组的声明和初始化

  • ② 如何调用数组的指定位置的元素

  • ③ 如何获取数组的长度

  • ④ 如何遍历数组

  • ⑤ 数组元素的默认初始化值

  • ⑥ 数组的内存解析

public class ArrayTest2 {public static void main(String[] args) {//1.二维数组的声明和初始化int[] arr = new int[]{1,2,3};//一维数组//静态初始化int[][] arr1 = new int[][]{{1,2,3},{4,5},{6,7,8}};//动态初始化1String[][] arr2 = new String[3][2];//动态初始化2String[][] arr3 = new String[3][];//错误的情况
//    String[][] arr4 = new String[][4];
//    String[4][3] arr5 = new String[][];
//    int[][] arr6 = new int[4][3]{{1,2,3},{4,5},{6,7,8}};//也是正确的写法:int[] arr4[] = new int[][]{{1,2,3},{4,5,9,10},{6,7,8}};int[] arr5[] = {{1,2,3},{4,5},{6,7,8}};//2.如何调用数组的指定位置的元素System.out.println(arr1[0][1]);//2System.out.println(arr2[1][1]);//nullarr3[1] = new String[4];System.out.println(arr3[1][0]);//3.获取数组的长度System.out.println(arr4.length);//3System.out.println(arr4[0].length);//3System.out.println(arr4[1].length);//4//4.如何遍历二维数组for(int i = 0;i < arr4.length;i++){for(int j = 0;j < arr4[i].length;j++){System.out.print(arr4[i][j] + "  ");}System.out.println();}}
}
  • 二维数组的使用:

  • 规定:二维数组分为外层数组的元素,内层数组的元素

  • int[ ][ ] arr = new int[4][3];

  • 外层元素:arr[0],arr[1]等

  • 内层元素:arr[0][0],arr[1][2]等

  • ⑤ **数组元素的默认初始化值 **

  • 针对于初始化方式一:比如:int[ ][ ] arr = new int[4][3];

  • 外层元素的初始化值为:地址值

  • 内层元素的初始化值为:与一维数组初始化情况相同

  • 针对于初始化方式二:比如:int[ ][ ] arr = new int[4][];

  • 外层元素的初始化值为:null

  • 内层元素的初始化值为:不能调用,否则报错。

  • ⑥ 数组的内存解析

public class ArrayTest3 {public static void main(String[] args) {int[][] arr = new int[4][3];System.out.println(arr[0]);//[I@15db9742 System.out.println(arr[0][0]);//0//    System.out.println(arr);//[[I@6d06d69cSystem.out.println("*****************");float[][] arr1 = new float[4][3];System.out.println(arr1[0]);//地址值System.out.println(arr1[0][0]);//0.0System.out.println("*****************");String[][] arr2 = new String[4][2];System.out.println(arr2[1]);//地址值System.out.println(arr2[1][1]);//nullSystem.out.println("*****************");double[][] arr3 = new double[4][];System.out.println(arr3[1]);//null(因为是引用类型)
//    System.out.println(arr3[1][0]);//报错}
}

//杨辉三角
package com.java.exer;public class YangHuiTest {public static void main(String[] args) {//声明二维数组int[][] yanghui=new int[10][];//赋值for (int i =0;i<yanghui.length;i++){//声明二维数组yanghui[i]=new int[i+1];//给首末元素赋值yanghui[i][0]=1;yanghui[i][i]=1;//给每行的非首末元素赋值if (i>=2){for(int j=1;j<yanghui[i].length-1;j++){yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];}}}for(int i=0;i<yanghui.length;i++){for(int j=0;j<yanghui[i].length;j++){System.out.print(yanghui[i][j]+"\t");}System.out.println();}}
}

数据结构:

1、数据与数据之间的逻辑关系:集合、一对一、一对多、多对多

2、数据存储结构

一对一

线性表:(比如):数组、链表、栈、队列

一对多关系

树形结构:二叉树

多对多

图模型结构:

算法:

排序算法:

搜索算法:

数组中 涉及的常见算法

数组元素的赋值(杨辉三角、回型数等)

求数值型数组中元素的最大最小值、平均数、总和等

package com.java.mianshi;
//[随机生成10-99]的数
//arr[i]=(int)(Math.random()*(99-10+1)+10);
import java.util.Scanner;public class Huishu {public static void main(String[] args) {Scanner scan=new Scanner(System.in);System.out.println("你想生成多少个随机数:\n请输入....");int len =scan.nextInt();int[] arr = new int[len];System.out.println();//生成不重复的数for (int i=0 ; i<arr.length ; i++){arr[i]=(int)(Math.random()*(99-10+1)+10);boolean flag=false;while(true){for(int j =0;j<i;j++){if(arr[j]==arr[i]){flag=true;break;}}if(flag){arr[i]=(int)(Math.random()*(99-10+1)+10);flag =false;continue;}break;}System.out.println(arr[i]);}//求和int sum=0;for (int i=0;i<arr.length;i++){sum +=arr[i];}System.out.println("\n总和为:"+sum);//求最大值int max = arr[0];for (int i=0;i<arr.length;i++){if(arr[i]>=max){max=arr[i];}}System.out.println("\n最大值为:"+max);//求最小值int min =arr[0];for(int i=0;i<arr.length;i++){if(arr[i]<=min){min =arr[i];}}System.out.println("\n最小值为:"+min);//平均值int avg =sum/len;System.out.println("\n平均值为:"+avg);}}

数组的复制、反转、查找、(线性查找、二分法查找)

package com.atguigu.exer;
/** 使用简单数组
(1)创建一个名为ArrayExer2的类,在main()方法中声明array1和array2两个变量,他们是int[]类型的数组。
(2)使用大括号{},把array1初始化为8个素数:2,3,5,7,11,13,17,19。
(3)显示array1的内容。
(4)赋值array2变量等于array1,修改array2中的偶索引元素,使其等于索引值(如array[0]=0,array[2]=2)。打印出array1。* * 思考:**array1和array2是什么关系?array1和array2地址值相同,都指向了堆空间的唯一的一个数组实体。*** 拓展:修改题目,实现array2对array1数组的复制*/
public class ArrayExer2 {public static void main(String[] args) {  //alt + /int[] array1,array2;array1 = new int[]{2,3,5,7,11,13,17,19};//显示array1的内容for(int i = 0;i < array1.length;i++){System.out.print(array1[i] + "\t");}//赋值array2变量等于array1//不能称作数组的复制。array2 = array1;//修改array2中的偶索引元素,使其等于索引值(如array[0]=0,array[2]=2)for(int i = 0;i < array2.length;i++){if(i % 2 == 0){array2[i] = i;}}System.out.println();//打印出array1for(int i = 0;i < array1.length;i++){System.out.print(array1[i] + "\t");}}
}
  package com.atguigu.java;
/** 算法的考查:数组的复制、反转、查找(线性查找、二分法查找)* * */
public class ArrayTest2 {public static void main(String[] args) {String[] arr = new String[]{"JJ","DD","MM","BB","GG","AA"};//数组的复制(区别于数组变量的赋值:arr1 = arr)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,j = arr.length - 1;i < j;i++,j--){
//      String temp = arr[i];
//      arr[i] = arr[j];
//      arr[j] = temp;
//    }//遍历for(int i = 0;i < arr.length;i++){System.out.print(arr[i] + "\t");}System.out.println();//查找(或搜索)//线性查找:String dest = "BB";dest = "CC";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("很遗憾,没有找到噢!");}//二分法查找:(熟悉)//前提:所要查找的数组必须有序。int[] arr2 = new int[]{-98,-34,2,34,54,66,79,105,210,333};int dest1 = -34;dest1 = 35;int head = 0;//初始的首索引int end = arr2.length - 1;//初始的末索引boolean isFlag1 = true;while(head <= end){int middle = (head + end)/2;if(dest1 == arr2[middle]){System.out.println("找到了指定的元素,位置为:" + middle);isFlag1 = false;break;}else if(arr2[middle] > dest1){end = middle - 1;}else{//arr2[middle] < dest1head = middle + 1;}}if(isFlag1){System.out.println("很遗憾,没有找到的啦!");}}
}

数组元素的排序算法

冒泡排序

package com.atguigu.java;
/** 数组的冒泡排序的实现* */
public class BubbleSortTest {public static void main(String[] args) {int[] arr = new int[]{43,32,76,-98,0,64,33,-21,32,99};//冒泡排序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;}}}for(int i = 0;i < arr.length;i++){System.out.print(arr[i] + "\t");}}
}

快速排序

package com.atguigu.java;/*** 快速排序* 通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,* 则分别对这两部分继续进行排序,直到整个序列有序。* @author shkstart* 2018-12-17*/
public class QuickSort {private static void swap(int[] data, int i, int j) {int temp = data[i];data[i] = data[j];data[j] = temp;}private static void subSort(int[] data, int start, int end) {if (start < end) {int base = data[start];int low = start;int high = end + 1;while (true) {while (low < end && data[++low] - base <= 0);while (high > start && data[--high] - base >= 0);if (low < high) {swap(data, low, high);} else {break;}}swap(data, start, high);subSort(data, start, high - 1);//递归调用subSort(data, high + 1, end);}}public static void quickSort(int[] data){subSort(data,0,data.length-1);}public static void main(String[] args) {int[] data = { 9, -16, 30, 23, -30, -49, 25, 21, 30 };System.out.println("排序之前:\n" + java.util.Arrays.toString(data));quickSort(data);System.out.println("排序之后:\n" + java.util.Arrays.toString(data));}
}

Arrays工具类的使用

package com.atguigu.java;import java.util.Arrays;/** java.util.Arrays:操作数组的工具类,里面定义了很多操作数组的方法* * */
public class ArraysTest {public static void main(String[] args) {//1.boolean equals(int[] a,int[] b):判断两个数组是否相等。int[] arr1 = new int[]{1,2,3,4};int[] arr2 = new int[]{1,3,2,4};boolean isEquals = Arrays.equals(arr1, arr2);System.out.println(isEquals);//2.String toString(int[] a):输出数组信息。System.out.println(Arrays.toString(arr1));//3.void fill(int[] a,int val):将指定值填充到数组之中。Arrays.fill(arr1,10);System.out.println(Arrays.toString(arr1));//4.void sort(int[] a):对数组进行排序。Arrays.sort(arr2);System.out.println(Arrays.toString(arr2));//5.int binarySearch(int[] a,int key)int[] arr3 = new int[]{-98,-34,2,34,54,66,79,105,210,333};int index = Arrays.binarySearch(arr3, 210);if(index >= 0){System.out.println(index);}else{System.out.println("未找到");}}
}

05 *面向对象

** * 一、Java面向对象学习的三条主线:(第4-6章)**

  • 1.Java类及类的成员:属性、方法、构造器;代码块、内部类

  • 2.面向对象的三大特征:封装性、继承性、多态性、(抽象性)

  • 3.其它关键字:this、super、static、final、abstract、interface、package、import等

  • “大处着眼,小处着手”

package com.atguigu.java;
/** 一、Java面向对象学习的三条主线:(第4-6章)* 1.Java类及类的成员:属性、方法、构造器;代码块、内部类* * 2.面向对象的三大特征:封装性、继承性、多态性、(抽象性)* * 3.其它关键字:this、super、static、final、abstract、interface、package、import等* * “大处着眼,小处着手”* * * 二、“人把大象装进冰箱”* * 1.面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做。* * ① 把冰箱门打开* ② 抬起大象,塞进冰箱* ② 把冰箱门关闭* * 2.面向对象:强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。* * 人{*     打开(冰箱){*       冰箱.开开();*     }* *     抬起(大象){*       大象.进入(冰箱);*     }* *     关闭(冰箱){*       冰箱.闭合();*     }* * }* * * 冰箱{*     开开(){}*     闭合(){}* }* * 大象{*     进入(冰箱){*     }* }* * 三、面向对象的两个要素:* 类:对一类事物的描述,是抽象的、概念上的定义* 对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)* >面向对象程序设计的重点是类的设计* >设计类,就是设计类的成员。* */
public class OOPTest {}
  • 属性 = 成员变量 = field = 域、字段

  • 方法 = 成员方法 = 函数 = method

  • 创建类的对象 = 类的实例化 = 实例化类

** 类和对象的使用**

(面向对象思想落地的实现):

  • 1.创建类,设计类的成员

  • 2.创建类的对象

  • 3.通过“对象.属性”或“对象.方法”调用对象的结构

package com.atguigu.java;
/** 一、设计类,其实就是设计类的成员* *  属性 = 成员变量 = field = 域、字段*  方法 = 成员方法 = 函数 = method* *  创建类的对象 = 类的实例化 = 实例化类* * 二、类和对象的使用(面向对象思想落地的实现):*  1.创建类,设计类的成员*  2.创建类的对象*  3.通过“对象.属性”或“对象.方法”调用对象的结构*
** * 三、如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)*   意味着:如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值。***   * 四、对象的内存解析*/
//测试类
public class PersonTest {public static void main(String[] args) {//2. 创建Person类的对象Person p1 = new Person();//Scanner scanner = new Scanner(System.in);//调用对象的结构:属性、方法//调用属性:“对象.属性”p1.name = "Tom";p1.isMale = true;System.out.println(p1.name);//调用方法:“对象.方法”p1.eat();p1.sleep();p1.talk("Chinese");//*******************************Person p2 = new Person();System.out.println(p2.name);//nullSystem.out.println(p2.isMale);//*******************************//将p1变量保存的对象地址值赋给p3,导致p1和p3指向了堆空间中的同一个对象实体。Person p3 = p1;System.out.println(p3.name);//Tomp3.age = 10;System.out.println(p1.age);//10}
}//1.创建类,设计类的成员
class Person{//属性String name;int age = 1;boolean isMale;//方法public void eat(){System.out.println("人可以吃饭");}public void sleep(){System.out.println("人可以睡觉");}public void talk(String language){System.out.println("人可以说话,使用的是:" + language);}}

内存解析

类中属性的使用

/** 类中属性的使用* * 属性(成员变量)   vs  局部变量* 1.相同点:*     1.1  定义变量的格式:数据类型  变量名 = 变量值*     1.2 先声明,后使用*     1.3 变量都有其对应的作用域 * * * 2.不同点:*     2.1 在类中声明的位置的不同*     属性:直接定义在类的一对{}内*     局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量*     *     2.2 关于权限修饰符的不同*     属性:可以在声明属性时,指明其权限,使用权限修饰符。*       常用的权限修饰符:private、public、缺省、protected  --->封装性*       目前,大家声明属性时,都使用缺省就可以了。*     局部变量:不可以使用权限修饰符。* *     2.3 默认初始化值的情况:*     属性:类的属性,根据其类型,都有默认初始化值。*       整型(byte、short、int、long):0*       浮点型(float、double):0.0*       字符型(char):0  (或'\u0000')*       布尔型(boolean):false* *       引用数据类型(类、数组、接口):null* *    ** 局部变量:没有默认初始化值。*      意味着,我们在调用局部变量之前,一定要显式赋值。*       特别地:形参在调用时,我们赋值即可。*** *     2.4 在内存中加载的位置:*     属性:加载到堆空间中   (非static)*     局部变量:加载到栈空间* */
public class UserTest {public static void main(String[] args) {User u1 = new User();System.out.println(u1.name);System.out.println(u1.age);System.out.println(u1.isMale);u1.talk("韩语");u1.eat();}
}class User{//属性(或成员变量)String name;public int age;boolean isMale;public void talk(String language){//language:形参,也是局部变量System.out.println("我们使用" + language + "进行交流");}public void eat(){String food = "烙饼";//局部变量System.out.println("北方人喜欢吃:" + food);}}

类中方法的声明和使用

  • 类中方法的声明和使用

  • 方法:描述类应该具有的功能。

  • 比如:Math类:sqrt()\random() ...

  • Scanner类:nextXxx() ...

  • Arrays类:sort() \ binarySearch() \ toString() \ equals() \ ...

  • 1.举例:

  • public void eat(){}

  • public void sleep(int hour){}

  • public String getName(){}

  • public String getNation(String nation){}

  1. 方法的声明:权限修饰符 返回值类型 方法名(形参列表){

  • 方法体

  • }

  • 注意:static、final、abstract 来修饰的方法,后面再讲。

  1. 说明:

  • 3.1 关于权限修饰符:默认方法的权限修饰符先都使用public

  • Java规定的4种权限修饰符:private、public、缺省、protected -->封装性再细说

  • 3.2 返回值类型: 有返回值 vs 没有返回值

***如果方法有返回值,**则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用return关键字来返回指定类型的变量或常量:“return 数据”。***如果方法没有返回值,**则方法声明时,使用void来表示。通常,没有返回值的方法中,就不需要*使用return.但是,如果使用的话,只能“return;”表示结束此方法的意思。

  • 3.2.2 我们定义方法该不该有返回值?

  • ① 题目要求

  • ② 凭经验:具体问题具体分析

  • 3.3 方法名:属于标识符,遵循标识符的规则和规范,“见名知意”

  • 3.4 形参列表: 方法可以声明0个,1个,或多个形参。

  • 3.4.1 格式:数据类型1 形参1,数据类型2 形参2,...

  • 3.4.2 我们定义方法时,该不该定义形参?

  • ① 题目要求

  • ② 凭经验:具体问题具体分析

  • 3.5 方法体:方法功能的体现。

** * 4.return关键字的使用:**

  • 1.使用范围:使用在方法体中

  • 2.作用:① 结束方法

  • **② 针对于有返回值类型的方法,使用"return 数据"方法返回所要的数据。**

  • 3.注意点:**return关键字后面不可以声明执行语句**。

public class CustomerTest {public static void main(String[] args) {Customer cust1 = new Customer();cust1.eat();//测试形参是否需要设置的问题
//    int[] arr = new int[]{3,4,5,2,5};
//    cust1.sort();cust1.sleep(8);}
}//客户类
class Customer{//属性String name;int age;boolean isMale;//方法public void eat(){System.out.println("客户吃饭");return;//return后不可以声明表达式
//    System.out.println("hello");}public void sleep(int hour){System.out.println("休息了" + hour + "个小时");eat();
//    sleep(10);}public String getName(){if(age > 18){return name;}else{return "Tom";}}public String getNation(String nation){String info = "我的国籍是:" + nation;return info;}//体会形参是否需要设置的问题
//  public void sort(int[] arr){
//
//  }
//  public void sort(){
//    int[] arr = new int[]{3,4,5,2,5,63,2,5};
//    //。。。。
//  }public void info(){//错误的
//    public void swim(){
//
//    }}
}
  1. 方法的使用中,可以调用当前类的属性或方法

  • ** 特殊的:方法A中又调用了方法A:递归方法。**

  • **方法中,不可以定义方法。**

理解“万事万物皆对象”

  • 1.在Java语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构

  • Scanner,String等

  • 文件:File

  • 网络资源:URL

  • 2.涉及到Java语言与前端Html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类、对象。

  • 二、内存解析的说明

  • 1.引用类型的变量,只可能存储两类值:null 或 地址值(含变量的类型)

  • 三、匿名对象的使用

  • 1.理解:我们创建的对象,没有显式的赋给一个变量名。即为匿名对象

  • 2.特征:匿名对象只能调用一次。

  • 3.使用:如下

public class InstanceTest {public static void main(String[] args) {Phone p = new Phone();
//    p = null;System.out.println(p);p.sendEmail();p.playGame();//匿名对象
//    new Phone().sendEmail();
//    new Phone().playGame();new Phone().price = 1999;new Phone().showPrice();//0.0//**********************************PhoneMall mall = new PhoneMall();
//    mall.show(p);//匿名对象的使用mall.show(new Phone());}
}class PhoneMall{public void show(Phone phone){phone.sendEmail();phone.playGame();}}class Phone{double price;//价格public void sendEmail(){System.out.println("发送邮件");}public void playGame(){System.out.println("玩游戏");}public void showPrice(){System.out.println("手机价格为:" + price);}}

方法

方法的重载

方法的重载(overload) loading...

1.定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。

"两同一不同":同一个类、相同方法名

  • 参数列表不同:参数个数不同,参数类型不同

  1. 举例:

  • Arrays类中重载的sort() / binarySearch()

3.判断是否是重载:

  • 跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!

  1. 在通过对象调用方法时,如何确定某一个指定的方法:

  • 方法名 ---> 参数列表

可变形参数的方法

  1. jdk 5.0新增的内容

2. 具体使用:

  • 2.1 可变个数形参的格式:数据类型 ... 变量名

  • 2.2 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,。。。

  • 2.3 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载

  • 2.4 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存。

  • 2.5 可变个数形参在方法的形参中,必须声明在末尾

  • 2.6 可变个数形参在方法的形参中,最多只能声明一个可变形参。

public class MethodArgsTest {public static void main(String[] args) {MethodArgsTest test = new MethodArgsTest();test.show(12);
//    test.show("hello");
//    test.show("hello","world");
//    test.show();test.show(new String[]{"AA","BB","CC"});}public void show(int i){}public void show(String s){System.out.println("show(String)");}//可变参数的写法public void show(String ... strs){System.out.println("show(String ... strs)");for(int i = 0;i < strs.length;i++){System.out.println(strs[i]);}}//不能与上一个方法同时存在
//  public void show(String[] strs){
//
//  }//The variable argument type String of the method //show must be the last parameter
//  public void show(String ...strs,int i){
//
//  }}

方法参数的值传递机制

关于变量的赋值:

  • 如果变量是基本数据类型,此时赋值的是变量所保存的数据值。

  • 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。

方法的形参的传递机制:值传递

(针对引用数据类型)

  • 形参:方法定义时,声明的小括号内的参数

  • 实参:方法调用时,实际传递给形参的数据

  • 2.值传递机制:

  • 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。(不能使用)

  • 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。

//目的把 m、n放到堆空间中 地址传递到swap方法中,这样swap中的data的地址值与new出来的data相等指向同一个堆空间中的对象。就可以进行修改了

package com.java.learn09;public class ValueTest {public static void main(String[] args) {Data data =new Data();shuxue s1=new shuxue();data.m=1;data.n=5;data.info();s1.swap(data);data.info();}}class shuxue{//方法void swap(Data data){int temp=data.n;data.n=data.m;data.m=temp;}
}
//目的把  m、n放到堆空间中  地址传递到swap方法中,这样swap中的data的地址值与new出来的data相等指向同一个堆空间中的对象。就可以进行修改了
class Data{//属性int m;int n;public void info(){System.out.println("m="+m+","+"n="+n);}
}

递归

递归方法的使用(了解)

1.递归方法:一个方法体内调用它自身。

  1. 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。

递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。

public class RecursionTest {public static void main(String[] args) {// 例1:计算1-100之间所有自然数的和// 方式一:int sum = 0;for (int i = 1; i <= 100; i++) {sum += i;}System.out.println(sum);// 方式二:RecursionTest test = new RecursionTest();int sum1 = test.getSum(100);System.out.println(sum1);System.out.println("*****************");int value = test.f(10);System.out.println(value);}// 例1:计算1-n之间所有自然数的和public int getSum(int n) {// 3if (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:斐波那契数列//例5:汉诺塔问题//例6:快排}

面向对象特征:

封装与隐藏

面向对象的特征一:封装与隐藏 3W:what? why? how?

一、问题的引入:

  • 当我们创建一个类的对象以后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。这里,赋值操作要受到

  • 属性的数据类型和存储范围的制约。除此之外,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值

  • 加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如:setLegs())

  • 同时,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值。则需要将属性声明为私有的(private).

  • -->此时,针对于属性就体现了封装性。

二、封装性的体现:

  • 我们将类的属性xxx私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值

  • 拓展:封装性的体现:① 如上 ② 不对外暴露的私有的方法 ③ 单例模式 ...

三、封装性的体现,需要权限修饰符来配合

  • 1.Java规定的4种权限(从小到大排列):private、缺省、protected 、public

  • 2.4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类

  • 3.具体的,4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类

  • 修饰类的话,只能使用:缺省、public

  • 总结封装性:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小。

构造器的使用

construct:建设、建造。 construction:CCB constructor:建设者

  • 一、构造器的作用:

  • 1.创建对象

  • 2.初始化对象的信息

  • 二、说明:

  • 1.如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器

  • 2.定义构造器的格式:权限修饰符 类名(形参列表){}

  • 3.一个类中定义的多个构造器,彼此构成重载

  • 4.一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器

  • 5.一个类中,至少会有一个构造器。

总结:属性赋值的先后顺序

  • ① 默认初始化

  • ② 显式初始化

  • ③ 构造器中初始化

  • ④ 通过"对象.方法" 或 "对象.属性"的方式,赋值

以上操作的先后顺序:① - ② - ③ - ④

JavaBean的使用

  • JavaBean是一种Java语言写成的可重用组件。

所谓JavaBean,是指符合如下标准的Java类:

>类是公共的>有一个无参的公共的构造器>有属性,且有对应的get、set方法(如下最简单的一个JavaBean)
public class Customer {private int id;private String name;public Customer(){}public void setId(int i){id = i;}public int getId(){return id;}public void setName(String n){name = n;}public String getName(){return name;}}

this关键字的使用

  • 1.this可以用来修饰、调用:属性、方法、构造器

  • 2.this修饰属性和方法:

  • this理解为:当前对象 或 当前正在创建的对象

  • 2.1 在类的方法中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法。但是,通常情况下,我们都选择省略"this."。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用"this.变量"的方式,表明此变量是属性,而非形参。

  • 2.2 在类的构造器中,我们可以使用"this.属性"或"this.方法"的方式,调用当前正在创建的对象属性或方法。但是,通常情况下,我们都选择省略"this."。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显式的使用"this.变量"的方式,表明此变量是属性,而非形参。

  1. this调用构造器

  • ① 我们在类的构造器中,可以显式的使用"this(形参列表)"方式,调用本类中指定的其他构造器

  • ② 构造器中不能通过"this(形参列表)"方式调用自己

  • ③ 如果一个类中有n个构造器,则最多有 n - 1构造器中使用了"this(形参列表)"

  • ④ 规定:"this(形参列表)"必须声明在当前构造器的首行

  • ⑤ 构造器内部,最多只能声明一个"this(形参列表)",用来调用其他的构造器

public class PersonTest {public static void main(String[] args) {Person p1 = new Person();p1.setAge(1);System.out.println(p1.getAge());p1.eat();System.out.println();Person p2 = new Person("Jerry",20);System.out.println(p2.getAge());}
}class Person{private String name;private int age;public Person(){//    this.eat();String info = "Person初始化时,需要考虑如下的1,2,3,4...(共40行代码)";System.out.println(info);}public Person(String name){this();this.name = name;}public Person(int age){this();this.age = age;}public Person(String name,int age){this(age);this.name = name;//this.age = age;//Person初始化时,需要考虑如下的1,2,3,4...(共40行代码)}public void setName(String name){this.name = name;}public String getName(){return this.name;}public void setAge(int age){this.age = age;}public int getAge(){return this.age;}public void eat(){System.out.println("人吃饭");this.study();}public void study(){System.out.println("人学习");}}

银行练习

package com.java.exer;
//账号类
public class Account {private double balance;//构造器public Account(double balance){this.balance=balance;}//方法public double getBalance(){return balance;}//取钱public void deposit(double amt){if(amt>balance){System.out.println("余额不足,无法取款");}else{balance -=amt;System.out.println("成功取款"+amt+"元");}}//存钱public void withdraw(double amt){balance +=amt;System.out.println("成功存入"+amt+"元");}}
//用户类
class Customer{private String firstName;private String lastName;private Account account;public Customer(String f,String l){firstName=f;lastName=l;}public Account getAccount() {return account;}public void setAccount(Account account) {this.account = account;}public String getFirstName() {return firstName;}public String getLastName() {return lastName;}}//银行类
class Bank{private Customer[] customers;private int numberofCustomer;public Bank(){//初始化数组customers=new Customer[100];}//构造一个新的 Customer 对象,然后把//它放到 customer 数组中。还必须把 numberOfCustomer 属性的值加 1。public void addCustomer(String f,String l){Customer customer=new Customer(f,l);customers[this.numberofCustomer]=customer;this.numberofCustomer++;}//获取用户个数public int getNumOfCustomers(){return numberofCustomer;}//public Customer getCustomer(int index){if(index>=0&&index<this.numberofCustomer){return customers[index];}return null;}}
package com.java.exer;public class BankTest {public static void main(String[] args) {//创建一个银行Bank bank=new Bank();//添加一个客户bank.addCustomer("jaen", "smith");//为该客户创建一个账户,初始存入金额2000元bank.getCustomer(0).setAccount(new Account(2000));//取款150元bank.getCustomer(0).getAccount().deposit(150.59);//取款2000元bank.getCustomer(0).getAccount().deposit(2000.0);//存入34元bank.getCustomer(0).getAccount().withdraw(34);//打印客户信息System.out.println("客户:"+bank.getCustomer(0).getFirstName()+" "+bank.getCustomer(0).getLastName()+",创建了一个银行账户并存入"+bank.getCustomer(0).getAccount().getBalance()+"元");}
}

package关键字的使用

一、package关键字的使用

  • 1.为了更好的实现项目中类的管理,提供包的概念

  • 2.使用package声明类或接口所属的包,声明在源文件的首行

  • 3.包,属于标识符,遵循标识符的命名规则、规范(xxxyyyzzz)、“见名知意”

  • 4.每"."一次,就代表一层文件目录。

补充:同一个包下,不能命名同名的接口、类。

      不同的包下,可以命名同名的接口、类。

MVC的设计模式

import关键字的使用

二、import关键字的使用

import:导入

  1. 在源文件中显式的使用import结构导入指定包下的类、接口

  1. 声明在包的声明和类的声明之间

  1. 如果需要导入多个结构,则并列写出即可

  1. 可以使用"xxx.*"的方式,表示可以导入xxx包下的所有结构

  1. 如果使用的类或接口是java.lang包下定义的,则可以省略import结构

  1. 如果使用的类或接口是本包下定义的,则可以省略import结构

  1. 如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类需要以全类名的方式显示。

  1. 使用"xxx.*"方式表明可以调用xxx包下的所有结构。但是如果使用的是xxx子包下的结构,则仍需要显式导入

继承性

一、继承性的好处:

  • ① 减少了代码的冗余,提高了代码的复用性

  • ② 便于功能的扩展

  • ③ 为之后多态性的使用,提供了前提

二、继承性的格式:

格式:class A extends B { }

  • A:子类、派生类、subclass

  • B:父类、超类、基类、superclass

  • 2.1体现:一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。

  • 特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。

  • 只有因为封装性的影响,使得子类不能直接调用父类的结构而已。

  • 2.2 子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。

  • 子类和父类的关系,不同于子集和集合的关系。

  • extends:延展、扩展

Eclipse Debug的使用

如何调试程序:

  1. System.out.println( ).

  1. Eclipse - Debug调试

打断点测试

方法的重写(override / overwrite)

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

  • 2.应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写父类的方法。

  1. 重写的规定:

  • 方法的声明: 权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型{

//方法体

   ** }**

约定俗称:子类中的叫重写的方法,父类中的叫被重写的方法

  • ① 子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同

  • ② 子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符

特殊情况:子类不能重写父类中声明为private权限的方法

  • ③ 返回值类型:

父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void

父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类

父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须也是double)

  • ④ 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型(具体放到异常处理时候讲)

super调用属性和方法

super关键字的使用

  • 1.super理解为:父类的

  • 2.super可以用来调用:属性、方法、构造器

  • 3.super的使用:调用属性和方法

  • 3.1 我们可以在子类的方法或构造器中。通过使用"super.属性"或"super.方法"的方式,显式的调用

父类中声明的属性或方法。但是,通常情况下,我们习惯省略"super."

  • 3.2 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的

使用"super.属性"的方式,表明调用的是父类中声明的属性。

  • 3.3 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的

  • 使用"super.方法"的方式,表明调用的是父类中被重写的方法。

  • 4.super调用构造器

  • 4.1 我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器

  • 4.2 "super(形参列表)"的使用,必须声明在子类构造器的首行!

  • 4.3 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一,不能同时出现

  • 4.4 在构造器的首行,没有显式的声明"this(形参列表)"或"super(形参列表)",则默认调用的是父类中空参的构造器:super()

  • 4.5 在类的多个构造器中,至少有一个类的构造器中使用了"super(形参列表)",调用父类中的构造器

子类对象实例化的过程

1. 从结果上来看:(继承性)

  • 子类继承父类以后,就获取了父类中声明的属性或方法。

  • 创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。

2. 从过程上来看:

  • 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,...

  • 直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有

  • 父类中的结构,子类对象才可以考虑进行调用。

  • 明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。

*多态性

  • 面向对象特征之三:多态性

  • 1.理解多态性:可以理解为一个事物的多种形态。

  • 2.何为多态性:

  • 对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)

  • **3. 多态的使用:**虚拟方法调用

  • 有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。

  • 总结:编译,看左边;运行,看右边。

  • 4.多态性的使用前提: ① 类的继承关系 ② 方法的重写

  • 5.对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)

public class PersonTest {public static void main(String[] args) {Person p1 = new Person();p1.eat();Man man = new Man();man.eat();man.age = 25;man.earnMoney();//*************************************************System.out.println("*******************");//对象的多态性:父类的引用指向子类的对象Person p2 = new Man();
//    Person p3 = new Woman();//多态的使用:当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法 ---虚拟方法调用p2.eat();p2.walk();//    p2.earnMoney();System.out.println(p2.id);//1001}
}

**从编译和运行的角度看: **

  1. 重载,是指允许存在多个同名方法,而这些方法的参数不同。编译器根据方法不 同的参数表,对同名方法的名称做修饰。对于编译器而言,这些同名方法就成了 不同的方法。它们的调用地址在编译期就绑定了。Java的重载是可以包括父类 和子类的,即子类可以重载父类的同名不同参数的方法。 所以:对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法, 这称为“早绑定”或“静态绑定”;

  1. 而对于多态,只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体 方法,这称为“晚绑定”或“动态绑定”。

  1. 引用一句Bruce Eckel的话:“不要犯傻,如果它不是晚绑定,它就不是多态。”

向下转型

多态小结** ****多态作用:

** 提高了代码的通用性,常称作接口重用 前提: 需要存在继承或者实现关系

 有方法的重写

 成员方法: 编译时:要查看引用变量所声明的类中是否有所调用的方法。

 运行时:调用实际new的对象所属的类中的重写方法。

 成员变量: 不具备多态性,只看引用变量所声明的类。

向下转型的使用

有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。

如何才能调用子类特有的属性和方法?

向下转型:使用强制类型转换符。

    Man m1 = (Man)p2;m1.earnMoney();m1.isSmoking = true;

使用强转时,可能出现ClassCastException的异常。

instanceof 操作符

  • 使用情境:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先

  • 进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。

  • x instanceof A:检验x是否为类A的对象,返回值为boolean型。

  • 要求x所属的类与类A必须是子类和父类的关系,否则编译错误。

  • 如果x属于类A的子类B,x instanceof A值也为true。

     /* instanceof关键字的使用* * a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。* * *  使用情境:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先*  进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。*  *  如果 a instanceof A返回true,则 a instanceof B也返回true.*  其中,类B是类A的父类。*/if(p2 instanceof Woman){Woman w1 = (Woman)p2;w1.goShopping();System.out.println("******Woman******");}if(p2 instanceof Man){Man m2 = (Man)p2;m2.earnMoney();System.out.println("******Man******");}if(p2 instanceof Person){System.out.println("******Person******");}if(p2 instanceof Object){System.out.println("******Object******");}//    if(p2 instanceof String){
//
//    }//练习://问题一:编译时通过,运行时不通过//举例一:
//    Person p3 = new Woman();
//    Man m3 = (Man)p3;//举例二:
//    Person p4 = new Person();
//    Man m4 = (Man)p4;//问题二:编译通过,运行时也通过
//    Object obj = new Woman();
//    Person p = (Person)obj;//问题三:编译不通过
//    Man m5 = new Woman();//    String str = new Date();//    Object o = new Date();
//    String str1 = (String)o;}
}//class Order{
//
//}

object类

java.lang.Object类

  • 1.Object类是所有Java类的根父类

  • 2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类

  • 3.Object类中的功能(属性、方法)就具有通用性。

  • 属性:无

  • 方法:equals() / toString() / getClass() /hashCode() / clone() / finalize()

wait() 、 notify()、notifyAll()

  1. Object类只声明了一个空参的构造器

垃圾回收的说明

垃圾回收机制关键点垃圾回收机制只回收JVM堆内存里的对象空间。对其他物理连接,比如数据库连接、输入流输出流、Socket连接无能为力现在的JVM有多种垃圾回收实现算法,表现各异。垃圾回收发生具有不可预知性,程序无法精确控制垃圾回收机制执行。可以将对象的引用变量设置为null,暗示垃圾回收机制可以回收该对象。

程序员可以通过System.gc()或者Runtime.getRuntime().gc()来通知系统进行垃圾回收,会有一些效果,但是系统是否进行垃圾回收依然不确定。

垃圾回收机制回收任何对象之前,总会先调用它的finalize方法(如果覆盖该方法,让一个新的引用变量重新引用该对象,则会重新激活对象)。永远不要主动调用某个对象的finalize方法,应该交给垃圾回收机制调用。

equals的使用

*面试题:==与equals()的区别

一、==:运算符

  1. 可以使用在基本数据类型变量和引用数据类型变量中

  1. 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)

  • 如果比较的是引用数据类型变量:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体

  • 补充: == 符号使用时,必须保证符号左右两边的变量类型一致。

二、equals()方法的使用:

  1. 是一个方法,而非运算符

  1. 只能适用于引用数据类型

  • 3.Object类中equals()的定义:

  public boolean equals(Object obj) {return (this == obj);}

说明:Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体

  1. 像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。

  1. 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们就需要对Object类中的equals()进行重写.

  • 重写的原则:比较两个对象的实体内容是否相同.

  //自动生成的equals()@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Customer other = (Customer) obj;if (age != other.age)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}//重写的原则:比较两个对象的实体内容(即:name和age)是否相同//手动实现equals()的重写
//  @Override
//  public boolean equals(Object obj) {
//    System.out.println("Customer equals()....");
//    if (this == obj) {
//            return true;
//        }
//
//    if(obj instanceof Customer){
//      Customer cust = (Customer)obj;
//      //比较两个对象的每个属性是否都相同if(this.age == cust.age && this.name.equals(cust.name)){return true;}else{return false;}
//
//      //或
//      return this.age == cust.age && this.name.equals(cust.name);
//    }else{
//      return false;
//
//    }
//
//  }//手动实现
//  @Override
//  public String toString() {
//    return "Customer[name = " + name + ",age = " + age + "]";
//  }
public class EqualsTest {public static void main(String[] args) {//基本数据类型int i = 10;int j = 10;double d = 10.0;System.out.println(i == j);//trueSystem.out.println(i == d);//trueboolean b = true;
//    System.out.println(i == b);char c = 10;System.out.println(i == c);//truechar c1 = 'A';char c2 = 65;System.out.println(c1 == c2);//true//引用类型:Customer cust1 = new Customer("Tom",21);Customer cust2 = new Customer("Tom",21);System.out.println(cust1 == cust2);//falseString str1 = new String("atguigu");String str2 = new String("atguigu");System.out.println(str1 == str2);//falseSystem.out.println("****************************");System.out.println(cust1.equals(cust2));//false--->trueSystem.out.println(str1.equals(str2));//trueDate date1 = new Date(32432525324L);Date date2 = new Date(32432525324L);System.out.println(date1.equals(date2));//true}
}

toString() 方法的使用

Object类中toString()的使用:

  1. 当我们输出一个对象的引用时,实际上就是调用当前对象的toString()

  1. Object类中toString()的定义:

  • public String toString() {

return getClass().getName() + "@" + Integer.toHexString(hashCode());

}

  1. 像String、Date、File、包装类等都重写了Object类中的toString()方法。使得在调用对象的toString()时,返回"实体内容"信息

  1. 自定义类也可以重写toString()方法,当调用此方法时,返回对象的"实体内容"。

Java中的JUnit单元测试

步骤:

  • 1.选中当前工程 - 右键选择:build path - add libraries - JUnit 4 - 下一步

  • 2.创建Java类,进行单元测试。

  • 此时的Java类要求:

  • ① 此类是public的 ②此类提供公共的无参的构造器

  • 3.此类中声明单元测试方法。

此时的单元测试方法:方法的权限是public,没有返回值,没有形参

  • 4.此单元测试方法上需要声明注解:@Test,并在单元测试类中导入:import org.junit.Test;

  • 5.声明好单元测试方法以后,就可以在方法体内测试相关的代码。

  • 6.写完代码以后,左键双击单元测试方法名,右键:run as - JUnit Test

  • 说明:

  • 1.如果执行结果没有任何异常:绿条

  • 2.如果执行结果出现异常:红条

包装类的使用

包装类:为了使基本数据类型具有类的特征

  • 1.针对八种基本数据类型定义相应的引用类型—包装类(封装类)

有了类的特点,就可以调用类中的方法,Java才是真正的面向对象

  • 2.掌握的:基本数据类型、包装类、String三者之间的相互转换

  • 基本数据类型 --->包装类:调用包装类的构造器

  • 包装类--->基本数据类型:调用包装类Xxx的xxxValue()

  • 基本数据类型、包装类--->String类型:调用String重载的valueOf(Xxx xxx)

  • 方式1:连接运算 //String str1 = num1 + "";

  • 方式2:调用String的valueOf(Xxx xxx)

float f1 = 12.3f;

String str2 = String.valueOf(f1);//"12.3"
  • String类型 --->基本数据类型、包装类:调用包装类的parseXxx(String s)

String str1 = "123";

int num2 = Integer.parseInt(str1);

System.out.println(num2 + 1);

JDK 5.0 新特性:自动装箱 与自动拆箱

  • 自动装箱:基本数据类型 --->包装类

  • 自动拆箱:包装类--->基本数据类型

public class WrapperTest {//String类型 --->基本数据类型、包装类:调用包装类的parseXxx(String s)@Testpublic void test5(){String str1 = "123";//错误的情况:
//    int num1 = (int)str1;
//    Integer in1 = (Integer)str1;//可能会报NumberFormatExceptionint num2 = Integer.parseInt(str1);System.out.println(num2 + 1);String str2 = "true1";boolean b1 = Boolean.parseBoolean(str2);System.out.println(b1);}//基本数据类型、包装类--->String类型:调用String重载的valueOf(Xxx xxx)@Testpublic void test4(){int num1 = 10;//方式1:连接运算String str1 = num1 + "";//方式2:调用String的valueOf(Xxx xxx)float f1 = 12.3f;String str2 = String.valueOf(f1);//"12.3"Double d1 = new Double(12.4);String str3 = String.valueOf(d1);System.out.println(str2);System.out.println(str3);//"12.4"}/** JDK 5.0 新特性:自动装箱 与自动拆箱*/@Testpublic void test3(){
//    int num1 = 10;
//    //基本数据类型-->包装类的对象
//    method(num1);//自动装箱:基本数据类型 --->包装类int num2 = 10;Integer in1 = num2;//自动装箱boolean b1 = true;Boolean b2 = b1;//自动装箱//自动拆箱:包装类--->基本数据类型System.out.println(in1.toString());int num3 = in1;//自动拆箱}public void method(Object obj){System.out.println(obj);}//包装类--->基本数据类型:调用包装类Xxx的xxxValue()@Testpublic void test2(){Integer in1 = new Integer(12);int i1 = in1.intValue();System.out.println(i1 + 1);Float f1 = new Float(12.3);float f2 = f1.floatValue();System.out.println(f2 + 1);}//基本数据类型 --->包装类:调用包装类的构造器@Testpublic void test1(){int num1 = 10;
//    System.out.println(num1.toString());Integer in1 = new Integer(num1);System.out.println(in1.toString());Integer in2 = new Integer("123");System.out.println(in2.toString());//报异常
//    Integer in3 = new Integer("123abc");
//    System.out.println(in3.toString());Float f1 = new Float(12.3f);Float f2 = new Float("12.3");System.out.println(f1);System.out.println(f2);Boolean b1 = new Boolean(true);Boolean b2 = new Boolean("TrUe");System.out.println(b2);Boolean b3 = new Boolean("true123");System.out.println(b3);//falseOrder order = new Order();System.out.println(order.isMale);//falseSystem.out.println(order.isFemale);//null}}class Order{boolean isMale;Boolean isFemale;
}

面试题:

//Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],保存了从-128~127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在-128~127范围内时,可以直接使用数组中的元素,不用再去new了。

目的:提高效率

/** 关于包装类使用的面试题*/
public class InterviewTest {@Testpublic void test1() {Object o1 = true ? new Integer(1) : new Double(2.0);System.out.println(o1);// 1.0}@Testpublic void test2() {Object o2;if (true)o2 = new Integer(1);elseo2 = new Double(2.0);System.out.println(o2);// 1}@Testpublic void test3() {Integer i = new Integer(1);Integer j = new Integer(1);System.out.println(i == j);//false//Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],//保存了从-128~127范围的整数。如果我们使用自动装箱的方式,给Integer赋值的范围在//-128~127范围内时,可以直接使用数组中的元素,不用再去new了。目的:提高效率Integer m = 1;Integer n = 1;System.out.println(m == n);//trueInteger x = 128;//相当于new了一个Integer对象Integer y = 128;//相当于new了一个Integer对象System.out.println(x == y);//false}}

练习题

package com.java.exer4;import java.util.Scanner;
import java.util.Vector;/** 利用Vector代替数组处理:从键盘读入学生成绩(以负数代表输入结束),找出最高分,并输出学生成绩等级。提示:数组一旦创建,长度就固定不变,所以在创建数组前就需要知道它的长度。而向量类java.util.Vector可以根据需要动态伸缩。创建Vector对象:Vector v=new Vector();给向量添加元素:v.addElement(Object obj); //obj必须是对象取出向量中的元素:Object obj=v.elementAt(0);注意第一个元素的下标是0,返回值是Object类型的。*/public class ScoreTest {public static void main(String[] args) {//1.实例化scanner,用于从键盘获取学生成绩Scanner scan=new Scanner(System.in);//2.创建Vector对象:Vector v=new Vector();Vector v=new Vector();//3.通过循环的方式for(;;),给Vector中添加数据,给向量添加元素:v.addElement(Object obj); int maxscore=0;for(;;){System.out.println("请输入学生成绩(以负数代表输入结束)");int score = scan.nextInt();if(score<0){break;}if(score>100){System.out.println("输入成绩不符合规范,请重新输入");continue;}//3.1添加操作:给向量添加元素:v.addElement(Object obj);//jdk5.0之前(由于形参要求是对象类型的所以需要将int转换成类类型integer)Integer intscore=new Integer(score);//多态v.addElement(intscore);//jdk5.0后//v.addElement(score);自动装箱//3.2跳出循坏//4.获取学生最大成绩if(maxscore<score){maxscore=score;}}//5.遍历Vector,取出每个学生的成绩,并与最大成绩比较,划分等级char level;for(int i=0;i<v.size();i++){Object obj=v.elementAt(i);//在jdk5.0之前(要比较大小必须把类类型转回int类型)Integer intscore=(Integer)obj;int score=intscore.intValue();if(maxscore-score<=10){level='A';}else if(maxscore-score<=20){level='B';}else if(maxscore-score<=30){level='C';}else{level='D';}System.out.println("学生编号为:"+i+"学生的成绩为:"+score+"学生的成绩等级为:"+level);}}}

Static关键字

如果想让一个类的所有实例共享数据,就用类变量!

static关键字的使用

  • 1.static:静态的

  • 2.static可以用来修饰:属性、方法、代码块、内部类

3.使用static修饰属性:静态变量(或类变量)

  • 3.1 属性,按是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量)

  • **实例变量:**我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。

  • **静态变量:**我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。

  • 3.2 static修饰属性的其他说明:

  • ① 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用

  • ② 静态变量的加载要早于对象的创建。

  • ③** 由于类只会加载一次,**则静态变量在内存中也只会缓存在一份:存在方法区的静态域中。

  • ④ 类变量 实例变量

          类           yes     no对象        yes     yes

类变量 vs 实例变量内存解析

4.使用static修饰方法:静态方法

  • ① 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用

  • ② 静态方法 非静态方法

  • 类 yes no

  • 对象 yes yes

  • ③ 静态方法中,只能调用静态的方法或属性

  • 非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性

  1. static注意点:

  • 5.1 在静态的方法内,不能使用this关键字、super关键字(因为this和super都是基于对象的,没有new对象就不能用)

  • 5.2 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。

  1. 开发中,如何确定一个属性是否要声明为static的?

  • 属性是可以被多个对象所共享的,不会随着对象的不同而不同的。

  • 类中的常量也常常声明为static

  • 开发中,如何确定一个方法是否要声明为static的?

  • 操作静态属性的方法,通常设置为static的

  • 工具类中的方法,习惯上声明为static的。 比如:Math、Arrays、Collections

单例 (Singleton)设计模式

单例设计模式:

  1. 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。

  1. 如何实现?

  • 饿汉式 vs 懒汉式

  1. 区分饿汉式 和 懒汉式

  • 饿汉式:

  • 坏处:对象加载时间过长。

  • 好处:饿汉式是线程安全的

  • 懒汉式:好处:延迟对象的创建。

  • 目前的写法坏处:线程不安全。--->到多线程内容时,再修改

public class SingletonTest1 {public static void main(String[] args) {Bank bank1 = Bank.getInstance();Bank bank2 = Bank.getInstance();System.out.println(bank1 == bank2);}
}//饿汉式
class Bank{//1.私有化类的构造器private Bank(){}//2.内部创建类的对象//4.要求此对象也必须声明为静态的private static Bank instance = new Bank();//3.提供公共的静态的方法,返回类的对象public static Bank getInstance(){return instance;}
}
/** 单例模式的懒汉式实现*/
public class SingletonTest2 {public static void main(String[] args) {Order order1 = Order.getInstance();Order order2 = Order.getInstance();System.out.println(order1 == order2);}
}class Order{//1.私有化类的构造器private Order(){}//2.声明当前类对象,没有初始化//4.此对象也必须声明为static的private static Order instance = null;//3.声明public、static的返回当前类对象的方法public static Order getInstance(){if(instance == null){instance = new Order();}return instance;}}

理解main方法的语法

  • main()方法的使用说明:

  1. main()方法作为程序的入口

  1. main()方法也是一个普通的静态方法

  1. main()方法可以作为我们与控制台交互的方式。(之前:使用Scanner)

代码块

类的成员之四:代码块(或初始化块)

  1. 代码块的作用:用来初始化类、对象

  1. 代码块如果有修饰的话,只能使用static.

  1. 分类:静态代码块 vs 非静态代码块

  1. 静态代码块

  • 内部可以有输出语句

  • 随着类的加载而执行,而且只执行一次

  • 作用:初始化类的信息

  • 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行

  • 静态代码块的执行要优先于非静态代码块的执行

  • 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构

  • 5.** 非静态代码块**

  • 内部可以有输出语句

  • 随着对象的创建而执行

  • 每创建一个对象,就执行一次非静态代码块

  • 作用:可以在创建对象时,对对象的属性等进行初始化

  • 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行

  • 非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法

public class BlockTest {public static void main(String[] args) {String desc = Person.desc;System.out.println(desc);Person p1 = new Person();Person p2 = new Person();System.out.println(p1.age);Person.info();}
}class Person{//属性String name;int age;static String desc = "我是一个人";//构造器public Person(){}public Person(String name,int age){this.name = name;this.age = age;}//非static的代码块{System.out.println("hello, block - 2");}{System.out.println("hello, block - 1");//调用非静态结构age = 1;eat();//调用静态结构desc = "我是一个爱学习的人1";info();}//static的代码块static{System.out.println("hello,static block-2");}static{System.out.println("hello,static block-1");//调用静态结构desc = "我是一个爱学习的人";info();//不可以调用非静态结构
//    eat();
//    name = "Tom";}//方法public void eat(){System.out.println("吃饭");}@Overridepublic String toString() {return "Person [name=" + name + ", age=" + age + "]";}public static void info(){System.out.println("我是一个快乐的人!");}}

执行顺序

由父及子 静态先行

对属性可以赋值的位置

  • ①默认初始化

  • ②显式初始化/⑤在代码块中赋值

  • ③构造器中初始化

  • ④有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值

  • 执行的先后顺序:① - ② / ⑤ - ③ - ④

final关键字

final:最终的

  1. final可以用来修饰的结构:类、方法、变量

  1. final 用来修饰一个类:此类不能被其他类所继承。

  • 比如:String类、System类、StringBuffer类

  • 3. final 用来修饰方法:表明此方法不可以被重写

  • 比如:Object类中getClass();

  • 4. final 用来修饰变量:此时的"变量"就称为是一个常量

  • 4.1 final修饰属性:可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化

  • 4.2 final修饰局部变量:

  • 尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。

  • static final 用来修饰属性:全局常量

*抽象类与抽象方法

随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。

  • 用abstract关键字来修饰一个类,这个类叫做抽象类。

  • 用abstract来修饰一个方法,该方法叫做抽象方法。

  • abstract关键字的使用

  • 1.abstract:抽象的

  • 2.abstract可以用来修饰的结构:类、方法

  1. abstract修饰类:抽象类

  • 此类不能实例化(不能造对象)

  • 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)

  • > 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作

  1. abstract修饰方法:抽象方法·

  • 抽象方法只有方法的声明,没有方法体

  • ** 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。**

  • > 若子类重写了父类中的所有的抽象方法后,此子类方可实例化

  • 若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰

abstract使用上的注意点:

  • 1.abstract不能用来修饰:属性、构造器等结构

  • 2.abstract不能用来修饰私有方法、静态方法、final的方法、final的类

多态的应用:模板方法设计模式(TemplateMethod)

*接口(interface)

一个类可以实现多个接口,打破了单继承的局限性

接口的使用

  • 1.接口使用interface来定义

  • 2.Java中,接口和类是并列的两个结构

  • 3.如何定义接口:定义接口中的成员

  • 3.1 JDK7及以前:只能定义全局常量和抽象方法

  • 全局常量:public static final的.但是书写时,可以省略不写

  • 抽象方法:public abstract的

  • 3.2 JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)

  1. 接口中不能定义构造器的!意味着接口不可以实例化

  1. Java开发中,接口通过让类去实现(implements)的方式来使用.

  • 如果实现类覆盖了(重写了)接口中的所有抽象方法,则此实现类就可以实例化

  • 如果实现类没有覆盖(重写)接口中所有的抽象方法,则此实现类仍为一个抽象类

  1. Java类可以实现多个接口 --->弥补了Java单继承性的局限性

  • 格式:class AA extends BB implements CC,DD,EE

  1. 接口与接口之间可以继承,而且可以多继承


  1. 接口的具体使用,体现多态性

  1. 接口,实际上可以看做是一种规范

面试题:抽象类与接口有哪些异同?

相同点:都不能实例化,都可以被继承

不同点:抽象类一定有构造器,接口不能声明构造器

         抽象类只能单继承,接口可以多继承定义的方式不一样
public class InterfaceTest {public static void main(String[] args) {System.out.println(Flyable.MAX_SPEED);System.out.println(Flyable.MIN_SPEED);
//    Flyable.MIN_SPEED = 2;Plane plane = new Plane();plane.fly();}
}interface Flyable{//全局常量public static final int MAX_SPEED = 7900;//第一宇宙速度int MIN_SPEED = 1;//省略了public static final//抽象方法public abstract void fly();//省略了public abstractvoid stop();//Interfaces cannot have constructors
//  public Flyable(){
//
//  }
}interface Attackable{void attack();}class Plane implements Flyable{@Overridepublic void fly() {System.out.println("通过引擎起飞");}@Overridepublic void stop() {System.out.println("驾驶员减速停止");}}//因为没有实现所有的抽象方法  所以该类还是一个抽象类
abstract class Kite implements Flyable{@Overridepublic void fly() {}}class Bullet extends Object implements Flyable,Attackable,CC{@Overridepublic void attack() {// TODO Auto-generated method stub}@Overridepublic void fly() {// TODO Auto-generated method stub}@Overridepublic void stop() {// TODO Auto-generated method stub}@Overridepublic void method1() {// TODO Auto-generated method stub}@Overridepublic void method2() {// TODO Auto-generated method stub}}
//************************************interface AA{void method1();
}
interface BB{void method2();
}interface CC extends AA,BB{}
/** 接口的使用* 1.接口使用上也满足多态性* 2.接口,实际上就是定义了一种规范* 3.开发中,体会面向接口编程!* */
public class USBTest {public static void main(String[] args) {Computer com = new Computer();//1.创建了接口的非匿名实现类的非匿名对象Flash flash = new Flash();com.transferData(flash);//2. 创建了接口的非匿名实现类的匿名对象com.transferData(new Printer());//3. 创建了接口的匿名实现类的非匿名对象USB phone = new USB(){@Overridepublic void start() {System.out.println("手机开始工作");}@Overridepublic void stop() {System.out.println("手机结束工作");}};com.transferData(phone);//4. 创建了接口的匿名实现类的匿名对象com.transferData(new USB(){@Overridepublic void start() {System.out.println("mp3开始工作");}@Overridepublic void stop() {System.out.println("mp3结束工作");}});}
}class Computer{public void transferData(USB usb){//USB usb = new Flash();usb.start();System.out.println("具体传输数据的细节");usb.stop();}}interface USB{//常量:定义了长、宽、最大最小的传输速度等void start();void stop();}class Flash implements USB{@Overridepublic void start() {System.out.println("U盘开启工作");}@Overridepublic void stop() {System.out.println("U盘结束工作");}}class Printer implements USB{@Overridepublic void start() {System.out.println("打印机开启工作");}@Overridepublic void stop() {System.out.println("打印机结束工作");}}

JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法

public interface CompareA {//静态方法public static void method1(){System.out.println("CompareA:北京");}//默认方法public default void method2(){System.out.println("CompareA:上海");}default void method3(){System.out.println("CompareA:上海");}
}
public class SubClassTest {public static void main(String[] args) {SubClass s = new SubClass();//    s.method1();
//    SubClass.method1();//知识点1:接口中定义的静态方法,只能通过接口来调用。CompareA.method1();//知识点2:通过实现类的对象,可以调用接口中的默认方法。//如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法s.method2();//知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,//那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。-->类优先原则//知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,//那么在实现类没有重写此方法的情况下,报错。-->接口冲突。//这就需要我们必须在实现类中重写此方法s.method3();}}class SubClass extends SuperClass implements CompareA,CompareB{public void method2(){System.out.println("SubClass:上海");}public void method3(){System.out.println("SubClass:深圳");}//知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法public void myMethod(){method3();//调用自己定义的重写的方法super.method3();//调用的是父类中声明的//调用接口中的默认方法CompareA.super.method3();CompareB.super.method3();}
}
/*
小应用
*/
interface Filial {// 孝顺的default void help() {System.out.println("老妈,我来救你了");}
}interface Spoony {// 痴情的default void help() {System.out.println("媳妇,别怕,我来了");}
}class Father{public void help(){System.out.println("儿子,就我媳妇!");}
}class Man extends Father implements Filial, Spoony {@Overridepublic void help() {System.out.println("我该就谁呢?");Filial.super.help();Spoony.super.help();}}

内部类

类的内部成员之五:内部类

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

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

  • 3.成员内部类:

  • 一方面,作为外部类的成员:

  • 调用外部类的结构

  • 可以被static修饰

  • 可以被4种不同的权限修饰

  • 另一方面,作为一个类:

  • 类内可以定义属性、方法、构造器等

  • 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承

  • 可以被abstract修饰

  • 4.关注如下的3个问题

  • 4.1 如何实例化成员内部类的对象

  • 4.2 如何在成员内部类中区分调用外部类的结构

  • 4.3 开发中局部内部类的使用 见《InnerClassTest1.java》

如何创建静态内部类和非静态内部类成员内部类的对象?

person static dog cat

静态:

person.dag d=new person.dog();

非静态:

person p=new person();

person.cat c=p.new person.cat();

public class InnerClassTest {public static void main(String[] args) {// 创建Dog实例(静态的成员内部类):Person.Dog dog = new Person.Dog();dog.show();// 创建Bird实例(非静态的成员内部类):// Person.Bird bird = new Person.Bird();//错误的Person p = new Person();Person.Bird bird = p.new Bird();bird.sing();System.out.println();bird.display("黄鹂");}
}class Person {String name = "小明";int age;public void eat() {System.out.println("人:吃饭");}// 静态成员内部类static class Dog {String name;int age;public void show() {System.out.println("卡拉是条狗");// eat();}}// 非静态成员内部类class Bird {String name = "杜鹃";public Bird() {}public void sing() {System.out.println("我是一只小小鸟");Person.this.eat();// 调用外部类的非静态属性eat();System.out.println(age);}public void display(String name) {System.out.println(name);// 方法的形参System.out.println(this.name);// 内部类的属性System.out.println(Person.this.name);// 外部类的属性}}public void method() {// 局部内部类class AA {}}{// 局部内部类class BB {}}public Person() {// 局部内部类class CC {}}}
public class InnerClassTest1 {//开发中很少见public void method(){//局部内部类class AA{}}//返回一个实现了Comparable接口的类的对象public Comparable getComparable(){//创建一个实现了Comparable接口的类:局部内部类//方式一:
//    class MyComparable implements Comparable{
//
//      @Override
//      public int compareTo(Object o) {
//        return 0;
//      }
//
//    }
//
//    return new MyComparable();//方式二:return new Comparable(){@Overridepublic int compareTo(Object o) {return 0;}};}
}

06 异常处理

异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常)

Java程序在执行过程中所发生的异常事件可分为两类:

  • 一、Error:Java虚拟机无法解决的严重问题。

  • 如:JVM系统内部错误、资源耗尽等严重情况。

  • 比如:StackOverflowError和OOM。一般不编写针对性的代码进行处理。

  • 二、Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:

  • 空指针访问试图读取不存在的文件网络连接中断数组角标越界

/** Error:* Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowError和OOM。* * 一般不编写针对性的代码进行处理。* * */
public class ErrorTest {public static void main(String[] args) {//1.栈溢出:java.lang.StackOverflowError
//    main(args);//2.堆溢出:java.lang.OutOfMemoryError Integer[] arr = new Integer[1024*1024*1024];}
}

异常体系结构

  • java.lang.Throwable

  • |-----java.lang.Error:一般不编写针对性的代码进行处理。

  • |-----java.lang.Exception:可以进行异常的处理

  • |------编译时异常(checked)

  • |-----IOException

  • |-----FileNotFoundException

  • |-----ClassNotFoundException

  • |------运行时异常(unchecked,RuntimeException)

  • |-----NullPointerException

  • |-----ArrayIndexOutOfBoundsException

  • |-----ClassCastException

  • |-----NumberFormatException

  • |-----InputMismatchException

  • |-----ArithmeticException

1.运行时异常 是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序

员应该积极避免其出现的异常。java.lang.RuntimeException类及它的子

类都是运行时异常。

 对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。2.编译时异常 是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一

般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。

 对于这类异常,如果程序不处理,可能会带来意想不到的结果。

面试题:常见的异常都有哪些?举例说明

public class ExceptionTest {//******************以下是编译时异常***************************@Testpublic void test7(){
//    File file = new File("hello.txt");
//    FileInputStream fis = new FileInputStream(file);
//
//    int data = fis.read();
//    while(data != -1){
//      System.out.print((char)data);
//      data = fis.read();
//    }
//
//    fis.close();}//******************以下是运行时异常***************************//ArithmeticException@Testpublic void test6(){int a = 10;int b = 0;System.out.println(a / b);}//InputMismatchException@Testpublic void test5(){Scanner scanner = new Scanner(System.in);int score = scanner.nextInt();System.out.println(score);scanner.close();}//NumberFormatException@Testpublic void test4(){String str = "123";str = "abc";int num = Integer.parseInt(str);}//ClassCastException@Testpublic void test3(){Object obj = new Date();String str = (String)obj;}//IndexOutOfBoundsException@Testpublic void test2(){//ArrayIndexOutOfBoundsException
//    int[] arr = new int[10];
//    System.out.println(arr[10]);//StringIndexOutOfBoundsExceptionString str = "abc";System.out.println(str.charAt(3));}//NullPointerException@Testpublic void test1(){//    int[] arr = null;
//    System.out.println(arr[3]);String str = "abc";str = null;System.out.println(str.charAt(0));}
}

异常处理的方式

 * 一、异常的处理:抓抛模型* * 过程一:"抛":程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象。*           并将此对象抛出。*           一旦抛出对象以后,其后的代码就不再执行。*     *     关于异常对象的产生:① 系统自动生成的异常对象*            ② 手动的生成一个异常对象,并抛出(throw)* * 过程二:"抓":可以理解为异常的处理方式:① try-catch-finally  ② throws

方式一:try - cath - finally

 * 二、try-catch-finally的使用* * try{*     //可能出现异常的代码* * }catch(异常类型1 变量名1){*     //处理异常的方式1* }catch(异常类型2 变量名2){*     //处理异常的方式2* }catch(异常类型3 变量名3){*     //处理异常的方式3* }* ....* finally{*     //一定会执行的代码* }* * 说明:* 1. finally是可选的。* 2. 使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,*    根据此对象的类型,去catch中进行匹配* 3. 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出*    当前的try-catch结构(在没有写finally的情况)。继续执行其后的代码* 4. catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。*    catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错* 5. 常用的异常对象处理的方式: ① String  getMessage()    ② printStackTrace()* 6. 在try结构中声明的变量,再出了try结构以后,就不能再被调用* 7. try-catch-finally结构可以嵌套* * 体会1:**使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。*     相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。***     * 体会2:**开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。*      针对于编译时异常,我们说一定要考虑异常的处理。**

finally的使用:

 * try-catch-finally中finally的使用:* * * 1.finally是可选的* * 2.finally中声明的是一定会被执行的代码。即使catch中又出现异常了,try中有return语句,catch中有* return语句等情况。* * 3.像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的*   进行资源的释放。此时的资源释放,就需要声明在finally中。* 
public class FinallyTest {@Testpublic void test2(){FileInputStream fis = null;try {File file = new File("hello1.txt");fis = new FileInputStream(file);int data = fis.read();while(data != -1){System.out.print((char)data);data = fis.read();}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally{try {if(fis != null)fis.close();} catch (IOException e) {e.printStackTrace();}}}@Testpublic void testMethod(){int num = method();System.out.println(num);}public int method(){try{int[] arr = new int[10];System.out.println(arr[10]);return 1;}catch(ArrayIndexOutOfBoundsException e){e.printStackTrace();return 2;}finally{System.out.println("我一定会被执行");return 3;}}@Testpublic void test1(){try{int a = 10;int b = 0;System.out.println(a / b);}catch(ArithmeticException e){e.printStackTrace();//      int[] arr = new int[10];
//      System.out.println(arr[10]);}catch(Exception e){e.printStackTrace();}
//    System.out.println("我好帅啊!!!~~");finally{System.out.println("我好帅啊~~");}}}

方式二:throws + 异常类型

 * 异常处理的方式二:throws + 异常类型* * 1. "throws + 异常类型"写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。*     一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常*     类型时,就会被抛出。异常代码后续的代码,就不再执行!*     * 2. 体会:try-catch-finally:真正的将异常给处理掉了。*        throws的方式只是将异常抛给了方法的调用者。  并没有真正将异常处理掉。  * * **3. 开发中如何选择使用try-catch-finally 还是使用throws?*   3.1 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着*       如果子类重写的方法中有异常,必须使用try-catch-finally方式处理。*   3.2 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法*       使用throws的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。**

方法重写的规则之一

/** 方法重写的规则之一:* 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型* */
public class OverrideTest {public static void main(String[] args) {OverrideTest test = new OverrideTest();test.display(new SubClass());}public void display(SuperClass s){try {s.method();} catch (IOException e) {e.printStackTrace();}}
}class SuperClass{public void method() throws IOException{}}class SubClass extends SuperClass{public void method()throws FileNotFoundException{}
}

手动抛出异常对象

public class StudentTest {public static void main(String[] args) {try {Student s = new Student();s.regist(-1001);System.out.println(s);} catch (Exception e) {
//      e.printStackTrace();System.out.println(e.getMessage());}}}class Student{private int id;public void regist(int id) throws Exception {if(id > 0){this.id = id;}else{
//      System.out.println("您输入的数据非法!");//手动抛出异常对象
//      throw new RuntimeException("您输入的数据非法!");
//      throw new Exception("您输入的数据非法!");throw new MyException("不能输入负数");//错误的
//      throw new String("不能输入负数");}}@Overridepublic String toString() {return "Student [id=" + id + "]";}
}

用户自定义异常类

/*
** * 如何自定义异常类?* 1. 继承于现有的异常结构:RuntimeException 、Exception* 2. 提供全局常量:serialVersionUID* 3. 提供重载的构造器*** */
public class MyException extends Exception{//唯一标识static final long serialVersionUID = -7034897193246939L;public MyException(){}public MyException(String msg){super(msg);}
}

练习题

/**  编写应用程序EcmDef.java,接收命令行的两个参数,要求不能输入负数,计算两数相除。对 数 据 类 型 不 一 致 (NumberFormatException) 、 缺 少 命 令 行 参 数(ArrayIndexOutOfBoundsException、除0(ArithmeticException)及输入负数(EcDef 自定义的异常)进行异常处理。提示:(1)在主类(EcmDef)中定义异常方法(ecm)完成两数相除功能。(2)在main()方法中使用异常处理语句进行异常处理。(3)在程序中,自定义对应输入负数的异常类(EcDef)。(4)运行时接受参数 java EcmDef 20 10 //args[0]=“20” args[1]=“10”(5)Interger类的static方法parseInt(String s)将s转换成对应的int值。如:int a=Interger.parseInt(“314”); //a=314;*/
public class EcmDef {public static void main(String[] args) {try{//从键盘输入agrs[0]int i=Integer.parseInt(args[0]);int j=Integer.parseInt(args[1]);int re=ecm(i,j);System.out.println(re);}catch(NumberFormatException e){System.out.println("数据类型不一致");}catch(ArrayIndexOutOfBoundsException a){System.out.println("缺少命令行");}catch(ArithmeticException a){System.out.println("除0");}catch(EcDef e){System.out.println(e.getMessage());}}public static int ecm(int i,int j) throws EcDef{if(i<0||j<0){throw new EcDef("输入的数不能为负数!");}return i/j;}}class EcDef extends Exception {private static final long serialVersionUID = -33875993124229948L;public EcDef() {}public EcDef(String s) {super(s);}}

07 多线程

基本概念:程序、进程、线程

多线程程序的优点:

  • 提高应用程序的响应。对图形化界面更有意义,可增强用户体验。

  • 提高计算机系统CPU的利用率

  • 改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改

线程的使用

创建多线程方式一:继承于Thread类



package atguigu.java;/*** 多线程的创建,方式一:继承于Thread类* 1. 创建一个继承于Thread类的子类* 2. 重写Thread类的run() --> 将此线程执行的操作声明在run()中* 3. 创建Thread类的子类的对象* 4. 通过此对象调用start()* <p>* 例子:遍历100以内的所有的偶数** @author shkstart* @create 2019-02-13 上午 11:46*///1. 创建一个继承于Thread类的子类
class MyThread extends Thread {//2. 重写Thread类的run()@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i % 2 == 0){System.out.println(Thread.currentThread().getName() + ":" + i);}}}
}public class ThreadTest {public static void main(String[] args) {//3. 创建Thread类的子类的对象MyThread t1 = new MyThread();//4.通过此对象调用start():①启动当前线程 ② 调用当前线程的run()t1.start();//问题一:我们不能通过直接调用run()的方式启动线程。
//        t1.run();//问题二:再启动一个线程,遍历100以内的偶数。不可以还让已经start()的线程去执行。会报IllegalThreadStateException
//        t1.start();//我们需要重新创建一个线程的对象MyThread t2 = new MyThread();t2.start();//如下操作仍然是在main线程中执行的。for (int i = 0; i < 100; i++) {if(i % 2 == 0){System.out.println(Thread.currentThread().getName() + ":" + i + "***********main()************");}}}}

package atguigu.java;/*** 测试Thread中的常用方法:* 1. start():启动当前线程;调用当前线程的run()* 2. run(): 通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中* 3. currentThread():静态方法,返回执行当前代码的线程* 4. getName():获取当前线程的名字* 5. setName():设置当前线程的名字* 6. yield():释放当前cpu的执行权* 7. join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才*           结束阻塞状态。* 8. stop():已过时。当执行此方法时,强制结束当前线程。* 9. sleep(long millitime):让当前线程“睡眠”指定的millitime毫秒。在指定的millitime毫秒时间内,当前*                          线程是阻塞状态。* 10. isAlive():判断当前线程是否存活*** 线程的优先级:* 1.* MAX_PRIORITY:10* MIN _PRIORITY:1* NORM_PRIORITY:5  -->默认优先级* 2.如何获取和设置当前线程的优先级:*   getPriority():获取线程的优先级*   setPriority(int p):设置线程的优先级**   说明:高优先级的线程要抢占低优先级线程cpu的执行权。但是只是从概率上讲,高优先级的线程高概率的情况下*   被执行。并不意味着只有当高优先级的线程执行完以后,低优先级的线程才执行。*** @author shkstart* @create 2019-02-13 下午 2:26*/
class HelloThread extends Thread{@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i % 2 == 0){//                try {
//                    sleep(10);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + i);}//            if(i % 20 == 0){
//                yield();
//            }}}public HelloThread(String name){super(name);}
}public class ThreadMethodTest {public static void main(String[] args) {HelloThread h1 = new HelloThread("Thread:1");//        h1.setName("线程一");//设置分线程的优先级h1.setPriority(Thread.MAX_PRIORITY);h1.start();//给主线程命名Thread.currentThread().setName("主线程");Thread.currentThread().setPriority(Thread.MIN_PRIORITY);for (int i = 0; i < 100; i++) {if(i % 2 == 0){System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + i);}//            if(i == 20){
//                try {
//                    h1.join();
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }}//        System.out.println(h1.isAlive());}
}

创建多线程方式二:实现Runnable接口

  1. 创建一个实现了Runnable接口的类

  1. 实现类去实现Runnable中的抽象方法:run()

  1. 创建实现类的对象

  1. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象

  1. 通过Thread类的对象调用start()

package atguigu.java;/*** 创建多线程的方式二:实现Runnable接口* 1. 创建一个实现了Runnable接口的类* 2. 实现类去实现Runnable中的抽象方法:run()* 3. 创建实现类的对象* 4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象* 5. 通过Thread类的对象调用start()*** 比较创建线程的两种方式。* 开发中:优先选择:实现Runnable接口的方式* 原因:1. 实现的方式没有类的单继承性的局限性*      2. 实现的方式更适合来处理多个线程有共享数据的情况。** 联系:public class Thread implements Runnable* 相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中。** @author shkstart* @create 2019-02-13 下午 4:34*/
//1. 创建一个实现了Runnable接口的类
class MThread implements Runnable{//2. 实现类去实现Runnable中的抽象方法:run()@Overridepublic void run() {for (int i = 0; i < 100; i++) {if(i % 2 == 0){System.out.println(Thread.currentThread().getName() + ":" + i);}}}
}public class ThreadTest1 {public static void main(String[] args) {//3. 创建实现类的对象MThread mThread = new MThread();//4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象Thread t1 = new Thread(mThread);t1.setName("线程1");//5. 通过Thread类的对象调用start():① 启动线程 ②调用当前线程的run()-->调用了Runnable类型的target的run()t1.start();//再启动一个线程,遍历100以内的偶数Thread t2 = new Thread(mThread);t2.setName("线程2");t2.start();}}

线程的生命周期

线程的同步

问题的提出多个线程执行的不确定性引起执行结果的不稳定

多个线程对账本的共享,会造成操作的不完整性,会破坏数据。

例子:创建三个窗口卖票,总票数为100张.使用实现Runnable接口的方式

  • 1.问题:卖票过程中,出现了重票、错票 -->出现了线程的安全问题

  • 2.问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票。

  • 3.如何解决:当一个线程a在操作ticket的时候,其他线程不能参与进来。直到线程a操作完ticket时,其他 线程才可以开始操作ticket。这种情况即使线程a出现了阻塞,也不能被改变。

  • 4.在Java中,我们通过同步机制,来解决线程的安全问题。

方式一:同步代码块

 *  方式一:同步代码块**   synchronized(同步监视器){*      //需要被同步的代码**   }**       补充:在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器。

方式二:同步方法

如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。

使用同步方法解决实现Runnable接口的线程安全问题***  **关于同步方法的总结:*  1. 同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。*  2. 非静态的同步方法,同步监视器是:this*     静态的同步方法,同步监视器是:当前类本身**

说明:1.操作共享数据的代码,即为需要被同步的代码。 -->不能包含代码多了,也不能包含代码少了。

  • 2.共享数据:**多个线程共同操作的变量。**比如:ticket就是共享数据。

  • 3.**同步监视器,****俗称:**锁。任何一个类的对象,都可以充当锁。

  • 要求:多个线程必须要共用同一把锁。

4.在Java中,我们通过同步机制,来解决线程的安全问题。

5.同步的方式,解决了线程的安全问题。---好处- 操作同步代码时,只能有一个线程参与,其他线程等待。相当于是一个单线程的过程,效率低。 ---局限性

class Window1 implements Runnable{private int ticket = 100;
//    Object obj = new Object();
//    Dog dog = new Dog();@Overridepublic void run() {
//        Object obj = new Object();while(true){synchronized (this){//此时的this:唯一的Window1的对象   //方式二:synchronized (dog) {if (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);ticket--;} else {break;}}}}
}
class Window3 implements Runnable {private int ticket = 100;@Overridepublic void run() {while (true) {show();}}private synchronized void show(){//同步监视器:this//synchronized (this){if (ticket > 0) {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);ticket--;}//}}
}public class WindowTest3 {public static void main(String[] args) {Window3 w = new Window3();Thread t1 = new Thread(w);Thread t2 = new Thread(w);Thread t3 = new Thread(w);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}}

线程安全的懒汉式

/*** 使用同步机制将单例模式中的懒汉式改写为线程安全的** @author shkstart* @create 2019-02-15 下午 2:50*/
public class BankTest {}class Bank{private Bank(){}private static Bank instance = null;public static Bank getInstance(){//方式一:效率稍差
//        synchronized (Bank.class) {
//            if(instance == null){
//
//                instance = new Bank();
//            }
//            return instance;
//        }//方式二:效率更高if(instance == null){synchronized (Bank.class) {if(instance == null){instance = new Bank();}}}return instance;}}

死锁

不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁****出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续

/*** 演示线程的死锁问题** 1.死锁的理解:不同的线程分别占用对方需要的同步资源不放弃,* 都在等待对方放弃自己需要的同步资源,就形成了线程的死锁** 2.说明:* 1)出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续* 2)我们使用同步时,要避免出现死锁。** @author shkstart* @create 2019-02-15 下午 3:20*/
public class ThreadTest {public static void main(String[] args) {StringBuffer s1 = new StringBuffer();StringBuffer s2 = new StringBuffer();new Thread(){@Overridepublic void run() {synchronized (s1){s1.append("a");s2.append("1");try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (s2){s1.append("b");s2.append("2");System.out.println(s1);System.out.println(s2);}}}}.start();new Thread(new Runnable() {@Overridepublic void run() {synchronized (s2){s1.append("c");s2.append("3");try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}synchronized (s1){s1.append("d");s2.append("4");System.out.println(s1);System.out.println(s2);}}}}).start();}
}
//死锁的演示
class A {public synchronized void foo(B b) { //同步监视器:A类的对象:aSystem.out.println("当前线程名: " + Thread.currentThread().getName()+ " 进入了A实例的foo方法"); // ①
//    try {
//      Thread.sleep(200);
//    } catch (InterruptedException ex) {
//      ex.printStackTrace();
//    }System.out.println("当前线程名: " + Thread.currentThread().getName()+ " 企图调用B实例的last方法"); // ③b.last();}public synchronized void last() {//同步监视器:A类的对象:aSystem.out.println("进入了A类的last方法内部");}
}class B {public synchronized void bar(A a) {//同步监视器:bSystem.out.println("当前线程名: " + Thread.currentThread().getName()+ " 进入了B实例的bar方法"); // ②
//    try {
//      Thread.sleep(200);
//    } catch (InterruptedException ex) {
//      ex.printStackTrace();
//    }System.out.println("当前线程名: " + Thread.currentThread().getName()+ " 企图调用A实例的last方法"); // ④a.last();}public synchronized void last() {//同步监视器:bSystem.out.println("进入了B类的last方法内部");}
}public class DeadLock implements Runnable {A a = new A();B b = new B();public void init() {Thread.currentThread().setName("主线程");// 调用a对象的foo方法a.foo(b);System.out.println("进入了主线程之后");}public void run() {Thread.currentThread().setName("副线程");// 调用b对象的bar方法b.bar(a);System.out.println("进入了副线程之后");}public static void main(String[] args) {DeadLock dl = new DeadLock();new Thread(dl).start();dl.init();}
}

Lock(锁)

import java.util.concurrent.locks.ReentrantLock;/*** 解决线程安全问题的方式三:Lock锁  --- JDK5.0新增** 1. 面试题:synchronized 与 Lock的异同?*   相同:二者都可以解决线程安全问题*   不同:synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器*        Lock需要手动的启动同步(lock()),同时结束同步也需要手动的实现(unlock())** 2.优先使用顺序:* Lock  同步代码块(已经进入了方法体,分配了相应资源)  同步方法(在方法体之外)***  面试题:如何解决线程安全问题?有几种方式* @author shkstart* @create 2019-02-15 下午 3:38*/
class Window implements Runnable{private int ticket = 100;//1.实例化ReentrantLockprivate ReentrantLock lock = new ReentrantLock();@Overridepublic void run() {while(true){try{//2.调用锁定方法lock()lock.lock();if(ticket > 0){try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + ":售票,票号为:" + ticket);ticket--;}else{break;}}finally {//3.调用解锁方法:unlock()lock.unlock();}}}
}public class LockTest {public static void main(String[] args) {Window w = new Window();Thread t1 = new Thread(w);Thread t2 = new Thread(w);Thread t3 = new Thread(w);t1.setName("窗口1");t2.setName("窗口2");t3.setName("窗口3");t1.start();t2.start();t3.start();}
}

面试题:synchronized 与 Lock的异同?

  • 相同:二者都可以解决线程安全问题

  • 不同:synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器

  • Lock需要手动的启动同步(lock()),同时结束同步也需要手动的实现(unlock())

线程的通信

线程通信的例子:使用两个线程打印 1-100。线程1, 线程2 交替打印

涉及到的三个方法:

  • wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。

  • notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。

  • notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。

说明:

  • 1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。

  • 2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。否则,会出现IllegalMonitorStateException异常

  • 3.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中。

class Number implements Runnable {private int number = 1;@Overridepublic void run() {for (int i = 0; i < 100; i++) {synchronized (this) {notifyAll();if (number <= 100) {try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName() + ": " + number);number++;try {//使得调用的线程进入阻塞状态wait();} catch (InterruptedException e) {throw new RuntimeException(e);}} else {break;}}}}
}public class communicationTest {public static void main(String[] args) {Number number = new Number();Thread t1 = new Thread(number);Thread t2 = new Thread(number);t1.setName("线程 1 ");t2.setName("线程 2 ");t1.start();t2.start();}
}

面试题

面试题:sleep() 和 wait()的异同?

1.相同点:

一旦执行方法,都可以使得当前的线程进入阻塞状态。

2.不同点:

1)两个方法声明的位置不同:Thread类中声明sleep() , Object类中声明wait()

2)调用的要求不同:sleep()可以在任何需要的场景下调用。 wait()必须使用在同步代码块或同步方法中

3)关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁。

经典例题:生产者消费者问题

分析:

  1. 是否是多线程问题?是,生产者线程,消费者线程

  1. 是否有共享数据?是,店员(或产品)

  1. 如何解决线程的安全问题?同步机制,有三种方法

  1. 是否涉及线程的通信?是

package com.learn.java2;/*** 线程通信的应用:经典例题:生产者/消费者问题* <p>* * 生产者(Productor)将产品交给店员(Clerk),而消费者(Customer)从店员处取走产品,* * 店员一次只能持有固定数量的产品(比如:20),如果生产者试图生产更多的产品,店员* * 会叫生产者停一下,如果店中有空位放产品了再通知生产者继续生产;如果店中没有产品* * 了,店员会告诉消费者等一下,如果店中有产品了再通知消费者来取走产品。** @author Lucaslee* @create 2022-11-02 11:10*/
//店员(Clerk)
class Clerk {private int chanpin = 15;public Clerk() {}public Clerk(int chanpin) {this.chanpin = chanpin;}public synchronized void Shengcheng() {if (chanpin<20){try {Thread.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}chanpin++;System.out.println(Thread.currentThread().getName()+" :开始生产第"+chanpin+"个产品");notify();}else{try {wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}}public synchronized void Xiaofei() {if (chanpin>0){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName()+" :开始消费第"+chanpin+"个产品");--chanpin;notify();}else{try {wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}}public void setChanpin(int chanpin) {this.chanpin = chanpin;}public int getChanpin() {return chanpin;}
}//生产者(Productor)
class Productor implements Runnable {private Clerk clerk;public Productor(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"开始生产产品....");while (true){try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}clerk.Shengcheng();}}
}//消费者(Customer)
class Customer implements Runnable {private Clerk clerk;public Customer(Clerk clerk) {this.clerk = clerk;}@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"开始消费产品....");while (true){try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}clerk.Xiaofei();}}
}public class ProductTest {public static void main(String[] args) {Clerk clerk = new Clerk();//生产者1对象Thread p1 = new Thread(new Productor(clerk));Thread p2 = new Thread(new Productor(clerk));Thread p3 = new Thread(new Productor(clerk));//消费者1对象Thread c1 = new Thread(new Customer(clerk));Thread c2 = new Thread(new Customer(clerk));Thread c3 = new Thread(new Customer(clerk));p1.setName("生产者 1");p2.setName("生产者 2");p3.setName("生产者 3");c1.setName("消费者 1");c2.setName("消费者 2");c3.setName("消费者 3");p1.start();p2.start();p3.start();c1.start();c2.start();c3.start();}
}

创建线程方式三:实现Callable接口

package com.learn.java2;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;/**
** * * 创建线程的方式三:实现Callable接口。 --- JDK 5.0新增*** ** ** * 如何理解实现Callable接口的方式创建多线程比实现Runnable接口创建多线程方式强大?* * 1. call()可以有返回值的。* * 2. call()可以抛出异常,被外面的操作捕获,获取异常的信息* * 3. Callable是支持泛型的** @author Lucaslee* @create 2022-11-02 14:34*/
//1.创建一个实现Callable的实现类
class NumThread implements Callable {//2.实现call方法,将此线程需要执行的操作声明在call()中@Overridepublic Object call() throws Exception {int sum = 0;for (int i = 1; i <= 100; i++) {if (i % 2 == 0) {System.out.println(i);sum += i;}}return sum;}
}public class ThreadNew {public static void main(String[] args) {//3.创建Callable接口实现类的对象NumThread numThread = new NumThread();//4.将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象FutureTask futureTask = new FutureTask(numThread);//5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象Thread t1 = new Thread(futureTask);//6.调用start(),开启线程t1.start();try {//7.获取Callable中call方法的返回值//get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。Object sum = futureTask.get();System.out.println("总和为:" + sum);} catch (InterruptedException e) {throw new RuntimeException(e);} catch (ExecutionException e) {throw new RuntimeException(e);}}
}

创建线程方式四:线程池使用

背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。

思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。

好处:

  • 提高响应速度(减少了创建新线程的时间)

  • 降低资源消耗(重复利用线程池中线程,不需要每次都创建)

  • 便于线程管理

corePoolSize:核心池的大小maximumPoolSize:最大线程数keepAliveTime:线程没有任务时最多保持多长时间后会终止

package com.learn.java2;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** @author Lucaslee* @create 2022-11-02 15:00*/class NumberThread implements Runnable{@Overridepublic void run() {for(int i = 0;i <= 100;i++){if(i % 2 == 0){System.out.println(Thread.currentThread().getName() + ": " + i);}}}
}class NumberThread1 implements Runnable{@Overridepublic void run() {for(int i = 0;i <= 100;i++){if(i % 2 != 0){System.out.println(Thread.currentThread().getName() + ": " + i);}}}
}public class threadPool {public static void main(String[] args) {//1.提供指定数量的线程池ExecutorService executorService = Executors.newFixedThreadPool(10);//设置线程池的属性System.out.println(executorService.getClass());//2.执行指定的线程的操作。需要提供实现Runnable接口或Callable接口实现类的对象executorService.execute(new NumberThread());//适用于runnableexecutorService.submit(new NumberThread1());//适用于callable//关闭连接池executorService.shutdown();}
}

08 Java常用类

字符串相关的类

String的特性

String:字符串,使用一对""引起来表示。

  • 1.String声明为final的,不可被继承,代表不可变的字符序列。

  • 2.String实现了Serializable接口:表示字符串是支持序列化的。

实现了Comparable接口:表示String可以比较大小

  • 3.String内部定义了final char[] value用于存储字符串数据

  • 4.**String:代表不可变的字符序列。**简称:不可变性。

体现:1. 当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。2. 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。3. 当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。

  • 5.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。

  • 6.字符串常量池中是不会存储相同内容的字符串的。

@Testpublic void test1(){String s1 = "abc";//字面量的定义方式String s2 = "abc";s1 = "hello";System.out.println(s1 == s2);//比较s1和s2的地址值System.out.println(s1);//helloSystem.out.println(s2);//abcSystem.out.println("*****************");String s3 = "abc";s3 += "def";System.out.println(s3);//abcdefSystem.out.println(s2);System.out.println("*****************");String s4 = "abc";String s5 = s4.replace('a', 'm');System.out.println(s4);//abcSystem.out.println(s5);//mbc}

String对象的创建

String的实例化方式:

方式一:通过字面量定义的方式

方式二:通过new + 构造器的方式

 @Testpublic void test2(){//通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。String s1 = "javaEE";String s2 = "javaEE";//通过new + 构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。String s3 = new String("javaEE");String s4 = new String("javaEE");System.out.println(s1 == s2);//trueSystem.out.println(s1 == s3);//falseSystem.out.println(s1 == s4);//falseSystem.out.println(s3 == s4);//falseSystem.out.println("***********************");Person p1 = new Person("Tom",12);Person p2 = new Person("Tom",12);System.out.println(p1.name.equals(p2.name));//trueSystem.out.println(p1.name == p2.name);//truep1.name = "Jerry";System.out.println(p2.name);//Tom}

面试题:String s = new String("abc");方式创建对象,在内存中创建了几个对象?

两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:"abc"

    @Testpublic void test3(){String s1 = "javaEE";String s2 = "hadoop";String s3 = "javaEEhadoop";String s4 = "javaEE" + "hadoop";String s5 = s1 + "hadoop";String s6 = "javaEE" + s2;String s7 = s1 + s2;System.out.println(s3 == s4);//trueSystem.out.println(s3 == s5);//falseSystem.out.println(s3 == s6);//falseSystem.out.println(s3 == s7);//falseSystem.out.println(s5 == s6);//falseSystem.out.println(s5 == s7);//falseSystem.out.println(s6 == s7);//falseString s8 = s6.intern();//返回值得到的s8使用的常量值中已经存在的“javaEEhadoop”System.out.println(s3 == s8);//true}

结论:

1.常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。

2.只要其中有一个是变量,结果就在堆中。

3.如果拼接的结果调用intern()方法,返回值就在常量池中

String常用方法

    /*
int length():返回字符串的长度: return value.length
*char charAt(int index): 返回某索引处的字符return value[index]
boolean isEmpty():判断是否是空字符串:return value.length == 0
String toLowerCase():使用默认语言环境,将 String 中的所有字符转换为小写
String toUpperCase():使用默认语言环境,将 String 中的所有字符转换为大写
String trim():返回字符串的副本,忽略前导空白和尾部空白
*boolean equals(Object obj):比较字符串的内容是否相同
*boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
String concat(String str):将指定字符串连接到此字符串的结尾。 等价于用“+”
*int compareTo(String anotherString):比较两个字符串的大小
String substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。(索引从0开始)
String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。*/@Testpublic void test2() {String s1 = "HelloWorld";String s2 = "helloworld";System.out.println(s1.equals(s2));System.out.println(s1.equalsIgnoreCase(s2));String s3 = "abc";String s4 = s3.concat("def");System.out.println(s4);String s5 = "abc";String s6 = new String("abe");System.out.println(s5.compareTo(s6));//涉及到字符串排序String s7 = "北京尚硅谷教育";String s8 = s7.substring(2);System.out.println(s7);System.out.println(s8);String s9 = s7.substring(2, 5);System.out.println(s9);}@Testpublic void test1() {String s1 = "HelloWorld";System.out.println(s1.length());System.out.println(s1.charAt(0));System.out.println(s1.charAt(9));
//        System.out.println(s1.charAt(10));
//        s1 = "";System.out.println(s1.isEmpty());String s2 = s1.toLowerCase();System.out.println(s1);//s1不可变的,仍然为原来的字符串System.out.println(s2);//改成小写以后的字符串String s3 = "   he  llo   world   ";String s4 = s3.trim();System.out.println("-----" + s3 + "-----");System.out.println("-----" + s4 + "-----");}
}
/*
boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束
boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始
boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true
int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引
int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索注:indexOf和lastIndexOf方法如果未找到都是返回-1*/@Testpublic void test3(){String str1 = "hellowworld";boolean b1 = str1.endsWith("rld");System.out.println(b1);boolean b2 = str1.startsWith("He");System.out.println(b2);boolean b3 = str1.startsWith("ll",2);System.out.println(b3);String str2 = "wor";System.out.println(str1.contains(str2));System.out.println(str1.indexOf("lol"));System.out.println(str1.indexOf("lo",5));String str3 = "hellorworld";System.out.println(str3.lastIndexOf("or"));System.out.println(str3.lastIndexOf("or",6));//什么情况下,indexOf(str)和lastIndexOf(str)返回值相同?//情况一:存在唯一的一个str。情况二:不存在str}
   /*
替换:
String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
String replace(CharSequence target, CharSequence replacement):使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
String replaceAll(String regex, String replacement):使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
String replaceFirst(String regex, String replacement):使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
匹配:
boolean matches(String regex):告知此字符串是否匹配给定的正则表达式。
切片:
String[] split(String regex):根据给定正则表达式的匹配拆分此字符串。
String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。*/@Testpublic void test4(){String str1 = "北京尚硅谷教育北京";String str2 = str1.replace('北', '东');System.out.println(str1);System.out.println(str2);String str3 = str1.replace("北京", "上海");System.out.println(str3);System.out.println("*************************");String str = "12hello34world5java7891mysql456";//把字符串中的数字替换成,,如果结果中开头和结尾有,的话去掉String string = str.replaceAll("\\d+", ",").replaceAll("^,|,$", "");System.out.println(string);System.out.println("*************************");str = "12345";//判断str字符串中是否全部有数字组成,即有1-n个数字组成boolean matches = str.matches("\\d+");System.out.println(matches);String tel = "0571-4534289";//判断这是否是一个杭州的固定电话boolean result = tel.matches("0571-\\d{7,8}");System.out.println(result);System.out.println("*************************");str = "hello|world|java";String[] strs = str.split("\\|");for (int i = 0; i < strs.length; i++) {System.out.println(strs[i]);}System.out.println();str2 = "hello.world.java";String[] strs2 = str2.split("\\.");for (int i = 0; i < strs2.length; i++) {System.out.println(strs2[i]);}}

String类与其他结构之间的转换

/**

  • 涉及到String类与其他结构之间的转换

  • @author shkstart

  • @create 2019 下午 2:39*/

public class StringTest1 {/*String 与 byte[]之间的转换编码:String --> byte[]:调用String的getBytes()解码:byte[] --> String:调用String的构造器编码:字符串 -->字节  (看得懂 --->看不懂的二进制数据)解码:编码的逆过程,字节 --> 字符串 (看不懂的二进制数据 ---> 看得懂)说明:解码时,要求解码使用的字符集必须与编码时使用的字符集一致,否则会出现乱码。*/@Testpublic void test3() throws UnsupportedEncodingException {String str1 = "abc123中国";byte[] bytes = str1.getBytes();//使用默认的字符集,进行编码。System.out.println(Arrays.toString(bytes));byte[] gbks = str1.getBytes("gbk");//使用gbk字符集进行编码。System.out.println(Arrays.toString(gbks));System.out.println("******************");String str2 = new String(bytes);//使用默认的字符集,进行解码。System.out.println(str2);String str3 = new String(gbks);System.out.println(str3);//出现乱码。原因:编码集和解码集不一致!String str4 = new String(gbks, "gbk");System.out.println(str4);//没有出现乱码。原因:编码集和解码集一致!}/*String 与 char[]之间的转换String --> char[]:调用String的toCharArray()char[] --> String:调用String的构造器*/@Testpublic void test2(){String str1 = "abc123";  //题目: a21cb3char[] charArray = str1.toCharArray();for (int i = 0; i < charArray.length; i++) {System.out.println(charArray[i]);}char[] arr = new char[]{'h','e','l','l','o'};String str2 = new String(arr);System.out.println(str2);}/*复习:String 与基本数据类型、包装类之间的转换。String --> 基本数据类型、包装类:调用包装类的静态方法:parseXxx(str)基本数据类型、包装类 --> String:调用String重载的valueOf(xxx)*/@Testpublic void test1(){String str1 = "123";
//        int num = (int)str1;//错误的int num = Integer.parseInt(str1);String str2 = String.valueOf(num);//"123"String str3 = num + "";System.out.println(str1 == str3);}}

StringBuffer类

关于StringBuffer和StringBuilder的使用

String、StringBuffer、StringBuilder三者的异同?

String:不可变的字符序列;底层使用char[]存储

StringBuffer:可变的字符序列;线程安全的,效率低;底层使用char[]存储

StringBuilder:可变的字符序列;jdk5.0新增的,线程不安全的,效率高;底层使用char[]存储

总结:增:append(xxx)

删:delete(int start,int end)

改:setCharAt(int n ,char ch) / replace(int start, int end, String str)

查:charAt(int n )

插:insert(int offset, xxx)

长度:length();

*遍历:for() + charAt() / toString()

**对比String、StringBuffer、StringBuilder三者的效率:从高到低排列:**StringBuilder > StringBuffer > String

public class StringBufferBuilderTest {/*对比String、StringBuffer、StringBuilder三者的效率:从高到低排列:StringBuilder > StringBuffer > String*/@Testpublic void test3(){//初始设置long startTime = 0L;long endTime = 0L;String text = "";StringBuffer buffer = new StringBuffer("");StringBuilder builder = new StringBuilder("");//开始对比startTime = System.currentTimeMillis();for (int i = 0; i < 20000; i++) {buffer.append(String.valueOf(i));}endTime = System.currentTimeMillis();System.out.println("StringBuffer的执行时间:" + (endTime - startTime));startTime = System.currentTimeMillis();for (int i = 0; i < 20000; i++) {builder.append(String.valueOf(i));}endTime = System.currentTimeMillis();System.out.println("StringBuilder的执行时间:" + (endTime - startTime));startTime = System.currentTimeMillis();for (int i = 0; i < 20000; i++) {text = text + i;}endTime = System.currentTimeMillis();System.out.println("String的执行时间:" + (endTime - startTime));}/*StringBuffer的常用方法:
StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串拼接
StringBuffer delete(int start,int end):删除指定位置的内容
StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str
StringBuffer insert(int offset, xxx):在指定位置插入xxx
StringBuffer reverse() :把当前字符序列逆转
public int indexOf(String str)
public String substring(int start,int end):返回一个从start开始到end索引结束的左闭右开区间的子字符串
public int length()
public char charAt(int n )
public void setCharAt(int n ,char ch)总结:增:append(xxx)删:delete(int start,int end)改:setCharAt(int n ,char ch) / replace(int start, int end, String str)查:charAt(int n )插:insert(int offset, xxx)长度:length();*遍历:for() + charAt() / toString()*/@Testpublic void test2(){StringBuffer s1 = new StringBuffer("abc");s1.append(1);s1.append('1');System.out.println(s1);
//        s1.delete(2,4);
//        s1.replace(2,4,"hello");
//        s1.insert(2,false);
//        s1.reverse();String s2 = s1.substring(1, 3);System.out.println(s1);System.out.println(s1.length());System.out.println(s2);}

日期和时间API

JDK 8之前日期和时间的API测试

public class DateTimeTest {/*java.util.Date类|---java.sql.Date类1.两个构造器的使用>构造器一:Date():创建一个对应当前时间的Date对象>构造器二:创建指定毫秒数的Date对象2.两个方法的使用>toString():显示当前的年、月、日、时、分、秒>getTime():获取当前Date对象对应的毫秒数。(时间戳)3. java.sql.Date对应着数据库中的日期类型的变量>如何实例化>如何将java.util.Date对象转换为java.sql.Date对象*/@Testpublic void test2(){//构造器一:Date():创建一个对应当前时间的Date对象Date date1 = new Date();System.out.println(date1.toString());//Sat Feb 16 16:35:31 GMT+08:00 2019System.out.println(date1.getTime());//1550306204104//构造器二:创建指定毫秒数的Date对象Date date2 = new Date(155030620410L);System.out.println(date2.toString());//创建java.sql.Date对象java.sql.Date date3 = new java.sql.Date(35235325345L);System.out.println(date3);//1971-02-13//如何将java.util.Date对象转换为java.sql.Date对象//情况一:
//        Date date4 = new java.sql.Date(2343243242323L);
//        java.sql.Date date5 = (java.sql.Date) date4;//情况二:Date date6 = new Date();java.sql.Date date7 = new java.sql.Date(date6.getTime());}//1.System类中的currentTimeMillis()@Testpublic void test1(){long time = System.currentTimeMillis();//返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差。//称为时间戳System.out.println(time);}
}

simpleDateFormat类

SimpleDateFormat的使用:SimpleDateFormat对日期Date类的格式化和解析

1.两个操作:

1.1 格式化:日期 --->字符串1.2 解析:格式化的逆过程,字符串 ---> 日期
2.SimpleDateFormat的实例化*/@Testpublic void testSimpleDateFormat() throws ParseException {//实例化SimpleDateFormat:使用默认的构造器SimpleDateFormat sdf = new SimpleDateFormat();//格式化:日期 --->字符串Date date = new Date();System.out.println(date);String format = sdf.format(date);System.out.println(format);//解析:格式化的逆过程,字符串 ---> 日期String str = "19-12-18 上午11:43";Date date1 = sdf.parse(str);System.out.println(date1);//*************按照指定的方式格式化和解析:调用带参的构造器*****************
//        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyy.MMMMM.dd GGG hh:mm aaa");SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");//格式化String format1 = sdf1.format(date);System.out.println(format1);//2019-02-18 11:48:27//解析:要求字符串必须是符合SimpleDateFormat识别的格式(通过构造器参数体现),//否则,抛异常Date date2 = sdf1.parse("2020-02-18 11:48:27");System.out.println(date2);}

Calendar日历类

/*Calendar日历类(抽象类)的使用*/@Testpublic void testCalendar(){//1.实例化//方式一:创建其子类(GregorianCalendar)的对象//方式二:调用其静态方法getInstance()Calendar calendar = Calendar.getInstance();
//        System.out.println(calendar.getClass());//2.常用方法//get()int days = calendar.get(Calendar.DAY_OF_MONTH);System.out.println(days);System.out.println(calendar.get(Calendar.DAY_OF_YEAR));//set()//calendar可变性calendar.set(Calendar.DAY_OF_MONTH,22);days = calendar.get(Calendar.DAY_OF_MONTH);System.out.println(days);//add()calendar.add(Calendar.DAY_OF_MONTH,-3);days = calendar.get(Calendar.DAY_OF_MONTH);System.out.println(days);//getTime():日历类---> DateDate date = calendar.getTime();System.out.println(date);//setTime():Date ---> 日历类Date date1 = new Date();calendar.setTime(date1);days = calendar.get(Calendar.DAY_OF_MONTH);System.out.println(days);}
}

JDK8中新日期时间API

LocalDateTime

而Calendar并不比Date好多少。它们面临的问题是:

  • 可变性:像日期和时间这样的类应该是不可变的。

  • 偏移性:Date中的年份是从1900开始的,而月份都从0开始。

  • 格式化:格式化只对Date有用,Calendar则不行。

  • 此外,它们也不是线程安全的;不能处理闰秒等。

LocalDate、LocalTime、LocalDateTime 的使用

说明:

1.LocalDateTime相较于LocalDate、LocalTime,使用频率要高2.类似于Calendar
public class JDK8DateTimeTest {@Testpublic void testDate(){//偏移量Date date1 = new Date(2020 - 1900,9 - 1,8);System.out.println(date1);//Tue Sep 08 00:00:00 GMT+08:00 2020}/*LocalDate、LocalTime、LocalDateTime 的使用说明:1.LocalDateTime相较于LocalDate、LocalTime,使用频率要高2.类似于Calendar*/@Testpublic void test1(){//now():获取当前的日期、时间、日期+时间LocalDate localDate = LocalDate.now();LocalTime localTime = LocalTime.now();LocalDateTime localDateTime = LocalDateTime.now();System.out.println(localDate);System.out.println(localTime);System.out.println(localDateTime);//of():设置指定的年、月、日、时、分、秒。没有偏移量LocalDateTime localDateTime1 = LocalDateTime.of(2020, 10, 6, 13, 23, 43);System.out.println(localDateTime1);//getXxx():获取相关的属性System.out.println(localDateTime.getDayOfMonth());System.out.println(localDateTime.getDayOfWeek());System.out.println(localDateTime.getMonth());System.out.println(localDateTime.getMonthValue());System.out.println(localDateTime.getMinute());//体现不可变性//withXxx():设置相关的属性LocalDate localDate1 = localDate.withDayOfMonth(22);System.out.println(localDate);System.out.println(localDate1);LocalDateTime localDateTime2 = localDateTime.withHour(4);System.out.println(localDateTime);System.out.println(localDateTime2);//不可变性(加)LocalDateTime localDateTime3 = localDateTime.plusMonths(3);System.out.println(localDateTime);System.out.println(localDateTime3);//减LocalDateTime localDateTime4 = localDateTime.minusDays(6);System.out.println(localDateTime);System.out.println(localDateTime4);}

瞬时:Instant

 /*Instant的使用类似于 java.util.Date类*/@Testpublic void test2(){//now():获取本初子午线对应的标准时间Instant instant = Instant.now();System.out.println(instant);//2019-02-18T07:29:41.719Z//添加时间的偏移量OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));System.out.println(offsetDateTime);//2019-02-18T15:32:50.611+08:00//toEpochMilli():获取自1970年1月1日0时0分0秒(UTC)开始的毫秒数  ---> Date类的getTime()long milli = instant.toEpochMilli();System.out.println(milli);//ofEpochMilli():通过给定的毫秒数,获取Instant实例  -->Date(long millis)Instant instant1 = Instant.ofEpochMilli(1550475314878L);System.out.println(instant1);}

DateTimeFormatter 类

/*DateTimeFormatter:格式化或解析日期、时间类似于SimpleDateFormat*/@Testpublic void test3(){
//        方式一:预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIMEDateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;//格式化:日期-->字符串LocalDateTime localDateTime = LocalDateTime.now();String str1 = formatter.format(localDateTime);System.out.println(localDateTime);System.out.println(str1);//2019-02-18T15:42:18.797//解析:字符串 -->日期TemporalAccessor parse = formatter.parse("2019-02-18T15:42:18.797");System.out.println(parse);//        方式二:
//        本地化相关的格式。如:ofLocalizedDateTime()
//        FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT :适用于LocalDateTimeDateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);//格式化String str2 = formatter1.format(localDateTime);System.out.println(str2);//2019年2月18日 下午03时47分16秒//      本地化相关的格式。如:ofLocalizedDate()
//      FormatStyle.FULL / FormatStyle.LONG / FormatStyle.MEDIUM / FormatStyle.SHORT : 适用于LocalDateDateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);//格式化String str3 = formatter2.format(LocalDate.now());System.out.println(str3);//2019-2-18**        //       重点: 方式三:自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");//格式化String str4 = formatter3.format(LocalDateTime.now());System.out.println(str4);//2019-02-18 03:52:09//解析TemporalAccessor accessor = formatter3.parse("2019-02-18 03:52:09");System.out.println(accessor);}}**

Java比较器

一、说明:

Java中的对象,正常情况下,只能进行比较:== 或 != 。不能使用 > 或 < 的但是在开发场景中,我们需要对多个对象进行排序,言外之意,就需要比较对象的大小。

**如何实现?使用两个接口中的任何一个:**Comparable 或 Comparator

二、Comparable接口与Comparator的使用的对比:

  • Comparable接口的方式一旦一定,保证Comparable接口实现类的对象在任何位置都可以比较大小。

  • Comparator接口属于临时性的比较。

** **public class CompareTest {** /*Comparable接口的使用举例:  自然排序1.像String、包装类等实现了Comparable接口,重写了compareTo(obj)方法,给出了比较两个对象大小的方式。2.像String、包装类****重写compareTo()方法****以后,进行了从小到大的排列3. 重写compareTo(obj)的规则:如果当前对象this大于形参对象obj,则返回正整数,如果当前对象this小于形参对象obj,则返回负整数,如果当前对象this等于形参对象obj,则返回零。4. 对于自定义类来说,如果需要排序,我们可以让自定义类实现Comparable接口,重写compareTo(obj)方法。在compareTo(obj)方法中指明如何排序*/**@Testpublic void test1(){String[] arr = new String[]{"AA","CC","KK","MM","GG","JJ","DD"};//Arrays.sort(arr);System.out.println(Arrays.toString(arr));}@Testpublic void test2(){Goods[] arr = new Goods[5];arr[0] = new Goods("lenovoMouse",34);arr[1] = new Goods("dellMouse",43);arr[2] = new Goods("xiaomiMouse",12);arr[3] = new Goods("huaweiMouse",65);arr[4] = new Goods("microsoftMouse",43);Arrays.sort(arr);System.out.println(Arrays.toString(arr));}** ****  /*Comparator接口的使用:定制排序1.背景:当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator 的对象来排序2.****重写compare(Object o1,Object o2)方法****,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2。*/**@Testpublic void test3(){String[] arr = new String[]{"AA","CC","KK","MM","GG","JJ","DD"};Arrays.sort(arr,new Comparator(){//按照字符串从大到小的顺序排列@Overridepublic int compare(Object o1, Object o2) {if(o1 instanceof String && o2 instanceof  String){String s1 = (String) o1;String s2 = (String) o2;return -s1.compareTo(s2);}
//                return 0;throw new RuntimeException("输入的数据类型不一致");}});System.out.println(Arrays.toString(arr));}@Testpublic void test4(){Goods[] arr = new Goods[6];arr[0] = new Goods("lenovoMouse",34);arr[1] = new Goods("dellMouse",43);arr[2] = new Goods("xiaomiMouse",12);arr[3] = new Goods("huaweiMouse",65);arr[4] = new Goods("huaweiMouse",224);arr[5] = new Goods("microsoftMouse",43);Arrays.sort(arr, new Comparator() {//指明商品比较大小的方式:按照产品名称从低到高排序,再按照价格从高到低排序@Overridepublic int compare(Object o1, Object o2) {if(o1 instanceof Goods && o2 instanceof Goods){Goods g1 = (Goods)o1;Goods g2 = (Goods)o2;if(g1.getName().equals(g2.getName())){return -Double.compare(g1.getPrice(),g2.getPrice());}else{return g1.getName().compareTo(g2.getName());}}throw new RuntimeException("输入的数据类型不一致");}});System.out.println(Arrays.toString(arr));}}
    public class Goods implements  Comparable{//指明商品比较大小的方式:按照价格从低到高排序,再按照产品名称从高到低排序@Overridepublic int compareTo(Object o) {
//        System.out.println("**************");if(o instanceof Goods){Goods goods = (Goods)o;//方式一:if(this.price > goods.price){return 1;}else if(this.price < goods.price){return -1;}else{
//                return 0;return -this.name.compareTo(goods.name);}//方式二:
//           return Double.compare(this.price,goods.price);}
//        return 0;throw new RuntimeException("传入的数据类型不一致!");}
}

System类

JAVA核心基础笔记(上)相关推荐

  1. Java核心基础笔记(下)

    09 枚举类与*注解 一.枚举类的使用 1.枚举类的理解:类的对象只有有限个,确定的.我们称此类为枚举类 2.当需要定义一组常量时,强烈建议使用枚举类 3.如果枚举类中只有一个对象,则可以作为单例模式 ...

  2. Java零基础笔记自用版(一)

    系列文章目录 一.Java零基础笔记自用版(一) 目录 系列文章目录 前言 一.⭐️Java概述 二.⭐️变量 三.⭐️运算符 四.⭐️控制结构 五.⭐️数组.排序.查找 写在最后 前言 最近在学习J ...

  3. Java核心类库(上)

    Java核心类库(上) 参加拉勾教育大数据训练营课程笔记 学会查阅API文档,根据包索引,搜索等. 常用类 java.lang - 唯一一个Java虚拟机自动访问,所以System等不需要import ...

  4. 阿里淘系 七面 0经验拿下offer 只因面试前死磕了Java核心面试笔记

    前几天一位粉丝朋友反馈,在九月份参加了阿里(淘系)面试,经过和面试官激励的七次博弈顺利拿下offer! 先看一下粉丝的个人情况: 粉丝属于是没有任何项目经验,和从业经历属于是新手小白,这位小粉丝也是把 ...

  5. java单引号转义_Java基础入门——Java语言基础(上)

    本篇我们开始进入Java的学习,首先在学习如何编写Java语言前要先了解Java程序的基本结构. 一.Java程序的基本结构 一个Java程序的基本结构大体可以分为包.类.main()主方法.标识符. ...

  6. 欢迎大家参加,Java核心基础快速总结与增强免费培训

    此次培训糅合了当今最新的Java思想.Java技术,以及众多的Java新特性.为期半个月,半个月时间内带领大家全面学习Java核心基础.面向对象.设计模式.J2SE6新特性.Java反射.代理.注解. ...

  7. java语言基础笔记——语句,函数

    java语言基础笔记 语句 判断结构(重点) 三种格式: 第一种:   if(条件表达式){ 执行语句;         }   System.out.println();   举例:   int a ...

  8. 阿里巴巴大神发布的Java零基础笔记,实战教程多到手软,跪了

    前言 现值金三银四之际,是面试高峰季,很多学校开始校招,也是跳槽转行的最佳时机.根据数据显示,程序员是金九银十里最热门的行业,也是需求量最大的行业,但是程序员是个门槛低,但金字塔顶峰比较高的行业,意味 ...

  9. Java笔记-Java日常笔记-Java核心语言-史上最全Java笔记-Java烂笔头-实时更新(~v~)

    阿一的日常Java笔记,实时更新,有什么问题可以留言交流一下,大家一起共同进步!!! 1.Java基础 1.1.基本语法 1.1.1.关键字 ​ 定义:被java赋予特殊含义的字符串(单词): ​ 关 ...

  10. java零基础 笔记总结【适合初学者】

    动力节点 java 课程笔记总结 关于二进制 关于字节 - Day 01 计算机历史 [1]显示文件扩展名 1.windows操作系统的文件扩展名设置 新建.java结尾的文件怎么做? *文件资源管理 ...

最新文章

  1. 比较v-bind和v-model
  2. VTK:网格之DeformPointSet
  3. 绝对不忽悠、暑期择机功能该咋选?
  4. java.lang.math.abs_java.lang.StrictMath.abs(int a)方法实例
  5. 塑料壳上下扣合的卡扣设计_一种塑料件卡扣结构制造技术
  6. spark 安装与使用 educoder
  7. 火车头采集器文章伪原创插件工具
  8. 把rmvb格式转化为avi格式
  9. ppt内嵌excel显示找不到服务器,翻遍互联网都找不到的干货:如何在 PPT 里面演示动态图表?...
  10. Python3 sorted自定义排序
  11. appstore软件销售数据统计分析软件Prismo
  12. android电商平台,基于Android的电商平台通用客户端的设计与实现
  13. 原生小程序实现手风琴
  14. logiscope系列-使用说明书
  15. Java程序员进阶架构师的五个阶段,你到了哪各阶段?
  16. 关于height:100%的简单理解
  17. 企业OA有哪些好处?所有企业都要用OA吗?
  18. php wmf png,php – 无法使用Imagemagick将SVG转换为WMF
  19. uniapp plus.downloader.createDownload 无反应问题
  20. linux centos6安装postgresql

热门文章

  1. pytorch 基本数学运算
  2. 腾讯360再较量  谁是反垄断巨头
  3. 小实验:PC9与PC10连通的命令操作
  4. 通过Ubuntu16.04编译Android下的osip动态库
  5. 笔记本不小心网络重置后,不能上网,网络适配器存在感叹号
  6. hdu5745 La Vie en rose(暴力)
  7. 有一种星光叫记忆:张国荣主演的九部经典影片
  8. 博科查看光功率_博科系交换机光模块信号强度查看
  9. android o壁纸,超实用壁纸应用大合集 - 你想要的壁纸在这里统统都能找到! - Android 应用 - 【最美应用】...
  10. 随笔-学习编程有没有必要做笔记?如何做笔记?