Java技术体系
第一阶段 JavaSE
java理解与基础
-
Windows的常用命令
1.切换盘符: d: e:
2.切换到具体的文件夹: cd+文件名
3.创建文件夹:md+文件名
4.删除文件夹:rd+文件名
5. 切换到上一级目录:cd…
6.创建一个人文件:echo aa>1.txt
echo bb>>1.txt(不覆盖原来的内容)
7.删除当前文件:del+文件名
———————————————— -
Java的语言特点
-
面向对象开发
- 封装性
- 继承性
- 多态性
-
可移植性
-
一次编译,到处运行,跨平台开发
-
-
配置环境变量
1.新建一个变量名:JAVA_HOME 变量值是:JDK的根目录
2.在path里添加: ;% JAVA_HOME%\bin
3.在win+R输入cmd命令行输入java javac -
注释
作用:解析代码,方便解读
特点:编译时不会运行,不管是否有bug
分类: a.当行注释 //
b.多行注释 /* / 快捷键是 ctrl + shift + /
c文档注释: 一般用于在类的开始
如: /*
* @version
* @author
*/
好处:a.方便读懂以前代码 b.方便调式 -
java划分了五块内存
a.栈(都是局部变量):
局部变量包含两部分- 方法里的参数
2.方法类的变量 - 只要离开作用域,值在栈里就不存在
- 所有的方法的执行都是在栈里执行
5.所有方法里的变量都是随着方法的开始而开始,方法的结束而结束(除了静态变量)
b.堆
只要是new 出来的东西都是在堆里, 所有存在堆里的数据都有一个内存地址,这个地址都是十六进制的。
所有存在堆里的基础数据类型,或者是引用数据类型都有默认值 。c. 方法区, class字节码的信息 方法里的基本信息(比如方法叫什么名字)
d.本地方法栈,系统有关
e.寄存器: cpu有关
- 方法里的参数
-
类型分类
java 八大基本数据类型有:
整数类型 int(整数) short(短整形) long( 长整形) byte 字节
小数类型 float ( 单精度) double (双精度)
真假类型 boolean (true, flase)
字符类型 char(单个字符) 一个中文占两个字节
引用数据类型:String(表示字符串,可以存多个字符)-
数据类型转换
数据类型转换 一个依据 :
byte< char=short<int=float< long = double
a.自动类型转换 小的转大的(不需要去处理)
b. 强制类型转换 大转小(需要进行处理)后果:会丢位
-
-
基本运算符
- 算术运算符 +(加) -(减法) *(乘法) /(除法) %(取余数)
num1++;num1–; 步骤: 先获取num1 的值 再进行 运算
++ num1;–num1步骤: 是先进行运算之后,再获取其值 - 赋值运算符 num+=5; ==> num = num+5;
3.逻辑运算符
&& 并且 也就是条件1 与 条件2 返回的结果都是真
|| 或者 也就是 条件1 与 条件2 返回的结果 只要有一个是真的, 最后这个表达式的结果就是真的
! 取相反的结果 - 三元运算符
语法: 表达式1 ? 表达式2 : 表达式3
注意:表达式2 与表达式3 的类型必须一样
- 算术运算符 +(加) -(减法) *(乘法) /(除法) %(取余数)
-
选择结构
-
if结构
-
单分子 if 选择结构
if(条件1){ 操作1}
else{ 操作2} -
多分支 if 选择结构
if(条件1){ 操作1
} else if(条件2){
操作2
}else if(条件3){
操作3
}else{
操作4} -
嵌套 if 选择结构
if(条件1){
if(条件2){
}
}
-
-
switch 选择结构
switch (表达式){
case 1:
操作1
break;
case 2:
操作2
break;
default:
操作3
break;
}
————————————————
注意点 : 1. 表达式必须是一个变量;
2.case必须是一个常量 ;
3.case 必须与break 进行搭配,如果 没有加break,有满足的条件还会继续往下执行 ,直到遇到 break;
4.default 相当于一个else ;
-
-
循环
执行的规律 : 外层循环循环一次 内存循环循环一遍。(记住,掌握)
-
while循环
while(条件){
执行的操作
}1.执行多次
2.条件必须是真或者假
3.先判断条件 再执行 -
do-while循环
do{
执行的操作
}while(条件)先执行操作,再判断条件。
至少执行一次
-
.for循环
for( 初始化的条件; 循环条件 ; 递增或递减的变量){
执行的操作}1.初始化变量只走一次
2.小括号的三个条件都是分号进行分割,小括号没有分号
-
普通for循环
-
增强for循环
语法: for(数据类型 变量的名称 : 需要遍历的数组或者是集合){ }
注意点 :
1.知道集合或者是数组存的类型(比如是 int 或者是String)
2.变量名称的后面 不是以分号,而是冒号:
3.每一次循环数组或者是集合都会把数据给变量的名称
-
-
break、continue、return区别
break:是结束循环,不会执行下面的次数了。
continue: 结束本次循环。
return:结束,一般用于方法额返回值里,在循环里 跟 break 是一样的功能.。
-
常规的死循环
while (true) 和 for (;?
-
-
数组
用多个变量来记录同一种类型的数据,即:就是一个容器 也就是一个特殊的变量
特点:
1.数组是引用数据类型2.可以存多个同类型的数据
3.数组的长度在运行期间不能够变改变
-
初始化数组
-
动态初始化
语法: 数据类型[] 数组的名称 = new 数据类型[数据的长度];
如:int[] arr = new int[6];
注意点:
1.前后的数据类型必须一致- 动态初始化必须给其长度
- 数组的类型既可以是引用数据类型也就是基础数据类型
- .数组只初始化都会有默认的值
-
静态初始化
语法:int[] moneys= new int[]{1,2}; 或 int[] moneys ={1,2};
注意点:
1.静态初始化时根据具体的值来推算出其长度
2.静态初始化不需要给其长度
-
-
多维数组
语法:
动态初始化 : 数据类型[][] 数据的名称 = new 数据类型[3][5]
注意点:
1.初始化的方式是一样的,只是多加了一个[]
2.它的 内存存方式跟一维数组符方式是 一样
3.如果使用嵌套for循环遍历二维数组,那长度的方式 :
外层的是 数组的名称.length(scores.length)
内层的循环是 数组的名称[i].length(scores[i].length) -
数组工具类的封装
工具类的名字叫 ToolUtils:好处:方便开发人员相互使用
-
遍历
public static void Traverse(int [] nums){
if (nums!=null&&nums.length>0){
for (int i=0;i<nums.length;i++){
System.out.println(nums[i]);
}
}
} -
冒泡
public static int [] sortArrays(int [] nums){
if (nums!=null&&nums.length>0){
for (int i=0;i<nums.length-1;i++){
for (int j=0;j<nums.length-1-i;j++){
if (nums[j]>nums[j+1]){
int temp=nums[j];
nums[j]=nums[j+1];
nums[j+1]=temp;} } } } return nums; }
-
最大值
public static int getMax(int [] nums){
int temp=0;
if (nums!=null&&nums.length>0){
temp=nums[0];
for (int i=0;i<nums.length;i++){
if (nums[i]>temp){
temp=nums[i];} } } return temp; }
-
动态增加长度
public static int[] addArrays(int length){
int [] nums=new int[length];
Scanner input=new Scanner(System.in);
for (int i=0;i<nums.length;i++){
nums[i]=input.nextInt();
}
return nums;}
-
交换位置
public static boolean sortAarrays(int [] nums,int start,int end){
if (nums!=null&&nums.length>0){
if (end<nums.length-1){
int temp=nums[start];
nums[start]=nums[end];
nums[end]=temp;
return true;
}
}
}return false; }
-
-
数组的处理的工具类 Arrays
1.binarySearch(int[] num ,5) 查找数组改元素的索引位置
2.equals(double[] a,double[] a2) 比较是具体数组里的值 == 比较的内存地址
3.fill(int[] a,int val) 向数组里填充 val 值
4.sort(moneys) 排序
5.toString(moneys) 字符串的格式输出
————————————————
-
面向对象
三大特性:
封装,继承,多态
面向对象开发的好处:
1.符合我们常规的方式,把复杂的问题简单化
2.由执行者变成指挥者
3.便于代码的扩展与维护
-
类与对象
类:是抽象的, 用于描述一个一类事物
成员属性: 是什么(名词) 如:年龄 性别 姓名
成员方法: 能够做什么(动词)如:吃猪脚饭 学习
对象 : 是具体的表现形式
类与对象的关系:类是对象的抽象(图纸) 对象是类的具体(房子)-
定义一个类
成员属性
* 数据类型 变量
* String name;
* int age;
成员方法
* // eat的方法
* public void eat(){
* 执行操作
* }
注意点:- 成员属性都是些在类里,而不是写在方法里
- 如果这个方法是成员方法必须把static 关键字去掉
-
匿名对象
定义:一次性对象,没有名字的对象 new Student()
-
特点
特点 :
1.不会在栈内存里有地址,但是会在堆内存里去开辟空间
2.这个一次性的对象用完就马上销毁, 所以节省内存空间
3.匿名对象 给成员变量赋值没有任何意义,如:play(new String[]{“30”,“40”,“50”,“60”})
使用情况:(两种)
1.一般是与作为方法的参数使用 getStudent(new Student())
2.直接调用其类里的方法 new Student().study();
-
-
属性私有化
关键字: private(加上私有的关键字之后,只能够本类访问)
可以私有化有:
1.对属性- 对方法
3 对类私有化
4.对接口私有化
私有化 其实就是一种简单的封装
-
好处
私有化的好处:
1.隐藏内部细节
2.保护数据的安全, 以及防止数据的错误
提供两个对外的方法:
setXXX() 赋值 和 getXXX() 取值
- 对方法
-
访问修饰符
访问修饰符: public > protected> 默认 > private
在同一个类中是否可以被访问 Yes Yes Yes Yes
不是同一个类是否可以被访问 Yes Yes Yes no
在不同包里有继承关系是否可以被访问 Yes Yes no no
没有继承关系也在同一个包里是否可以被访问 Yes no no no总之:
在开发里如果想对外提供就使用 public,只想自己本类使用就使用 private
-
-
封装
抽取出来的方法就是封装
好处:
1.隐藏内部代码实现的细节
2.代码可重用性
3.提高代码的可维护性
属性的封装
1.私有化属性 2.给相应的get 和 set 方法-
方法
定义:一组操作的集合
-
最基础的方法的申明
最基础的申明方式 :
public static void 方法的名称(){
方法体:(也就是执行语句: 可以是一条,也可以是多条)}方法名的规范: 遵循驼峰命名规格(也就是首字母小写,第二个单词首字母大写)
注意点:
- 多有的方法都写在class 里
- 方法没有顺序之说, 可以随意方法, 方法都是平等的
- 方法不能相互嵌套
- 想执行方法里的操作必须调用
- 如果这个方法有多个参数 必须使用 逗号来分割
- 如果这个方法有返回值,必须有retrun 关键字
- retrun的值必须跟 方法定义的时候的类型一样
方法调用的语法 :
1.方法的名称();
如: Vegetables(); (重点)
2.打印调用
如:System.out.println(flag(arr,2,6,4) )
3. 赋值调用
使用方法的好处:- 代码清晰明了
2.代码的可扩展行 可维护性高
-
申明方法的格式
-
访问修饰符 返回值类型 方法的名称(参数1,参数2,...){
-
方法体
-
return 返回值
-
}
-
其中return :
-
1.停止这个方法 返回值
-
2. 表示生产的产品.一般是被调用者使用
返回值的使用:
- void 修饰的表示其没有返回(可以使用retrun,不能retrun 具体的类型, 格式是:return;)
2.普通的打印就不会使用带返回值的
3.带返回值 : 想被调用者 所得到的结果是多少
4.需要传递参数: 也就是说执行 的操作 跟参数密切相互 就需要传递
-
-
调用方法在内存
1.首先是方法来加载 class字解码以及方法的基本信息
2.开辟main方法的空间
3.其他方法也会在栈里面开辟一个空间,如果这个方法存在返回值, 把返回值给main方法之后销毁(方法的生命周期随着方法的调用开始执行到最后一行代码结束) -
(构造)方法的重载
要求:
1.必须在同一个类里
2.必须是参数不同:参数的个数不同,或者是参数的类型不同 (不包含参数的变量名不一样)
3.必须名字一样
4.与返回值没有关系
-
方法的重写
在继承中,方法名是相同,参数是一样的
-
意义
子类调用父类的方法的同时,也可以做自己想做的事
-
注意点
注意点;
1.子类的方法的作用域不能 大于父类方法 返回值的作用域:所有类的直接父类 与间接父类都是Object();
2.访问修饰符 : 子类的访问修饰符权限不能严与父类(父类给的是公有的访问的修饰权限,子类不能给私有的访问权限 private)
3.@Override 看到这个注解肯定重写了父类的方法
-
-
构造方法
-
组成
构造器、构造方法、构造函数
-
满足条件
满足的条件:
1.方法名与类名相同
2.在方法名面前没有返回值类型声明
3.在方法中不能用return来返回一个值,可以使用 return; 表示结束构造方法注意事项:
1.可以有无参构造 ,也可以有有参构造
2.系统会给类提供一个默认的构造方法 (无参构造方法),只要是类里写了无参数 或者有参构造, 系统就不会给其提供无参数构造, ( 一个类里面会有一个无参有一个有参)
3.一个对象创建的时候,只走一个构造方法 -
作用
在创建这个对象时,并给成员属性赋值,只能在创建时候赋值一次。
-
语法
语法:
访问修饰符 类名(参数1,参数2,参数3){
this .name = 参数1;}
注意点:
访问修饰符 : public private(只能本类进行访问)类名: 必须与类名完全一样(包含大小写)
参数: 一定要与成员变量的类型对应上
构造方法:
不能通过对象来 调用其构造方法,是由java jvm 来执行 ,在创建这个对象的时候,给执行, 只执行一次 -
set 与构造方法 区别
相同点; 都可以赋值
不同点: 构造方法只能在创建的时候赋值一次,而set 方法可以赋值多次
使用场景:
这个成员变量需要多次赋值的时候,就使用set;
在创建的时候赋值一次 就使用构造方法,相对简单
-
-
静态方法
静态方法的引进:没有静态之前 ,相同数据会在内存里去开辟新的空间,占用内存后期维护比较麻烦, 能不能把相同额数据放在一个地方存储。
有静态之后 : 静态的数据 都存在内存里的静态空间里,静态区间又在方法区里实现 数据的共享,可以节省内存,在开发里尽量少使用。
-
关键字: static
静态可以修饰 属性 方法 类等
-
使用
1.静态是随着 class 的加载而加载 (影响用户的体验度)
2.静态优先于对象的存在,不依赖与对象
3.静态的调用方式不同,可以通过类型直接调用,也就可以通过对象名调用 ,但是一般建议通过类名直接调用 调用语法是通过类名. 属性的名称Actor.country
-
注意点
1.静态方法里只能是静态的 ( 静态的属性, 静态的方法)
原因:静态是最先随着类进行加载,成员的方法或者属属性,一开始没有加载出来,静态使用的时候,都可能没有加载这个变量 或者方法到内存。
2.不能在方法里申明静态变量.
3.普通的方法是可以加载静态的资源(属性,方法)
-
-
-
变量
变量的作用域问题 : 一般是就近原则 : 也就是 取这个变量近的值
-
局部变量
局部变量:方法里的变量叫做局部变量,包含方法里的参数
-
成员变量
成员变量:类下面的变量叫做什么成员变量
-
静态变量
静态变量又称为类变量
-
获取变量的三种方法
1.直接获取(一般是获取局部变量)
- 通过 this(获取成员)
- 获取super 父类的变量
-
-
关键字
-
this
本类的对象引用 ==> 也就是谁调用的这个方法, 这个对象就是谁
-
使用说明
this. 变量:获取的都是成员变量
this.调用其方法:方法肯定是成员方法
在 一个方法里面:如果成员变量与局部变量的名字 是一样的,局部变量的作用域优先于成员变量
-
-
super
得到父类的属性或者方法构造都通过 super 关键字来拿
-
使用说明
继承中使用
得到父类属性:
super.属性名 得到其方法
super.方法名() 得到其构造 super();
-
-
-
工具类,api帮助文档
api:定义:应用程序接口(帮助文档)
告诉一些工具的方法以及作用,还有构造信息 等等, 不是给你写代码比如:对数组的处理的工具类 Arrays
-
-
继承
父类:超类、基类
子类:派生类
满足条件:is-a关系才能使用继承,两个类才有关系
父类:与创建普通类的语法一样java里的单继承: 只能存在一父类 ,所有类有一个直接父类或者间接父类是Object
继承的好处:
可扩展性 ,可维护性 ==> 好处大于坏处: 开发中经常会使用继承
坏处 : 耦合度比较高-
关键字 : extends
1,继承时,父类获取不了子类的东西
2,继承时,子类可以获取父类的所有东西
3.在子类与父类中有同一个成员变量,如果实例是子类的对象,首先获取的是子类的成员变量,如果子类没有,就依次往上寻找父类的成员变量,如果都没有这个变量就报错. -
方法的重写
在继承中,方法名是相同,参数是一样的。
意义:子类调用父类的方法的同时,也可以做自己想做的事-
注意点
注意点;
1.子类的方法的作用域不能 大于父类方法 返回值的作用域:所有类的直接父类 与间接父类都是Object();
2.访问修饰符 : 子类的访问修饰符权限不能严与父类(父类给的是公有的访问的修饰权限,子类不能给私有的访问权限 private)
3.@Override 看到这个注解肯定重写了父类的方法
-
-
子父类中构造的使用
在继承中
- 如果没有调用 父类的其它构造,系统会默认调用 父类的无参构造
- 子类可以调用父类重载的构造 语法: super(参数的值)
- 调用父类的构造必须放在第一句, 一个构造只能放一个super() 否则报错
-
关键字
-
this
本类的对象引用 ==> 也就是谁调用的这个方法, 这个对象就是谁
-
使用说明
this. 变量:获取的都是成员变量
this.调用其方法:方法肯定是成员方法
在 一个方法里面:如果成员变量与局部变量的名字 是一样的,局部变量的作用域优先于成员变量
-
-
super
得到父类的属性或者方法构造都通过 super 关键字来拿
-
使用说明
继承中使用
得到父类属性:
super.属性名 得到其方法
super.方法名() 得到其构造 super();
-
-
final
意思:最终,不能变改变
-
修饰类
注意点: 被final 修饰的类不能够被继承
-
语法
语法:实在类的前面加上这个关键字 final
-
final修饰的静态的类
如果想这个类不被实例化,因为实例化的代码对于布局就是多余的,而且实例化的对象又没有被使用,也就说明没有释放资源,所以对这个类要写成私有的,即给个私有的构造。
-
-
修饰方法
2.方法: 父类里final 修饰符方法不能够被继承
-
修饰变量
-
成员变量
- 成员变量:final 修饰的成员变量, 必须给其默认的值,设置后就不能改变了
-
局部变量
4.局部变量: 在局部变量中final 可以不给默认 , 但是一旦设置默认值之后就不能变改变,在开发中 final 一般与 static 配合的使用
-
-
-
-
-
多态
定义: 在继承的前提下的一种事物有多种形态
前提:
1.多态必须在继承的前提下
2.多态里一般都会方法重写
3.父类的引用指向子类的对象-
语法
父类的对象 对象名称 = new 子类的对象();
父类的对象引用执行之类对象的引用 (向上转型)-
多态里成员变量的获取
在多态里, 编译看左边,赋值看左边
即:多态中获取成员变量都是看左边 -
多态里方法是如何获取
调用方法结论: 编译看左边 ,运行看右边
-
多态的向下向上转型
向上转型的语法:
父类 对象名称 = new 子类(); (类似于向上自动类型转换) eg:Pet pet = new Dog()
向下进行转换(还原 成原来的样子)语法:
子类 子类名称= (子类)向上转型的对象名 eg:Dog dog =(Dog)pet -
instanceof关键字的用法
情境:转型还原的不正确会产生一个错误:
强制类型转换异常 java.lang.ClassCastException
解决方法: instanceof 判断是否能够还原成功
-
-
两种体现形式
- 第一种是以父类作为参数
- 第二种是以父类作为返回值
-
抽象类
定义:抽取公共的抽象的属性或者是方法
-
关键字:abstract
-
语法
public abstract 类名{ }
-
注意点
1.在返回值前面加上关键字abstract
2.抽象方法都没有方法体
3.抽象方法必须在抽象类里,反之, 抽象类里不一定是抽象方法,可以是普通的方法
4.抽象方法一般调用是没有意思 ,只有子类重写之后才能产生意义
5.子类继承了抽象类,子类必须重写父类的抽象方法, 除非子类也是一个抽象方法
6.抽象类不能够被实例化,也就是不能够 new 出来
7.抽象类的构造都是为了给其子类进行赋值,调用父类的super() -
抽象VS普通
-
抽象类VS普通类
区别:
1.抽象类必须用abstract关键字来修饰- 抽象类不能够被实例化
-
抽象方法VS普通方法
区别:
- 抽象方法也用abstract 关键字来修饰
2.抽象方法是没有方法体
- 抽象方法也用abstract 关键字来修饰
-
-
-
接口
定义:用于规定方法名称的规则的集合。也就是一些规范 , 也就是定义一些方法
-
关键字:interface
-
语法
public interface 接口的名称{ }
-
实现接口关键字:implements
1.接口里的方法都是抽象方法,抽象方法系统默认会加上public abstract,不可以有普通方法
- 接口编译后也是一个class 文件
- 实现类必须实现接口里所有的方法
- 接口不能够被实例化,只能实例化实现类
- 接口没有构造方法:(实现类都是干爹,只存在一个爸爸)
-
变量
接口里的变量:
在接口里 不能有变量 ,只能有常量. 会给常量默认加上一个final
eg: public static final String NAME=“hhh”; -
赋值
-
第一种通过传递父类参数
第一种通过传递父类参数
public void play(Pager pager,Link link){
System.out.println(“您要打印的是”+pager.getPager()+"\t"+link.getColor());}
-
第二种set
private Pager pager;
private Link link;
public void setPager(Pager pager) {
this.pager = pager;
}
public void setLink(Link link) {
this.link = link;
} -
第三种通过构造方法
第三种通过构造方法
private Pager pager;
private Link link;
public Printer(Pager pager, Link link) {
this.pager = pager;
this.link = link;
}
-
-
类,接口之间的关系
a.类与类:(extends)
继承关系:可以单继承,不可以多继承,可以多层继承
b.类与接口:(implements)
实现关系:可以单实现,可以多实现,不可以多层实现
c.接口与接口:(extends)
继承关系:可以单继承,可以多继承,也可以多层继承
-
-
内部类
定义:类里面嵌套一个类
语法:
public class 外部类名{
public class 内部类名{ }
}-
特点
- 内部类可以获取外部类的属性与方法(包括私有的)
- 外部类获取不到 内部类的属性与方法
-
成员内部类
公有的内部类 :
获取内部类的语法是 :
外部类名.内部类 对象的名称 = new 外部类().new 内部类()
私有的内部类:只能够本类访问注意点:
变量重名:如果外部类的变量与内部类的变量重名
访问外部变量的语法: 类名.this. 变量名 -
静态内部类
定义:在成员内部类加上静态的关键字static(一般会去掉访问修饰符)
语法:
外部类.内部类 对象的名称 = new 外部类.内部类()
eg:Body.Heart h = new Body.Heart(); -
方法内部类
定义:在方法中的内部类。
语法:
访问修饰符 返回值 方法名称 (参数列表){
class 类名 {
// 成员属性
// 成员方法
// 构造
}
}注意点:
- 内部类不能有访问修饰符
- 生命周期随着方法的开始而开始,结束而结束
- 在方法里的内部类的方法,不能够直接调用,但是可以间接调用;在外部类的方法里实例化这个对象(内部类),然后调用其(内部类)方法
-
匿名内部类
定义:没有名字的内部类
使用前提:一般是在继承或者实现的基础上-
语法
使用前提:一般是在继承或者实现的基础上
new 抽象类或者接口{
// 必须实现的方法} -
例子
-
第一个
public static void main(String[] args) {
Iter iter=new Iter(){
@Override
public void show{
System.out.println(“匿名内部类”);
}
};
// 调用方法
iter.show();
} -
第二个
public static void main(String[] args) {
new Pet(){
@Override
public void eat(){
System.out.println(“内部类”);
}
}.eat();
}
-
-
-
-
-
常用的类
库:
1.jdk 提供的
2.自己封装的
3.第三方的库:
步骤:
1.下载jar (导入到工具类)
2.在项目里新建一个文件夹 lib jar 包放入到lib
3. 添加项目lib
4. 使用类库: 就是把java文件编译成.class,然后打包生成jar包,导入jar包就可以使用jar包的全部类型,各种包就合成一类库。
-
Object类
导包java.lang(只要值在这个包下面的都不需要进行导包)
-
方法
-
构造方法
无参构造方法
-
基本方法
toString方法
public String toString() toString 方法会返回一个“以文本方式表示”此对象的字符串1.没有重写之前: toString返回值的介绍 : getClass().getName() + “@” + Integer.toHexString(hashCode()
getClass().getName() 返回当前类的完成的包名+ 类名
Integer.toHexString(hashCode()) 把哈希值转换为16进制
2…默认toString()返回的没有任何意义,所有需要重写: 一般重写是得到 这个类的成员属性的值 快捷键是 Alt+insert
equals方法
public boolean equals(Object obj) 要与之比较的引用对象 (比较的是两个引用数据类型的地址是否一样
没有重写之前:这个方法最后还是== 进行比较的
== 与 equals()的区别:
相同点: 都可以做比较(做引用数据类型的比较)
不同点: == 如果是基本数据类型比较的是 具体的值, 如果是引用数据类型比较的是内存地址
equals() 只能比较引用数据类型的地址值(一般都要进行重写)public int hashCode() 返回该对象的哈希码值
- 如果是同一个对象, 两次调用 hashCode() 返回的哈希码值 是一样的
- 两个对象的哈希值一样并不一定同一一个对象
- Integer.toHexString(obj.hashCode()) 把哈希值转换为16进制
getClass()方法
public final Class<?> getClass() 返回此 Object 的运行时类,描述类的类的信息
其实存的是一些字节码文件getName()方法
public String getName() 返回当前类的完成的包名+ 类名
-
-
-
Scanner类
导包java.util
System.in 输入流对象(从键盘获取你输入的数据)-
方法
构造:Scanner(InputStream source)
实例化一个对象 的步骤:- 导包
2.实例化 类名 对象名 =new 类名()
3.对象名.方法名() 对象名.属性
普通方法:
nextInt() nextBoolean nextDouble nextByte() nextDouble(基础数据类就没有 nextChar())接收字符串的两个方法:
next()
nextLine() 读取的一行的记录 - 导包
-
-
String类
1.它是一个字符串 是一个引用数据类型
2.在java.lang下,不需要进行导包
3.字符串字面值是存在方法区里的字符串常量池里
4.符串是常量;它们的值在创建之后不能更改(不能改变的就是具体的值,而引用地址是可以改变)可以实现数据共享-
内存分析
字符串字面值都是存在 方法区里的常量池里,如果新建一个字符串字面值,都会先去常量池里查找是否存在,如果存在,直接把地址指向新建的,不存在重新开辟空间存.
-
常用方法
-
判断功能
1.equals(Object anObject) 判断两个字符串是否相等:
2.boolean contains(CharSequence s) 判断字符串是否包含此字符
3.boolean endsWith(String suffix) 判断此字符串的后缀结尾
4.startsWith(String prefix) 判断字符串的前缀
5.public boolean equalsIgnoreCase(String anotherString) 判断两个字符串忽略大小写
6.public boolean isEmpty() 进行非空验证 -
获取功能
- public char charAt(int index) 根据索引来获取字符串相对应的值,索引是0 开始的
- public int length() 返回的是字符串的长度
- public int indexOf(int ch) 返回字符串第一次出现的索引值(找到返回的是索引值,找不到返回的是-1)
4.public String substring(int beginIndex,int endIndex):获取指定索引范围的字符串 (包头不包尾) (beginIndex 开始的索引,endIndex 结束的索引 )
5.public String[] split(String regex) 根据什么进行拆分
-
转换功能
1.public byte[] getBytes() 将一个字符串转换成一个字节数组
2.public String replace(char oldChar,char newChar)返回一个新的字符,第一个参数是需要替换的字符 第二参数是插入的字符
3.public String toUpperCase(Locale locale) 把当前字符串转换成大写
4.public String toUpperCase(Locale locale) 把字符串转换成小写
5.public String trim() 去掉前后的空格
6.public static String valueOf(int i)把int类型转换成String类型,这是一个静态的方法(基本数据类型之间相互转换)
7.public char[] toCharArray() 把字符串转换成一个char的数组
-
-
-
StringBuffer类
1.线程安全的可变字符序列(即可变的字符串)
2.有一个类似String的字符串缓冲区
3.某些方法的调用可以改变该序列的长度与内容,如:append()和insert()方法-
与String的区别
相同点: 都是对字符序列进行操作
不同点:- String的数据是不可变的,StringBuffer的内容是可变的
2.StringBuffer 自带缓存区,读取数据块,效率更高
- String的数据是不可变的,StringBuffer的内容是可变的
-
与String的相互转换
String转换成一个StringBuffer:
1.通过构造方法 new StringBuffer(“abc”);
2.通过调用其append new StringBuffer().append(“abc”)’;
StringBuffer转换成一个String:
1.通过toString() 方法- 通过String构造方法 new String(sb)
-
方法
-
构造方法
无参的构造:默认会给16个字符大小的缓冲区
capacity() 是获取缓冲区容量的大小
StringBuffer(int capacity)会默认给一个容量的大小值 -
普通方法
-
追加
1.append() 向末尾追加数据
2.insert(int offset, char c) 向指定位置追加数据 -
删除
1.deleteCharAt(int index) 根据索引进行删除
2.delete(int start, int end) 根据区间进行删除 -
获取
1.charAt(int index) 根据索引获取字符
2.indexOf(String str) 查找是否存在这个字符,存在返回当前的索引,不存在返-1
3.length() 获取字符串的长度 -
替换
1.replace(int start, int end, String str) 替换 根据区间来进行替换
2.reverse() 控制翻转
3.toString() 转换成String
-
-
-
与StringBuilder的联系
1.一个可变的字符序列
2.多个线程是不安全的
StringBuffer 与StringBuilder 的 区别:
版本不一样:
StringBuffer 1.0 StringBuilder 1.5
StringBuffer:多线程安全, 效率低 (开发里使用这个多一点)
StringBuilder:多线程不安全 效率高
-
-
包装类
包装类型 int ==》 Integer char ==> Character 其它的包装类型都是把首字母换成大写
好处:
1.使用包装类型的方法- 类型的相互转换
- 集合里的数据类型都必须是引用数据类型
-
Integer类型
类在对象中包装了一个基本类型 int 的值。
Integer 类型的对象包含一个 int 类型的字段-
构造方法
1.public Integer(int value)
- public Integer(String s) 第二个构造传递的参数是String类型, 但是必须是数字 ,否则会出现这个异常 : java.lang.NumberFormatException
-
常量
public static final int MAX_VALUE 获取int类型最大的值
public static final int MIN_VALUE 获取int类型最小的值
public static final int SIZE 获取int类型的位数 -
普通方法
1.public byte byteValue() 返回值是一个 byte,相互转换的时候不要超过最大的范围
2.public static int parseInt(String s) 静态方法:把String转换成int类型的方法(最常用)
3.public static String toBinaryString(int i) 把int 类型转换成二进制
4.public static String toOctalString(int i) 把int 类型转换成 八进制
5.public static String toHexString(int i) int 类转换为16进制
6.public static Integer valueOf(int i) 把int 类型转换成包装类 -
String,int ,Integer (数据类型的相互装换)
String转换成int 类型的三种方式:
1.通过构造 new Integer()
2.通过parseInt(String s)(常用)
3.valueOf(String str)
int 类型转换成String类型
1.new String(int i)
2.拼接 +""(常用)
3.toString()方法
int类型转换成Integer 类型
1.通过构造方法 new Integer()
2.valueOf(int i)
Integer转换成 int 类型
1.intValue()
2.直接赋值(Integer i = 10)
-
-
装箱与拆箱
自动包装: 把基本数据类型转换成包装类 (穿了一层衣服)
自动拆箱: 把包装类转换成 基本数据类型(拖了这一层衣服)
在 jdk1.5 之后会自动包装,自动拆箱 ( 不用去管了)
手动装箱 :Integer integer = new Integer(10)
手动拆箱 : intValue()
———————————————— -
正则表达式
定义:就是一个字符串 (校验规则的字符串)
好处:主要是做验证,把复杂的问题的简单化
坏处:记忆量大,且不一定写的对-
三个方法
第一个是比较 matches(str) 检验是否匹配
第二个是 split("") 切割
第三个是: replaceAll(reg,"") 替换 -
字符类
[abc] a、b 或 c(简单类)
[^abc] 任何字符,除了 a、b 或 c(否定)
[a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围)
[a-d[m-p]] a 到 d 或 m 到 p:[a-dm-p](并集)
[a-z&&[def]] d、e 或 f(交集)
[a-z&&[^bc]] a 到 z,除了 b 和 c:[ad-z](减去)
[a-z&&[^m-p]] a 到 z,而非 m 到 p:[a-lq-z](减去) -
预定义字符类
. 任何字符(与行结束符可能匹配也可能不匹配)
\d 数字:[0-9]
\D 非数字: [^0-9]
\s 空白字符:[ \t\n\x0B\f\r]
\S 非空白字符:[^\s]
\w 单词字符:[a-zA-Z_0-9]
\W 非单词字符:[^\w] -
Greedy 数量词
X? X,一次或一次也没有
X* X,零次或多次
X+ X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超过 m 次 -
例子QQ号
Scanner input=new Scanner(System.in);
System.out.println(“输入QQ号:”);
String str=input.nextLine();
System.out.println(str.matches("[1-9]\d{4,14}")==true?“是QQ号”:“假的”);
-
-
Math类
-
两个常量
E:自然对数的底数
PI:圆周率 -
普通方法
abc(数字类型):返回该参数的绝对值
cbrt(double d):返回d的开立方根
sqrt(double d):返回d的正平方根
ceil(double d):返回d的向上取整
floor(double d):返回d的向下取整
max(int a,int b):返回a,b的较大值(重点)
min(int a,int b):返回a,b的较小值(重点)
pow(int a,int b):返回a的b次幂
random():返回0.000-0.999的随机数(重点)
-
-
System类
该类不用创建对象,且没有构造方法。
-
常用字段
System.in 标准的输入流
System.out 标准的输出流
System.err 标准的错误输出流(在控制台红色的打印 System.err.println 一般用于异常的输入) -
普通方法
public static long currentTimeMillis() 获取系统当前的毫秒值 是从 1970 01-01 开始计算
public static void exit(int status) 终止 jvm 运行 参数是0表示正常终止, 非0非正常终止
public static void gc(): 回收垃圾 (gc : 垃圾回收器 ) -
垃圾回收,gc问题
在开发里常常遇到gc问题:
1.内存溢出:内存已经满了,没有空间来开辟新的东西了
2.内存泄漏 : 该回收的对象没有被回收
垃圾回收原则:
1.没有任何引用的对象会被回收
2.计数算法:也就是当这个对象被持有引用时都会+1,这个对象的计数是0表示其可以被回收了
3.可欲达算法:在root上直接引用或者间接引用,而有一些不引用root即脱离了root的对象就会或被回收
如果想要一个变量快速回收:使用弱引用或者软引用
如果想慢速回收:使用强引用 static 变量就是强引用 最难被回收在开发中不建议使用的:
1.静态 2. 多线程 3.强引用 4. 监听器 5.如果不用了 最设置为null
原因:回收慢
-
-
Date类
一个时间对象,需要进行导包 java.util.Date
构造方法-
构造方法
public Date() 返回的是当前系统的时间
public Date(long date) 传入的是毫秒值(去换算) -
普通方法
public long getTime() 得到设置的时间毫秒值
public long setTime() 设置时间毫秒值获取当前Date毫秒值
- 第一种通过Date 对象 new Date().getTime()
- 获取系统当前的毫秒值: System.currentTimeMillis()
-
DateFormat类
一个时间格式化类 , 不能够被实例化(对时间进行格式化)
具体的子类 SimpleDateFormat-
格式化的方法
public String format(date) 返回的是一个字符串
eg: new simpleDateFormat().format(Date) ==> 把Date 对象 转换为字符串格式
public Date parse(String text) 把时间字符串转换成Date对象
eg:new simpleDateFormat().parse(“2018-08-15”) 把标准的时间字符串格式 转换成一个Date对象
-
-
例子
分析以下需求,并用代码实现:
(1)通过键盘录入日期字符串,格式(2015-10-20)
(2)输出该日期是星期几及这一年的第几天
(3)如输入:2015-10-20,输出"2015年-10月-20日 是 星期二,是 2015年的第 293 天"
具体代码:
public static void main(String[] args) throws ParseException {
System.out.println(showDate());} //2015-10-20,输出"2015年-10月-20日 是 星期二,是 2015年的第 293 天" public static String showDate() throws ParseException {
Scanner input=new Scanner(System.in);
System.out.println(“输入日期(格式为年-月-日):”);
String date=input.nextLine();
Date d = new SimpleDateFormat(“yyyy-MM-dd”).parse(date);
SimpleDateFormat sdf=new SimpleDateFormat(“yyyy年-MM月-dd日是E,是yyyy年的第D天”);
return sdf.format(d);}
-
-
Calendar类
需要导包 java.util.Calendar ==》日历对象
Calendar 类是一个抽象类 不能被实例化
通过调用 Calendar.getInstance();-
获取 Calendar
常用的方法来获取 : public int get(int field)
eg:int year=cal.get(Calendar.YEAR) -
常量
1.获取当前的年份 Calendar.YEAR
2.获取月份 Calendar.MONTH 这个月份需要+1
3.获取日 Calendar.DAY_OF_MONTH
4.获取小时 Calendar.HOUR_OF_DAY
5.获取分钟 Calendar.MINUTE
6.获取秒 Calendar.SECOND
7.获取星期几 Calendar.DAY_OF_WEEK (获取星期的时候需要 -1)
8.获取当前的 时区 cla.getTimeZone()- 表示上午: 获取的是Calendar. AM
10.表示下午: 获取的是 Calendar.PM
- 表示上午: 获取的是Calendar. AM
-
设置
- public int set(int field)
设置时间: public final void set(int year, int month,int date, int hourOfDay,int minute)
-
-
枚举类
枚举类 :枚举类里都是常量
定义枚举的产量的时候 一般都是大写
每一个常量都是以逗号进行分割-
例子
public enum Daily {
Mon,Tue,Wed, Thus, Fri, Sat, Sun
}public class Test7 {
public static void main(String[] args) {
study(Daily.Sun);
}
public static void study(Daily daily){
switch (daily){
case Mon:
System.out.println(“学了进程”);
break;
case Tue:
System.out.println(“学了线程”);
break;
case Wed:
System.out.println(“学了集合”);
break;
case Thus:
System.out.println(“学了流对象”);
break;
case Fri:
System.out.println(“学了Date类”);
break;
case Sat:
System.out.println(“自习”);
break;
case Sun:
System.out.println(“睡觉”);
break;
default:
System.out.println(“超时空”);
break;}
}
}
-
-
集合
对象数组:
语法:类名[] 对象名=new 类名[5];
缺点:扩展性差,数组本身的长度是固定的,一旦创建就无法修改
所以有了集合。
集合:集合也是一个容器,用于存数据。
-
数组与集合的区别
相同点:
1.数组与集合都是用来存数据, 都可以通过索引来获取数据
2.数组与集合都是采用数组的方法来进行存的
不同点:
1.数组可以存基本数据类型,也可以存引用数据类型,而集合只能够存引用数据类型
2.数组的长度是固定的,集合的长度是可变的 -
集合的分类
-
单列集合Collection(根接口)
每个元素都是一个单独的个体
Collection 层次结构中的根接口,索引也是从0开始-
子接口
-
List接口
导包 java.util是一个接口
有序的子接口,有序,有索引,可以重复-
普通方法
public void add(int index, E element) 根据索引的位置来进行添加
E get(int index) 根据索引来获取其值
E remove(int index) 根据索引来进行删除
E set(int index, E element) 也是替换 (前提这个已经存在)
总结: 这些方法都是根据索引来进行操作的 -
ArrayList
1.有顺序 2. 有索引 3.可以重复 5.线程不安全 6.插入慢,查询快
以数组的方式来存数据 :特点 :查询快 增加 删除修改慢 (最常用的)
-
方法
add() 添加(默认也是向末尾添加数据)
get(index) 获取,根据索引来获取 ( 最常用的)
-
-
LinedList
特点: 增加 删除 修改 速度快,效率高 查询慢,插入快
两个构造 : 一般使用空的构造
-
方法
public void addFirst(E e) 插入数据到集合的头部
public void addLast(E e) 插入到末尾 注意点: 比评查插入的效率要高
public E getFirst() 拿到集合中 第一个元素
public E getLast() 获取最后一个数据
public E removeLast() 移除最后一个元素
public E removeLast() 移除第一个元素
-
-
Vector
线程安全 线程安全的, 已经被ArrayList替换,也是以数组的方式来进行存 (了解) 构造方法与 ArrayList 是一样的 - 方法 public void addElement(E obj) 向末尾来添加数据 public E elementAt(int index) 根据索引来获取 public boolean removeElement(Object obj) 删除集合里的对象 Element 都是根据节点来进行操作
-
-
Set接口
无序的子接口,因为没有索引,不可以用普通的for循环俩遍历,不能包含重复的元素
set集合不能够值重复 :常规的方法跟 Collection是一样的
- HashSet
1. 基层存 是由哈希表结构进行存(查询速度快) 2. 不能包含重复的元素,可以包含"" 的数据 用于检查是否重复,执行了两个方法 第一个是HashCode方法 第二个是equals()方法 3.无序(不能使用普通的for循环) :存入的数据顺序与取出来的顺序不一样 - 方法 HashSet 常规的方法: add(E e) 添加 - 子类LinkedHashSet LinkedHashSet(有序): 父类是HashSet(无序) 存的方式是采用的数据+ 双重链表式 第一种链表式用于来把相同hash值的元素进行串联 第二种链表式来记录每一值的顺序 有序的:存与取都是一致的 - 子类TreeSet 二叉数存储 底层数据结构是红黑树(红黑树是一种自平衡的二叉树) 根据元素实际值来进行排序.(可以确保元素唯一并且元素排序)
-
遍历set集合
-
使用没有泛型 转换成数组的方式
1.第一种使用没有泛型 转换成数组的方式
Object[] o= set.toArray();//返回的是Object类
for (Object ob:o){
System.out.println(ob);
} -
迭代器
2.使用迭代器的方式
Iterator iter=set.iterator();
while (iter.hasNext()){
System.out.println(iter.next());
} -
增强for 循环
3.使用增强for 循环的方式
for (Object obj:set){
System.out.println(obj);
} -
使用带泛型,转换成数组
4.使用带泛型,转换成数组的方式
HashSet set = new HashSet();
set.add(“苍老师”);
set.add(“波多老师”);
String [] str = set.toArray(new String[]{});
for(int i =0;i<str.length;i++){
System.out.println(str[i]);
}
-
-
-
父类方法
boolean add(E e) 添加,返回值是bealoon 添加成功返回true
boolean contains(Object o) 判断是否有此元素 如果存在返回true 否则false
boolean isEmpty() 判断集合里是否有元素
boolean remove(Object o) 根据集合里的元素进行删除
int size() 获取到集合的长度
Object[] toArray() 把集合转换成数组
void clear() 清空数组里的所有的元素
iterator() 把集合转换成迭代器的方法
所有带All 的方法:- addAll(Collection<? extends E> c) 把小集合添加到大集合里, 例如: co.addAll©; 把集合 c的所有数据添加到co
- boolean containsAll(Collection<?> c) 如果此 collection 包含指定 collection 中的所有元素,则返回 true。
- removeAll(Collection<?> c) 返回值:如果存在交集返回 是true , 返回的是没有较交集的数据
- retainAll(Collection<?> c) 返回值 判断是否发生该变,如果发生该变返回true,不发生该变返回false 取出来的是交集的结果
-
遍历集合
-
普通for循环
-
增强for 循环
增强for 循环的底层也是使用迭代器来实现,也是通过指针
-
迭代器
Iterator : 是一个接口,不能够被实例化
java.util.ConcurrentModificationException 对象的并发修改
ListIterator 这个迭代器是针对list 集合而存在, 它的父类也是Iterator-
普通方法
hasNext() 判断是否有下一个元素, 如果有返回true
Next()获取到下一个元素
remove() 移除迭代器的某一个元素 -
语法
while 循环 (迭代器.hasNext()){
next() // 获取其元素
}
-
-
-
-
泛型
对,类 ,接口后者方法的一个约束,泛型其实就是一个参数来替换所有的类型 (泛型中没有继承)。
场景: 当不知道集合存什么类型的数据的时候就使用泛型。在jdk1.7之后 ArrayList list = new ArrayList<>(); (注意点就是后面<>里的可以省略,前面不可以进行省略)
在jdk1.7之前 ArrayList list = new ArrayList();必须这样写, 前后的泛型类型必须是一样-
作用
没有泛型:
好处: 默认如果没有添加泛型,默认的是Object, 所有的数据类型都可以进行存
坏处:不安全,会报错(java.lang.ClassCastException) 强制类型转换错误有泛型后:
好处: 1.避免强制转型 2.把错误由运行出错提前到编译出错
坏处: 只能够存一种数据类型
注意点:如果使用迭代器来遍历集合,迭代器的泛型必须与集合的泛型是一样的 -
泛型约束类
public class ArrayList
语法: 访问修饰符 关键字(class) 类名<泛型>{
类里的具体的内容
}注意点 :
1.在 写这个类的具体的信息的时候,没有给其具体的类型
2.也就是在new 的时候给其具体的类型
3.当给类加泛型之后,类里所有的都可以使用这个泛型 -
泛型约束方法
语法 : 访问修饰符<泛型> 返回值类型 方法的名称(参数(参数可以使用泛型的数据类型)){
方法体
}
例子: 给方法加泛型的语法
public void printWorld(T t){
System.out.println(t);
}
注意点:在调用其方法的时候知道其泛型静态方法:也可以加泛型:
注意点:静态方法不能使用类的泛型的,只能有方法的泛型 -
泛型约束接口
语法:
访问修饰符 interfance 接口的名称{
抽象方法
}
例子:
public interface Iter {
}如果接口有泛型,实现类有两种表现形式:
1.实现类确定具体的泛型了- 实现类不能够确定其泛型(也就是在 new 的时候确定其泛型)
第二种情况的语法: public class IterUpdateImpl implements IterUpdate {}
- 实现类不能够确定其泛型(也就是在 new 的时候确定其泛型)
-
泛型通配符
? 任意的泛型
<? extends E> 这种表示 是 E 泛型的子类或者是它本身 <? super E> 这种表示是 E 泛型的父类或者它本身
特点:
1.不能在实例化的时候给?泛型
2,一般是作为参数的类型
-
-
双列集合Map(根接口)
每个操作都是针对一对数据来进行的,一对数据作为一个单位(以键值对存key、values)
map 里的键都是唯一的,不能够重复, values是可以重复,每一个键只能对应一个值(一一对应,就是映射的关系)-
子类(实现类)
-
HashMap
HashMap : 父接口是map 它的存储方式也是以hash表的结构来进行存储 (无序)
-
HashMap 与HashSet 的关联
1.都是以hash表结构来进行存储(查询速度快) HashSet 相当于 map 里没有values 那一部分,只用去关注键的那一部分(hash值 与equals()来判断键是否重复)
2.HashMap: 只关注键,不关注值(任意的值都可以,还可以重复 ) -
子类LinkedHashMap
数组加上双重链表来进行存储, 有序
-
-
Hashtable
Hashtable 类表示了一个持久的属性集 可以当成是一个map使用
-
与HashMap 的区别
- 版本不一样: Hashtable 1.0 HashMap 1.2
2 Hashtable 不符合命名规范 HashMap 是符合 - Hashtable 线程安全,效率地 HashMap 线程不安全 ,效率高
- HashMap 已经替换掉 Hashtable 常用hashMap
- 版本不一样: Hashtable 1.0 HashMap 1.2
-
子类Properties
-
构造方法
public Properties()
-
普通方法
1.加载流的资源的方法 public void load(InputStream inStream)
2.获取值的方法 public String getProperty(String key)- public Object setProperty(String key,String value) put() 设置值
- public void store(OutputStream out,String comments) 把修改的数据结合流对象放入到文件里
- public Set stringPropertyNames() 获取到所有的键的方法
————————————————
-
遍历
遍历的两种方式:
1.获取到所有的键 stringPropertyNames() 返回的是一个set集合
2.继承了hashtable 使用第二种遍历方法 : entrySet() 返回值是一个 Map.Entry -
读取配置文件
开发中用的最多的就是读取配置文件:
1.需要实例化这个对象 Properties
2.使用方法加载流对 load(InputStream)
3.就可以同键值对来获取数据 getProperty(String key)
————————————————
-
-
-
TreeMap
-
-
Map普通方法
添加的方法: V put(K key,V value) 通过键值对来进行添加
移除的方法: V remove(Object key) 通过键来删除键值对 (没有根据索引来移除)
判断类型的方法:
boolean containsKey(Object key) 判断这个键是否存在boolean containsValue(Object value) 判断这个值是否存在
boolean isEmpty() 是否存在元素
获取性的方法:
void clear() 清除所有的元素V get(Object key) 通过键来获取值
int size() 获取集合的长度
Collection values() 获取所有的values()
Set keySet() 获取map中所有的键 返回值是一个Set
修改: put(K key,V value) 根据键来修改值,键必须存在
-
遍历集合
- 获取到所有的key,来得到具体的值
- 把每一组数据当成是一个整体来进行遍历
-
第一种遍历
-
迭代器
获取所有键
Set set = map.keySet();
// 转换成迭代器
Iterator iter = set.iterator();
// 使用迭代器
while (iter.hasNext()){
Integer key =iter.next();
System.out.println(key+"---->"+map.get(key));
} -
增强for循环
获取所有键
Set set = map.keySet();
for (Integer in :set){
System.out.println(in+"—>"+map.get(in));}
-
-
第二种遍历(Entry)
// 把每一组当做一个整体
Set<Map.Entry<Integer,Student>> set = map.entrySet();
// 转换成迭代器
Iterator<Map.Entry<Integer,Student>> iter = set.iterator();
while (iter.hasNext()){
// 当前的每组数据
Map.Entry<Integer,Student> entry = iter.next();
// 得到键得到值
System.out.println(entry.getKey()+"\t"+entry.getValue());}
-
map嵌套map 进行遍历
规律:从外层往内层剥皮
public class Test5 {
public static void main(String[] args) {
Student student1=new Demo4.Student(“小明”,19);
Student student2=new Demo4.Student(“小话”,20);
Student student3=new Demo4.Student(“小红”,18);
Map<Integer,Student> map=new HashMap<>();
map.put(1,student1);
map.put(2,student2);
map.put(3,student3);
Map<String,Map<Integer,Student>> jobMap=new HashMap<>();
jobMap.put(“java”,map);
Set set=jobMap.keySet();// 获取外层的jobMap的键值
Iterator iter=set.iterator();// 外层jobMap开始遍历
while (iter.hasNext()){
String key=iter.next();
System.out.println(key); // 输出外层的键值
Map<Integer,Student> innerMap =jobMap.get(key);// 通过get取外层的value值,也就是内层的innerMap(map)
Set innerSet =innerMap.keySet(); // 获取内层的键值
Iterator innerIter=innerSet.iterator(); // 构造内层迭代器
while (innerIter.hasNext()){ // 内层循环遍历
Integer innerKey=innerIter.next();
System.out.println(innerKey+" "+innerMap.get(innerKey));// 获取内层的键值对
}
}
}
}
-
-
Collection 与 Map联系
单列集合(存的数据都是独立)
单列集合的数据结构都是都是具体的数据
单列中的set集合不能出现重复的数据双列集合 (以键值对进行存储)
双列集合的数据结构都是正对与键
双列集合是键不能出现重复的数据
-
IO流
总结的流为:八流
写入:
BufferedWriter ==》 OutputStreamWriter 》FileOutputStream
读出:
BufferedReader》InputStreamReader ==》 FileInputStream
FileReader FileWrite
————————————————
例子:
public static void main(String[] args) throws IOException {
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(“5.txt”),“utf-8”));
bw.write(“中公好”);
bw.newLine();
bw.write(“中公正好\r\n”);
bw.write(“中公真的好\r\n”);
bw.flush();
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(“5.txt”),“utf-8”));
String str=null;
while ((str=br.readLine())!=null){
System.out.println(str);
}
br.close();
bw.close();
}
-
异常
1.在程序运行时发生的错误
2.异常是一个对象throwable-
异常的体系结构
Throwable类:Java 语言中所有错误或异常的超类
Error :严重的错误,一般是jvm报的错, 需要修改源代码
Exception:这个不是很严重的异常,这种异常必须解决
RuntimeException:运行是异常,开发人员不需要去处理,是由jvm来给其处理 -
处理异常
流的异常的处理:
1.io 流异常处理:
1.一定要进行捕获,不要抛给jvm (不包括方法)- 在 finally 关闭资源一定要进行非null判断
-
jvm 处理异常
1.第一种(位置,时间,异常的信息)打印出来
2.程序进行终止
如果程序发生了异常,,没有任何方法或者是类来处理这个异常,最后就有jvm来处理 -
手动处理异常
1.抛出异常,让调用值去处理 (捕获异常)
2.自己来处理
处理异常的五个关键字: try catch finally throw throws-
第一种
语法:
try {
有可能发生异常代码}catch (异常的类型 的申明,比如控制针异常,算术异常等等){ 发生异常之后执行 这里面的代码 }
常见的异常:
ArithmeticException 算术异常:
ParseException 格式转化异常错误
java.lang.NullPointerException 空指针异常
第一种方式处理多个异常:
try {
有可能发生异常代码}catch (异常的类型1的申明){ 发生异常类型1之后执行 这里面的代码 }catch (异常的类型1的申明){ 发生异常类型2之后执行 这里面的代码 }
注意点:
- catch 里的代码必须与进行匹配,才能满足条件,走 catch 代码块
- 多个 catch 异常的时候,必须先写小的异常,再写大异常
-
第二种(常用)
try {
有可能发生异常代码}catch (异常的类型1的申明){ 发生异常类型1之后执行 这里面的代码 }catch (异常的类型1的申明){ 发生异常类型2之后执行 这里面的代码 }finally { 不管发生不发生异常都会执行这里面代码 }
注意点:
1.如果遇到return 关键字,先执行完finally里的代码,然后再return ,只有这种方式杀死jvm(System.exit(0))2作用: 关闭与释放资源(一般是对流资源)
3.在jdk1.7 之后是catch 申明是可以存在多个异常 用|连接
- 在开发中,如果有多个异常:最后都会捕获一个最大是异常也是Exception
5.捕获异常,如果具体到某一种类型的异常,尽量具体一点:方便解决问题
-
第三种
(不常用) try {
可能发生异常的代码, 并没有具体去捕获}finally { 不管发生不发生异常都会执行这里面代码 }
好处: 让代码进行分离,结构更加清晰
-
-
异常的分类
编译时异常: 也就是在运行之前就报错(编译时异常 的父类是Exception
运行时异常 :RuntimeException 或者是它的子类
编译异常必须进行处理, 运行时异常 可以暂时不处理 (jvm)-
方法
Throwable子类没有什么特别的方法
public StackTraceElement[] getStackTrace() 打印其堆栈信息,(也就异常信息)
public String getMessage() 返回此 throwable 的详细消息字符串。
public String toString() 返回此 throwable 的简短描述
-
-
throw:声明
异常的声明或者是定义(声明)
声明异常的格式: throw new NullPointerException(); throw(关键字)+ 具体的异常好处:可以在方法里声明自己想声明的异常
注意点:
-
声明的异常必须写在方法里
-
声明的异常必须是Exception 是子类或者是自己
-
声明的异常如果是运行时异常可以不做处理,其它的都要做处理
-
-
throws: 抛出
好处: 自己不处理,让调用这去处理
语法: throws Exception 也就是 throws 加上具体的异常注意点:
1.必须写在方法的小括号后面
2.声明的异常必须是Exception 是子类或者是自己在异常的处理方式,1.抛出异常 2.捕获
-
自定义异常
继承父类一般分为两种情况
第一个是继承 RuntimeException
第二种是 Exception(常用)
一般自定义异常的名字是:xxxException 以Exception 进行结尾
一般也就是重写其构造:
-
-
File类
一个文件对象 文件和目录路径名的抽象表示形式 导包是java.io.File。
-
路径
绝对路径 也就是根路劲(也就是到具体的盘符)
相对路径 (也就是有参照物)
Windows: 根路径也就是其盘符 UNIX: 表示一个斜杠
注意点:File 类的实例是不可变的;也就是说,一旦创建,File 对象表示的抽象路径名将永不改变 -
方法
-
构造方法
public File(String pathname) 通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例
public File(String parent,String child) parent 表示父级目录路径(字符串), child 表示子目录(字符串)
public File(File parent,String child) 表示父级目录路径(文件对象),child 表示子目录(字符串)
注意点: 只要有父子关系,必须父目录存在 -
创建
创建文件的方法:createNewFile()
创建一个文件夹 public boolean mkdir() 创建一个文件夹
public boolean mkdirs() 如果父目录不存在,一同创建父目录 -
删除
public boolean delete() 删除一个文件 包括空的文件夹
注意点: 不会进电脑垃圾回收站
重命名文件: public boolean renameTo(File dest)
注意点:如果在同一个目录下,是修改其名字,如果不在同一个的目录下是剪切+修改名字 -
判断
public boolean exists() 判断这个文件是否存在
public boolean isDirectory() 判断是否是文件夹
public boolean isFile() 是否是一个文件 -
获取
public String getAbsolutePath() 获取文件的其绝对路径
public String getPath() 获取构造方法传递的那个参数的路径 new File(“d:\1.txt”)
public String getName() 获取文件的名称
public String getParent() 返回上一级目录
public long length() 文件内容的的长度(字节数)
public String[] list() 返回的是改目录下的第一级的所有文件包括文件夹
-
-
递归
所谓递归就是方法自己调用自己
-
例子
键盘录入一个文件夹路径,统计该文件夹下的各种后缀名的文件的个数
public class Test7_1 {
private static HashMap<String,Integer> map = new HashMap<>(); public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.println("请输入你要统计的地址"); String path = input.next(); File file = new File(path); show(file); System.out.println(map); } // 递归文件的方法 public static void show(File file){ // 第一步进行非null判断 if(file !=null){ // 判断是否是文件夹 if(file.isDirectory()){ // 获取下所有的文件 File [] files = file.listFiles(); // 对数组进行非null验证 if(files != null && files.length>0){ // 进行遍历 for(File f :files){ // 如果包含其. if(f.getName().contains(".")){ // 截取.后面的文件后缀名 String fileName = f.getName(); int index = fileName .lastIndexOf("."); String prx = fileName.substring(index); // 防map 有两种情况 第一种情况就是 如果不存在 直接放 // 如果 存在拿到上一次的数据+1 if(!map.containsKey(prx)){ map.put(prx,1); }else{ map.put(prx,map.get(prx)+1); } } // 进行递归 show(f); } } } } }
}
-
-
-
字节流
使用流的时候:
都是导入java.io下的jar包;
需要注意异常;
关闭流,释放资源;都是抽象类
-
输出流OutputStream
把内存的数据写入硬盘中,称为输出流
-
普通方法
public void close():关闭与释放资源;
public void flush():强制性刷新缓存区;
public void write(byte[] b):将字节数组中的数据写入到输出流里;
public void write(byte[] b,int off,int len):将字节数组的数据指定区间写入到输出流里;
public abstract void write(int b):将单个字节写入到输出流里; -
子类
-
FileOutputStream文件输出流(重点)
一般用于向文件写入数据
-
方法
-
构造方法
public FileOutputStream(File file);
public FileOutputStream(String name);
public FileOutputStream(String name,boolean append)append默认是false,表示覆盖- 实例化FileOutputStream的一个对象
- 如果这个文件不存在,会默认创建这个文件
- 把FileOutputStream指向需要写入数据的位置(文件)
-
-
原理与步骤
写入数据的原理:
java–>jvm–>OS(操作系统)–>调用系统的写入方法
写入数据的基本步骤:
实例化对象==》调用其写入方法==》关闭资源
-
-
(对象流)ObjectOutputStream对象输出流
把对象写入到文件里
-
构造方法
public ObjectOutputStream(OutputStream out) 需要来传递OutputStream 可以构建一个文件地址或者是文件
-
写入方法
public final void writeObject(Object obj) 这个方法就是写一个对象
使用步骤:
1.实例化ObjectOutputStream
2.调用写的方法
3.关闭资源 -
序列化
序列化: 对象从内存到其他设备的过程。(把对象转换成字节序列==>才能保存在文件里 )
反序列化:对象从其他设备到内存的过程。(把字节序列转换成对象 ==> 方便读取 )
-
实现步骤
写对象的时候必须序列化:
步骤:
1.实现序列化的接口
Serializable
2.需要生成一个唯一的表示符 -
序列化异常
java.io.NotSerializableException api:当实例需要具有序列化接口时,抛出此异常 (序列化异常)
serialVersionUID 相当于对象序列化的唯一表示符, 如果在序列化的时候,不加这个标识符系统会给.
生成一个标识符, 只要修改类的信息就会生成一个新的表示符 ,所有产生了这个问题: 解决方式:给其生成一个标识符UID
-
-
-
FilterOutputStream过滤器输出流
-
子类BufferedOutputStream
BufferedOutputStream是FilterOutputStream的直接子类,内部封装了一个字节数组(自带缓冲区)
-
方法
-
构造方法
public BufferedOutputStream(OutputStream out)
-
写入方法
public void flush():刷新此缓冲的输出流(也就是把缓冲区的数据写入到文件里)
void write(byte[] b, int off, int len):将指定byte数组中从偏移量off开始的len个字节写入此缓冲的输出流;
void write(int b):要写入的字节的长度;
————————————————
-
-
子类BufferedWriter
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
-
构造方法
public BufferedWriter(Writer out) 传递了 一个Writer 对象
-
写入方法
public void newLine() 等同于"\r\n" ==>也就是换行
使用缓冲区流来写入数据的一个基本步骤:
1.实例化 BufferedWriter
2.调用其write()
3.关闭资源
-
-
-
PrintStream打印流
-
构造方法
- public PrintStream(File file)
2.public PrintStream(File file,String csn) 第一个参数是文件对象 第二个参数是设置字符编码集 - public PrintStream(OutputStream out,boolean autoFlush) 第一参数是一个输出流对象, 第二个参数是 是否自动刷新缓冲区
- public PrintStream(File file)
-
普通方法
public void print(long l)
public void println(long l)
public void write(int b)
-
-
-
ByteArrayOutputStream内存输出流
内存流: 把数据保存到内存里
-
构造方法
public ByteArrayOutputStream() 因为所有的输入流对象都会传递一个文件的参数而这个对象的构造没有这个参数,所有需要借助其它的流对象.
-
普通方法
public byte[] toByteArray()创建一个新分配的 byte 数组。
public String toString()转换为字符串
close() 关闭 ByteArrayOutputStream 无效。
-
-
PipedOutputStream管道输出流
-
-
-
输入流.InputStream
把硬盘的数据读取到内存中,称为输入流
-
普通方法
public int available():返回的是当前输入流里的字节数;
public void close():关闭资源的方法;
public abstract int read():一个一个字节读取(返回值是读取的具体数据《内容为0-127,对应ASCAII码表,如果是其他,对应系统的编码格式返回int类型》返回-1,表示读取完毕),每调用一次,指针往后移一个单位;
public int read(byte[] b):把数组读取到字节数组里(数组就是缓冲区,一般数组长度为1024的倍数),返回值是读取的有效字符长度;
public int read(byte[] b,int off,int len):可以读取指定区间的数据,off起始位置,len长度; -
子类
-
FileInputStream文件输入流
一般用于从文件中读取数据
-
方法
-
构造方法
构造方法:
public FileInputStream(File file);
public FileInputStream(String name)步骤:
创建FileInputStream的对象
把FileInputStream对象指向需要读取的文件的位置
-
-
原理与步骤
读取数据的原理:
java–>jvm–>OS(操作系统)–>调用系统的读取方法
读取数据的基本步骤:
实例化对象==》调用其读取方法==》关闭资源
-
-
(对象流)ObjectInputStream对象输入流
把文件中的对象读取出来
注意点: ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化-
构造方法
ObjectInputStream(InputStream in)
-
读取方法
读对象的方法:
public final Object readObject()步骤:
1.实例化ObjectInputStream
2.调用读的方法
3.关闭资源 -
例子
public class Student implements Serializable{
两种构造+set和get方法
}下面是输出多个对象两种方法:
public static void main(String[] args) throws IOException, ClassNotFoundException {
// // 第一种循环输出多个对象
// ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(“7.txt”));
// oos.writeObject(new Student(“林俊杰”,19));
// oos.writeObject(new Student(“周杰伦”,20));
// oos.writeObject(null);
// oos.close();
// ObjectInputStream ois=new ObjectInputStream(new FileInputStream(“7.txt”));
// Object obj=null;
// while ((obj=ois.readObject())!=null){
// System.out.println(obj);
//
// }// 第二种用集合封装好再输出 ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("8.txt")); ArrayList<Student> list=new ArrayList<>(); list.add(new Student("林俊杰",19)); list.add(new Student("周杰伦",20)); oos.writeObject(list); oos.close(); ObjectInputStream ois=new ObjectInputStream(new FileInputStream("8.txt")); ArrayList<Student> list1=(ArrayList<Student>) ois.readObject(); System.out.println(list1);
}
-
-
FilterInputStream过滤器输入流
-
子类BufferedInputStream
FilterInputStream的直接子类,内部封装了一个字节数组(自带缓冲区)
-
方法
-
构造方法
public BufferedInputStream(InputStream in)
-
读取方法
public int read();
public int read(byte[] b,int off,int len);
-
-
子类BufferedReader
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取(速度快,效率高)
-
构造方法
public BufferedReader(Reader in) 需要传递一个Reader 对象
-
读取方法
public String readLine() 读取一行数据 返回值是读取的当前数据
使用缓冲区流来进行读取的步骤:
1.实例化 BufferedReader
2.调用 readLine()
3.关闭资源
-
-
-
-
ByteArrayInputStream字节输入流
-
PipedInputStream管道输入流
-
SequenceInputStream合并(流)输入流
-
-
-
-
字符流
-
读取字符流Reader
用于读取字符流的抽象类
-
子类InputStreamReader(转换流)
InputStreamReader: 字节流通向字符流的桥梁
建议:为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader
-
子类 FileReader
FileReader 来读取字符文件的便捷类 ==> super(new FileInputStream(file)); 还是转换为字节流开始读取 == > GBK 因为GBK 里两个负数表示一个汉字,读取到两个负数之后再把其合拼起来,正数就直接显示了.
注意:FileReader 用于读取字符流。要读取原始字节流,请考虑使用 FileInputStream
-
构造方法
public FileReader(File file) 参数是一个文件的名称
public FileReader(String fileName) 文件的路径
构造的书写过程:- 实例化这个FileReader
- 把这个FileReader 对象指向要读文件的位置
-
普通方法
int read() 读取单个字符。
int read(char[] cbuf, int offset, int length) 将字符读入数组中的某一部分。 -
FileReader使用步骤:
1.实例化这个类 2.调用其read()方法 3. 关闭资源
-
读取方式
1.一个一个字符进行读取,
2.读取多个
-
-
方法
-
构造方法
public InputStreamReader(InputStream in,Charset cs)
第一个参数是一个 InputStream 第二个参数传递的是要设置的编码格式 -
普通方法
常规的方法:
read() -
使用步骤
- 实例化InputStreamReader
- 调用其读的方法
3.关闭资源
-
-
-
方法
int read() 读取单个字符。
int read(char[] cbuf) 将字符读入数组。
int read(char[] cbuf, int off, int len) 指定数组读取的范围
-
-
写入字符流Writer
写入字符流的抽象类
-
子类 OutputStreamWriter(转换流)
字符流通向字节流的桥梁
建议:为了获得最高效率,可考虑将 OutputStreamWriter 包装到 BufferedWriter 中,以避免频繁调用转换器-
子类 FileWriter
FileWriter: 用来写入字符文件的便捷类
注意点:用于写入字符流。要写入原始字节流,请考虑使用 FileOutputStream
-
构造方法
FileWriter(File file)
FileWriter(String fileName)
构造的书写过程:
1.实例化这个FileWriter- 如果这个文件不存在会创建文件
- 把 FileWriter 执行要写入文件位置
-
FileWriter使用步骤
1.实例化这个对象
2.调用其写的方法: 用FileWriter 来写自带一个缓冲区(也就是将字符转换成字节)
3.调用其flush() 方法 , 将缓冲区里的数据刷到文件里
4.关闭资源
-
-
方法
-
构造方法
public OutputStreamWriter(OutputStream out,Charset cs)
第一个参数是: 输出流对象 , 第二个:设置编码格式 -
普通方法
常规的方法:
write() -
使用步骤
- 实例化OutputStreamWriter
- 调用其写的方法
3.关闭资源
-
-
-
方法
close() 关闭此流,但要先刷新它。
abstract void flush() 刷新该流的缓冲。
void write(char[] cbuf) 写入字符数组。
abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分。
void write(int c) 写入单个字符。
void write(String str) 写入字符串。
void write(String str, int off, int len) 写字符串的指定的一部分
-
-
-
随机流(不属于io流)
随机流 此类的实例支持对随机访问文件的读取和写入 父类是 Object 不属于io流之内
-
构造方法
构造方法: public RandomAccessFile(String name,String mode) 第一个参数传递的是路径 , 第二个参数传递的是模式值。
mode含义:
“r” 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
“rw” 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。
“rws” 打开以便读取和写入,对于 “rw”,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
“rwd” 打开以便读取和写入,对于 “rw”,还要求对文件内容的每个更新都同步写入到底层存储设备。 -
普通方法
seek(long pos) 设置指针的偏移量
getFilePointer() 获取指针的偏移量
read() 读
write(int b) 写
-
多线程
并发(高并发) ==>在同一个时间段,来执行两个或者是多个操作 (交替执行) (一人吃两个馒头)
并行 ==> 在同一个时刻执行,两个或者是多个操作 (两个人吃两个馒头)
进程: 一个正在运行程序,在内存里开辟过空间 比如查看电脑的进程: ctrl+alt+delete
线程:表示每一条执行的路径
进程与线程之间的关系:
一个进程里可以存在多个线程, 而一个线程只能在一个进程里
。
单纯的执行main 方法:属于单线程,从上到下执行
-
实现多线程
-
第一种继承Thread类
==> run() 如果直接调用run 是在主线程里执行,没有cpu新开辟一条执行的路径
==>start() 只有调用这个方法才会去开辟一条心的路径注意点:
一个线程只能够开启一次,重复开启会产生错误: java.lang.IllegalThreadStateException-
步骤
继承线程类Thread 。Java 虚拟机允许应用程序并发地运行多个执行线程
实现多线程的步骤:- 创建一个Thread 的子类
- 重写其run() run方法也就是子线程要执行的操作
3 实例化这个子类 - 调用 start() 开启线程`
-
-
第二种实现Runnable接口
-
步骤
实现的步骤:
1.定义一个类来实现这个接口- 实现run()方法
3.实例化和这个实现类
4.实例化一个Thread,传递参数是 是这个实现类
5.调用start方法
好处:
1.解决java单继承的问题- 可扩展性增强, 实现申明与调用的分离 降低了耦合度
3.继承Thread 还是实现了这个接口
坏处:实现多线程效率:对于整个系统来说,效率是提高,但是对于具体的某一个线程,效率就是降低
- 实现run()方法
-
-
线程池
-
步骤
1.获取线程池的对象
2.创建任务类对象
3.将任务对象提交到线程池中 -
实现方式
-
第一种
public class RunableImpl implements Runnable{
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println(Thread.currentThread().getName()+"\t"+i);} }
}
public static void main(String[] args) {
RunableImpl runable = new RunableImpl();es.submit(runable); es.submit(runable); es.submit(runable); }
-
第二种
public class MyCallable implements Callable {
private int num;public MyCallable(int num) { this.num = num; } @Override public Integer call() throws Exception { int sum=0; for (int i=0;i<=num;i++){ sum+=i; } return sum; }
}
public static void main(String[] args) {
ExecutorService e= Executors.newFixedThreadPool(1); Future<Integer> f= e.submit( new MyCallable(10)); try { System.out.println(f.get()); } catch (InterruptedException e1) { e1.printStackTrace(); } catch (ExecutionException e1) { e1.printStackTrace(); } }
-
-
-
匿名内部类调用线程
使用类名内部来实现多线程:
第一种方式:
Thread thread = new Thread(new Runnable() {})
第二种方式 :
Thread thread = new Thread(runnable);
Runnable runnable = new Runnable() {}
补充:
第一种方式
Thread 对象名 = new Thread(new Runnable() {
@Override //重写run()方法
public void run() {
执行的操作
}
});第二种方式
Runnable 对象名1 =new Runnable() {
@Override //重写run()方法
public void run() {
执行的操作
}
}
Thread 对象名2 = new Thread(对象名1);
-
-
常规方法
public static Thread currentThread() 返回对当前正在执行的线程对象的引用(也就是当前线程)
getName() 获取线程的名称 线程名字的默认规则是 Thread+i(i 是从0开启)
public final void setName(String name) 设置线程的名称 (一定要在开启线程之前进行设置)
==》也可以通过构造的方式来设置线程的名称: public Thread(Runnable target,String name)
public static void sleep(long millis) 表示让当前线程睡一会,别的线程可以执行了
public final void setPriority(int newPriority) 设置线程的优先级 最小是1 默认是5 最大是10
注意: 设置优先级不一定是最先执行,只是优先执行的机遇更大一点
public final void join() 如果有两个线程: A线程 调用了join方法, A线程执行完成之后,B线程才能执行
注意点- 这个方法必须在线程开启之后进行调用
- 这个方法底层还是调用了wait()方法
public static void yield() 礼让 : 如果有A线程 B线程, 这如果A线程调用了yield() 并不一定b线程就会执行
public final void setDaemon(boolean on) 守护线程 如果A,B 线程 A是被守护线程 B守护线程 如果A终止了,B线程也会终止
public final boolean isDaemon() 判断其是否是守护线程
-
线程安全
当多个线程同时访问某一个类(对象或方法)时,对象对应的公共数据区出现错误。
-
同步代码块
同步代码块
语法: synchronized (){}分析:
同步的关键字 synchronized
() 跟着是对象,这个对象可以是任意的对象
{} 会出现共享数据问题的代码注意点:
1.对象可以是任意的对象
2.三个对象必须是这个锁对象
3.锁对象,保证只有一个线程进入 -
同步方法
也就是同步方法:
1.也就是把可能出现数据问题的代码抽取成一个方法
2.给方法加上锁的关键字
3…锁的对象是 this
注意:
static 修饰的同步方法,使用的锁不是this,而是字节码文件,即类名.class。
所以,要使得是同步,则同步代码块的锁对象必须是字节码文件,如:synchronized (ticket.class) 。 -
Lock接口
Lock是一个接口
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。
此实现允许更灵活的结构实现类:(常规的两个方法: )
public void lock() 获取锁
public void unlock() 释放锁使用步骤:
1.实例化这个对象
2.在同步可以出现数据异常的头部调用其lock()
3.在同步可以出现数据异常的 尾部加上 unlock() (不是特别常用)
-
-
线程通信
在多线程里的通信: 就是两个线程进行交互
-
生产者与消费者模型
-
所需条件
两个角色,一个产品仓库。
两个角色:生产者和消费者
一个产品库:存放数据
两个角色之间属于竞争关系 -
特点
1.生产者只需关心仓库是否为空,不用管消费者
2.消费者也只需关心仓库是否为空,不用关心生产者
3.生产者与消费者之间是互斥关系,即仓库只能其中一者访问到
4.仓库为空时不能进行消费
5.仓库满时不能进行生产 -
具体代码
public class Test {
//肯定要有一个产品类(内部类) static class Product{ //定义一个变量来记录产品的信息 //volatile 这个关键字的作用是 ,数据可视化 //也就是a线程的数据发生改变,b线程可以立马知道 public static volatile String values; } //定义一个生产者的类,实现多线程 static class Producter extends Thread{ // 定义一个产品 Object lock; public Producter (Object lock){ this.lock =lock; } @Override public void run() { // 如果不为空,代表有产品,思考,能保证消费者与生产者的线程只有一个执行, 也就是要加锁 while(true){ synchronized (lock) { if(Product.values !=null){ try { lock.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //生产产品(什么情况下生产产品) Product.values="生产者生产的产品是:"+System.currentTimeMillis(); System.out.println(Product.values); // 通知消费者进行消费(换醒其它线程) lock.notify(); } } } } //消费者 static class Customer extends Thread{ // 也要提供一个产品进行操作 Object lock; public Customer(Object lock){ this.lock = lock; } @Override public void run() { //关键点 消费产品(什么时候进行消费) while(true){ synchronized (lock) { if(Product.values ==null){ // 线程阻塞 try { lock.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // 不同于同null 消费 System.out.println("当前消费的产品是"+Product.values); //消费完成之后,把产品设置为null Product.values=null; // 通知生产者进行生产 lock.notify(); } } } } // 这样就保证线程a 执行一次 , 线程b 执行了一次 public static void main(String[] args) { Object object = new Object(); // 首先生产产品 new Producter(object).start(); // 调用消费者的线程 new Customer(object).start(); }
}
-
-
-
线程生命周期
五种状态:
创建——>就绪——>阻塞——>运行——>死亡NEW
至今尚未启动的线程处于这种状态。
RUNNABLE
正在 Java 虚拟机中执行的线程处于这种状态。
BLOCKED
受阻塞并等待某个监视器锁的线程处于这种状态。
WAITING
无限期地等待另一个线程来执行某一特定操作的线程处于这种状态。
TIMED_WAITING
等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态。
TERMINATED
已退出的线程处于这种状态。
————————————————
版权声明:本文为CSDN博主「须臾亦无穷」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_44413573/article/details/100108726-
线程方法
wait()和notify(),notifyAll()是Object类的方法
void wait() 在其他线程调用此对象的 notify() 方法或者 notifyAll()方法前,导致当前线程等待。void wait(long timeout)在其他线程调用此对象的notify() 方法 或者 notifyAll()方法,或者超过指定的时间量前,导致当前线程等待。
notify()是开启当前锁
notifyAll():开启当前的所有锁interrupt() 中断线程 由运行状态到死亡状态
-
中断线程操作实质上是修改了一下中断标示位为true
-
当前线程正在运行,仅仅修改标示位,不在做其他的事
-
当前线程正在阻塞,修改标识位,如果是join,sleep,yield,则会抛出Interrup异常,修改标示位为false
-
Timer类
定时操作类
一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。-
方法
public void schedule(TimerTask task, long delay)安排在指定延迟后执行指定的任务。参数:task - 所要安排的任务。delay - 执行任务前的延迟时间,单位是毫秒。
public void schedule(TimerTask task, Date firstTime, long period)参数:task - 所要安排的任务。firstTime - 首次执行任务的时间。period - 执行各后续任务之间的时间间隔,单位是毫秒。
类 TimerTask(抽象类)
是实现定时操作的任务对象,由 Timer 安排为一次执行或重复执行的任务。 -
例子
public class MyTimerTask extends TimerTask {
@Override
public void run() {
System.out.println(“小胖你先跑!”);
}
}public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new MyTimerTask(),2000);}
-
-
-
-
-
单例设计模式
单例设置模式 : 有且紧加载一个类, 静态的也可以有且紧加载一次(问题比较多)
单例设计模式 : 只要是这个类在内存里只加载一次, 工具类大部分情况都是的是单例设计模式
三个必须条件:
私有的属性 这个属性是当前类( 外部不能来访问这个属性)
私有的构造 不让外部来实例化这个类,使用私有的构造
公有的方法 提供一个对外的方法,让别人进行访问-
饿汉模式
一开始就实例化出来 ,缺点超级多 : 1.运行就卡 有点 :线程安全
具体代码:
public class DateUtils {
// 私有的属性
private static DateUtils dateUtils=new DateUtils();
// 私有的构造
private DateUtils() {
}
// 公有的方法
public static DateUtils getInstance(){return dateUtils; } public Date dateFormatStr(String str){ try { return new SimpleDateFormat("yyyy-MM-dd").parse(str); } catch (ParseException e) { e.printStackTrace(); } return null; }
}
public static void main(String[] args) {
System.out.println(DateUtils.getInstance().dateFormatStr(“2019-8-27”)
} -
懒汉模式
public class StringUtils {
private StringUtils stringUtils;private StringUtils() { } public StringUtils getStringUtils(){ if (stringUtils==null){ stringUtils=new StringUtils(); } return stringUtils; } public static String getStr(String str){ return new StringBuffer(str.substring(str.length()-2,str.length())).reverse().toString().toUpperCase(); }
}
public class Test5 {
// 懒汉式
public static void main(String[] args) {
System.out.println(StringUtils.getStr(“asdfgh”));
}
} -
双重锁
public class FileCallable {
private static FileCallable fileCallable;private FileCallable() { } public synchronized static FileCallable getIntance(){ if (fileCallable==null){ synchronized (FileCallable.class){ if (fileCallable==null){ return fileCallable }
}
}
return null;
}
}public class FiCallable implements Callable {
@Override public FileCallable call() throws Exception { return FileCallable.getIntance(); }
}
public class FiCallable1 implements Callable {
@Override
public FileCallable call() throws Exception {
return FileCallable.getIntance();
}
}// 双重所
public class Test6 {
public static void main(String[] args) {
ExecutorService es= Executors.newFixedThreadPool(2);
try {
Future f= es.submit(new FiCallable());
Future f1= es.submit(new FiCallable1());
System.out.println(f.get()==f1.get());
} catch (Exception e) {
e.printStackTrace();
}
}
}
-
-
简单工厂者模式
生产产品 (对象) ==> 就是多态的一种体现
体现形式:
1.以父类作为返回值 简单工厂者
2.以父类作为参数-
第一种
以父类作为返回值 简单工厂者
public abstract class Pet {
public abstract void shout();
}
public class Dog extends Pet {
@Override
public void shout() {
System.out.println(“汪汪汪!”);
}
}public class Penguin extends Pet {
@Override
public void shout() {
System.out.println(“嘎嘎嘎!”);
}
}
public class Cat extends Pet {@Override public void shout() { System.out.println("喵喵喵!"); }
}
public interface Factory {
Pet shout();}
public class CatFactory implements Factory{
@Override public Pet shout() { return new Cat(); }
}
public class DogFactory implements Factory {
@Override
public Pet shout() {
return new Dog(); }
}
public class PenguinFactory implements Factory {
@Override
public Pet shout() {
return new Penguin();
}
}public class Test7 {
public static void main(String[] args) {
DogFactory dogFactory=new DogFactory();
Pet pet= dogFactory.shout();
pet.shout();
}
} -
第二种
以父类作为参数
public abstract class Book {
public abstract void read() ;
}public class ChineseBook extends Book {
@Override public void read() { System.out.println("粒粒皆辛苦"); }
}
public class MathBook extends Book{
@Override
public void read() {
System.out.println(“1+1=2”);
}
}public class BookFactory {
Book getRead(String type){
if (“MathBook”.equals(type)){return new MathBook(); }else if ("ChineseBook".equals(type)){ return new ChineseBook(); }
return null;
}
}
public class Test6 {
public static void main(String[] args) {
BookFactory bookFactory=new BookFactory();
bookFactory.getRead(“ChineseBook”).read();}
}
-
网络编程
即是计算机网络: 是不同地区,通过网络来传递数据,来进行数据的交互
-
三大要素
-
IP
ip 是每一台电脑的唯一标识
-
两种分类
ip4:是由0-255组成,是四个字节 一般网络都192.168==>c类网络 a类一般政府(军事用途),
一般子网络是: 10.08 本地的特殊的ip 是 127.0.0.1(this)
查看当前电脑的ip地址 ipconfig 拼服务器是否连通了,也就是拼ip地址(重点)ip6 :是由8个数组数组,四个16精制组成
-
获取IP的类 InetAddress
public static InetAddress getLocalHost() 返回本地主机
public String getHostAddress() 获取ip地址
public String getHostName() 获取ip的主机名:public String getHostName()
-
-
端口号
每一个软件(每一个进程的唯一标识)
当软件开启之后,系统给其生成的一个,也可以自己去设置,
当软件开启是端口号系统产生,当软件关闭的时候,回收 -
协议
各个计算机网络传输的一个规范。
协议分为7层
传输层 : TCP UDP + xmpp 协议 ==> 即时通讯(qq,微信)-
TCP 与 UDP的区别
UDP面向无连接的协议: 传输的数据快,但是可以会丢数据(cts飞q) 会出现卡顿
TCP 面向连接的协议: 传输慢,不会丢失数据(三次握手) ==>qq传消息 文字需要准确性,使用的就是这个协议 -
web主要协议 http https
http 与https==>都是属于一次性的连接==>也就是客户端给服务器发送请求,当交互完,这个请求就断开了
https =http+ssl 证书,这个证书保证数据的传输的安全性 大部分上线的网站都会使用https协议 -
TCP通信
面向协议来进行通信 :TCP 做一个对象。
注意:运行的时候,要先运行服务器,再运行客户端
-
Socket 对象
接字是两台机器间通信的端点。
-
构造方法
public Socket(String host,int port) 如果是本机ip地址传递localhost
传递两个参数 一个ip地址, 一个是端口号 (女孩子的微信号) -
普通方法
public OutputStream getOutputStream()throws IOException 写数据的流对象
public InputStream getInputStream()throws IOException 读取数据的对象
public void shutdownOutput()throws IOException 类似于flush()方法 -
客户端
客户端(女孩子)==> 发送消息的过程
1.实例化这个socket对象
2.通过socket对象 得到输出流 OutputStream
3.调用 write()
4.shutdownOutput()
5.拿到输入流 InputStream
6.new BufferReader(new InputStreamReader(new FileInputStream))
7.关闭资源
-
-
ServerSocket 对象
此类实现服务器套接字
-
构造方法
public ServerSocket(int port) 需要与客户端的端口号一样
-
普通方法
public Socket accept()throws IOException 监听客户端发送的消息,返回一个Socket
-
服务器
1.实例化ServerSocke
- 调用 accept() 返回的是一个socket对象
3.拿到输入流 InputStream - new BufferReader(new InputStreamReader(new FileInputStream))
5.得到OutputStream 对象
6.调用 write()
7.shutdownOutput()
8.关闭资源
- 调用 accept() 返回的是一个socket对象
-
-
多线程解决通信
如果有两个客户端, 一个服务器,就会产生这样一个错误
Connection refused: connect
解决这个问题 : 用多线程解决这个问题 : 解决多个客户端对应一个服务器的问题-
具体代码
// 第一个客户端
public static void main(String[] args) {
try {
Socket socket=new Socket(“localhost”,2328);
OutputStream os=socket.getOutputStream();
//InputStream is=socket.getInputStream();
os.write(“我要吃鸡腿”.getBytes());
socket.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
}
}// 第二个客户端
public static void main(String[] args) {
try {
Socket socket=new Socket(“localhost”,2328);
OutputStream os=socket.getOutputStream();
InputStream is=socket.getInputStream();
os.write(“我要吃大鸡腿”.getBytes());
socket.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
}
}//线程
public class MyThread extends Thread {
private Socket socket;public MyThread(Socket socket) { this.socket = socket; } // 重写服务器代码 run方法 @Override public void run() { try { // ServerSocket serverSocket = new ServerSocket(2328); // Socket socket=serverSocket.accept(); InputStream is=socket.getInputStream(); // OutputStream os=socket.getOutputStream(); BufferedReader br=new BufferedReader(new InputStreamReader(is)); String str=null; while ((str=br.readLine())!=null){ System.out.println(str); } } catch (IOException e) { e.printStackTrace(); } }
}
// 服务器
public static void main(String[] args) {
try {
ServerSocket serverSocket=new ServerSocket(2328);
Socket socket=null;
while (true){
socket=serverSocket.accept();
MyThread myThread=new MyThread(socket);
myThread.start();/* InputStream is=socket.getInputStream(); OutputStream os=socket.getOutputStream(); BufferedReader br=new BufferedReader(new InputStreamReader(is)); String str=null; while ((str=br.readLine())!=null){ System.out.println(str); } socket.shutdownInput(); socket.close(); */ } } catch (IOException e) { e.printStackTrace(); } }
-
-
实现文件上传
客户端:
1.读取出需要上传的图片
2 .通过socket拿到的输出流写入到服务器服务器:
1.通过socket拿到输入流把图片读取出来
注意:(1.需要创建一个文件夹来保存所有的图片,2.避免图片被覆盖)2.保存在本地
以上都是基于tcp协议来进行操作的:面向连接 传输的时候不会丢失数据,但是传输慢
-
具体代码
// 客户端
public static void main(String[] args) {
try {
FileInputStream fis=new FileInputStream(new File(“D:\小电影2\刘亦菲.jpg”));
Socket socket=new Socket(“localhost”,10110);
OutputStream os = socket.getOutputStream();
byte[] b=new byte[1024];
int leng=-1;
while ((leng=fis.read(b))!=-1){
os.write(b,0,leng);} socket.shutdownOutput(); os.flush(); os.close(); } catch (IOException e) { e.printStackTrace(); }
}
// 服务器
public static void main(String[] args) {
try {
File file=new File(“E:\图片库”);
if (!file.exists()){
file.mkdirs();
}
String str=System.currentTimeMillis()+"";
File file1=new File(file,str+".jpg");
FileOutputStream fos=new FileOutputStream(file1);ServerSocket serverSocket=new ServerSocket(10110); Socket socket=serverSocket.accept(); InputStream is= socket.getInputStream(); byte[] b=new byte[1024]; int leng=-1; while ((leng=is.read(b))!=-1){ fos.write(b,0,leng); fos.flush(); } socket.shutdownInput(); fos.close(); } catch (IOException e) { e.printStackTrace(); } }
-
-
-
UDP通信
基于UDP协议进行传输,类似于发包裹。
传输的类主要是 DatagramSocket 此类表示用来发送和接收数据报包的套接字。
-
DatagramSocket对象
-
重要构造方法
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
DatagramPacket(byte[] buf, int length)
DatagramPacket 此类表示数据报包 (包裹对象)
第一个参数是 字节数组
第二个参数是从字节数组的什么地方开始
第三个是到什么结束
第四个:获取的ip对象
第五个就是端口号 -
重要普通方法
public SocketAddress getSocketAddress() 返回的就是SocketAddress
public byte[] getData() 获取缓冲区的数据 -
构造方法
public DatagramSocket(int port,InetAddress laddr) 第一个数端口号 第二个参数是地址
public DatagramSocket(int port)参数是端口号 -
普通方法
public void send(DatagramPacket p)throws IOException 发送数据包
public void receive(DatagramPacket p)throws IOException 接收数据包 -
发送端
1.实例化这个对象
2.构建一个数据包
3…发送数据
4.关闭资源 -
接收端
- 实例化这个对象DatagramSocket
- 构建一个包裹对象
3.接收数据 receive()
4.关闭资源
-
例子
// 客服端
public static void main(String[] args) {
try { while (true){ //String str="你好,我是客服端!"; String str=new Scanner(System.in).next(); DatagramSocket datagramSocket=new DatagramSocket(); InetAddress inetAddress=InetAddress.getByName("localhost"); DatagramPacket dp=new DatagramPacket(str.getBytes(),0,str.getBytes().length,inetAddress,8990); datagramSocket.send(dp); // 接收信息 byte[] b=new byte[1024]; DatagramPacket dp1=new DatagramPacket(b,b.length); datagramSocket.receive(dp1); byte[] by= dp1.getData(); System.out.println(new String(by,0,by.length)); } } catch (IOException e) { e.printStackTrace(); } }
// 服务器
public static void main(String[] args) {
try { DatagramSocket datagramSocket=new DatagramSocket(8990); while (true){ byte[] b=new byte[1024]; DatagramPacket dp=new DatagramPacket(b,b.length); datagramSocket.receive(dp); byte[] by=dp.getData(); System.out.println(new String(by,0,by.length)); // 回复信息 //String st="我已经接收到了。"; String st=new Scanner(System.in).next(); SocketAddress address=dp.getSocketAddress(); DatagramPacket dp1=new DatagramPacket(st.getBytes(),0,st.getBytes().length,address); datagramSocket.send(dp1); } } catch (IOException e) { e.printStackTrace(); } }
-
-
-
-
-
套接字的定义
应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题。
多个TCP连接或多个应用程序进程可能需要 通过同一个TCP协议端口传输数据。
为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字 (Socket)的接口,区分不同应用程序进程间的网络通信和连接。
反射
在程序运行过程中,可以对任意一个类型进行任意的操作。
将各个类的每一部分封装成一个class对象
好处:
1.可以修改正在运行的代码(热修复)==.》通过反射技术来修改上线的bug
2.所有框架的编写必须用到这个对象
-
class对象
把文件读到控制台的代码
注意:文件是包加类名
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(“1.txt”)));
String str=null;
Class c=null;
while ((str=br.readLine())!=null){
c=Class.forName(str);
}
System.out.println©;-
获取字节码对象方法
第一种:(对象名.getClass)
Student student = new Student();
Class c = student.getClass();
第二种:(类名.class)
Class c1 = Student.class;
第三种:( Class.forName(参数是***包名+类名***))
Class c2 = Class.forName(“com.offcn.day24.test.Student”) -
常用的方法
public T newInstance() 表示实例化一个对象
-
获取所有构造方法
public Constructor<?>[] getConstructors() 获取所有的公有的构造
public Constructor<?>[] getDeclaredConstructors() 获取所有的构造,包含私有(受保护的)代码:
Class c=Class.forName(“Demo1.Student”);
Constructor con =c.getConstructor(String.class,int.class);
Student student=(Student) con.newInstance(“林俊杰”,20);
student.show(); -
获取单个构造方法
public Constructor getConstructor(Class<?>… parameterTypes) 获取是当个公有的构造,参数是构造参数的数组,
public Constructor getDeclaredConstructor(Class<?>… parameterTypes) 获取私有的构造方法(其中… 表示可以传递多个参数)代码:
System.out.println("++++++++++++++++++暴力反射++++++++++++++++++++++++");
Constructor co=c.getDeclaredConstructor(String.class);
co.setAccessible(true);
Student student1=(Student) co.newInstance(“周杰伦”);
student1.show(); -
获取方法
public Method[] getMethods() 获取所有公有的方法(同时也会获取到父类公有的方法)
public Method[] getDeclaredMethods() 获取所有的包括私有的方法(不包含父类的)
public Method getMethod(String name,Class<?>… parameterTypes) 获取单个公有的方法 第一个参数是方法的名称 第二个参数是方法类型的class
public Method getDeclaredMethod(String name,Class<?>… parameterTypes)-
调用获取方法
public Object invoke(Object obj,Object… args) 第一个参数 是对象 ,第二个参数: 方法的具体的参数
容易发生的错误:
错误是: class com.offcn.day24.test.Student with modifiers “private” 也就是没有除去私有 -
获取公有的方法代码
Class c=Class.forName(“Demo1.Student”);
Constructor con =c.getConstructor(String.class,int.class);
Student student=(Student) con.newInstance(“林俊杰”,20);
Method m=c.getMethod(“show”); // 共有的方法
m.invoke(student); -
获取有返回值的方法
Class c1=Class.forName(“Demo1.Student”);
Constructor co1=c1.getDeclaredConstructor();
co1.setAccessible(true);
Method m1= c1.getMethod(“show1”,int.class,int.class);
Object o= m1.invoke(co1,2,3);
System.out.println(o);
-
-
获取属性
public Field[] getFields() 获取所有公有的属性
public Field[] getDeclaredFields() 所有所有的属性(包含私有的)
public Field getField(String name) 获取当个公有的属性 参数:属性的名称
public Field getDeclaredField(String name) 获取私有的属性-
Field 的方法
设置值:
public void set(Object obj,Object value) d第一个参数是对象,第二个参数是具体赋的值
取值:
第一种取值的方法 Object obj = c2.newInstance(); Student student = (Student) obj;
第二种取值的方法是 : public Object get(Object obj) 参数传递的是对象 -
实现代码
-
获取公有属性代码
Class c2 = Class.forName(“com.offcn.day24.test.Student”);
Field [] f= c2.getFields();
System.out.println(Arrays.toString(f)); -
获取所有公有的属性
Class c2 = Class.forName(“com.offcn.day24.test.Student”);
Field []f = c2.getDeclaredFields();
System.out.println(Arrays.toString(f)); -
获取单个公有的属性,并赋值
Class c2 = Class.forName(“com.offcn.day24.test.Student”);
Object obj = c2.newInstance();
Field f = c2.getField(“age”);
// 给其赋值
f.set(obj,200);
System.out.println(f.get(obj));// 通过对象来获取其值 Student student = (Student) obj; System.out.println(student.age);
-
获取私有的属性并给去赋值,取值
Class c2 = Class.forName(“com.offcn.day24.test.Student”);
Field f = c2.getDeclaredField(“name”);
Object obj = c2.newInstance();// 暴力反射 f.setAccessible(true); // 给属性设置值 f.set(obj,"您好,我来了"); // 取值 System.out.println(f.get(obj));
-
-
-
-
properties与反射结合
properties文件内容:
name=Demo2.Dog
method=run
————————————————————//狗类
public class Dog {
public void run(){
System.out.println(“狗在跑”);
}
}
// 猫类
public class Cat {
public void eat(){
System.out.println(“猫在吃鱼”);
}
}// main方法的实现代码
Properties properties=new Properties();
//ClassLoader c=Test2.class.getClassLoader;
InputStream is=Test2.class.getResourceAsStream(“1.properties”);
properties.load(is);
String name=properties.getProperty(“name”);
String meth=properties.getProperty(“method”);Class cla=Class.forName(name); Object obj=cla.newInstance(); Method method=cla.getMethod(meth); method.invoke(obj);
java8新特性
-
Lambda表达式
1、是对匿名内部类对象的一种简化写法
2、java8中引入了一个新的操作符”->”,叫做箭头操作符,Lambda操作符
3、箭头操作符,将表达式分隔成两部分
4、左边:表示的Lambda表达式的参数列表
5、右边:表示的是方法的方法体,Lambda体
6、语法格式1:没有参数,也没有返回值
() -> System.out.println(“Hello Lambda”);
7、语法格式2:有一个参数,没有返回值
(x)->System.out.println(x);
说明:如果只有一个参数,那么前面的小括号可以不写
x -> System.out.println(x);
8、语法格式3:有两个参数,没有返回值
(x, y) -> System.out.println(x + “…” + y);
9、语法格式4:lambda体有多句,需要在多句话外面加上大括号
x -> {
System.out.println(x);
System.out.println(x + “…”);
}
10、语法格式5:如果Lambda体只有一句,那么大括号和return关键字都可以省略
x -> x * x;
11、注意事项:
使用lambda表达式的前提条件:接口中只有一个抽象方法
如果在一个接口中只有一个抽象,称这种接口为:函数式接口
使用注解:@FunctionalInterface,检查当前接口是否是函数式接口。
————————————————-
实例
-
1
public class Demo08_Lambda表达式1 {
public static void main(String[] args) {
Inter1 i1 = new Inter1() {
@Override
public void test() {
System.out.println(“Hello NoName innerClass!!”);
}
};
i1.test();Inter1 i2 = () -> System.out.println("Hello Lambda"); i2.test();
}
}interface Inter1 {
public abstract void test();
} -
2
public class Demo09_Lambda表达式2 {
public static void main(String[] args) {
Inter2 i1 = new Inter2() {
@Override
public void test(String x) {
System.out.println(x);
}
};
i1.test(“Hello Noname innerclass”);Inter2 i2 = qq -> System.out.println(qq); i2.test("Hello Lambda");
}
}interface Inter2 {
public abstract void test(String x);
} -
3
public class Demo10_Lambda表达式3 {
public static void main(String[] args) {
Inter3 i1 = new Inter3() {
@Override
public void test(int x) {
System.out.println(x);
System.out.println(x + “…”);
}
};
i1.test(666);Inter3 i2 = x -> { System.out.println(x); System.out.println(x + "..."); }; i2.test(888);
}
}
interface Inter3 {
public abstract void test(int x);
} -
4
public class Demo11_Lambda表达式4 {
public static void main(String[] args) {
Inter4 i1 = new Inter4() {
@Override
public int op(int x) {
x = x + 1;
return x * x;
}
};
System.out.println(i1.op(5));Inter4 i2 = x -> { x = x + 1; return x * x; }; System.out.println(i2.op(5)); Inter4 i3 = x -> x * x; System.out.println(i3.op(5));
}
}
@FunctionalInterface
interface Inter4 {
public abstract int op(int x);
}
-
-
-
函数式接口
函数式接口概述:
1、lambda表达式使用的前提,就是接口必须是一个函数式接口。
2、函数式接口:
在接口中,如果只有一个方法,那么这种接口就是函数式接口
3、用注解来检查当前的接口是否是函数式接口:
@FunctionalInterface
如果不是函数式接口,就编译报错
4、作用:
想表达的是一个方法的内容,需要把这个方法传递到其他需要这个方法的位置
Java中不能将方法当做一个数据,不能作为方法的参数进行传递,也不能作为对象的成员变量存在。
只能在方法外加一层接口的声明-
常用内置函数式接口
1、Consumer :消费型接口
void accept(T t);
2、Supplier :供给型接口
T get();
1、Function<T, R>:函数型接口
R Apply(T t)
2、Predicate:断言型接口
boolean test(T t) -
接口实例
-
消费性接口
public class Demo12_函数式接口_消费性接口 {
public static void main(String[] args) {
happy(8000, x -> System.out.println(“班长喜欢大宝剑,每次消费” + x + “元”));
}public static void happy(int money, Consumer con) {
con.accept(money);
}}
-
供给型接口
ublic class Demo13_函数式接口_供给型接口 {
public static void main(String[] args) {
// List list = getNumList(10, () -> {
// Random rd = new Random();
// int x = rd.nextInt(31) + 20;
// return x;
//
// });
List list = getNumList(10, () -> new Random().nextInt(31) + 20);
System.out.println(list);
}public static List getNumList(int num, Supplier sup) {
List list = new ArrayList<>();
for(int i = 1; i <= num; i++) {
list.add(sup.get());
}
return list;
}}
-
函数型接口
public class Demo14_函数式接口_函数型接口 {
public static void main(String[] args) {
//调用strHandler方法,将字符串两端的空格删除
String result = strHandler("\t\t\t我优就业威武 ! ", x -> x.trim());
System.out.println(result);
}public static String strHandler(String str, Function<String, String> fun) {
return fun.apply(str);
}}
-
断言型接口
public class Demo15_函数式接口_断言型接口 {
public static void main(String[] args) {
List list = Arrays.asList(“Hello”, “www”, “ujiuye”, “ok”, “Lambda”);
//将满足条件的字符串,筛选出来,存储到另外一个集合中
List result = filtStr(list,x -> x.length() > 3);
System.out.println(result);
}public static List filtStr(List list, Predicate pre) {
List result = new ArrayList<>();
for (String str : list) {
if (pre.test(str)) {
result.add(str);
}
}
return result;
}}
-
-
第二阶段 JavaEE
第三阶段 Java框架
第四阶段 分布式和微服务
XMind: ZEN - Trial Version