javaSE学习笔记
前言
1、 什么是Android开发?
Android是一个安装在移动端设备上的操作系统,android应用程序开发(APP)。
2、 为什么要学习Android?
因为Android操作系统使用率最高
3、 如何学习?
Java语言,被公认为是世界上最简单的语言,Java是一种纯面向对象的编程语言。
Android操作系统上运行的程序,都是由Java语言编写的。
学习安排:
第一阶段,JavaSE学习(Java基础学习)40-50天,可以开发简单的桌面应用程序。
第二阶段,android学习,50天左右,可以开发简单的手机应用。
第三阶段,项目实战,便利+ ……
第一部分 Java学习
一、 认识Java编程
1、Java简介
Java的三个分支:
J2SE:Java语法基础、面向对象概念、常用类库、窗体设计、桌面软件;
J2ME:嵌入式开发
J2EE:企业级开发,主要开发管理软件和Web应用。
Java的开发环境
JDK:Java开发的工具包
JRE:Java的开发环境
JVM:Java虚拟机
2、Java开发环境搭建
(1)下载并安装JDK,一路下一步,安装到默认路径;
(2)查看文件夹中是否有内容C:Program FilesJava,查看
(3)测试是否安装成功,开始键+R,调出运行框口,输入cmd打开DOS命令窗口,在DOS命令窗口中输入java,回车执行,如果有提示,则安装成功
(4)配置环境变量步骤:
第一步:复制路径C:Program FilesJavajdk1.8.0_92in
第二步:在计算机上点右键,打开“高级系统设置”,选择“高级”选项卡,点击右下角的“环境变量”;
第三步:在系统变量栏中找到“Path”变量,点击编辑;
第四步:在变量值中,末尾处填写:英文输入法的分号 ; ,然后把复制的bin目录路径粘贴,确定保存。
测试环境变量配置成功:调出DOS窗口,运行javac
3、编写第一个Java程序
(1) 在硬盘中新建一个文本文档;
(2) 在文档中编写Java代码,(所有的符号都是英文输入法下编辑的)
public class Hello{ public static void main(String[] args){ System.out.println("智递科技欢迎你!"); } } |
(3) 把文档名,重名为Hello.java
(4) 在此处运行DOS命令
执行:javac Hello.java ,自动创建Hello.class文件;
执行:java Hello ,程序执行,打印输出语句的内容;
注意事项:
(1) class后面的是类名,类名可以自定义,但是要和文件保持一致,使用英文来命名,类名首字母要大写;
(2) 大小写要区分;
(3) 符号要使用英文;
(4) 如果源代码更新,要重新编译(执行javac);
(5) 执行命令,javac编译生成.class文件;java是执行程序,执行的是生成后的.class 文件,不带扩展名;
(6) 在记事本中编辑;
4、Java的运行机制
(1) 通过javac命令,将.java的源代码文件编译为.class的字节码文件(.class字节码文件与操作系统无关,与JVM有关);
(2) 再使用java命令,通过Java虚拟机(JVM)将.class字节码文件解释为特定平台能够识别的机器码;
5、 Java源码书写规范
(1) 在java源文件中,只能有一个使用public修饰的类,源文件名称要和public修饰的类名保持一致;
如果源文件中没有public修饰的类,文件名可以自定义;
(2) 所有类名首字母应为大写(规范),并且类名不能以数字开头;
(3) 类名中只能使用下划线“_” 和美元 “$”,这两种符号;
(4) 在类的内部,还可以继续编写类,称其为内部类;内部类的访问权限与源文件名称无关;
(5) 一个类中只能有一个main方法(即程序的入口),书写的格式是固定;
(6) 在输出语句中,字符串用双引号修饰,如果要进行算术运算,可以直接写数字;
字符串与其他内容拼接时,使用 + 号,如果字符串后面直接跟+号,后面的所有+号默认都是拼接;
拼接的+号后面如果要进行算术运算,可以使用小括号;
(7) 在Java中可以声明变量,变量可以赋值
int 代表整数型,double代表小数型;
(8)Java中的注释:
在程序中对某行或某段代码作解释说明的文本内容,就称为注释。在Java中有三种注释方式:
a.使用 // 双斜杠注释,行内注释
b./*
注释的内容
*/ 多行注释
c.文档注释,使用文档注释的内容,可以生成本地的API文档。
源代码解释:
6、eclipse的使用
(1)选择工作空间
(2)操作窗口
(3)修改文本字体大小
(4)包的命名规范
在项目的src下写源码,类要放在包内,包名的命名规范为当前项目域名的倒置,例如:com.taobao.car
二、Java基础语法
1、标识符
(1)使用在类名、方法名、变量名等需要自定义并且与其他代码或代码块作识别的一种符号标识;
(2)标识符由:数字、字母、下划线“_”、美元$组成;
(3)首字符不能使用数字;
(4)不能使用Java关键字和保留字;
(5)对大小写敏感;
(6)类名的规范:首字母大写,多个单词组合的类名,每个单词的首字母都要大写;
(7)方法名的规范:使用驼峰式写法,多个单词组合的方法名,第一个单词全部小写,从第二单词开始首字母大写;
2、变量的概念
局部变量的存储机制
(1)语法
int a ; //声明变量a a = 1; //为变量a赋值,1 // int a = 1; //简写方式 |
语法规则:
- 先声明、再赋值;
- 没有声明的变量,不能直接赋值;声明后没有赋值的局部变量,不能直接使用;
- 局部变量
(2)变量类型
² 声明在方法体、代码块中的变量称为局部变量;
² 生命周期:从方法执行到该变量声明位置时创建,到方法结束时销毁;
² 只能被final修饰,变为常量;
² 局部变量没有默认值,在使用之前必须要赋值;
- 成员变量(实例变量)
² 声明在类中,在方法体和代码块之外;
² 成员变量有默认值,可以直接使用;
² 成员变量是属于每一个具体实例的(对象的),在类的外部使用时,要用对象来调用;
² 成员变量可以使用访问修饰符修饰,也可以使用非访问修饰符修饰(static、final);
² 通常把成员变量的访问权限设为私有的(private),通过公共的方法对其赋值和取值,这种形式称为封装;
- 类变量
² 使用static关键字修饰的成员变量,被称为类的变量;
² 类变量是属于类所有的,不属于某一个对象,被该类的所有对象共同拥有;
² 类变量既可以使用对象来调用,也可以使用类名来调用;
² 在同类中,类变量可以被静态方法直接调用;
3、基本数据类型
(1)整数型:byte、short、int(默认)、long
public class Test { public static void main(String[] args) { System.out.println("字节类型byte的取值范围:"); System.out.println("长度="+Byte.SIZE); System.out.println("最大值="+Byte.MAX_VALUE); System.out.println("最小值="+Byte.MIN_VALUE); System.out.println("短整型short的取值范围:"); System.out.println("长度="+Short.SIZE); System.out.println("最大值="+Short.MAX_VALUE); System.out.println("最小值="+Short.MIN_VALUE); System.out.println("整数型int的取值范围:"); System.out.println("长度="+Integer.SIZE); System.out.println("最大值="+Integer.MAX_VALUE); System.out.println("最小值="+Integer.MIN_VALUE); System.out.println("长整型long的取值范围:"); System.out.println("长度="+Long.SIZE); System.out.println("最大值="+Long.MAX_VALUE); System.out.println("最小值="+Long.MIN_VALUE); } } |
控制台输出:
字节类型byte的取值范围: 长度=8 最大值=127 最小值=-128 短整型short的取值范围: 长度=16 最大值=32767 最小值=-32768 整数型int的取值范围: 长度=32 最大值=2147483647 最小值=-2147483648 长整型long的取值范围: 长度=64 最大值=9223372036854775807 最小值=-9223372036854775808 |
整数型中的每种类型的取值范围:
Byte型:最大值27-1 ;最小值 -27
Short型:最大值 215-1;最小值 -215
Int型:最大值 231-1;最小值 -231
Long型:最大值 263-1;最小值 -263 ,当值大于int型时,值的末尾要加L
(2)浮点型:
单精度32位 float,默认值是0.0f,当值为整数型时,值的末尾不需要加 f ,当值为小数时,末尾要加 f ;
双精度64位 double(默认)
System.out.println("浮点型float的取值范围:"); System.out.println("长度="+Float.SIZE); System.out.println("最大值="+Float.MAX_VALUE); System.out.println("最小值="+Float.MIN_VALUE); System.out.println("浮点型double的取值范围:"); System.out.println("长度="+Double.SIZE); System.out.println("最大值="+Double.MAX_VALUE); System.out.println("最小值="+Double.MIN_VALUE); |
控制台输出:
浮点型float的取值范围: 长度=32 最大值=3.4028235E38 最小值=1.4E-45 浮点型double的取值范围: 长度=64 最大值=1.7976931348623157E308 最小值=4.9E-324 |
(3)字符型
表示单个字符的一种类型 char,在Java的底层,char类型默认是以int类型进行换算
最大值: ‘uffff’
最小值: ‘u0000’
public static void main(String[] args) { char a = 'A'-2; int b = 1+'a'; System.out.println(b); } |
(4) 逻辑型(布尔型)
布尔型boolean只表示一种结果,值为:true和false,默认值为false
public static void main(String[] args) { boolean b = false;// 假 boolean c = true;// 真 System.out.println(b); System.out.println(c); } |
4、类型转换
(1)强制类型转换(显式转换)
当大类型转小类型时,需要强制类型转换
public static void main(String[] args) { int a = 200; short b = 1; //大类型转小类型,会出现风险 b = (short)a; //赋值,把=号右边变量的值 赋给 =号左边的变量 System.out.println(b); } |
(2)自动类型转换(隐式转换)
当小类型转大类型时,不需要强制类型转换
byte b = 2; int a = 1; a = b; |
(3)int和char类型转换
int ==> char 需要强制类型转换,结果为char类型
int a = 70; char c = 'B'; c = (char) a; |
char ==> int 自动类型转换,因为char类型底层是以int进行换算的,结果为int类型
int a = 70; char c = 'B'; a = c; |
5、常量
在Java中声明一个不可改变的量,就叫常量,使用final关键字修饰;为了与变量区分,常量名通常要全部使用大写字母;
应用场景:π= 3.14
6、转义字符
7、运算符
(1)算术运算
(2)赋值运算
(3)比较运算
(4)逻辑运算
- &&(短路与)和 &(按位与),都可以作为逻辑运算符,表示“并且”,当两边的值都为true时,结果true,反之为false;
- ||(短路或)和 |(按位或),都可以作为逻辑运算符,表示“或者”,当两个的值有一个为true时,结果为true;
- !(非),结果为值取反;
- &(按位与) 和 |(按位或),除了可以作为逻辑运算符之外,还可以进行位运算;
- 在做位运算时,要先把进行运算的值转为二进制,然后再进行位运算;
&(按位与)运算时,两个值转为二进制,逐位比较,比较的两个值都为1,结果为1;
int a = 5; // 101 int b = 7; // 111 // 结果:101 |
|(按位或)运算时,两个值转为二进制,逐位比较,比较的两个值有一个为1,结果为1;
int a = 10; // 1010 int b = 3; // 0011 //结果:1011 |
当两个字符做位运算时,把字符对应的ASCII码表的十进制数转为二进制,再逐位比较;
char a = 'A'; // ASCII-->65 --> 1000001 char b = 'a'; // ASCII-->97 --> 1100001 // 结果:1100001 System.out.println(a | b); |
- ^(异或),是作位运算,两边的值先转为二进制,逐位比较,比较的两个值不相等时,结果为1,反之结果为0;
char a = 'A'; // ASCII-->65 --> 1000001 char b = 'a'; // ASCII-->97 --> 1100001 // 结果:0100000 System.out.println(a ^ b); |
&(按位与)和&&(短路与)的区别:
- 相同点是两个都可以作为逻辑运算符,两边都为true,结果为true;
- 不同点,按位与是两边都判断才计算结果,而短路与在判断第一个条件为false时,就直接计算结果,不再去判断第二个;
- 所以在判断字符串是否为空时,应使用短路与。
示例:
String s = null; if(s!=null && !s.equals("") ){ System.out.println(s); }else{ System.out.println("空"); } |
(5)三目运算
语法:
声明类型 变量名 = 条件 ? 为true的值 : 为false的值 ;
int week = 6; String s = (week>=1 && week <=5) ? "上班" : "打游戏" ; System.out.println(s); |
8、修饰符
Java提供的修饰符由两类:访问修饰符、非访问修饰符。
(1)访问修饰符
- 控制其他类对该类中的属性、方法调用的权限。
- 访问权限有4种,分别是:public(公共的)、protected(受保护的)、default(默认的)、private(私有的)。
- 访问修饰符有3个,分别是:public、protected、private,默认访问权限什么都不写。
- 访问修饰符可以修饰类、实例成员和类的成员;不能修饰局部变量;
- 类只有两种访问权限,分别是public和default;
- 非访问修饰符可以修饰类、属性、方法、代码块,与该类的访问权限无关,是为其修饰的元素增加附加的功能。
- 非访问修饰符有:static、final、abstract、synchronized 和 volatile。
- static 可以修饰成员方法、成员变量、代码块、内部类;当修饰成员方法和成员变量时,该方法和变量就变为了类的方法和类的变量;修饰代码块时,该代码块叫静态代码块,是优先于构造方法执行;
- final 可以修饰类、成员变量、局部变量、成员方法;当修饰变量时,该变量成为常量,必须要赋初始化值,值不能被修改,final修饰成员变量时通常和static配合使用;修饰类时,该类不能被继承;修饰方法时,不能被子类重写;
- abstract可以修饰类和成员方法,用来创建抽象类和抽象方法。
(2)非访问修饰符
三、流程控制
1、分支语句
(1)if-else 分支
语法:
if(判断条件){
满足条件要执行的代码语句;
}
String name = "小明"; int cont ;// 代表成绩的变量 cont = 90; if(cont >= 90 && cont <= 100){ System.out.println(name+"的成绩为:优"); } if(cont >= 80 && cont <90){ System.out.println(name+"的成绩为:良"); } if(cont >= 60 && cont <80){ System.out.println(name+"的成绩为:中"); } if(cont >= 0 && cont <60){ System.out.println(name+"的成绩为:差"); } |
升级版
String name = "小明"; int cont ;// 代表成绩的变量 cont = 90; if(cont >= 90 && cont <= 100){ System.out.println(name+"的成绩为:优"); }else if(cont >= 80 && cont <90){ System.out.println(name+"的成绩为:良"); }else if(cont >= 60 && cont <80){ System.out.println(name+"的成绩为:中"); }else if(cont >= 0 && cont <60){ System.out.println(name+"的成绩为:差"); }else{ System.out.println("输入有误"); } |
(2)switch语句分支
把一个变量与一系列的值进行对比,找到匹配的那一个,然后执行下面的代码,直到遇见break关键字才结束。
int week = 1; switch(week){ case 1: System.out.println("今天是周一"); break; case 2: System.out.println("今天是周二"); break; case 3: System.out.println("今天是周三"); break; case 4: System.out.println("今天是周四"); break; case 5: System.out.println("今天是周五"); break; case 6: System.out.println("今天是周六"); break; case 7: System.out.println("今天是周日"); break; default: System.out.println("输入有误"); } |
Switch使用规则:
a) case后面跟的值的类型,应该与要判断的变量类型保持一致;
b) case后面的值不能重复,并且必须为字面常量或者是常量;
c) switch(x),x的类型可以为:byte、short、int、char,在jdk1.7后,又扩展了String。
2、循环语句
(1)while循环
语法:
While(条件){
满足条件后执行的代码;
}
int a = 0; while(a<10){ a++;// a = a+1 System.out.println("hello:"+a); } |
int a = 0; boolean b = true; while(b){ a++;// a = a+1 System.out.println("hello:"+a); if(a == 5){ b = false; } } |
(2)do-while循环
语法:
do{
要执行的代码;
}while(条件);
与while循环的区别:
do-while当条件不满足时,至少也会被执行一次;
int a = 0; do{ a++;//变量的迭代 System.out.println("a="+a); }while(a<=0); |
(3)for循环
语法:
for(变量声明;条件子句;迭代){
满足条后执行的代码;
}
//变量声明、条件、迭代 for (int i = 1; i < 3;i++ ) { System.out.println("i="+i); } |
(4)跳出循环
- break:跳出当前的循环,继续执行循环下面的代码,可以使用在任何循环和switch语句中;
- continue:结束当前的本次循环,continue后面的代码不会被执行,继续下一次迭代循环;可以使用在任何的循环语句中;
- 跳出多重循环体,可以使用Java的标签,
标签名:(标签名是自定义的)
out: for (int i = 0; i <5;i++ ) { System.out.println("***i="+i+"*****"); for(int j=0; j< 5;j++){ if(j==3){ // break out;//跳出out标签后面的循环 continue out; } System.out.println("j="+j); } } |
四、数组
1、数组的概念
是一组相同类型的数的集合,数组也可以理解为是一个容器;
2、数组的声明
- 方法一
数据类型[] 数组名 = new 数据类型[长度];
// int[] arry = new int[11]; // arry[0] = 1; // arry[1] = 2; // arry[2] = 3; |
赋值和取值都是通过下标来完成
- 方法二
数据类型[] 数组名 = { 值1,值2,值3…… } ;
int[] arry = {1,2,3,4,5,6,7,8,9,10,20,30,40,50,55,60,90}; for(int i = 0 ; i < arry.length ; i++){ System.out.println(arry[i]); } |
取值,可以通过循环来取值
- 方法三
数据类型[] 数组名 = new 数据类型[]{值1,值2,……};
int[] arry = new int[]{1,2,3,4,5,6}; |
3、数组的赋值
a) 通过下标赋值
b) 通过声明方法二的形式,直接赋值
4、数组的遍历
通过循环的方式取得数组中的值,参考声明方法二
5、多维数组
int[] a = {1,2,3,4};//数组中的值的声明语句是int int[] b = {5,6,7,8,9,10}; int[] c = {9,10,11,12,13}; int[][] arry = {a,b,c};//int[] for(int i = 0 ; i < arry.length ; i++){ for(int j = 0 ; j < arry[i].length ; j++){ System.out.print(arry[i][j]+","); } System.out.println(); } |
6、增强for循环
语法:
for(数据类型 标识符 : 数组名){
}
int[] a = {3,1,7,5,4,9,2}; for(int i : a){ System.out.println(i); } |
7、数组排序
(1)冒泡排序
相邻的两个元素对比,交换数据,从后往前依次确定最大或最小值。
int[] a = {3,1,7,5,4,9,2}; for (int i = 1; i < a.length; i++) { for(int j = 0 ; j < a.length - i ; j++){ if(a[j] < a[j+1]){ int temp = a[j]; a[j] = a[j+1]; a[j+1] = temp; } } } System.out.println("排序后:"); for (int i : a) { System.out.print(i+" "); } |
(2)选择排序
第一元素和后面的元素依次对比,交换数据,从前往后依次确定最大或最小值。
int[] a = {3,1,7,5,4,9,2}; for (int i = 0; i < a.length-1; i++) { for(int j = i+1 ; j < a.length; j++){ if(a[i] < a[j]){ int temp = a[i]; a[i] = a[j]; a[j] = temp; } } } System.out.println("排序后:"); for (int i : a) { System.out.print(i+" "); } |
五、面向对象
1、面向对象的概念
对象是指一切客观存在的可见事物和一切不可见事物;
面向对象就是把客观事物在计算机中去创建模型的思想;
对象是由属性和行为组成的;
类就是对象在计算机中的模型;
使用成员变量来表示数据模型(成员属性);
语法:访问修饰 数据类型 属性名
//成员属性-->数据模型 public String name; public String gender; public int age ; |
使用成员方法来表示行为模型;
语法:
访问修饰符 返回值类型(void) 方法名(参数列表){
要执行的代码;
}
//成员方法-->行为模型 // 无参无返回值方法 public void eat(){ System.out.println("吃饭……"); } |
2、类的使用
(1)创建对象(实例化对象)
语法:
类名 对象名 = new 构造器();
//创建对象 Person xw = new Person();//构造器 |
(2)对象赋值
语法:
对象名.属性名;
//创建对象 Person xw = new Person();//构造器 xw.age = 20; xw.name = "小王"; xw.gender = "男"; |
(3)方法调用
语法:
对象名.方法名();
Person p1 = new Person(); p1.name = "张三"; p1.age = 22; p1.gender = "女"; p1.eat(); |
(4)方法参数和返回值
Person类:
public class Person { public String name; public String gender; public double weight; public String jianfei(int i){ return name+"是个"+gender+"胖子体重"+weight+"kg。某天他开始减肥," + "经过不懈努力,减了"+i+"kg。减肥后的体重是"+(weight-i)+"kg。"; } } |
Test类:
Person p1 = new Person(); p1.name = "小王"; p1.gender = "男"; p1.weight = 200; String s = p1.jianfei(40); System.out.println(s); |
3、成员变量和局部变量
区别:
- 成员变量声明在类中,局部变量声明在方法体或代码块内;
- 成员变量作用域在整个类中,局部变量作用在当前的方法体或代码块内;
- 成员变量有初识化值,局部变量没有初始化值,不赋值不能直接使用;
- 当成员变量和局部变量重名的时候,如果直接使用变量名,默认使用的是局部变量,要想使用成员变量,可以加上this关键字;
4、方法重载
原则:
(1) 在同一个类中,声明多个同名的方法;
(2) 方法名相同,参数列表不同,与返回值无关;
(3) 参数列表的个数,类型,类型的顺序不相同;
public class Test { //方法重载 public void a(int j,double i){ } public void a(){ } public void a(double j,int i){ } public void a(int i){ } public static void main(String[] args) { Test t = new Test(); t.a(1); } } |
5、构造方法
构造方法是一个特殊的方法,只有在实例化对象时才会被调用。
语法:
访问修饰符 类名(参数列表){
}
当一个类中没有显式的构造方法,程序在执行的时候会自动创建一个公开的无参的构造方法;
如果类中有一个显式的构造方法,程序在执行时,就不会自动创建公开的无参构造方法;
作用:一般是用于对类中成员变量的赋初始化值;
public class Person { public String name; public int age; //通过构造方法的形式为成员变量赋初始化值 public Person(String name,int age){ this.name = name; this.age = age; } public Person(){ } } |
public static void main(String[] args) { Person p1 = new Person("小明",20); Person p2 = new Person("小王",10); Person p3 = new Person("小李",22); System.out.println(p1.name); System.out.println(p2.name); System.out.println(p3.name); } |
6、this关键字
用法:
(1)是指当前对象;
(2)当局部变量与成员变量名称冲突时,使用this关键字来表示成员变量;
(3)在构造方法中可以调用另一个构造方法,使用this(参数列表)来表示调用构造方法;
public class Person { public String name; public int age; public Person(){ this(1); } public Person(int a){ // this(); this.age = a; } } |
7、static关键字
用法:
(1)static可以直接修饰,成员变量、成员方法、代码块;
(2)使用static关键字修饰的成员变量、成员方法被称为类的变量和类的方法;没有使用static关键字修饰的成员变量、成员方法被称为实例变量和实例方法;
(3)静态成员可以直接调用静态成员,如果调用实例成员,必须要先实例化对象,用具体的对象调用实例成员;
实例成员可以直接调用静态成员和实例成员;
Person类
public class Person { public static String name;//类的 public int age;//实例的,具体对象的 } |
Test类
public void print(){ Person.name = ""; Person p = new Person(); p.age = 1; } |
(4)静态成员是属于类的,所有该类的对象共享静态成员的数据;
Account类
public class Account { public String name; public static double balance; public void qu(double b){ balance -= b; System.out.println(name+"取了"+b+"元,当前余额"+balance+"元"); } public void cun(double b){ balance += b; System.out.println(name+"存了"+b+"元,当前余额"+balance+"元"); } public void print(){ System.out.println(name+"查看,当前余额为"+balance+"元"); } } |
Test类
public static void main(String[] args) { Account wy = new Account(); wy.name = "网银"; Account zfb = new Account(); zfb.name = "支付宝"; Account wx = new Account(); wx.name = "微信"; wy.cun(100); zfb.cun(200); wx.cun(100); wx.qu(300); wy.print(); zfb.print(); wx.print(); } |
(5)static修饰代码块时,该代码块为静态代码块,在类加载的时候先执行,如果有多个静态代码块,按照先后顺序依次执行;一般用于初始化成员变量;
8、访问修饰符
访问修饰符 |
同类 |
同包 |
同包子类 |
不同包 |
不同包子类 |
public |
√ |
√ |
√ |
√ |
√ |
protected |
√ |
√ |
√ |
× |
× |
默认的 |
√ |
√ |
√ |
× |
× |
private |
√ |
× |
× |
× |
× |
9、封装
对属性的封装,私有(private)的属性,公开(public)的方法(getter & setter)
Account类
public class Account { private String id; private String name; private String pwd; private double balance; public void setBalance(double balance){ this.balance = balance; } public double getBalance(){ return balance; } } |
Test类
public static void main(String[] args) { Account a = new Account(); a.setBalance(-20); double d= a.getBalance(); System.out.println(d); } |
10、继承
(1)概念
当多个类中具有相同的属性和行为时,可以把这些相同的元素抽取到一个类中,多个类继承这一个类,就具有了这些元素;
(2)子类的语法
[访问修饰符] class 子类的类名 extends 父类的类名{
}
子类可以继承父类所有非私有的属性和方法;
当父类的方法无法满足子类的需求时,子类可以重写父类的方法;
(3)重写的规则
- 子类重写方法的访问修饰符必须大于等于父类方法的访问权限;
- 声明名部分必须和父类的方法保持一致(返回值,方法名,参数列表);
- 子类继承父类的方法,子类对象调用该方法时,执行的是父类的方法;
- 子类重写父类的方法,子类对象调用该方法时,执行的是子类重写后的方法;
- 子类重写方法抛出的异常范围不能大于父类;
- 在执行子类的构造方法之前,先执行父类的构造方法;
- super()指父类的构造方法,super(参数列表)是指父类的有参构造方法;在子类中如果没有显式的super(),程序执行时会默认创建;
- super()必须在子类的构造方法中第一行执行;
- 在父类中的this关键字,指的是子类的对象;父类中this()指的是当前类的无参构造方法;
- 子类不能继承父类的构造方法;
- 当存在多重继承关系时,先执行最高级别的父类,然后在依次向下执行;
- 在Java中的继承关系是单继承,一个子类只能有一个父类,但是父类可以有多个子类;
- 当父类的属性为子类和父类共同享有时,无论在哪个类中super.属性,this.属性,都是指父类中的那个属性;
(4)子类创建的流程
如果父类和子类具有相同名称的属性,this.属性是指当前类的属性,super.属性是指父类的属性;
11、多态
实现多态的前提:
(1) 具有继承关系;
(2) 子类重写父类方法;
(3) 父类的引用指向子类的对象
语法:
父类类名 引用名 = new 子类构造器();
情景一:
Animal cat = new Cat(); Cat c = (Cat) cat;//cat对象是 Cat类的实例,程序不会出现异常 c.eat(); |
情景二:
Animal cat = new Cat(); Dog d = (Dog) cat;//cat对象不是Dog类的实例,会出现类型转换异常 d.eat(); |
异常信息:
Exception in thread "main" java.lang.ClassCastException: com.zhidi.zoo.Dog cannot be cast to com.zhidi.zoo.Cat |
在对象之间做强制类型转换时,我们要先判断要强转的对象是否为某一类的实例,可以使用instanceof关键字做验证。
示例:
//父类的引用cat,指向子类的对象 cat --> 猫对象 Animal cat = new Cat(); //cat对象如果是Dog类的实例,则返回true,反之返回false if(cat instanceof Dog){ Cat c = (Cat) cat; c.eat(); }else{ System.out.println("类型不匹配"); } |
12、抽象类
(1)概念
- 没有具体的功能,没有方法体的方法就是抽象方法;
- 包含抽象方法的类,一定是抽象类,使用abstract关键字修饰;
- 抽象类和普通类类似,只是多了抽象方法而已;
- 抽象类不能被实例化对象,只能被继承;
- 继承抽象类的子类必须重写抽象类中的所有抽象方法;
- 抽象类可以用于声明;
- 抽象类也可以继承于其他类,成为子类;
(2)语法
抽象方法:
[访问修饰符] abstract 返回值类型 方法名([参数列表]) ;
抽象类:
[访问修饰符] abstract class 类名 [extends 父类]{
}
13、接口
(1)概念
- 接口是定义程序开发中的规范,是更加抽象的抽象类;
- 声明接口是使用interface关键字;
- 接口中只能声明常量和抽象方法,可以省略abstract关键字;
- 接口不能被实例化,只能被类实现,使用implements来实现接口;一个类可以同时实现多个接口;
- 一个接口可以继承另一个或多个接口,成为子接口;
- 接口也是可以被声明为变量的;
(2)语法
[访问修饰符] interface 接口名 [extends 父接口1,父接口2,……] {
[常量];
[抽象方法];
}
14、内部类
(1)成员内部类
声明在类的内部,和外部类的成员属性、成员方法属于同一级别;
public class Outer { //成员属性 public int i = 1; //成员方法 public void print(){ } //成员内部类 public class Inner{ public int i = 2; public void abc(){ System.out.println(Outer.this.i);//指外部类的成员属性i System.out.println(this.i);//指内部类的成员属性i } } } |
实例化内部类:
public static void main(String[] args) { Outer o = new Outer(); Outer.Inner in = o.new Inner();//实例化内部类的对象 in.abc(); } |
(2)静态内部类
声明在类的内部,使用static关键字修饰的类,叫静态内部类。
public class Outer { //静态属性属于类的 public static int i = 0; public int j = 2; //静态方法,是属于类的 public static void print(){ } //静态员内部类 public static class Inner{ public int i = 1; public void abc(){ System.out.println(i);//调用静态内部中的属性 System.out.println(Outer.i);//调用外部类的静态属性 Outer o = new Outer();//调用外部类的非静态属性 System.out.println(o.j); } } } |
实例化静态内部类:
public static void main(String[] args) { Outer.Inner in = new Outer.Inner(); in.abc(); } |
(3)局部内部类
声明在外部类的成员方法或代码块中的类,称为局部内部类,其作用域范围只存在于所处的方法内部,所以只能在其所处的方法中实例化对象。
public class Outer { //成员属性 public int i = 1; //成员方法 public void print(){ int j = 2;//局部变量 //局部内部类 class Inner{ public int i = 3; public void abc(){ System.out.println(i);//指局部内部类Inner的成员属性 System.out.println(Outer.this.i);//指外部类Outer的成员属性 System.out.println(j);//指外部类Outer的print()中的局部变量 } } Inner in = new Inner();//实例化局部内部类对象 in.abc(); } } |
执行局部内部类的方法:
public static void main(String[] args) { Outer o = new Outer(); o.print(); } |
(4)匿名内部类
匿名内部类的声明方式和局部内部类相同,匿名内部类没有类名,实现匿名内部类的前提:必须要继承一个类或实现一个接口,二者选一。
语法:
new 父类构造器(){
重写父类后的方法;
};
示例:
抽象类Person:
public abstract class Person { public abstract void eat(); } |
匿名内部类:
Person p = new Person(){ @Override public void eat() { System.out.println("吃饭"); } }; p.eat(); |
以上代码,等同于以下代码:
抽象类Person:
public abstract class Person { public abstract void eat(); } |
Man类继承Person:
public class Man extends Person { @Override public void eat() { System.out.println("吃饭"); } } |
测试类:
Person p = new Man(); p.eat(); |
匿名内部类的用途:
一般是用于实例化抽象类和接口的对象。
六、Java常用类库
1、Object类
(1)toString()方法
Student类:
public class Student { public String name; public int age; public char gender; public Student(String name, int age, char gender) { super(); this.name = name; this.age = age; this.gender = gender; } public Student() { } } |
测试类:
Student s1 = new Student(); s1.name = "张三"; //直接输出对象名,是默认调用的Object类的toString()方法 System.out.println(s1); System.out.println(s1.toString()); //toString()方法返回值的获得详解 String name = s1.getClass().getName();//获得类的全路径; String haxi = Integer.toHexString(s1.hashCode());//得到对象的16进制表示的哈希值 String toString = name+"@"+haxi;//对象的内存地址:对象的全路径 + @ + 16进制哈希值 System.out.println(toString); |
(2)equals()方法
重写Object类的equals()方法,可以对比两个对象内部的属性,通过对比属性来判断两个对象是否表示同一个事物。
2、字符串操作
(1)String类
- 构造方法:
² String(char[] value) 把char[]数组转为字符串类型
² String(String str)
- 常用方法:
² charAt(int index) 根据下标(index)返回对应的字符
² contains(CharSequence c) 判断字符串中是否包含指定内容
² endsWith(String s) 判断是否以指定内容结束
² startsWith(String s) 判断是否以指定内容开始
² length() 返回字符串的长度(以字符为单位)
² toString() 返回此字符串
² equals(Object obj) 对比两个字符串内容是否相等
² getBytes() 把字符串转为字节数组
² indexOf() 返回指定字符或字符串第一次出现的位置
² lastIndexOf() 返回指定字符或字符串最后一次出现的位置
² replace() 替换指定字符,返回新的字符串
² split() 按照指定的内容截取字符串,返回字符串数组
² subString() 按照下标截取字符串,返回子字符串
² toCharArray() 把字符串转为字符数组
² toLowerCase() 把字符串中的大写转为小写
² toUpperCase() 把字符串中的小写转为大写
² trim() 清除字符串前后的空格
² valueOf() 把指定内容转为字符串
(2)StringBuffer/StringBuilder类
以StringBuffer为例:
- 常用方法:
² append() 追加
² delete(int start,int end) 删除,包含开始下标,不包含结束下标
² insert(int index,Object obj) 插入,插入到第index的下标位置,obj是插入内容
(3)String、StringBuffer和StringBuilder的区别
- String对象可以指向字面常量,字面常量是存储在常量池中,一旦创建内容不可修改;
- StringBuffer和StringBuilder是以对象的形式创建,创建的字符串是可以修改的;
- StringBuffer是线程安全的,StringBuilder是线程不安全的,StringBuilder的存储速度比StringBuffer要快;
3、基本数据类型的包装类
Character:
char c = 'A'; Character ch = new Character(c);//封箱 Character ch1 = Character.valueOf(c);//封箱 System.out.println("是否为数字:"+Character.isDigit(c)); System.out.println("是否为非数字和标点:"+Character.isLetter(c)); System.out.println("是否为空格:"+Character.isWhitespace(c)); System.out.println("是否为大写字母:"+Character.isUpperCase(c)); System.out.println("是否为小写字母:"+Character.isLowerCase(c)); System.out.println("转为大写:"+Character.toUpperCase(c)); System.out.println("转为小写:"+Character.toLowerCase(c)); |
4、Date类
// long time = System.currentTimeMillis(); long time = 1488935537022L; long time2 = 1488935537023L; Date d = new Date(time); Date d2 = new Date(time2); System.out.println(d.before(d2)); |
补充:
//获得时区对象 TimeZone tz = TimeZone.getDefault(); //获得所有时区ID String[] str = TimeZone.getAvailableIDs(); for (String id : str) { //根据时区id来获得此TimeZone对象 TimeZone zone = TimeZone.getTimeZone(id); System.out.println(id+"--->"+zone.getDisplayName()); } //设置时区 TimeZone timzone = TimeZone.getTimeZone("Africa/Abidjan");//获得格林威治时区对象 TimeZone.setDefault(timzone); long time = 0; Date date = new Date(time); System.out.println(date); |
5、日期格式化
long time = 0L; Date d = new Date(time); //按照给定的模式,格式化时间对象 SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); String date = sdf.format(d); System.out.println(date); //获得当前时间 System.out.println(sdf.format(new Date())); |
6、Calendar类
//获得日历对象 Calendar c = Calendar.getInstance(); // c.set(2017, 3, 8,12,20,30);//设置时间,如果没有设置时间,默认为当前时间 //添加时间 // c.add(Calendar.MONTH, 100);//如果往后推算,用正数,往前推算用负数 // c.add(Calendar.HOUR_OF_DAY, 20); System.out.println("年:"+c.get(Calendar.YEAR));//年 System.out.println("月:"+(c.get(Calendar.MONTH)+1));//月,从0开始计算 System.out.println("日:"+c.get(Calendar.DAY_OF_MONTH));//日 System.out.println("时:"+c.get(Calendar.HOUR_OF_DAY));//时 System.out.println("分:"+c.get(Calendar.MINUTE));//分 System.out.println("秒:"+c.get(Calendar.SECOND));//秒 System.out.println("星期:"+(c.get(Calendar.DAY_OF_WEEK)-1));//星期(这周的第几天,从周日开始算为第1天) //把日历对象转为Date对象 Date date = c.getTime(); //格式化Date对象 SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日E HH:mm:ss"); System.out.println(sdf.format(date)); |
获得字段的最大/最小值:
//返回指定字段的最大值 int i = c.getActualMaximum(Calendar.DAY_OF_YEAR); //返回指定字段的最小值 int j = c.getActualMinimum(Calendar.DAY_OF_YEAR); |
格里高利日历对象:
//获得日历对象 Calendar cal = Calendar.getInstance(); //设置指定日历字段的具体值 cal.set(Calendar.YEAR, 2020); //Calendar类中表示年份的字段 int yearField = Calendar.YEAR; //获得当前日历对象中的年份数据 int year = cal.get(yearField); //实例化格里高利日历对象 GregorianCalendar gc = new GregorianCalendar(); //判断Calendar日历对象中的年份是否为闰年 boolean b = gc.isLeapYear(year); if(b){ System.out.println(year+"年是闰年"); }else{ System.out.println(year+"年是平年"); } |
7 、日期解析
//获得一个具体时间 Scanner sc = new Scanner(System.in); System.out.println("请输入一个日期:"); String str = sc.nextLine(); //按照获取的时间格式来设定解析模式 SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); //解析时间字符串 Date d = sdf.parse(str); System.out.println(d); |
8、正则表达式
正则符号:
含义 |
符号 |
数字 |
[0-9] \d |
字母 |
[a-zA-Z] |
空白字符 |
[ fx0B] |
表示非 |
[^规则] |
任意字符(换行除外) |
. (点) |
正则开始 |
^ |
正则结束 |
$ |
正则数量:
符号 |
含义 |
+ |
n≥1 1到多个 |
* |
n≥0 0到多个 |
? |
0≤ n ≤1 0或1个 |
{n} |
n个 |
{n,} |
n ≤ n到多个 |
{n,m} |
n≤ num ≤m n到m个 |
正则逻辑:
含义 |
符号 |
分组 |
() |
或 |
| |
且 |
什么都不写 |
示例1:
//要验证的字符串 String str = "abc123ABC"; //[]内放的是匹配的规则 boolean b = str.matches("^[a-zA-Z0-9]{6,8}$"); if(b){ System.out.println("匹配"); }else{ System.out.println("不匹配"); } |
示例2:
String str = "abc12bA"; //必须是包含大写、小写、数字,必须以大写字母开头,6-8位 //boolean b = str.matches("^([A-Z])(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{5,7}$"); //必须是包含大写、小写、数字,6-8位 boolean b = str.matches("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{6,8}$"); if(b){ System.out.println("匹配"); }else{ System.out.println("不匹配"); } |
七、异常处理
1、异常的层级关系
2、常见异常类
(1)ArithmeticException 算术异常
int i,j; i = 1; j = 0; System.out.println(i/j); |
(2)NullPointerException 空指针异常
String s = null; System.out.println(s.toString()); |
(3)ArrayIndexOutOfBoundsException 数组下标越界异常
int[] arr = new int[5]; System.out.println(arr[-5]); |
(4)StringIndexOutOfBoundsException 字符串下标越界异常
String s = "hello"; char c = s.charAt(6); System.out.println(c); |
(5)InputMismatchException 输入不匹配异常
Scanner sc = new Scanner(System.in); int i = sc.nextInt(); System.out.println(i); |
(6)ParseException 解析时异常
Scanner sc = new Scanner(System.in); System.out.println("请输入一个日期:"); String date = sc.nextLine(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); Date date2 = sdf.parse(date); System.out.println(date2); |
(7)ClassCastException 类型转换异常
//父类的引用指向子类的对象,o执行的是Integer对象 Object o = new Integer(1); //可以强转为int类型 // int i = (int) o; //不能再强转为String类型 String s = (String) o; System.out.println(s); |
3、异常处理的方式
(1)使用try-catch-fiannly 语句捕获异常
int i,j; i = 1; j = 0; try{//可能会出现问题的代码 System.out.println(i/j); String s = null; System.out.println(s.toString()); Object o = new Integer(1); String str = (String) o; System.out.println(str); }catch(ArithmeticException e){//捕获相关问题 //解决异常的代码 e.printStackTrace();//打印追踪异常信息 }catch(NullPointerException e){ //解决异常的代码 }catch(Exception e){ //解决异常的代码 }finally{ //无论是否出现异常,finally语句块始终会被执行 } System.out.println("程序结束"); |
注意:当有多个catch语句块时,捕获异常的顺序应该为由小到大,子类异常在前,父类异常在后
(2)使用throws抛出异常
语法:
[访问修饰符] 返回值类型 方法名(参数列表) throws 异常类{
//执行的代码
//存在异常情况的代码语句
}
public static void main(String[] args) { Test t = new Test(); int i = t.abc(1, 0); System.out.println(i); System.out.println("main方法结束"); } //除法运算 public int abc(int cs,int bcs) throws ArithmeticException{ if(bcs == 0){ throw new ArithmeticException("b除数不能为0"); } int rel = cs / bcs; System.out.println("abc方法结束"); return rel; } |
4、自定义异常类
语法:
[访问修饰符] class 类名 extends 异常父类(Exception){
}
public class SuanShuException extends Exception { public SuanShuException(String mess) { super(mess); } } |
使用:
public static void main(String[] args) throws SuanShuException { Test t = new Test(); int i = t.abc(1, 0); System.out.println(i); System.out.println("main方法结束"); } //除法运算 public int abc(int cs,int bcs) throws SuanShuException{ if(bcs == 0){ throw new SuanShuException("b除数不能为0"); } int rel = cs / bcs; System.out.println("abc方法结束"); return rel; } |
八、集合
1、序列ArrayList类
规则:声明时无需定义长度,使用get()方法通过下标取值,是有顺序的。
常用方法:
(1) add(Object obj) 添加,可以添加任意对象类型
(2) addAll(Collection<E> c) 添加集合
(3) get(int index) 根据下标获取对应的值
(4) size() 获得序列的长度
(5) set(int index,Object obj) 修改序列中指定下标的内容,返回被修改的对象
(6) clear() 清除序列中所有的数据
(7) remove(int index) 根据下标删除对应数据
(8) remove(Object obj) 根据对象删除对应数据,返回boolean类型,删除成功返回true,反之为false
(9) iterator() 迭代器,遍历集合,返回Iterator<E>类型
(10) contains(Object obj) 判断集合中是否包含某对象,判断的是地址
添加方法:
ArrayList list = new ArrayList();//序列 //增 list.add(1); list.add(2); list.add(3); list.add(0,4); //把4添加到下标为0的位置 |
Student s1 = new Student("张三",20); Student s2 = new Student("李四",22); Student s3 = new Student("王五",23); //泛型,规定集合中只能存放哪种类型的元素 List<Student> list = new ArrayList<Student>();//使用多态 //增 list.add(s1); list.add(s2); list.add(s3); Student s4 = new Student("Tom",20); Student s5 = new Student("Jack",22); Student s6 = new Student("Lily",23); Student[] arry = {s4,s5,s6}; // List<Student> list2 = new ArrayList<Student>(); // list2.add(s4); // list2.add(s5); // list2.add(s6); //把数组转为集合,添加到list中 list.addAll(Arrays.asList(arry)); |
修改方法:
Student s4 = new Student("小明",22); Object obj = list.set(3, s4); //修改成功,返回被修改的对象 |
删除方法:
// list.clear(); // list.remove(3); //根据下标删除 boolean b = list.remove(s2); //根据对象删除,删除成功返回true |
查询方法:
for (Object obj : list) { System.out.println(obj); } |
for (int i = 0; i < list.size(); i++) { Integer index = (Integer) list.get(i); System.out.println(index); } |
使用迭代器遍历:
Student s1 = new Student("张三",20); Student s2 = new Student("李四",22); Student s3 = new Student("王五",23); //泛型,规定集合中只能存放哪种类型的元素 List<Student> list = new ArrayList<Student>();//使用多态 //增 list.add(s1); list.add(s2); list.add(s3); //使用迭代器查询 Iterator<Student> it = list.iterator(); while(it.hasNext()){ Student stu = it.next(); System.out.println(stu.getName()); } |
集合与数组的转换:
//数组转为集合 List<Student> stuList = Arrays.asList(arry); //把集合转为数组 Object[] stuArry = list.toArray(); for (Object obj : stuArry) { if(obj instanceof Student){ Student s = (Student) obj; System.out.println(s.getName()); } } |
2、set集中HashSet类
概念:set集是无序的,不可重复的。
常用方法:
(1) add(Object obj) 添加对象
(2) addAll(Collection<E> c) 添加集合
(3) contains(Object obj) 判断集合中是否存在某对象
(4) isEmpty() 判断集合中是否有元素
(5) iterator() 使用迭代器遍历集合
(6) remove(Object obj) 删除指定对象
(7) size() 返回集合的长度
添加方法:
Student s1 = new Student("张三",20); Student s2 = new Student("李四",22); Student s3 = new Student("王五",23); Set<Student> set = new HashSet<Student>(); //添加方法 set.add(s1); set.add(s2); set.add(s3); |
Student s4 = new Student("Tom",20); Student s5 = new Student("Jack",22); Student s6 = new Student("Lily",23); // List<Student> list = new ArrayList<Student>(); // list.add(s4); // list.add(s5); // list.add(s6); // Student[] arry = {s4,s5,s6}; // List<Student> list = Arrays.asList(arry); Set<Student> stuSet = new HashSet<Student>(); stuSet.add(s4); stuSet.add(s5); stuSet.add(s6); set.addAll(stuSet); |
修改方法:
//间接修改集合元素 //先遍历集合中所有元素 for (Student stu : stuSet) { //判断查询的对象中是否包含名字为“Tom”的学生 if(stu.getName().equals("Tom")){ //如果存在该学生,将其删除 boolean b = set.remove(stu); if(b){ //删除成功,添加新对象 set.add(new Student("HanMeimei",20)); } } } |
删除方法:
//根据对象的属性删除指定元素 Iterator<Student> it = set.iterator(); while(it.hasNext()){//遍历所有元素 Student stu = it.next(); if(stu.getName().equals("张三")){//判断指定的学生对象 it.remove();//调用Iterator对象的remove()方法删除 } } //清除集合中所有元素 set.clear(); //删除集合中指定元素 set.remove(obj); |
查询方法:
//使用foreach查询 for (Student stu : set) { System.out.println(stu.getName()); } //使用迭代器查询 Iterator<Student> it = set.iterator(); while(it.hasNext()){ Student stu = it.next(); System.out.println(stu.getName()); } |
3、Collection接口思维导图
4、集合排序
Collections.sort(list);//升序 Collections.reverse(list);//倒置 Collections.shuffle(list);//随机排 |
5、Map映射
Map是以键值对的形式存在的,语法:Map<Key,Value>,键是不可重复,值可以重复,即一个键对应一个值,每个值可以有多个键。
常用方法:
(1) put(Object key,Object value) 添加方法
(2) putAll(Map<K,V> m) 添加map集合
(3) get(Object key) 通过键查询对应值
(4) size() 返回map集合中元素的个数
(5) remove(Object key) 通过键删除元素,返回被删除元素的值
(6) clear() 清空所有元素
(7) keySet() 返回所有键的集合
(8) entrySet() 返回所有键值对映射项的集合,使用Entry对象中的getKey()和getValue()方法分别获得键和值
(9) containsKey(Object key) 判断map集合中是否包含某个键
(10) containsValue(Object value) 判断map集合中是否包含某个值
(11) values() 返回map集合中值的Collection集合
(12) isEmpty() 判断map集合中是否存在映射项,没有返回true
添加方法:
Map<Integer,String> map = new HashMap<Integer,String>(); //添加 map.put(1, "张三"); map.put(2, "李四"); map.put(3, "王五"); map.put(4, "赵六"); //通过键查询对应的值 String s = map.get(1); System.out.println(s); |
修改方法:
String s1 = map.put(1, "张三"); System.out.println(s1); //s1 = null,因为这是第一次添加 String str = map.put(1,"Tom"); System.out.println(str); //str = “张三”,返回本次修改前的值 String str2 = map.put(1,"Jack"); System.out.println(str2); //str2 = “Tom” |
删除方法:
//清空所有元素 map.clear(); //根据键删除元素 String s = map.remove(1);//返回的是被删除元素的值 |
通过值删除元素:
Map<String,String> map2 = new HashMap<String,String>(); map2.put("校长", "Tom"); map2.put("主任", "Tom"); map2.put("老师", "Lily"); map2.put("副校长", "Tom"); System.out.println("删除前map的长度:"+map2.size()); Set<String> set = map2.keySet(); Set<String> temp = new HashSet<String>();//存要删除的键 for (String s : set) { String name = map2.get(s);//根据键获得值 if(name.equals("Tom")){//判断值是否满足条件 temp.add(s);//把该值映射的键存到临时的集合中 } } System.out.println("要删除元素的个数:"+temp.size()); //通过键删除map集合中的元素 for (String key : temp) { String v = map2.remove(key); System.out.println(v+"被删除了"); } System.out.println("删除后map的长度:"+map2.size()); |
查询方法:
//查询所有元素 Set<Integer> set = map.keySet();//把所有的键以set集合形式返回 for (Integer i : set) { String str = map.get(i); System.out.println(i+":"+str); } //把map集合中的键值对项作为对象,以set集合来存储这些键值对项 Set<Entry<Integer,String>> set = map.entrySet(); for (Entry<Integer, String> entry : set) { System.out.println(entry.getKey()+":"+entry.getValue()); } |
6、集合中对象的排序
步骤:
(1) 实体类要实现Comparable<T>接口,并重写compareTo()方法
(2) 实例化对象存到List集合,调用Collections.sort(list)方法进行排序
示例:
Student类
public class Student implements Comparable<Student> { private String name; private String className; private Double cj; //基本数据类型要用封装类的对象才可以使用compareTo()方法排序 @Override public int compareTo(Student o) { return cj.compareTo(o.cj); } } |
Test类
List<Student> list = new ArrayList<Student>(); list.add(new Student("Tom","java",90)); list.add(new Student("Jack","php",91)); list.add(new Student("Lilei","css",92)); list.add(new Student("Luch","html",80)); Collections.sort(list); |
九、IO流
1、File类
常用方法:
(1) createNewFile() 创建文件
(2) mkdir() 创建目录
(3) mkdirs() 创建多级目录
示例:
File f = new File("F:\abc\a"); boolean b = f.createNewFile();//创建文件 boolean b = f.mkdir();//创建目录 boolean b = f.mkdirs();//创建多级目录 System.out.println(b); |
File f = new File("F:\demo.txt"); if(!f.exists()){ boolean b = f.createNewFile(); if(b){ System.out.println("文件创建成功"); } }else{ System.out.println("文件已存在"); boolean b = f.delete(); if(b){ System.out.println("文件被删除"); } } |
2、RandomAccessFile类
输入流:数据从硬盘流向内存,read
输出流:数据从内存流向硬盘,write
示例:
File f1 = new File("E:\11.mp4"); File f2 = new File("F:\22.mp4"); RandomAccessFile r1 = new RandomAccessFile(f1, "rw"); RandomAccessFile r2 = new RandomAccessFile(f2, "rw"); int i;//用来存储读取的每一个字节 while((i=r1.read()) != -1){//从f1文件对象读取1个字节,把该字节赋值给变量i r2.write(i);//把f1对象读到1个字节写到f2文件对象 } //关闭资源 r1.close(); r2.close(); |
3、IO流
(1)字节流
- 字节输入流:InputStream,所有字节输入流的父类
² 子类:FileInputStream
// File f = new File("F:\abc.txt"); FileInputStream fis = new FileInputStream("F:\abc.txt"); byte[] b = new byte[1024];//每次读取1024个字节 int len; while((len = fis.read(b)) != -1){ //解码byte数组从下标0开始,到读取字节数减1的位置 String s = new String(b,0,len); System.out.println(s); } //关闭资源 fis.close(); |
- 字节输出流:OutputStream,所有字节输出流的父类
² 子类:FileOutputStream
FileOutputStream fos = new FileOutputStream("F:\demo.txt"); String s = "abcdefg"; fos.write(s.getBytes()); fos.close(); |
示例:
FileInputStream fis = new FileInputStream("E:\11.mp4"); FileOutputStream fos = new FileOutputStream("F:\11.mp4"); byte[] b = new byte[1024];//每次读的字节数 int i; while( (i=fis.read(b)) != -1){ fos.write(b); } //关闭资源 fis.close(); fos.close(); |
(2)序列化和反序列化(对象流)
在做序列化之前,实体类要先实现Serializable接口。
先序列化(保存对象文件),再做反序列化(读取对象文件)。
Student类:
public class Student implements Serializable{ public String name; public int age; public String gender; public Student() { } public Student(String name, int age, String gender) { super(); this.name = name; this.age = age; this.gender = gender; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + ", gender=" + gender + "]"; } } |
序列化:
//要序列化的对象,可以是数组、集合、实体对象 Student[] stu = {new Student("张三",20,"男"),new Student("李四",22,"男"),new Student("王五",26,"男"),new Student("赵六",20,"男")}; List<Student> list = Arrays.asList(stu); FileOutputStream fos = new FileOutputStream("F:\stu.cctv"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(list); //关闭资源 oos.close(); fos.close(); |
反序列化:
FileInputStream fis = new FileInputStream("F:\stu.cctv"); ObjectInputStream ois = new ObjectInputStream(fis); // Student stu = (Student) ois.readObject(); // Student[] stu = (Student[]) ois.readObject(); // for (Student student : stu) { // System.out.println(student); // } List<Student> list = (List<Student>) ois.readObject(); for (Student student : list) { System.out.println(student); } //关闭资源 ois.close(); fis.close(); |
(3)字符流
字符输入流:Reader,InputStreamReader子类
InputStreamReader isr = new InputStreamReader(new FileInputStream("F:\abc.txt")); StringBuffer sb = new StringBuffer(); char[] c = new char[1024]; int i; while((i=isr.read(c)) != -1){ sb.append(c); } System.out.println(sb.toString()); isr.close(); |
字符输出流:Writer,OutputStreamWriter
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("F:\demo.txt")); osw.write("智递科技"); osw.close(); |
文件复制示例:
InputStreamReader isr = new InputStreamReader(new FileInputStream("E:\2.doc"),"ISO-8859-1"); OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("F:\2.doc"),"ISO-8859-1"); //读取到内存 char[] c = new char[1024]; int i; while((i=isr.read(c)) != -1){ osw.write(c); } isr.close(); osw.close(); |
(4)缓冲流
缓冲输入流:BufferedReader
//缓冲流-->字符输入流-->字节流 // BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("F:\练习.txt"))); //缓冲流-->字符流,FileReader是InputStreamReader的子类 BufferedReader br = new BufferedReader(new FileReader("F:\练习.txt")); String str; while((str=br.readLine()) != null){ System.out.println(str); } br.close(); |
缓冲输出流:BufferedWriter
//缓冲流-->字符流-->字节流 // BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("F:\abc.txt"))); BufferedWriter bw = new BufferedWriter(new FileWriter("F:\abc.txt")); bw.write("智递 智递");// 表示换行 bw.close(); |
十、多线程
1、语法
(1)继承Thread类
步骤:
- 自定义线程类,继承Thread类;
- 重写run方法,线程中要执行的内容,写到run方法中;
- 实例化自定义线程;
- 使用线程对象调用start方法;
示例:
public class A extends Thread{ @Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println("i="+i); } } } |
Test类:
A a = new A(); a.start();//启动线程 |
(2)实现Runnable接口
步骤:
- 自定义线程类,实现Runnable接口;
- 重写run方法;
- 实例化自定义线程对象;
- 实例化Thread对象,把线程对象作为参数;
- 使用Thread对象调用start方法;
示例:
public class A implements Runnable{ @Override public void run() { for (int i = 0; i < 1000; i++) { System.out.println("i="+i); } } } |
Test:
// Runnable a = new A();//多态,父类的引用指向子类对象 A a = new A(); Thread t1 = new Thread(a); t1.start();//启动线程 |
2、线程生命周期
(1)新建状态,线程对象创建;
(2)就绪状态,执行start方法后;
(3)执行状态,获得CPU资源后,开始执行run方法;
(4)阻塞状态,CPU资源过期后,重新回到就绪状态,等待CPU下次分配资源;
(5)终止状态,run方法执行结束后;
3、常用方法
(1)Sleep(long ms) 睡眠方法,静态方法可以直接用类名调用
示例:
public void run() { for (int i = 0; i < 1000; i++) { System.out.println("i="+i); if(i==500){ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } } } |
(2)currentThread() 返回当前线程对象
@Override public void run() { Thread t = Thread.currentThread(); for (int j = 0; j < 1000; j++) { System.out.println(t.getName()+"="+j); } } |
(3)getName 获得当前线程名称
(4)setName 设置线程名称
Thread t1 = new Thread(a); t1.setName("线程A"); t1.start();//启动线程 |
(5)getID 获得当前线程的唯一标识
(6)getPriority() 获得当前线程的优先级
(7)setPriority(int i) 设置当前线程的优先级
4、线程同步
概念:
被多线程并发访问时如果一个对象有可能出现数据不一致的问题,那么这个对象称为线程不安全的对象。
解决:
在需要同步的方法声明部分添加synchronized修饰符;
或者是
Synchronized(对象){
同步的代码;
}
示例:
Bank类:
public class Bank { public double balance;//余额 public Bank(double money){ this.balance = money; } //取钱 // public synchronized void getMoney(double money){ // System.out.println(Thread.currentThread().getName()+"查询当前余额为"+balance+"元"); // balance -= money;//取钱 // System.out.println(Thread.currentThread().getName()+"取了"+money+"元,取款后余额为"+balance+"元"); // } public void getMoney(double money){ synchronized (this) {//this指当前对象 System.out.println(Thread.currentThread().getName()+"查询当前余额为"+balance+"元"); balance -= money;//取钱 System.out.println(Thread.currentThread().getName()+"取了"+money+"元,取款后余额为"+balance+"元"); } } } |
取钱的线程类:
public class Qu extends Thread{ public Bank bank; public double money; /** * 构造方法 * @param bank 要操作的账户 * @param money 取款金额 */ public Qu(Bank bank,double money){ this.bank = bank; this.money = money; } @Override public void run() { bank.getMoney(money); } } |
测试类:
Bank b = new Bank(1000); //你用网银取款 Qu wy = new Qu(b,100); wy.setName("网银"); //你妈在家用支付宝取款 Qu zfb = new Qu(b,100); zfb.setName("支付宝"); //你媳妇在单位用微信取款 Qu wx = new Qu(b,100); wx.setName("微信"); wy.start(); zfb.start(); wx.start(); |
十一、配置文件操作
1、XML文件
(1)使用pull方式解析
//1.创建解析工厂对象 XmlPullParserFactory xmlFactory = XmlPullParserFactory.newInstance(); //2.获得解析器对象 XmlPullParser xmlParser = xmlFactory.newPullParser(); //3.指定资源路径 FileReader fr = new FileReader("F:\book.xml"); xmlParser.setInput(fr); int event = xmlParser.getEventType(); while(event != END_DOCUMENT){ switch(event){ case START_DOCUMENT://文档开始 System.out.println("=====开始解析文档======"); break; case START_TAG://标签开始 String tagname = xmlParser.getName();//获得标签名称 switch(tagname){ case "name": String name = xmlParser.nextText(); System.out.println(name); break; case "jiage": String jiage = xmlParser.nextText(); System.out.println(jiage); break; case "zz": String zz = xmlParser.nextText(); System.out.println(zz); break; case "cb": String cb = xmlParser.nextText(); System.out.println(cb); break; } break; case END_TAG://标签结束 tagname = xmlParser.getName(); System.out.println("======文档解析结束======="); break; } event = xmlParser.next();//获取下一个事件 } |
(2)使用pull方式写入
//1.创建解析工厂 XmlPullParserFactory xmlFactory = XmlPullParserFactory.newInstance(); //2.创建序列化对象 XmlSerializer xmls = xmlFactory.newSerializer(); //3.指定文件资源 FileWriter fw = new FileWriter("F:\stu.xml"); xmls.setOutput(fw); xmls.startDocument("utf-8", false);//生成xml文档头信息 xmls.startTag(null, "student");//student标签开始 xmls.startTag(null, "id");//id标签开始 xmls.text("1234");//文本内容 xmls.endTag(null, "id");//id标签结束 xmls.endTag(null, "student");//student标签结束 xmls.endDocument();//文档结束 |
2、json文件
(1)使用gson方式解析
//1.实例化解析对象 JsonParser jp = new JsonParser(); //2.读取要解析的json文件 FileReader fr = new FileReader("F:\stu.json"); //3.解析json文件 JsonObject jo = (JsonObject) jp.parse(fr); System.out.println("姓名:"+jo.get("name").getAsString()); System.out.println("年龄:"+jo.get("age").getAsDouble()); System.out.println("是否有车:"+jo.get("car").getAsBoolean()); //获取数组 JsonArray jarr = jo.get("hobby").getAsJsonArray(); for (int i = 0; i < jarr.size(); i++) { JsonObject j = (JsonObject)jarr.get(i); System.out.println("id:"+j.get("id").getAsString()); } |
(2)写入json文件
//1.创建json对象 JsonObject jo = new JsonObject(); //2.添加键值对 jo.addProperty("name", "张三"); jo.addProperty("age", 20); jo.addProperty("car", true); JsonObject hobby1 = new JsonObject();//数组中的第1个元素 hobby1.addProperty("id", "java"); JsonObject hobby2 = new JsonObject();//数组中的第2个元素 hobby2.addProperty("id", "php"); JsonArray ja = new JsonArray();//数组对象 ja.add(hobby1); ja.add(hobby2); jo.add("hobby", ja);//把数组对象添加到json的hobby属性中 //3.保存到json文件 FileOutputStream fos = new FileOutputStream("F:\abc.json"); fos.write(jo.toString().getBytes()); fos.close(); |
3、properties文件
(1)解析properties
//1.实例化properties对象 Properties prop = new Properties(); //2.获得属性文件 FileInputStream fis = new FileInputStream("F:\stu.properties"); //3.使用属性对象的load()方法获取内容 prop.load(fis); //4.根据键获得值 String name = prop.getProperty("userName"); System.out.println(name); String pwd = prop.getProperty("pwd"); System.out.println(pwd); //5.关闭资源 fis.close(); |
(2)写入properties
//1.创建properties对象 Properties prop = new Properties(); //2.指定输出文件 FileOutputStream fos = new FileOutputStream("F:\stu.properties"); //3.设置要输出的属性 prop.setProperty("userName", "java456"); prop.setProperty("pwd", "abc123"); //4.保存文件 prop.store(fos, "abc"); //5.关闭资源 fos.close(); |