目录
30、Date和Calender,SimpleDateFormate
2、实现Runnable接口,传入Runnable类型的target(使用有参构造方法)
1、InputStrem和OutputStrem(字节输入,输出流)
1、进制之间的转换:
十进制转其t进制:将十进制的值除以t,得到商和余数,商接着除以t,除到商为0为止,余数倒着看,就是十进制转为t进制的结果;
t进制转十进制:位权法,二进制数值从右向左以此对应t的次方,从0次方开始,上下对齐相乘,再前后相加,得到的和就是对应的十进制的值;
十六进与二进制的转换:
十六进制 -> 二进制:
将一位十六进制转为四位二进制,不够前面补0;
二进制 -> 十六进制:
从右向左,每四位二进制转为一位十六进制;
2、十进制小数转二进制小数:
整数部分转整数部分;
小数部分转小数部分;
小数部分:值成以二,如果值大于1,则在小数位补1,值小于1则补0,重复这个过程,直到结果为0或者循环为止,如果是循环,则结果保留八位,
十六进制和二进制小数的转换:整数部分转整数,小数部分转小数
十六进制 -> 二进制:
小数部分:一位十六进制转为四位二进制,不够前面补0;
二进制 -> 十六进制:
小数部分:从小数部分以2的-1次方开始,然后上下相乘,再前后相加得到的值就是十六进制小数的值;
3、为什么计算机中小数是不精准的?
就是由于十进制小数转二进制小数的过程中,二进制小数会出现循环,大部分十进制小数如0.1、0.2、0.3转成二进制小数都会有循环,只有0.5转换过去是0.1为精准的,因此计算机中大部分小数是不精准的。
4、计算机中的单位
最基本的单位 byte,
1byte = 8bit(位);
1kb = 1024byte;
1mb = 1024kb
1gb = 1024mb
....
5、取值范围
1byte的取值范围为:-2^7 ~ 2^7-1 (-128 ~ 127) 01111111 ~ 10000000;
2byte的的取值范围 -2^15 ~ 2^15-1 (-32768 ~ 32767) 1(符号位) + 15个0 ~ 0(符号位) + 15个1;
4byte的取值范围 -2^31 ~ 2^31 (-2147483648 ~ 2147483647) 1 + 63个0 ~ 0 + 63个1;
8byte为 -2^63 ~ 2^63 -1;
6、为什么4个字节的浮点型取值范围大于8个字节的整型;
4个字节的浮点型存储时的结构为
1个符号位 + 8个指数位(一个符号位 + 7个数值位) + 23个尾数位 取值范围为 -2^127~2^127;
8个字节的浮点型的结构为 1个符号位 + 11个指数位(1个符号位+10个数值位) + 52个尾数位 -2^1023 ~ 2^1023;
7、原码、反码、补码:
有符号数和无符号数:
有符号数:就是负数;
无符号数:只有正数(包含0);
正数:
三码合一;
负数:
原码:十进制直接转为二进制(8位不够补0),加符号位 的就是原码;
反码:原码中符号位不变,其余位取反(1变0,0变1);
补码:反码加1;
计算机中数据的存储,运算都是以补码的形式存在;
8、java的基础知识
环境变量的配置 JAVA_HOME = "jdk所在的路径";path=%JAVA_HOME%\bin\
javac Test.java javac将java源文件编译成字节码文件;
java Test(class) java运行字节码文件;
9、关键字和标识符:
关键字:有特殊含义的,被保留的(goto),不能随意使用的。
public class static void 等这些都是关键字。
标识符:我们自己定义的类名、变量名、方法名
规则:
硬性要求:
1.字母、数字、下划线、$、中文都可以
2.但是数字不能开头
3.标识符不能是关键字
4.常用的就是纯字母,或者字母+数字
软性要求:
大驼峰:每个单词的首字母大写(类名)
小驼峰:第一个单词首字母小写,此后每个单词的首字母大写(变量名、方法名)。
10、常量的分类
整型、浮点型、布尔型、字符型、字符串型;
常量的值是不能被改变的;
11、变量
变量名不能重复;
变量必须赋值后才能使用;
12、java中的数据类型
基本数据类型型和引用数据类型;
基本数据类型:
数值类型和非数值类型
数值类型:
整型和浮点型:
整型(默认为int):
byte(1字节)(-128~127);
short(2字节)(-32768~32767);
int(4字节)(-2147483648 ~ 2147483647);
long(8字节)(-2^63 ~ 2^63 -1)如 long l = 122323445L ;
浮点型(默认float):
float(4字节)(-2^127~2^127)如 float f = 123.456F;
double(8字节)(-2^1023 ~ 2^1023);
非数值类型:
char(2字节)(0~65535)、boolean(1字节)
引用数据类型:(保存的是对象在内存中的地址)
String、Date、Math、UUID等
数据类型的转换
自动类型转换和强制类型转换:
自动类型转换:
小范围类型向大范围类型变量转换;
语法:
大范围类型 变量名 = 小范围的值(常量/变量);
char和int会互相进行自动类型转换;
只要整型常量的值不超过byte、short、char的取值范围就完全可以存储;
byte、short、char这些类型的变量来说,在做运算的时候,会自动被提升为int类型;
强制类型转换:
大范围向小范围类型的变量转换:
语法 小范围类型 变量名 = (小范围类型)大范围的值(常量/变量);
会出现精度丢失和数据溢出的情况;
13、java中的运算符
+ :
1、+两边都是数值型,则进行加法运算;
2、+两边又一边是字符串,则进行的是拼接操作;
- :减法运算
* :乘法
/ : 除法
如果两边中都是整型,则结果为整形,如果有一边是浮点型,则结果为浮点型
= :赋值操作
== :等于
!= :不等于
!:取反
% :模运算 取余
如果两边都是整型,则结果为整数
如果有一边是浮点型,则结果为浮点数
逻辑运算 && 和 ||
&& 逻辑与 符号两边的为布尔值 如果有一边为false,则整个结果就为false;如果两边都为true,则结果为true;(如果左边为false,则结果就直接为false,不再继续右边的判断)(短路功能的体现)
|| 逻辑或 符号两边的为布尔值 如果有一边为true,则整个结果就为true;如果两边都为false,则结果为false;(如果左边为true,则结果就直接为true,不再继续右边的判断)(短路功能的体现)
!:取反
右边为布尔值;
三元运算符
判断条件 ? 表达式1 : 表达式2
一般写法: 表达式1和2的数据类型 变量名 = 判断条件 ? 表达式1 : 表达式2
++ -- (自增自减运算)
单独运算:
a++和++a是不区分的,都是先运算再使用;
混合运算:
++a 是先运算再使用(赋值/输出)
a++ 是先使用(赋值/输出)后运算
+=: a+=b 相当于 a = a+b;
好处是有时候需要强制类型转换的时候,不需要我们自己去做,底层就会帮我们自动进行强制类型转换;
14、流程控制
if语句
格式:
if(判断条件){
判断条件为真时所要执行的
}
if(判断条件){
判断条件为真时所要执行的
}else{
判断条件为假时所要执行的
}
if(判断条件1){
判断条件1为真时所要执行的
}else if(判断条件2){
判断条件2为真时所要执行的
}else{
判断条件都不满足时所要执行的
}
//else if可以写多个
注意事项:从语法上来说,if分支的大括号可以省略,如果省略,则if只包含紧邻的下一条语句。
用于等值判断和区间判断
switch语句
格式:
switch(表达式){
case 常量1:
//对应的代码
break;
....
case 常量n:
//对应的代码
break;
default:
//前面判断都为false,要执行的代码
break;
}
注意事项:
1. case后面的常量不能重复
2. case后面的值必须是常量
3. break结束switch结构
4. 表达式的类型可以是 byte short int char String 枚举
5. swicth会出现穿透现象,
穿透现象:
就是当一个case里没有break;会一进入到下一个case中,并且不会触发case里对应的判断,知道有break的case为止;
当我们有好几个常量所对应的结果都相同时,可以使用switch的穿透特性来简化代码如:
switch(mounth){
case3:
case4:
case5:
System.out.println("春季");
break;
}
switch的底层结构使用了跳转表(数组),也就是为什么switch里的常量的值不能超过int类型的取值范围,也就是常量里不能使用long、double、float等大于int取值范围的变量的原因;
if分支:可以做等值判断,也可以做区间判断
switch:只能做等值判断,不能做区间判断。
如果是等值判断,建议使用switch,效率高。
15、循环
for(①初始化变量;②条件判断;④步进语句){
③循环体
}
//初始化变量可以是多个
//死循环的写法
for(;;){}
2.while循环
基本格式:
while(条件判断为真){
//循环体
}
扩展格式:
①初始化变量
while(②条件判断){
//③循环体
④步进语句
}
3.do while循环
基本格式:
do{
//循环体
}while(条件判断);
扩展格式:
①初始化变量
do{
//循环体
//步进语句 //循环体和步进语句的先后顺序因具体情况而定
}while(④条件判断);
//区别:
do while:即使条件不满足,也会执行一次
4.三种循环的区别
语法区别:
1.do while:即使条件不满足,也会执行一次。for while条件不满足一次都不执行
2.for初始化变量只能在所属范围内使用(大括号),
do while 和while能再所有范围内使用。
5.循环控制break语句
作用:终止当前循环
6.循环控制continue语句
作用:跳过本次循环,继续下次循环
7.循环嵌套
外层循环走一遍,内层循环走一圈
外层循环控制行数,内层循环控制列数
16、方法(method)
作用:提高代码的复用性,精简代码;
定义:修饰符 返回值类型 方法名(形式参数){}
调用:静态方法(static修饰)方法名(实际参数);
实例方法 实例对象.方法名(实际参数);
方法重载:
方法名相同,但形参的数量,类型,顺序不同;
注意:方法重载与修饰符和返回值类型无关;
17、数组
定义:是可以存储多个同种类型的数据结构
特点:
1、数组在内存空间上是一块连续的内存空间;
2、其地址空间是连续的;
3、查询效率极高,但增加删除的效率极低(末尾的增加和删除没有效率影响);
4、数组存储的数据范围不超过int类型;
5、数组不能存储大数据量,因为在内存空间上没有特别大且连续的空间
18、地址值
在计算机中每一个字节都会有一个编号,这个编号就是内存地址,内存地址一般是十六进制;
19、面向对象
1、类:
一类具有相同性质的事物的总称;
基本组成部分:属性,方法;
属性(对类的静态描述)
方法(类的行为)
每一个类就是一个类型
2、对象
类的实例化/具体化;
类与对象的关系:
类是对对象的抽象,对象是类的实例/具体;
3、类的定义:
public class 类名{
//成员变量(属性)
修饰符 (任意)数据类型;
//成员方法
修饰符 返回值类型 方法名(){
}
}
4、对象的创建语法:
步骤:
1、导包:java.lang包里的类不用导,同包下的类不用导,不同包下的类需要导入,
格式:imort 报名.类名; eclipse下导包的快捷键 window下 alt+? Mac下 option + ?(快速补全的快捷键也是这个)
2、创建对象
格式:类型对象 引用(标识符)(保存的是对象在内存中的地址值) = new 类名();
咧: Person p = new Person();
3、使用(调用类的成员变量 / 成员方法);
格式:引用.成员方法() / 引用.成员变量;
咧: p.age; p.eat();
5、对象在内存中的位置:
每 new 一个对象都会在堆内存空间1中开辟一块新的空间用来存储该对象的属性;
6、使用自定义类型作为方法的参数
方法的参数可以是任意类型
对象(自定义类型)作为参数,传递的是地址值
7、使用自定义类型作为方法的返回值
方法的返回值可以是任意类型
对象作为返回值,返回的是地址值。
8、成员变量和局部变量的区别
位置 作用范围 默认值
成员变量 类里面,方法外面 整个类都可见 有,和数组中一样
局部变量 方法里面 该方法中 没有,必须先赋值再使用
成员变量在堆中,随着对象的创建而产生,随着垃圾回收而消亡。(生命周期长)相对
局部变量在栈中,随着方法的入栈而产生,随着方法的出栈而消亡。(生命周期短)相对
20、 this关键字
this:区分同名的局部变量和成员变量
什么是this:谁调用方法,谁就是this
1.局部变量和成员变量可以同名吗?可以
2.使用的时候用的是哪一个:如果有同名的局部变量和成员变量,局部变量的优先级比较高
3.加了this指向的是成员变量,不加this指向的是局部变量
21、构造方法
使用:new对象时会调用构造方法
构造方法的作用:
无参数的:创建对象
有参数的:创建对象并且给成员变量赋值
语法:
修饰符 方法名(参数列表){}
强调:
a.方法名和类名完全一致
b.没有返回值,连void都没有
其他注意事项:
1.如果没有显示的写一个构造方法,那么默认会赠送一个无参数的构造方法
2.如果显示的写了一个构造方法,则没有默认赠送
3.构造方法可以重载
4.一般我们定义一个类的时候会有一个无参数的构造方法,再来一个全参数的构造方法。(建议)
22、面向对象三大特性:封装,继承,多态;
1、封装:
private关键字的作用及使用
private:
操作成员变量的时候,有可能会有非法赋值
过程:
1、私有化成员变量:
不能直接操作成员变量:私有化成员变量,用private来修饰成员变量
2、提供相应公有的getter和setter方法:
取值(getter):getXxx();要有返回值
咧:public 返回值类型 getPrice(){
return 返回值类型;
}
赋值(setter):setXxx(数据类型 参数名);没有返回值,但要有参数
咧:public void setPrice(形参){
this.成员变量 = 形参;
咧:this.price = price(形参);
}
2、继承:
共性抽取,提高代码的复用性。
多个类中,如果有相同功能的代码,可以进行提取(把相同的代码)写在一个父类。
子类去继承父类,子类中可以直接使用父类中(非private修饰的成员信息) 成员信息。
使用protected修饰的成员变量,子类可以直接使用。
语法:
修饰符 class 子类 extends 父类{
}
继承关系下成员变量的访问特点:=左边是谁,访问的就是谁
一个类如果没有显示的继承一个父类,则默认继承自Object顶级父类
继承关系下成员方法的访问特点:new的是谁,访问的就是谁的方法。
方法覆盖重写:在继承关系下
方法名相同,参数项相同,
修饰符相同
返回值相同
@Override添加在方法上面去判断是否是一个正确的覆盖重写。
加上这个注解不报错,就是正确的覆盖重写。
加上这个注解报错,不是正确的覆盖重写
继承关系下构造方法的访问特点:
在子类的构造方法中,如果没有显示的写一个super(参数),则默认会赠送一个super();
如果显示的写了,则不再赠送。
如果要显示的写一个super(参数),必须是第一个语句。
创建子类对象的时候,都会调用到父类的构造方法。
super关键字的三种用法:
super.父类的成员变量
super.父类的成员方法
super(参数);//访问父类的构造方法。必须写在子类的构造方法中。
this关键字的三种用法:
this.本类成员变量
this.本类成员方法
this(参数);//调用本类的其他(自己不能调用自己)构造方法
this(参数),必须是构造方法中的第一个语句。
和super()不能同时存在,如果显示的写了this()则不再赠送super()了。
注意事项:
构造方法不能递归
继承的特点:
1. Java是单继承,一个子类只能有一个直接父类
2. Java是多级继承,父类还可以有父类
3. 一个父类可以有多个子类
Object是顶级父类
3、多态
条件:在继承关系下或者实现关系下;
概念:一个事物(对象)的多种形态。
特点:
1、多态场景下,成员变量访问特点:编译看左边,运行看左边;
2、多态场景下,成员方法访问特点:编译看左边,运行看右边;
分类:
1、典型写法(向上转型)
父类型的引用 指向子类型的对象;
接口类型的引用 指向实现类的对象;
语法:
父类型 引用 = new 子类名();
接口类型 引用 = new 实现类名();
2、向下转型
子类型的引用 指向父类类型的对象;
实现类的引用 指向接口类型的对象;
语法:
子类型 引用 = new 父类名();
实现类型 引用 = new 接口名();
向下转型有风险,可能会出现类型转换异常(ClassCastException) 需要在转型前进行判断;使用instanceof关键字
boolean b = 父类类型的对象 instanceof 子类;
boolean b = 接口类型的对象 instanceof 实现类;
instanceof 类型判断:
boolean b = 子类型对象 instanceof 父类型
抽象类:
1.使用abstract关键字修饰,位置修饰符的后面,class的前面
2. 抽象类不能实例化(创建对象),但是抽象类中可以有构造方法(供子类调用)。
3. 一个子类继承了一个父类则必须覆盖重写该父类中所有的抽象方法。
除非子类是抽象的。
抽象方法:
1. 抽象方法没有方法体
2.抽象方法使用abstract关键字来修饰。关键字的位置写在修饰符的后面,返回值的前面。
3.抽象方法必须写在抽象类中。
23、如何定义一个标准的类
四个组成部分:
1.私有化属性
2.getXxx setXxx
3.无参数的构造方法
4.全参数的构造方法
5.彻底重写toString()和equals();
24、常用类
1、ArrayList<E e> 数组集合类
E get(int index);获取指定下标处的元素;
E remove(int index) 通过指定下标移除某一个元素
E remove(Object o)通过指定元素移除集合里某一个元素;
如果集合里是元素 如果想通过元素去移除对应的元素时,但又因为该方法传递的是对象,
所以此时应该将基本数据类型转为包装数据类型 如 Integer i = 100;
boolean add(E e)将元素添加到列表末尾
boolean add(int index ,Object o) 将元素添加到指定的索引处;
clear() 清除元素列表内所有的元素;
E set(int index,E element) 将指定的位置处的元素修改为指定的元素
int size() 返回集合的长度大小
2、Math类
random()
nextInt(int a)返回一个0 ~ 1但不包含1范围内的数字 和Math.random()很像
如生成一个 0 ~ a (不包括)之间的数就是 : rd.nextInt(a)
如果是包括的话就是:rd.nextInt(a+ 1);
生成 x ~ y 之间都包含的是 :rd.nextInt(y - x +1) +x;
Math:
static double random();
static final double PI = 3.14....;
static int abs(int n);//绝对值
static long round(double d) //四舍五入
;
static double ceil(double d); //向上取整
static double floor(double d);//向下取整
3、一个类就是一种数据类型;
4、泛型(未知的数据类型)E e;
5、String类:
特点:
1. 字符串的内容可以共享
2. 底层存储是使用char[] 数组
3. 字符串的内容不能改变
所属包:java.lang;
构造方法:
public String();
public String(String str);
public String(byte[] array);
public String(byte[] array,int off,int len);
public String(char[] array);
public String(char[] array,int off,int len);
成员方法:
boolean equals(Object obj);
boolean equalsIgnoreCase(String str);
String toUpperCase();
String toLowerCase();
int length();
char charAt(int index);
String concat(String str);
boolean contains(CharSequence cs);
boolean endsWith(String str);
boolean startsWith(String str);
byte[] getBytes();
char[] toCharArray();
String substring(int beginIndex);//从beginIndex到字符串结尾
String substring(int beginIndex,int endIndex);//从beginIndex到endIndex,左闭右开
int indexOf(String str);
int lastIndexOf(String str);
String replace(char oldChar,char newChar);
String replace(CharSequence oldStr,CharSequence newStr);
String[] split(String regex)
String类里面做了一些特殊操作,打印对象的时候不是地址
字符串的内容,是一个空字符串 "" 里面什么都不写就是空字符串
6、static静态修饰符可以修饰:
成员变量:
位置:写在权限修饰符 和 数据类型 之间。
被static修饰的成员变量,也叫做类变量,在内存中只有一份。
访问方式:
可以通过
对象名取访问:不推荐
可以通过类名去访问:推荐
成员方法:
访问:
可以通过对象名取访问:不推荐
可以通过类名去访问:推荐
静态方法和成员方法:
静态方法中:只能访问静态成员(变量、方法),不能访问非静态变量和非静态方法
成员方法:可以访问静态成员,也可以访问非静态成员。
静态代码块:
位置:类里面,方法外面
语法:
static{
//静态代码块只执行一次。(一个类在jvm中加载起来以后就会执行静态代码块中的代码)
//先于构造方法执行
}
特点:只执行一次
可以访问:只能访问静态成员,不能访问非静态成员
作用:初始化静态变量(给静态变量赋值)
构造代码块:
语法:{}
位置:类里面,方法外面;
特点: 静态代码块在没次创建对象时都会调用,并且每一个构造方法里都会有构造代码块里的代码
作用:可以将所有构造方法里的相同的代码放到构造代码块里 , 使得相同代码不用重复去写;
原理:其实就是将这个代码到构造方法执行时,将构造代码块里的代码放到构造方法里,且是在最前面。
7、System类:
static PrintStream out;
static PrintStream err;
static InputStream in
static void arraycopy(Object src,int srcIndex,Object dest,int destIndex,int len);
static Long currentTimeMillions
String LineSeparator()输出系统的换行符
25、接口
定义:一组功能的定义;
语法:修饰符 interface 接口名{
//接口中有静态常量 public static final可以省略 接口名去调用
public static final 数据类型 常量名 = 对应数据类型的值
//静态方法 public 可以省略 接口名去调用(推荐)
public static 返回值类型 方法名(参数){}
//抽象方法 public可以省略 实现类对象去调用
public abstract 返回值类型 方法名(参数)
//默认方法 public可以省略 实现类对象调用
public default 返回值类型 方法名(参数){}
//私有方法 或者静态私有方法 (jdk1.9后才有的新特性)
private static 返回值类型 方法名(参数){}
}
类和接口的关系是实现关系 关键字 implements
类可以实现多个接口,接口可以继承多个接口;
语法:修饰符 class 类名 implements 接口名1,接口名2,接口名3{}
实现类必须覆盖重写接口中所有的抽象方法,除非实现类是抽象类(可以重写一部分,也可以不重写)。
实现类不一定要重写接口里的默认方法。
如果重写了默认方法,则调用重写后的。
如果没重写,则调用接口里的默认方法。
实现类不能覆盖重写静态方法。通过接口名去访问静态方法
特点:
1、接口无法被实例法;
2、接口里不能有构造方法,不能有静态代码块;
26、final关键字
final关键字可以修饰:
类:
被修饰过的类不能被继承
String,Math等类都是被static修饰的;
成员变量(常量):
特点:
修改值:被final修饰的成员变量其值不能变:
基本数据类型的值不能被改变
引用数据类型的地址值不能不被改变,但对象的内容(实例变量的值)是可以被改变的
赋值:必须赋值
赋值方式:
一、初识化的时候直接赋值
二、在构造方法里赋值,但这样,每一个构造方法里都需要单独赋值,因为创建爱你对象只会执行一次,所以这个单独赋的值只属于通过这个构造方法所创建的对象;
成员方法:
被final修饰的方法,不能被覆盖重写。
final 和 abstract 不能同时使用。
局部变量:
被final修饰的局部变量其值不能变:
基本数据类型:值不能变
引用数据类型:地址值不能变
27、权限修饰符(Y:代表可以访问到 N:代表不能访问到)
28、内部类
1、成员内部类
语法 :
修饰符 class 外部类名{
//成员属性
// 成员方法
// 成员内部类
修饰符 class 内部类名{
在成员内部类的成员方法中,可以直接访问外部类的成员信息
//访问外部类同名的成员方法:外部类.this.成员方法
//访问外部类同名的成员变量:外部类.this.成员变量
//成员内部类字节码文件的名字:外部类$内部类
//静态成员内部类中可以有静态成员也可以有非静态成员。
//非静态成员内部类中只能有非静态成员,不能有静态成员
}
}
创建成员内部类对象:
外部类.成员内部类 对象名 = new 外部类().new 成员内部类();
在外部类创建成员内部类的对象语法:
内部类类型 引用 = new 内部类名();
2、局部内部类
在外部内的成员方法里的类
特点 :
修饰符只能是abstract 或者 final 或者不写
局部内部类里不能有静态成员
使用范围:
成员方法内
访问同级的成员属性,只能取值不能赋值
使用:
直接在方法内创建对象
类型 引用 = new 类名(){};
3、匿名内部内
没有名字的类
条件:
在继承关系下或者实现关系下
使用场景:如果一个类只使用一次(只创建一个对象),则使用匿名内部类比较简单
语法:
接口 对象名 = new 接口(){
//覆盖重写方法
};
类名 对象名 = new 类名(){
}.method();
调用内部的方法或者变量
new 类名(){
}.method();
29、StringBuilder:
作用:做字符串的多次拼接,使用StringBuilder效率高。
所属包:java.lang;
构造方法:
public StringBuilder();
成员方法:
StringBuilder append(Object obj);//
String toString();
StringBuilder delete(int start,int end);//左闭右开
int length()
StringBuilder reverse()字符串反转
底层:
StringBuilder底层是char数组
调用无参数的构造方法的时候:初始长度16
扩容:新容量 = 旧容量 * 2 + 2;
现在:String的+操作底层进行了优化,使用的也是StringBuilder ,但是String的 + 拼接操作 每一个 = 都会new一个 StringBuilder。
30、Date和Calender,SimpleDateFormate
1、Date
构造方法:
Date Date(); //获取当前系统的时间
Date Date(long time)//指定的毫秒值所对应的系统时间的日期对象
成员方法:
long getTime()//获取当前所在时间对应的毫秒值
2、simpleDateFormate
构造方法:
SimpleDateFormate SimpleDateFormate(String patter);//创建日期格式化类 patter指定日期格式化的格式
成员方法:
String format(Date date);//将时间格式化成指定的时间
Date parse(String str);//将字符串时间转换成时间对象
3、Calendar
所属包:java.util;
无构造方法:
但可以通过Calendar.getStance()得到Calendar对象;
静态方法:
static Calendar getInstance();//当前系统时间的日历对象
静态常量:
public static final int YEAR = 1;等等
成员方法:
Date calendar.getTime() //获取当前系统的时间;
int calendar.get(int filed)//获取指定的年,月,日,星期等属性;
void setTime(date);//指定calendar对象所指向的时间;
void set(int year,int month,int day);
void set(int field,int value); //指定calendar中某个属性的值;
void add(int field,int count);//某个属性值增加
void setTimeInMillis(long time);
long getTimeInMillis();
31、Object类(顶级父类)
任意引用数据类型未指定父类,默认是继承Object;
构造方法:
Object Object();
成员方法:
1、toString()
返回的是包名.类名+@+"十六进制的哈希值(地址值)"
2、equals(Onject obj)
比较的是地址值
注意事项:
除了重写过toString方法和equals()的引用数据类型,其余都会默认调用Object的toString方法和equals();
重写toString和equals():
比较两个对象如果不想比较地址值,则可以在该类中覆盖重写equals方法。
打印某个类型的对象,如果不想输出地址值,则需要覆盖重写toString方法。
32、==和equals比较的是什么:
==:
基本数据类型:比较值是否相等
引用数据类型:地址值是否相等
equals:
Object类的equals方法比较的是地址值
String类的equals方法比较的是字符串的内容(覆盖重写了Object的equals方法)
自定义类的equals方法,根据覆盖重写的规则进行比较(一般比较的是两个对象成员变量的值)
33、常量与常量的拼接结果在常量池,原理是编译器优化。
1、常量池中不会存在相同内容的常量。
2、只要其中一个是变量,结果就在堆中。变量的拼接原理是StringBuilder。
3、如果拼接的结果调用intern()方法,则主动将常量池中还没有的字符串对象放入池中,并返回此对象的地址。
34、集合
1、单列集合:Collection接口
List接口:有索引值,有序,元素可重复。 数组
ArrayList: 特点:查询快,增删慢,但对于末尾的元素的增删不存在效率的问题。底层是 Object[]
LinkedList:查询慢,增删快。 链表
Vector:功能和ArrayList一致,线程安全,但效率低;
ArrayList线程不安全,但效率高;
Set接口:无索引,元素不可重复
HashSet:无序。哈希表
LinkedHashSet:有序。链表+哈希表
TreeSet:可排序。红黑树
常用方法(Collection中的公共的方法,其下所有的子类都可以使用):
Collection<E>接口中的常用方法:
boolean add(E e); //向集合中添加元素
boolean remove(Object obj); //从集合中移除某一个元素
boolean contains(Object obj); //集合中是否包含某一个元素
boolean isEmpty(); //集合里是否为空
void clear(); //清空集合
int size(); //集合的长度 元素个数
Object[] toArray(); //把集合转为数组
<T> T[] toArray(T[] array); //包含泛型的抽象方法
Iterator<E> iterator() //迭代器
2、 双列集合:Map接口
HashMap:无序。哈希表
LinkedHashMap:有序。链表+哈希表
TreeMap:可排序。红黑树
Hashtable:功能和HashMap一致,线程安全,效率低。
HashMap线程不安全,效率高。
3、Iterator<E>接口:
无构造方法:但可以通过集合的iterator()生成Iterator对象
成员方法:
E next() //获取下一个元素;
Boolean hasNext() //判断是否有下一个元素
void remove() //移除当前元素;
4、增强for循环(forEach)
语法:for(被遍历的集合里的数据类型 变量名 : 被遍历的集合){
System.out.println(变量名) //变量名 每一项元素
}
集合的遍历:
1、hasNext() + next() + while()
2、增强for循环
使用范围:集合,数组都可以使用
35、泛型:未知的数据类型
1、含有泛型的类:
修饰符 class 类名<字母>{//定义类的时候不知道具体的类型
//成员变量的类型可以是泛型类型
注意:泛型不能实例化
//方法的参数和返回值也可以是泛型类型
}
//创建对象的时候,尖括号里面写的是什么类型,泛型就是什么类型
//如果尖括号中没有写具体的类型,则泛型是Object类型。
修饰符 interface 接口名<字母>{
//接口中的常量不能是泛型类型。
//方法的参数和返回值可以是泛型类型
}
2、实现含有泛型的接口:
1.实现该接口的时候,可以确定泛型的类型
修饰符 class 类名 implements 接口名<具体的数据类型>{
//覆盖重写的方法中凡是泛型的地方,就可以写"具体的类型"
}
2.实现该接口的时候,不能确定泛型的类型。跟着写泛型。
修饰符 class 类名<泛型> implements 接口名<泛型>{
//覆盖重写的方法中凡是泛型的地方,还是泛型
}
3、含有泛型的方法:
修饰符 <T> 返回值类型 方法名(参数);
4、泛型的通配符:
?:可以表示任意的引用数据类型
5、泛型的限定:
? super T:泛型可以是T或者T的父类/接口类型
? extends T:泛型可以是T或者T的子类/实现类
36、Collection
Collection 迭代器的实现原理:
Collection<E>:
Iterator<E> iterator();
//下面这些实现类覆盖重写iterator方法以后,都要返回一个Iterator类型的对象。
//下面这些实现类覆盖重写iterator方法以后,都要返回一个Iterator实现类的对象。
ArrayList:要覆盖重写iterator()
LinkedList :要覆盖重写iterator()
HashSet:要覆盖重写iterator()
LinkedHashSet:要覆盖重写iterator()
TreeSet:要覆盖重写iterator()
迭代器的实现原理:一ArrayList为例去说明。()每一个实现类的迭代器实现原理都不同
hasNext()
next()
public class ArrayList<E>{
//成员变量
private Object[] elementData;
private int size;
//成员方法
public Iterator<E> iterator(){
return new Itr();
}
//成员内部类
private class Itr implements Iterator<E> {
//成员内部类的成员变量
int cursor;
//成员内部类的成员方法
public boolean hasNext(){
return cursor != size;
}
public E next(){
return (E) elementData[cursor++];
}
}
}
总结:
1. hasNext方法,游标(初始值是0)和size进行比较,如果不相同就是有元素
2. next方法,获取游标指向位置(索引值位置)的元素,然后游标+1
37、List接口
List<E>接口:有索引值,有序(存入顺序和取出顺序一致),可以重复。
常用方法
E get(int index);
void add(int index,E e);
E set(int index,E e);
E remove(int index);
int indexOf(Object obj);
int lastIndexOf(Object obj)
ArrayList:底层是数组。查询快、增删慢
LinkedList:底层是双向链表。查询慢、
LinkedList类的独有方法(底层双向链表): 但是linkedList里可以通过index 获取元素,这个index是假的索引
E addFirst();//向头部添加元素
E addLast();//向尾部添加元素
E getFirst();//获取头部元素
E getLast();//获取尾部元素
E removeFirst();//移除头部元素
E removeLast();//移除尾部元素
38、Set接口:
特点:没有索引值,无序,不可重复
HashSet:底层数据结构 哈希表(数组+链表+红黑树)。无序(新增顺序和取出顺序不一定 一致)
LinkedHashSet:底层数据结构 链表+哈希表。有序
TreeSet<E>:底层数据结构红黑树。可排序。
成员方法:
方法和collectiion里一致:没有额外扩展的功能。
hashCode()
因为Set集合是不允许元素重复的,因此默认会调用Object的hashCode方法,hashCode()的返回值的是地址值转换后的hash值;
一般是不满足我们的需求,因此我们需要重写该方法。Idea生成;
TreeSet
构造方法:
public TreeSet();
public TreeSet(Comparator<E> c);
重复:判断重复的标准
哈希值相同 && equals相同
哈希值:通过调用hashCode方法得来
1、因为TreeSet是可排序的,因此需要提供排序的规则,如果没有,则会报错;
2、提供排序规则的方式
1、要使用到的类里继承Comparable接口,并实现compareTo(),里面返回的是排序的规则
可选择,升序或者降序;
升序:return this.XXX - o.getXXX();
降序:return o.getXXX - this.XXX;
2、如果使用到的类没有实现compareTo(),则需要在new TreeSet()对象时里调用有参构造,里面传入CompareTor类型的对象,
这里就需要用到匿名内部类 比如:
Comparator<Person> comparator = new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o2.getName().length() - o1.getName().length();
}
};
Set<Person> set = new TreeSet<>(comparator);
使用TreeSet的时候,泛型必须是Comparable类型。如果不是则需要通过构造方法传入一个Comparator类型的对象。
39、hashCode()和equals():
1、对于需要大量并且快速的对比的话如果都用equals()去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用hashCode()去对比,
2、如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equals()去再对比了),如果hashCode()相同,此时再对比他们的equals(),
如果equals()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性!
3、这种大量的并且快速的对象对比一般使用的hash容器中,比如HashSet,HashMap,HashTable等等,比如HashSet里要求对象不能重复,
则他内部必然要对添加进去的每个对象进行对比,而他的对比规则就是像上面说的那样,先hashCode(),如果hashCode()相同,再用equals()验证,
如果hashCode()都不同,则肯定不同,这样对比的效率就很高了。
4、然而hashCode()和equals()一样都是基本类Object里的方法,而和equals()一样,Object里hashCode()里面只是返回当前对象的地址,
如果是这样的话,那么我们相同的一个类,new两个对象,由于他们在内存里的地址不同,则他们的hashCode()不同,所以这显然不是我们想要的,
所以我们必须重写我们类的hashCode()方法,即一个类,在hashCode()里面返回唯一的一个hash值。
40、两种比较器的区别与联系
1、Comparable接口和Comparator的区别?
1、位置不同:Comparable在java.
2、实现方式不同:Comparable需要通过实现类去实现里面的ComparaTo()方法,Compatator是需要实现类实现里面的compare()方法
41、Collections类(集合工具类)
addAll(Collection<? super T>c, T... elements) T...表示可变参数 将一个数组或集合添加到一个list集合里;
sort(List<T> list) 根据其元素的natural ordering对指定的列表进行排序。
sort(List<T> list, Comparator<? super T>c) 对一个集合进行指定规则进行排序
42、Map接口 (双列集合)
1、Map<K,V>接口:
1、特点:
1. 一个元素有一个键(K)和一个值(V)两部分组成。
2. K,V可以是任意的引用数据类型
3. K不能重复(重复的标准和Set一样),一个K对应唯一的一个
2、常用实现类:
HashMap:底层是哈希表。无序
LinkedHashMap:底层是链表+哈希表。有序
TreeMap<K,V>:底层是红黑树。可排序(根据K来排序)。
Hashtable:功能和HashMap一致,线程安全,效率低。
HashMap线程不安全,效率高。
HashTable的K和V不能为null,如果有为null,会报错NullPointer。 HashMap的K,V可以为null。
3、构造方法:
public TreeMap();
public TreeMap(Comparator<K> c);
4、常用方法:
V put(K k,V v);//如果K重复,则返回被替换的V。如果K不重复,返回null
V get(Object key);//根据K获取V,如果K不存在返回null
V remove(Object key);//根据K删除元素,返回被删除元素的V,如果K不存在返回null
boolean containsKey(Object key);
boolean containsValue(Object value);
boolean isEmpty();
void clear();
int size();
Collection<V> values();
Set<K> keySet();
Set<Entry<K,V>> entrySet();
5、Set接口的底层就是Map
new 一个 HashSet 底层会new一个 HashMap
new 一个 LinkedHashSet 底层会new一个 LinkedHashMap
new 一个 TreeSet 底层会new一个 TreeMap
2、Entry<K,V>接口:
K getKey();
V getValue();
43、数据结构
栈:先进后出
队列:先进先出
数组:查询快,增删慢
链表:查询慢,增删快
红黑树:查询,增删 都比较快
44、HashSet的源码分析
1、哈希表:(数组+链表+红黑树)
1、什么类型的数组:java.util.HashMap.Node<K,V>{
int hash;
K k;
V v;
Node<K,V> next;//单项链表
2、数组的初识长度:16
3、什么情况下会扩容:
1. 当元素的个数占满"格子"的0.75的时候,会扩容。
2. 当某个索引值位置下的元素>8个的时候 && 数组长度<64,会扩容
4、新容量:新容量=旧容量*2
newCap = oldCap << 1
5、红黑树:
当某个索引值位置下的元素个数>8个 && 数组长度>=64,会把该索引值下的链表结构转成红黑树
6、新增过程:
1. 计算新增元素的 哈希值
2. 哈希值%数组长度,确定新增元素的索引值位置。
如果该位置没有元素:新增
如果该位置有元素:则判断新增元素和该位置的元素是否重复。
如果相同:则不新增
如果不相同:挂在该索引值下链表的最末尾
7、判断重复的标准:
p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))
哈希值相同 && (地址值相同 || equals相同)
2、 Set:
1、HashSet:
构造方法:
public HashSet();
public HashSet(int capacity);//实际的长度是>=capacity的一个2的次方的值。
public HashSet(int capacity,float loadFactor)
2、Set的底层就是Map。
3、ArrayList:
什么类型的数组:Object[]
数组的长度:
调用无参数的构造方法,会创建一个长度为0的数组,第一次调用新增方法,底层会创建一个长度是10的数组。
有参数的构造方法,传入多大的数值,创建一个多大的数组
扩容:newCapacity = oldCapacity + (oldCapacity >> 1)。
新容量 = 旧容量的1.5
45、Throwable类(异常类)
成员方法:
void printStackTrace
子类:
1、Error:
java.lang.StackOverflowError (栈溢出异常)
java.lang.OutOfMemoryError (OOM 内存)
2、Exception:
运行期异常:java命令运行.class文件。
RuntimeException及其子类都是运行期异常。
编译期异常:javac命令,把.java文件编译成.class文件时。
ParseException
Exception下,除了运行期异常都是编译期异常。
必须处理,不处理不能通过编译。
3、处理异常:try catch finally throws throw
1、try - catch代码块
try{
//有可能发生异常的代码
}catch(XxxException e){
//对异常的处理
e.printStackTrace();
}
2、try - catch - finally
try{
//有可能发生异常的代码
}catch(XxxException e){
//对异常的处理
e.printStackTrace();
}finally{
//无论是否发生异常,都要执行的代码
}
3、try - finally (很少这样写)
try{
//有可能发生异常的代码
}finally{
//无论是否发生异常,都要执行的代码
}
4、throws:声明某个方法抛出了异常
位置:在方法小括号的后面大括号的前面
不是彻底的处理异常的方式,只是让编译期异常能通过编译。
遇到异常以后,不是直接结束程序。而是交给方法的调用处去处理。
如果一路都没有处理异常,则最后交给jvm处理,jvm进行中断处理。
如果自己没处理,二是抛给调用者,那么该异常代码后面的语句页将不会再执行;
5、throw:抛出异常
位置:方法里面
语法:throw 异常类型的对象
6、遇到多个异常的处理方式:
一个try catch块:多个异常之间有逻辑关系
多个try catch块:多个异常之间没有逻辑关系
一个try块,多个catch:多个异常之间有逻辑关系,但是发生异常以后,不同的异常希望有不同的处理逻辑。
如果多个catch块之间有子父类关系,则子类异常写面,父类异常写后面
7、自定义异常
需要继承某个异常一般为RuntimeException,再实现两个构造方式,并使用它。
46、进程与线程:
1、进程:一个软件就是一个进程,一个软件可以有多个进程
2、线程:一个软件可以有一个/多个线程;
3、并行和并发:
并行:多个任务在同一时间点(同时)去执行。多核CPU
并发:多个任务在同一时间段(有先后顺序)去执行。
4、调度方式:
抢占式调度,先执行谁不确定,谁执行多长时间不确定。
5、Thread类:
多线程就是创建一个Thread类型的对象,启动执行。
构造方法:
public Thread();
public Thread(String ThreadName);
public Thread(Runnable target);
public Thread(Runnable target, String ThreadName);
静态方法:
static Thread currentThread();//获取当前执行代码的线程
static void sleep(long millis);//单位是毫秒,程序睡眠millis毫秒
成员方法:
String getName();
void setName(String name);
void start();//线程启动以后会执行run方法中的代码
void run();
State getState(); //State 为枚举类 里面有定义了六种类型也就是线程的六种状态
void join();
6、多线程:就是创建一个Thread类型的对象,启动执行。
好处:充分利用多核CPU的效率
7、创建多线程的方式:
1、继承Thread类:
1、创建一个Thread的实现类,并重写run(),然后new 实现类对象 调用start();
例: public class SubThread extends Thread{
@Override
public void run() {
System.out.println("hello java");
}
}
//创建一个线程
Thread t = new SubThread();
//启动线程
t.start();
2、匿名内部类
例: //创建一个线程
Thread t = new Thread() {
@Override
public void run() {
System.out.println("通过匿名内部类,创建Thread类型的对象");
}
};
//启动线程
t.start();
2、实现Runnable接口,传入Runnable类型的target(使用有参构造方法)
例: //通过匿名内部类的方式创建Runnable类型的对象
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
};
Thread t = new Thread(r);
t.setName("线程1");
t.start();
3、使用Runnable的方式比使用Thread类的方式的优势:
1. 可以避免单继承的局限性。
2. 任务和线程分离,实现了解耦合,提高了代码的健壮性。
3. 在线程池中,只能传入Runnable,不能使用Thread。
8、多线程的安全性:
线程安全:
概念:单线程没有问题,在多线程场景下,和预期结果不一致。
什么情况下会产生线程安全:多个线程访问 同一个 资源 有可能发生线程安全问题
解决线程安全问题的方式:
1、 使用synchronized代码块
synchronized(锁对象){//可以是任意类型的对象,但多个线程访问的必须是同一个锁对象。(可以使用类名.class 也是唯一的)
//有可能发生线程安全问题的代码
}
例子: Thread t1 = new Thread() {
public void run() {
for (int i = 0; i < 100000; i++) {
synchronized(this) {
a++;
}
}
}
};
2、 synchronized方法
方法的返回值和修饰符之间加上synchronized关键字
静态方法:锁对象是当前类的反射对象
非静态方法:锁对象是this
例子:public static synchronized void increment() {
a++;
}
3、 Lock锁
Lock接口
void lock();//上锁
void unlock();//开锁
实现类:
ReentrantLock类
构造方法:
public ReentrantLock();
例子:Runnable r = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
//上锁
lock.lock();
a++;
//释放锁 (必须手动释放,可以放到finally代码块里)
lock.unlock();
}
}
};
9、synchronized与Lock锁的对比?
1、synchronized不管是同步代码块还是同步方法,都是在一对{}结束之后,才会释放锁对象(同步监视器);
2、Lock是通过两个方法来控制需要同步的代码块,更加灵活;
3、Lock作为接口,有更多的实现类,可以适用于更加复杂的场景;
10、线程的状态:
NEW:新建状态。一个线程创建好以后,启动之前。
RUNNABLE:可运行状态。当线程装在执行任务。
TERMINATED:消亡状态。线程把任务执行结束后。
BLOCKED:阻塞状态,获取synchronized锁对象失败。
WAITING:无限等待状态,获取Lock锁对象失败。
t1.join了以后,t2就处于WAITING状态
TIMED_WAITING:计时等待状态,执行sleep方法。
新建状态 和 消亡状态 只能出现一次。
11、栈,本地栈,程序计数器是线程独有的;
方法区,堆,是线程共享的;
47、线程间的通信:
1、 等待唤醒机制:
A B
执行 等待
执行结束唤醒B 执行
等待 执行结束唤醒A
2、Object类:
void wait();//会让程序进入WAITING状态
void wait(long millions);//会让线程进入TIMED_WAITING状态
☆ 这个和sleep的区别是:核心区别:Object的wait()会自动释放锁对象,而sleep()不会自动释放锁对象;
☆ 释不释放的定义:就是某一线程执行完,等待的其他线程就能拿到锁对象;拿到就是指 -->: 能进入到synchronized代码块里
void notify();//唤醒当前锁对象上等待的某一个线程
void notifyAll();//唤醒当前锁对象上等待的所有线程
注意事项:
1. 上面方法在使用的时候必须在synchronized代码块 或者 方法中
2. 调用上述方法的对象,必须和锁对象一致
3、//获取当前类的反射对象。类名.class (也就是获取当前类)
48、lambda表达式:
作用:可以通过lambda的方式创建函数式接口类型的对象
函数式接口:一个接口中只有一个抽象方法的接口。函数式接口可以使用@FunctionalInterface注解来修饰 Comparator 和Runnable都是函数式接口
语法:
()->{}
():接口中抽象方法的参数。形参
->:固定写法
{}:可以理解为对方法的覆盖重写
例子一://通过lambda的方式创建Runnable类型的对象
Runnable r = ()->{System.out.println("hello java");}; {} 里的就是重写方法里的方法体
//通过匿名内部类的方式创建Comparator类型的对象
Comparator<Integer> c = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
};
例子二: //通过lambda的方式创建Comparator类型的对象
Comparator<Integer> c = (Integer o1, Integer o2)-> {
return o2-o1;
};
49、死锁:
当不同的线程占有对方需要的同步资源不放弃,都在等待对方放弃自己所需要的资源时,就会形成死锁
当我们调用一个同步方法的时候,就已经相当于手里握了一把锁;
一个线程可以同时握多个锁
诱发死锁的原因:
1、互斥条件
2、占用且等待
3、不可抢夺(不可抢占)
4、循环等待
解决死锁:
1、死锁一旦出现,基本无法解决,尽量规避,可以考虑打破诱发条件;
针对条件1:互斥条件下,基本很难人为干预;因为线程安全就是通过互斥条件达到的;
针对条件2:可以考虑一次性申请所有的需要等待的资源,这样就不存在等待的问题;
针对条件3:如果已经占有资源的线程,进一步申请资源,可以考虑在一定时间内拿不到资源,就可以释放手中的资源,供其他线程使用;
针对条件4:可以考虑将资源改为线性顺序,先拿序号小的,这样就避免了循环等待;
50、线程池(ThreadPoolExecutor)
存放了多个线程
1、线程池的优点:
(1)提高了响应速度;int prestartCoreThread() int prestartAllCoreThread() 提前启动核心线程
(2)降低资源消耗;(每个线程大约需要消耗1M的内存);
(3)提高线程的可管理性;
2、线程池构造方法的参数:
int corePoolSize, //核心线程数量。
int maximumPoolSize,//最大线程数量
long keepAliveTime,//线程存活时间
TimeUnit unit,//时间单位
BlockingQueue<Runnable> workQueue,//工作队列 (核心线程数量满了后,线程存放的队列,先进先出)
ThreadFactory threadFactory,//线程工厂(生产线程)
RejectedExecutionHandler handler//拒绝策略(当已达到最大线程数量后,执行的拒绝策略)
成员方法:
int getActiveCount();//获取正在执行任务的最大线程数量
int getCorePoolSize();//获取核心线程数
int prestartAllCoreThreads();//可以提前启动核心线程数量的线程。
int getLargestPoolSize() //获取线程池中同时进行的最大线程数。
int getPoolSize() //返回池中当前的线程数。
3、线程池执行任务的流程步骤:
1. 有任务时,先启动核心线程数量的线程去执行。
2. 当核心线程消耗完后,把任务存入工作队列中
3. 当工作队列存满以后,会启动最大线程数量 线程去执行任务
4. 当线程数量达到最大线程数量的时候,还有任务,则启动拒绝策略。
存活时间:线程空闲以后,到了指定的时间,回收大于核心线程数量的线程
拒绝策略:
AbortPolicy:抛出异常
CallerRunsPolicy:由主线程去执行任务
DiscardPolicy:不执行任务,但是不抛出异常(就是将加入的任务丢弃掉)
DiscardOldestPolicy 如果已经达到最大线程池数量,会将工作队列中最早的线程丢弃掉,存入新执行的任务。
4、Executors类:
静态方法:
static ExecutorService newFixedThreadPool(int nThread);//固定线程池
static ExecutorService newCachedThreadPool();//缓存线程池
static ExecutorService newSingleThreadExecutor();//单例线程池
static ScheduledExecutorService newScheduledThreadPool(int nThread);//调度线程池
5、ExecutorService接口:
成员方法:
void executor(Runnable r);//开启线程执行任务 (一次一个) (有返回值)
<T> Future<T> submit(Callable<T> c); //开启线程执行任务(有返回值)
Future<?> submit(Runnable r); //开启线程执行任务 (没有返回值)
void shutdown(); //关闭线程池
6、Future接口
成员方法
<T> get(); //用于获取线程执行任务结束后的返回值 (也就是调用submit(Callable callable)才有值)不然结果就为空,也就是各类型的默认值。
7、ScheduledExecutorService接口:
成员方法:
ScheduledFuture<?> schedule(Runnable r,long delay,TimeUnit tu);//开启线程 (没有返回值)
<T> ScheduledFuture<T> schedule(Callable<T> r,long delay,TimeUnit tu);//里面执行
Runnable类型的对象。有返回值
ScheduledFuture<?> scheduleAtFixedRate(Runnable r,long initialDelay,long
period,TimeUnit tu); //没有返回值 initialDelay 需要等待多长时间才执行第一次 period 后面每隔多
长时间开启一个线程 tu 时间单位。
51、File类:
一个File类型的对象表示一个文件或目录
一个文件 或 目录 是否存在,不影响File对象的创建。
所属包:java.io;
构造方法:
public File(String path);
public File(String parent,String child);
public File(File parent,String child);
成员方法:
String getAbsolutePath();//获取绝对路径。带盘符的路径
String getPath();//获取相对路径。相对于当前项目的根目录
String getParent();//获取父路径
String getName();//获取文件或目录的名称
long length();//单位是字节。获取文件的大小,如果文件不存在,返回0.
boolean isFile();//是否是文件,是true,不是false,不存在是false
boolean isDirectory();//是否是目录,是true,不是false,不存在是false
boolean createNewFile();//创建文件(不能创建文件夹),成功true,失败是false(存在继续创建)
boolean delete();//删除文件 或 目录(空目录)
boolean mkdir();//创建目录
boolean mkdirs();//创建多层目录
boolean exists();
String[] list();
String[] list(FileFilter filter)
File[] listFiles();
File[] listFiles(FileFilter filter); //FileFilter是一个函数式接口,可使用lambda表达式
递归:
直接递归:方法自己调用自己
间接递归:a方法调用b方法,b方法调用a方法。
注意事项:
1. 递归必须要退出机制
2. 即使有退出机制,递归的次数也不能太多
⭐️: 斐波拉契数列: 第一,二项为1,后面每一项都是前两项之后 1 1 2 3 5 8 13 21 34 fn(i-1)+fn(i-2) 结束条件 i==1 或 i==2
52、深浅拷贝:
要克隆一个对象,调用Object父类的clone方法
该方法是被protected修饰的,不能直接使用,使用的类要覆盖重写该方法。
要调用clone方法的类必须是Cloneable(接口)类型。需要实现了接口
深拷贝:两个成员变量(引用数据类型)的地址值不相同
浅拷贝:两个成员变量(引用数据类型)的地址值相同
53、IO(输入输出)
1、InputStrem和OutputStrem(字节输入,输出流)
IO可以操作文件(读,写);
1、基准:
数据出内存:写
数据进内存:读
2、字节输出流(OutputStream抽象类)
常用方法:
void write(int data);//写出一个字节的数据
void write(byte[] array);
void write(byte[] array,int offset,int len);
void close();
常用子类:FileOutputStream
构造方法:
//如果文件不存在,会自动创建。但是如果某一层目录不存在,则会抛出FileNotFoundException
public FileOutputStream(String path);
public FileOutputStream(File file);
public FileOutputStream(String path,boolean append);
//上面三个构造方法,都是调用的这一个构造方法
⭐️ public FileOutputStream(File file,boolean append);
//append:false表示覆盖,true表示追加。
3、字节输入流(InputStream抽象类)
常用方法:
int read();//读取一个字节的数据,返回读取的数据,如果没有数据则返回-1
int read(byte[] array);//读取数据存入参数数组中,返回读取的长度,如果没有数据则返回-1
void close();
常用子类:FileInputStream
构造方法:
public FileInputStream(String path);
public FileInputStream(File path);
2、字符输出流:Writer
常用方法:
void write(int data);//写出一个字符的数据
void write(char[] array);
void write(char[] array,int off,int len);
void write(String str);
void write(String str,int off,int len);
void close();
常用子类:FileWriter
⭐️: 调用下面构造方法的时候,底层会创建一个长度是8192的byte数组(缓冲区)。
调用写出方法的时候,会把字符转换成字节,存入缓冲区中。
当byte数组存不下数据 或者 显示的调用flush方法,会把缓冲区中的数据写出去。
调用close方法的时候,底层会调用到flush方法。
构造方法:
public FileWriter(String path);
public FileWriter(File path);
public FileWriter(String path,boolean append);
public FileWriter(File path,boolean append);
3、处理IO异常注意的点(资源需关闭):
方式1: try with resource:会自动释放资源(比如:流不需要显示的调用close(),会帮你自动调用close() )
try(资源对象的创建){
//有可能发生异常的代码
}catch(XxxException){
//对异常的处理
}
资源对象: java.lang.AutoCloseable类型的对象就是资源对象
例子: try (
⭐️ Reader r = new FileReader("/Users/a13571442004/Desktop/a.txt");
⭐️ Writer w = new FileWriter("a.txt");
) {
char[] ch = new char[1024 * 10];
long start = System.currentTimeMillis();
while (true) {
int len = r.read(ch);
if (len == -1) {
break;
}
w.write(ch);
⭐️ w.flush();
}
long end = System.currentTimeMillis();
System.out.println("复制完成" + (end - start));
} catch (IOException e) {
e.printStackTrace();
}
方式2: 使用try - catch - finally:
例子:
Reader r =null;
Writer w =null;
try {
r = new FileReader("/Users/a13571442004/Desktop/TCP套接字.docx");
w = new FileWriter("副本1.docx");
char[] ch = new char[1024*10];
long start = System.currentTimeMillis();
while (true) {
int len = r.read(ch);
if (len == -1) {
break;
}
w.write(ch);
w.flush();
}
long end = System.currentTimeMillis();
System.out.println("复制完成"+(end-start));
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
⭐️ r.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
⭐️ w.close();
} catch (IOException e) {
e.printStackTrace();
}
方式3:throw
4、缓冲流
1、字节缓冲流(会在new 对象时,在底层创建一个byte[8192]的缓冲区 默认)
1、字节输出缓冲流(BufferedOutputStream)
优点:减少写出次数,提高写出效率。
构造方法:
调用下面构造方法的时候,底层会创建一个长度是8192的byte数组
写出的数据存入8192的byte数组中,
当该数组存不下数据 或者 显示的调用flush方法,则会把8192byte数组中的数据写出到目标位置。
BufferedOutputStream(OutputStream os);
BufferedOutputStream(OutputStream os,int size);size 设置缓冲区的大小
成员方法:
void write(byte b)//只写一个字节的数据
void write(byte[] ba)//可以写一个数组的字节
2、字节输入缓冲流(BufferedInputStream)
优点:减少读取次数,提高读取效率
构造方法:
调用下面构造方法底层会创建一个长度是8192/size的byte数组
调用读取方法,会一次读取8192字节的数据,存入该byte数组中
从对应索引值位置获取数据,进行操作。
BufferedIntputStream(IntputStream os);
BufferedIntputStream(IntputStream os,int size);size 设置缓冲区的大小
成员方法:
void read()//只读一个字节的数据
void read(byte[] ba)//可以读取一个数组的字节
void read(byet[] ba,int src,int len)//读取指定长度的字节
2、字符缓冲流(会在new 对象时差创建一个char[8192]的缓冲区 默认长度 8192 )
1、字符输出缓冲流(BufferedWriter)
优点:高效:字符-->字节
构造方法:
调用下面构造方法,底层会创建一个长度是8192/size的char数组
写出的数据存入8192的char数组中,然后当存不下 或者 调用flush方法
会把8192char数组中的数据 转换 存入 8192的byte数组中
写出到目标位置。
BufferedWriter(Writer w);
BufferedWriter(Writer w,int size);
成员方法:
void write()写一个字符
void newLine() 写出一个换行符
2、字符输入缓冲流(BufferedReader)
优点:高效:字节-->字符
构造方法:
调用下面构造方法的时候,底层会创建一个长度是8192/size的char数组
当调用读取方法的时候,会把读取的数据存入8192的byte数组,然后转换(字节-->字符)存入8192/size的char数组中
操作的数据,从8192/size的char数组中获取。
BufferedReader(Reader r)
BufferedReader(Reader r,int size)
成员方法:
void read() 读一个字符
void readLine() 读一行字符
5、转换流
1、输出转换流(OutputStreamWriter)
构造方法:
OutputStreamWriter(OutputStream os)字符集默认的为编辑器的编码
OutputStreamWriter(OutputStream os,String charset)
成员方法:
OutputStream里的方法它都实现了
2、输入转换流(InputStreamReader)
构造方法:
InputStreamReader(InputStream is) 字符集默认的为编辑器的编码
InputStreamReader(InputStream is,String charset)
成员方法:
IntputStream里的方法它都实现了
6、对象流
1、序列化输出流(ObjectOutputStream)
构造方法:
ObjectOutputStream(OutputStream os)
成员方法:
void writeObject(Object obj) 将对象序列化 该对象必须实现了SeriaLizable接口
2、反序列化输入流(ObjectInputStream)
构造方法:
ObjectInputStream(InputStream is)
成员方法:
Object readObject();
3、序列化&反序列化注意事项:
1、操作的对象必须是Serializable类型,因此,要操作的对象必须实现Serializable接口,
其对象成员变量,也必须是Serializable类型;
2、反序列化时的类结构要和序列化时的类结构要一致;如果不一致,会抛出异常;如果想要不一致,可以在该类添加一个常量serialVersionUID
如: private static final long serialVersionUID = 1L;
3、如果想让某个成员属性不参与序列化,可以使用transient关键字修饰。
7、字符编码和字符集:
字符集:
ASCII字符集:
ASCII编码
GBK字符集:
GBK字符编码:一个中文2字节
Unicode字符集
UTF-8:一个中文3个字
53、Prpperties类
继承了HashTable;
Hashtable的方法它都能使用
也有自己的独有的方法:
Object setProperty(String Key,String vlaue); //新增元素
String getProperty() //通过键去获取值;
Set<String> stringPropertyNames()//获取所有的键
void store(OutputStream out,String comments) // 用于将Properties对象里的数据存储到某个文件里 comments 对于文件的说明,相当于注释
void store(Writer w, String comments)
void load(InputStream in) //读取某个文件里的数据并读取到对象里
void load(Reader r)
⭐️:一般有图片或者特殊格式的文件使用字节流,不然可能会出现乱码的情况
54、网络编程:
软件结构:
cs:客户端 和 服务器端
bs:浏览器 和 服务器端
网络编程有三要素:协议 ip 端口号
协议:
应用层
传输层:
TCP:客户端和服务器区分,面向连接的协议。
连接:三次握手。断开连接:四次挥手。
特点:数据安全,效率低
UDP:面向无连接的协议。
特点:数据可能会丢失,但是效率高。
网络层
物理层
ip:确定发送的目标位置
ipconfig(window下)
ipv4:a.b.c.d //每个部分一个字节,四个部分就是四个字节
//可以表示42亿多个地址
ipv6:128位,8组,每组16位
端口号:占用2个字节,范围0~65535
表示本机的ip地址:
127.0.0.1
localhost
本机的真实ip地址
Socket类:
所属包:java.net;
构造方法:
public Socket(String host,int port);
成员方法:
OutputStream getOutputStream()
InputStream getInputStream()
shutdownOutput() 告诉接收方已经传输完毕
shutdownInput()
UUID:
静态方法:UUID randomUUID()
55、常用函数式接口:
1、Suuplier<T t>
抽象方法:
<T> get();
2、Predicate<T t>
抽象方法:
boolean test(T t);
默认方法:
Predicate<T> and(Predicate<? super T> other)
Predicate<T> negate()
Predicate<T> or(Predicate<? super T> other)
两个使用:比如
Predicate <T t> p1;
Predicate<V v> p2;
p1.and(p2).test(T t>)
3、Consumer<T t >
抽象方法:
void accept(T t);
默认方法:
Consumer<T> andThen(Consumer<? super T> after)
4、Function<T t, V v> //T 要转换的数据类型 V 被转换的数据类型
抽象方法:
T t apply(V v)
默认方法:
<V> Function<T, V> andThen(Function<? super R, ? extends V> after)
56、枚举(ENUM)
枚举:如果没有显示的写一个构造方法,则默认赠送一个无参数的构造方法。
构造方法语法:
修饰符 枚举(){}
注意:枚举构造方法的修饰符只能是private