JavaSE
2021-01-14 08:25:18 0 举报
AI智能生成
最全javase基础内容
作者其他创作
大纲/内容
选择和分支结构
选择结构
if
if..else
if...else if...esle
分支结构
switch
局部变量
概念:声明在函数内部的变量,必须先赋值再使用。
作用范围:定义行开始到所在的代码块结束。
注意:多个变量,在重合的作用范围内,不可出现重名(命名冲突)。
循环结构
while
while(布尔表达式){
语句块;
}
语句块;
}
特点:先进行判断,在执行语句块
do while
do{
循环操作;
迭代部分;
}while(循环条件);
循环操作;
迭代部分;
}while(循环条件);
特点:先执行后判断
for
for(初始部分;循环条件;迭代部分){
循环操作;
}
循环操作;
}
特点:首次即有入口条件,先判断、再执行,适用于循环次数明确的情况。
流程控制
break
(1)结束的是整个循环,它用于switch和循环结构里面
continue
(2)结束的时本次循环,循环还会执行下一次,它用于循环结构里面
嵌套循环
概念:在一个完整的循环当中,嵌套另一个完整的循环结构。
1.2 经验:
1).打印图形:外层控制行数、内层控制列数。
2).其他: 外层控制循环次数、内层控制单次循环操作。
1).打印图形:外层控制行数、内层控制列数。
2).其他: 外层控制循环次数、内层控制单次循环操作。
注意:循环要注意结束条件,不要造成死循环
数组
1.数组的概念:一组连续的存储空间, 存储多个相同数据类型的值。
数组的创建语法
先声明、再分配空间:
数据类型[] 数组名;
数组名= new数据类型[长度];
数据类型[] 数组名;
数组名= new数据类型[长度];
声明并分配空间:
数据类型[] 数组名= new数据类型[长度];
数据类型[] 数组名= new数据类型[长度];
声明并赋值(繁)
数据类型[] 数组名= new数据类型0 {value1,vale2.val.3...};
数据类型[] 数组名= new数据类型0 {value1,vale2.val.3...};
声明并赋值(简) :
数据类型[] 数组名= {value1,valu2,ale3...}; //显示初始化,注意:不可换行
数据类型[] 数组名= {value1,valu2,ale3...}; //显示初始化,注意:不可换行
数组的使用
数组中的每个数据格被称为“数组元素”。
对每个元素进行赋值或取值的操作被称为“元素的访问”。
对每个元素进行赋值或取值的操作被称为“元素的访问”。
访问元素时,需要使用“下标”(从0开始,依次+1,自动生成)。
访问的语法:数组名[下标]; //例如存: a[0]=10; 取: a[0];
数组下标:范围是1-数组的长度-1。数组的长度(数组名.length)
访问的语法:数组名[下标]; //例如存: a[0]=10; 取: a[0];
数组下标:范围是1-数组的长度-1。数组的长度(数组名.length)
访问无效下标会导致java.lang .ArrayIndexOutOfBoundsException
数组的默认值
整数:0
小数:0.0
字符:\u0000(空字符)
布尔:false
其他:null
小数:0.0
字符:\u0000(空字符)
布尔:false
其他:null
数组的遍历
概念:从头至尾,逐一-对数组的每个元素进行访问
实例
数组的扩容
创建数组时,必须显示指定长度,并在创建之后不可更改长度。
扩容的思路:
创建大于原数组长度的新数组。
将原数组中的元素依次复制到新数组中。
扩容的思路:
创建大于原数组长度的新数组。
将原数组中的元素依次复制到新数组中。
数组扩容的方法
(1)for循环实现
int[] a = {10,20,30,40,50};
int a1 = new int[a.length * 2];
for(int i =0;i<a.length;i++){
a1[i] = a[i]; }
int[] a = {10,20,30,40,50};
int a1 = new int[a.length * 2];
for(int i =0;i<a.length;i++){
a1[i] = a[i]; }
(2)System.Arraycopy(a,num1,a1,num2,l);
a :原数组 a1:目标数组 num1:原数组的起始下标 num2:目标数组的起始下标 l:要复制的元素的个数
a :原数组 a1:目标数组 num1:原数组的起始下标 num2:目标数组的起始下标 l:要复制的元素的个数
(3)先导入java.util.Arrars;
int[] a = {10,20,30,40,50};
int[] a1 = Arrays.copyOf(a,6);
int[] a = {10,20,30,40,50};
int[] a1 = Arrays.copyOf(a,6);
地址的替换
基本数据类型的变量存储的是值
引用数据类型的变量存储的是地址
引用数据类型的变量存储的是地址
nums = newNums; //将新数组的地址,赋值给nums变量,进而在后续操作nums时,则操作长度更大的新数组。
数组类型的参数
基本数据类型的参数是传入的值,一方改变另一方不受影响
引用数据类型的参数是传入的地址,一方改变另一方也随着改变
可变长参数:
概念:可接收多个同类型实参,个数不限,使用方式与数组相同。
语法:数据类型...形参名//必须定义在形参列表的最后,且只能有一个,支持0~N个参数。
int...= int[]
String... = String[]
char... = char[]
double... = double[]
method(x , xx[] , xx... );//可变长参数,是对数组的一种便利写法的补充(80%的场景用数组,20%的场 景用可变长参数)
String... = String[]
char... = char[]
double... = double[]
method(x , xx[] , xx... );//可变长参数,是对数组的一种便利写法的补充(80%的场景用数组,20%的场 景用可变长参数)
实例:
传入的实参可以为m(1,2,23,3,4,5)或者m(arr)//arr为定义的数组
Public static void m(int... b)
传入的实参可以为m(1,2,23,3,4,5)或者m(arr)//arr为定义的数组
Public static void m(int... b)
排序
冒泡排序
相邻的两个值比较大小,互换位置。比如第一个值和第二个值比完后第二个值然后再和第三个比。。。。按照给定的if判断条件进行位置的互换。
记忆: 外层length-1 ;内层length -1-i
补充:嵌套循环约定俗称的变量命名,一重循环 i; 二重循环j;三重循环k;
记忆: 外层length-1 ;内层length -1-i
补充:嵌套循环约定俗称的变量命名,一重循环 i; 二重循环j;三重循环k;
选择排序
固定值与其他值比较大小,互换位置。现将第一个值和其他后面各个值比较如果第一个值大于后面的某个值,那就将它两个调换位置,继续向后比较,这样循环一次的结果就是吧最小的值移到了最前面。
2).记忆:外层length-1 ;同时外层i作为固定值,内层的j=i+1 作为其他值的起始
2).记忆:外层length-1 ;同时外层i作为固定值,内层的j=i+1 作为其他值的起始
二维数组
概念:一维数组中的一维数组,数组中的元素,还是数组。
声明语法
声明、再分配空间:
数据类型[][] 数组名;
数组名= new数据类型[高维长度][低维长度];
数据类型[][] 数组名;
数组名= new数据类型[高维长度][低维长度];
声明、再分配空间:
数据类型[][] 数组名;
数组名= new数据类型[高维长度][低维长度];
数据类型[][] 数组名;
数组名= new数据类型[高维长度][低维长度];
声明并赋值(繁):
数据类型[][] 数组名= new数据类型[高维长度][]; //不规则数组, 自行new低维数组,这时候高维数组里面存的不是低纬数组的地址 而是null,前面数组的默认值里面提到的引用类型默认值为null
数据类型[][] 数组名= new数据类型[高维长度][]; //不规则数组, 自行new低维数组,这时候高维数组里面存的不是低纬数组的地址 而是null,前面数组的默认值里面提到的引用类型默认值为null
声明并赋值(简) :
数据类型[][] 数组名= { {v1,v2,v3},{v4,v5},{v6,v7,v8,v9} }; // 显示初始化
数据类型[][] 数组名= { {v1,v2,v3},{v4,v5},{v6,v7,v8,v9} }; // 显示初始化
注意:高维数组中的每一个元素,保存了低维数组的地址。访问array[0]等价于在访问0x0000A111("二维数组的内存分配图")
集合
Collection(克莱克深)概念及接口方法
I. Collection父接口:该体系结构的根接口,代表一组对象,称为“集合”,每个对象都是该集合的“元素”。
II. List接口的特点:有序、有下标、元素可重复。
III.Set接口的特点:无序、无下标、元素不可重复。
II. List接口的特点:有序、有下标、元素可重复。
III.Set接口的特点:无序、无下标、元素不可重复。
IV. Collection接口方法
特点:代表- -组任意类型的对象,无序、无下标。
方法:
boolean add(Object obj) //添加-一个对象。
boolean addAll(Collection c) //将一个集合中的所有对象添加到此集合中。
void clear() /清空此集合中的所有对象。
boolean contains(Object o) //检查此集合中是否包含o对象
boolean equals(Object o) //比较此集合是否与指定对象相等。
boolean isEmpty() /判断此集合是否为空
boolean remove(Object o) //在此集合中移除o对象,也可以传入下标
int size() //返回此集合中的元素个数。
Object[] toArray() //将此集合转换成数组。
方法:
boolean add(Object obj) //添加-一个对象。
boolean addAll(Collection c) //将一个集合中的所有对象添加到此集合中。
void clear() /清空此集合中的所有对象。
boolean contains(Object o) //检查此集合中是否包含o对象
boolean equals(Object o) //比较此集合是否与指定对象相等。
boolean isEmpty() /判断此集合是否为空
boolean remove(Object o) //在此集合中移除o对象,也可以传入下标
int size() //返回此集合中的元素个数。
Object[] toArray() //将此集合转换成数组。
注意:集合下面的实现类多查阅API文档
泛型集合【重点-解决应用问题】:
I. 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
II. 特点:
1). 编译时即可检查,而非运行时抛出异常。
2). 访问时,不必类型转换(拆箱)。
3). 不同泛型之间引用不能相互赋值,泛型不存在多态。
1). 编译时即可检查,而非运行时抛出异常。
2). 访问时,不必类型转换(拆箱)。
3). 不同泛型之间引用不能相互赋值,泛型不存在多态。
Collections工具类:
概念:集合工具类,定义了除了存取以外的集合常用方法。
方法
I. public static <T extends Comparable<? super T>> void sort(List<T> list) //排序,要求:必须实现Comparable,必须可与自身类型比,以及父类类型比
II. public static void reverse(List<?> list) //反转、倒置元素
III. public static void shuffle(List<?> list) //随机重置顺序
II. public static void reverse(List<?> list) //反转、倒置元素
III. public static void shuffle(List<?> list) //随机重置顺序
collection集合体系
Set集合
I. 特点:无序、无下标、元素不可重复(当插入新元素时,如果新元素与已有元素进行equals比较,结果为true时,则拒绝新元素的插入)
II. 方法:全部继承自Collection中的方法
II. 方法:全部继承自Collection中的方法
foreach循环:
for(数据类型 变量名 : 容器名称){ //可遍历集合或数组(常用在无序集合上)
}
for(数据类型 变量名 : 容器名称){ //可遍历集合或数组(常用在无序集合上)
}
Set接口实现类
I. HashSet【重要】:
1). HashSet的底层使用的HashMap类,即是将所有需要存入HashSet的值,直接保存在HashMap中
2). HashSet如何去掉重复?
3). 先判断hashCode是否一致,==比较地址,equals比较内容
1). HashSet的底层使用的HashMap类,即是将所有需要存入HashSet的值,直接保存在HashMap中
2). HashSet如何去掉重复?
3). 先判断hashCode是否一致,==比较地址,equals比较内容
II. LinkedHashSet【了解】:
1). 底层使用LinkedHashMap(链表结构)存储,节点形式单独存储数据,并可以指向下一个节点,通过顺序访问节点,可保留元素插入顺序
1). 底层使用LinkedHashMap(链表结构)存储,节点形式单独存储数据,并可以指向下一个节点,通过顺序访问节点,可保留元素插入顺序
III. TreeSet【了解】:
1). 实现了SortedSet接口,要求必须可以对元素排序。
2). 所有插入元素,必须实现Comparable接口,覆盖compareTo方法。
3). 根据compareTo方法返回0作为去重的依据,(意味重复)
1). 实现了SortedSet接口,要求必须可以对元素排序。
2). 所有插入元素,必须实现Comparable接口,覆盖compareTo方法。
3). 根据compareTo方法返回0作为去重的依据,(意味重复)
List子接口
List基本属性及方法
I. 特点:有序、有下标、元素可以重复。
II. 继承可父接口提供的共性方法,同时定义了一些独有的与下标相关的操作方法。
II. 继承可父接口提供的共性方法,同时定义了一些独有的与下标相关的操作方法。
III.接口中的方法
特点:有序、有下标、元素可以重复。
方法:
void add(int index, Object o) //在index位置插入对象o。
boolean addAll(int index, Collection c) //将一个集合中的元素添加到此集合中的index位置。
Object get(int index) //返回集合中指定位置的元素。
List subList(int fromIndex, int toIndex) //返回fromIndex和toIndex之间的集合元素。
方法:
void add(int index, Object o) //在index位置插入对象o。
boolean addAll(int index, Collection c) //将一个集合中的元素添加到此集合中的index位置。
Object get(int index) //返回集合中指定位置的元素。
List subList(int fromIndex, int toIndex) //返回fromIndex和toIndex之间的集合元素。
List实现类
概念
I. JDK8的ArrayList,实际初始长度是0
II. 首次添加元素时,需要实际分配数组空间,执行数组扩容操作
III. 真正向数组中插入数据,(Lazy懒)用的时候再创建,或再加载,有效的降低无用内存的占用
II. 首次添加元素时,需要实际分配数组空间,执行数组扩容操作
III. 真正向数组中插入数据,(Lazy懒)用的时候再创建,或再加载,有效的降低无用内存的占用
ArrayList类
I. 数组结构存储,查询快,增删慢。//注册(1次)-> 查询(N次)
II. JDK 1.2发布,执行效率快,线程不安全。
II. JDK 1.2发布,执行效率快,线程不安全。
Vector类
I. 数组结构存储,查询快,增删慢。
II. JDK 1.0发布,执行效率慢,线程安全。
II. JDK 1.0发布,执行效率慢,线程安全。
LinkedList
I. 链表(链接列表)结构存储,查询慢、增删快。
II. 了解:Queue接口:队列、双端队列
III. 了解:栈结构Last In First Out(后进先出)
IV. 了解:队列结构First In First Out(先进先出)
II. 了解:Queue接口:队列、双端队列
III. 了解:栈结构Last In First Out(后进先出)
IV. 了解:队列结构First In First Out(先进先出)
Map体系集合
I. Map:地图、映射
I. 概念:存储一对数据(Key-value),无序、无下标、键不可重复、值可以重复。
I. 概念:存储一对数据(Key-value),无序、无下标、键不可重复、值可以重复。
HashMap
II. HashMap算法:拿到任何一个对象好,通过hash(key)做运算,key>>>16(除以16),只可能得到0~15之间的一个数组,作为插入数组的下标
JDK 1.2版本 线程不安全,运行效率快
Hashtable
III. Hashtable:HashMap的线程安全版本
Properties
V. Properties:Hashtable 子类,主要用于存储key和value都是字符串的情况,常在读取配置文件之后,保存文件中的键值对。反射、JDBC
TreeMap
IV. TreeMap:自动对key做排序,根据compareTo的返回值去重
泛型
高级类别的知识,熟练应用,需要时间、经验的积累(常用名称:E = Element / T = Type / K = Key / V = Value)
I. 概念:约束-规范类型
II. 泛型的场景:
1). 定义泛型:
A). 实例泛型:
a). 类:创建对象时,为类所定义的泛型,进行参数化赋值
b). 接口:实现接口时,为接口所定义的泛型,进行参数化赋值
a). 类:创建对象时,为类所定义的泛型,进行参数化赋值
b). 接口:实现接口时,为接口所定义的泛型,进行参数化赋值
B). 静态泛型:
a). 定义在方法的返回值类型前面:<T>、<T extends Object>、<T extends Comparable<T>>、<T extends Comparable<? super T>>
2). 定义在方法的形参列表当中:<?>、<? extends Object>、<? super Integer>,不支持使用&
a). 定义在方法的返回值类型前面:<T>、<T extends Object>、<T extends Comparable<T>>、<T extends Comparable<? super T>>
2). 定义在方法的形参列表当中:<?>、<? extends Object>、<? super Integer>,不支持使用&
定义泛型方法
当泛型方法调用时,由传入的参数的类型确定
注意
当泛型类和泛型方法上都有同一个自定义泛型,根据就近原则来决定数据类型由哪个泛型确定!
定义泛型静态方法
概念
将泛型定义在静态方法上
注意
普通方法可以使用泛型类上的泛型
静态方法不可以使用泛型类上的泛型
泛型通配符
概念
规定泛型确定类型的范围!
分类
<?>
泛型的确定类型可以是任意类型
<? extends E>
泛型的确定类型可以是E及子类
<? super E>
泛型的确定类型可以是E及父类
反编译
反编译:javap -verbose 文件名称(是.class) > 自定义文件名称.bytecode
IO框架
流的概念
I.内存与存储设备之间传输数据的通道
流的分类
I.方向(重点)
(1)输入流:将<存储设备>中的内容读入到<内存>中
输出流:将<内存>中的内容写入到<存储设备>中
输出流:将<内存>中的内容写入到<存储设备>中
II.单位
(1)字节流:以字节为单位,可以读写所有数据 。
(2)字符流:以字符为单位,只能读写文本数据
(2)字符流:以字符为单位,只能读写文本数据
III.功能
(1)节点流:具有实际传输数据的读写功能
(2)过滤流:在节点流的基础之上增强功能。
(2)过滤流:在节点流的基础之上增强功能。
字节流
字节流父类
InputStream(抽象类):字节输入流
public int read(){}
public int read(byte[] b){}
public int read(byte[] b,int off,int len){}
public int read(){}
public int read(byte[] b){}
public int read(byte[] b,int off,int len){}
OutputStream(抽象类):字节输出流
public void write(int n){}
public void write(byte[] b){}
public void write(byte[] b,int off,int len){}
public void write(int n){}
public void write(byte[] b){}
public void write(byte[] b,int off,int len){}
字节过滤流
(1)BufferedOutputStream
(2)BufferedInputStream
(3)提供了IO效率,减少访问磁盘的次数。数据存放在缓冲区中。flush刷新缓冲区,提交数据
(2)BufferedInputStream
(3)提供了IO效率,减少访问磁盘的次数。数据存放在缓冲区中。flush刷新缓冲区,提交数据
对象流
(1)ObjectOutputStream
(2)ObjectInputStream
(3)增强了读写8种基本数据类型和字符串功能
(4)读写对象,实现对象的持久化存储
(5)增强了读写对象的功能:
①readObject() 从流中读取一个对象
②writeObject(Object obj) 向流中写入一个对象
(2)ObjectInputStream
(3)增强了读写8种基本数据类型和字符串功能
(4)读写对象,实现对象的持久化存储
(5)增强了读写对象的功能:
①readObject() 从流中读取一个对象
②writeObject(Object obj) 向流中写入一个对象
对象的属性必须实现Serializable接口
字节节点流
FileOutputStream:
public void write(byte[] b) //一次写多个字节,将b数组中所有字节,写入输出流。
public void write(byte[] b) //一次写多个字节,将b数组中所有字节,写入输出流。
FileInputStream:
public int read(byte[] b) //从流中读取多个字节,将读到内容存入b数组,返回实际
读到的字节数;如果达到文件的尾部,则返回-1
public int read(byte[] b) //从流中读取多个字节,将读到内容存入b数组,返回实际
读到的字节数;如果达到文件的尾部,则返回-1
V.序列化/反序列化
(1)必须实现Serializable接口。 标识序列化功能
(2)必须保证所有属性均支持序列化。
(3)Transient修饰的为临时属性,不参与序列化
(4)读取到文件末尾时:java.IO.EOFException
(2)必须保证所有属性均支持序列化。
(3)Transient修饰的为临时属性,不参与序列化
(4)读取到文件末尾时:java.IO.EOFException
字符流
字符流的父类
Reader字符输入流
①public int read(){}
②public int read(char[] c){}
③public int read(char[] b,int off,int len){}
②public int read(char[] c){}
③public int read(char[] b,int off,int len){}
Writer字符输出流
①public void write(int n){}
②public void write(String str){}
③public void write(char[] c){}
②public void write(String str){}
③public void write(char[] c){}
字符节点流
FileReader字符输入节点流
public int read(char[] c) //从流中读取多个字符,将读到内容存入c数组,返回实际
读到的字符数;如果达到文件的尾部,则返回-1。
读到的字符数;如果达到文件的尾部,则返回-1。
FileWriter字符输出节点流
(1)FileWriter:public void write(String str) //一次写多个字符,将b数组中所有字符,写入输出流
字符过滤流
BufferedReader
readLine一次读一行
BufferedWriter
①支持输入换行符。
②可一次写一行
②可一次写一行
PrintWriter
封装了print() / println()方法,支持写入后换行。
I.桥转换流
InputStreamReader
OutputStreamWriter
(3)可将字节流转换为字符流,可设置编码方式(编码与解码要一致)
使用步骤
(1)创建节点流
(2)[创建过滤流,设置字符编码集]
(3)封装过滤流
(4)读写数据
(5)关闭流
(2)[创建过滤流,设置字符编码集]
(3)封装过滤流
(4)读写数据
(5)关闭流
桥转换流的具体使用
//1.先创建字节输出流
OutputStream fos = new FileOutputStream("files\\fos.txt");
//编码2.创建桥转换流(转换为字符输出流)
OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");//指定输出的数据 编码格式
//3.包装成字符过滤流
PrintWriter prw = new PrintWriter(osw);
OutputStream fos = new FileOutputStream("files\\fos.txt");
//编码2.创建桥转换流(转换为字符输出流)
OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");//指定输出的数据 编码格式
//3.包装成字符过滤流
PrintWriter prw = new PrintWriter(osw);
File
FileFilter接口
public interface FileFilter
boolean accept(File pathname)
boolean accept(File pathname)
当调用File类中的listFiles()方法时,支持传入FileFilter接口接口实现类,
对获取文件进行过滤,只有满足条件的文件或者文件夹的才可出现在listFiles()的返回
值中。
对获取文件进行过滤,只有满足条件的文件或者文件夹的才可出现在listFiles()的返回
值中。
File常用方法
System.out.println(file.canExecute());//所有可以打开的文件或文件夹,都是可执行的!
// System.out.println(file.canWrite());//能不能修改文件
// System.out.println(file.canRead());//能不能执行文件
//
// System.out.println(file.createNewFile());//新建一个文件,如果不存在的话
// System.out.println(file.delete());如果文件存在,则删除,返回true
// Thread.sleep(2000);
// file.deleteOnExit();//JVM终止时,执行删除文件
// System.out.println(file.exists());
// System.out.println(file.getAbsolutePath());//绝对
// System.out.println(file.getPath());//相对
// System.out.println(file.getName());//文件名 名字.后缀
// System.out.println(file.getFreeSpace() / 1024 / 1024/ 1024);//获取硬盘的空闲空间
// System.out.println(file.getTotalSpace()/1024 / 1024 / 1024);//总空间
// System.out.println(file.getParent());//指定文件的上一级目录
// System.out.println(file.canWrite());//能不能修改文件
// System.out.println(file.canRead());//能不能执行文件
//
// System.out.println(file.createNewFile());//新建一个文件,如果不存在的话
// System.out.println(file.delete());如果文件存在,则删除,返回true
// Thread.sleep(2000);
// file.deleteOnExit();//JVM终止时,执行删除文件
// System.out.println(file.exists());
// System.out.println(file.getAbsolutePath());//绝对
// System.out.println(file.getPath());//相对
// System.out.println(file.getName());//文件名 名字.后缀
// System.out.println(file.getFreeSpace() / 1024 / 1024/ 1024);//获取硬盘的空闲空间
// System.out.println(file.getTotalSpace()/1024 / 1024 / 1024);//总空间
// System.out.println(file.getParent());//指定文件的上一级目录
网络编程
网络:由点和线构成,表示诸多对象间的相互联系
计算机网络
为实现资源共享和信息传递,通过通信线路连接起来的若干主机(Host)。
互联网:(Internet)点与点相连
万维网:(WWW – World Wide Web)端与端相连
物联网:( IoT - Internet of things) 物与物相连 •
万维网:(WWW – World Wide Web)端与端相连
物联网:( IoT - Internet of things) 物与物相连 •
网络编程:让计算机与计算机之间建立连接、进行通信
网络模型
OSI(Oper System Interconnection)开放式系统互联
第七层:应用层负责文件访问和管理、可靠运输服务、远程操作服务。(HTTP、FTP、SMTP)
第六层:表示层负责定义转换数据格式及加密,允许选择以二进制或ASCII格式传输。
第五层:会话层负责使应用建立和维持会话,使通信在失效时继续恢复通信。(断点续传)
第四层:传输层负责是否选择差错恢复协议、数据流重用、错误顺序重排。(TCP、UDP)
第三层:网络层负责定义了能够标识所有网络节点的逻辑地址。(IP地址)
第二层:链路层在物理层上,通过规程或协议(差错控制)来控制传输数据的正确性。(MAC)
第一层:物理层为设备之间的数据通信提供传输信号和物理介质。(双绞线、光导纤维)
第六层:表示层负责定义转换数据格式及加密,允许选择以二进制或ASCII格式传输。
第五层:会话层负责使应用建立和维持会话,使通信在失效时继续恢复通信。(断点续传)
第四层:传输层负责是否选择差错恢复协议、数据流重用、错误顺序重排。(TCP、UDP)
第三层:网络层负责定义了能够标识所有网络节点的逻辑地址。(IP地址)
第二层:链路层在物理层上,通过规程或协议(差错控制)来控制传输数据的正确性。(MAC)
第一层:物理层为设备之间的数据通信提供传输信号和物理介质。(双绞线、光导纤维)
TCP/IP模型
一组用于实现网络互连的通信协议,将协议分成四个层次
第四层:应用层负责传送各种最终形态的数据,是直接与用户打交道的层,典型协议是HTTP、FTP等。
第三层:传输层负责传送文本数据,主要协议是TCP、UDP协议。
第二层:网络层负责分配地址和传送二进制数据,主要协议是IP协议。
第一层:接口层负责建立电路连接,是整个网络的物理基础,典型的协议包括以太网、ADSL等等
第三层:传输层负责传送文本数据,主要协议是TCP、UDP协议。
第二层:网络层负责分配地址和传送二进制数据,主要协议是IP协议。
第一层:接口层负责建立电路连接,是整个网络的物理基础,典型的协议包括以太网、ADSL等等
网络协议
TCP/UDP协议
TCP
TCP协议:Transmission Control Protocol 传输控制协议
是一种面向连接的、可靠的、基于字节流的传输层通信协议。数据大小无限制。建立连 接的过程需要三次握手,断开连接的过 程需要四次挥手。
是一种面向连接的、可靠的、基于字节流的传输层通信协议。数据大小无限制。建立连 接的过程需要三次握手,断开连接的过 程需要四次挥手。
UDP
UDP协议:User Datagram Protocol 用户数据报协议
是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,每个包的大小 64KB。
是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,每个包的大小 64KB。
IP协议
Internet Protocol Address 互联网协议地址/网际协议地址
分配给互联网设备的数字标签(唯一标识)。
分配给互联网设备的数字标签(唯一标识)。
IPV4
4字节32位整数,并分成4段8位的二进制数,每8位之间用圆点隔开,每8位 整数可以转换为一个0~255的十进制整数。 格式:D.D.D.D 例如:255.255.255.255
应用分类
A类:政府机构,1.0.0.1 ~ 126.255.255.254
B类:中型企业,128.0.0.1 ~ 191.255.255.254
C类:个人用户,192.0.0.1 ~ 223.255.255.254
D类:用于组播,224.0.0.1 ~ 239.255.255.254
E类:用于实验,240.0.0.1 ~ 255.255.255.254
回环地址:127.0.0.1,指本机,一般用于测试使用。
查看IP命令:ipconfig • 测试IP命令:ping D.D.D.D
B类:中型企业,128.0.0.1 ~ 191.255.255.254
C类:个人用户,192.0.0.1 ~ 223.255.255.254
D类:用于组播,224.0.0.1 ~ 239.255.255.254
E类:用于实验,240.0.0.1 ~ 255.255.255.254
回环地址:127.0.0.1,指本机,一般用于测试使用。
查看IP命令:ipconfig • 测试IP命令:ping D.D.D.D
IPV6
16字节128位整数,并分成8段十六进制数,每16位之间用圆点隔开,每16 位整数可以转换为一个0~65535的十进制数。 格式:X.X.X.X.X.X.X.X 例如:FFFF.FFFF.FFFF.FFFF.FFFF.FFFF.FFFF.FFFF
Port端口
端口号:在通信实体上进行网络通讯的程序的唯一标识。
端口的分类
公认端口:0~1023
注册端口:1024~49151
动态或私有端口:49152~65535
常用端口:
MySql:3306
Oracle:1521
Tomcat:8080
SMTP:25
Web服务器:80
FTP服务器:21
Oracle:1521
Tomcat:8080
SMTP:25
Web服务器:80
FTP服务器:21
InetAddress类
概念:表示互联网协议(IP)地址对象,封装了与该IP地址相关的所有信息,构造方法私有化,无法创建对象 并提供获取信息的常用方法。
方法
public static InetAddress getLocalHost() 获得本地主机地址对象
public static InetAddress getByName(String host) 根据主机名称获得地址对象
public static InetAddress[] getAllByName(String host) 获得所有相关地址对象
public String getHostAddress() 获取IP地址字符串
public String getHostName() 获得IP地址主机名
public static InetAddress getByName(String host) 根据主机名称获得地址对象
public static InetAddress[] getAllByName(String host) 获得所有相关地址对象
public String getHostAddress() 获取IP地址字符串
public String getHostName() 获得IP地址主机名
5.基于TCP的网络编程(Socket)
Socket编程
Socket(套接字)是网络中的一个通信节点。
分为客户端Socket与服务器ServerSocket。
通信要求:IP地址 + 端口号
分为客户端Socket与服务器ServerSocket。
通信要求:IP地址 + 端口号
II.开发步骤
第一步:建立通信连接(会话)
创建ServerSocket,指定端口号
调用accept等待客户端接入
调用accept等待客户端接入
第二步:客户端请求服务器
创建Socket,指定服务器IP + 端口号
使用输出流,发送请求数据给服务器
使用输入流,接收响应数据到客户端(等待)
使用输出流,发送请求数据给服务器
使用输入流,接收响应数据到客户端(等待)
第三步:服务器响应客户端
使用输入流,接收请求数据到服务器(等待)
使用输出流,发送响应数据给客户端
使用输出流,发送响应数据给客户端
反射
1.类对象
类的对象:基于某个类 new 出来的对象,也称为实例对象。
类对象:类加载的产物,封装了一个类的所有信息(类名、父类、接口、 属性、方法、构造方法)
类对象:类加载的产物,封装了一个类的所有信息(类名、父类、接口、 属性、方法、构造方法)
2.类对象的获取(创建)
通过类的对象,获取类对象
Student s = new Student();
Class c = s.getClass();
Student s = new Student();
Class c = s.getClass();
通过类名获取类对象
Class c = 类名.class;
Class c = 类名.class;
通过静态方法获取类对象 ,常用的
Class c=Class.forName(“包名.类名”);
Class c=Class.forName(“包名.类名”);
类对象的常用方法
• public String getName() 获取类对象的全限定名
• public Package getPackage() 获取类对象的包名
• public Class<? super T> getSuperclass() 获取父类的Class对象
• public Class<?>[] getInterfaces() 获取接口的Class对象
• public Field[] getFields() //获取属性(自身+父类的公开属性)
• public Field[] getDeclaredFields()//获得Class对象的自身所有属性(包括私有)
• public Method[] getMethods() 获取方法(自身+父类的所有公开方法)
• public Method[] getDeclaredMethods()//获得Class对象的自身所有方法(包括私有)
• public Constructor<?>[] getConstructors() 获得构造方法
• public T newInstance()//用Class对象创建实例对象
• public Package getPackage() 获取类对象的包名
• public Class<? super T> getSuperclass() 获取父类的Class对象
• public Class<?>[] getInterfaces() 获取接口的Class对象
• public Field[] getFields() //获取属性(自身+父类的公开属性)
• public Field[] getDeclaredFields()//获得Class对象的自身所有属性(包括私有)
• public Method[] getMethods() 获取方法(自身+父类的所有公开方法)
• public Method[] getDeclaredMethods()//获得Class对象的自身所有方法(包括私有)
• public Constructor<?>[] getConstructors() 获得构造方法
• public T newInstance()//用Class对象创建实例对象
设计模式
工厂设计模式
开发中有一个非常重要的原则“开闭原则”,对拓展开放、对修改关闭。
工厂模式主要负责对象创建的问题。
可通过反射进行工厂模式的设计,完成动态的对象创建。
工厂模式主要负责对象创建的问题。
可通过反射进行工厂模式的设计,完成动态的对象创建。
单例模式
单例(Singleton):只允许创建一个该类的对象。
方式1:饿汉式(类加载时创建,天生线程安全)
方式2:懒汉式(使用时创建,线程不安全,加同步)
双重锁
方式3:懒汉式(使用时创建,线程安全)
私有静态内部类·
语言基础
变量
计算机内存的存储空间,存储数据的基本单位
组成部分
数据类型
变量名
值
声明方式
先声明,后赋值
int i;
i = 1;
i = 1;
声明并赋值
int a = 1;
多个同类型的变量声明并复制
数据类型
基本数据类型
int 整型
byte
short
int
整数的默认类型
long
小数
float
double
小数的默认类型
boolean 布尔型
true
false
字符
char
转义字符
\'
\"
\\
\t
缩进
\n
换行
引用数据类型
String 字符串
数组
对象
数据类型转换
自动类型的转换
两种类型兼容,目标类型大于原类型
强制类型的转换
两种类型兼容,目标类型小于原类型
转换规则
整数长度够,数据完整
整数长度不够,数据截断
小数强转整数,小数部份丢失
字符整数互转,数据完整
要保证再字符的取值范围内0~65535
boolean不能与其他类型互转
运算符
算数运算符
+ - * / % ++ --
赋值运算符
=,*=,+=,-=,/=,%=
逻辑运算符
&&,||,!
关系运算符
>,<,>=,<=,==,!=
三元运算符
boolean表达式 ? 结果1: 结果2;
自动类型提升
两个操作数其中一个为double类型,计算结果提升为double
两个操作数中没有double,有一个为float类型,计算结果提升为float类型
两个操作数没有double和float类型,有一个为long类型,计算结果提升为long类型
两个操作数没有double,float和long类型,有一个为int类型,计算结果提升为int类型
两个操作位为short和byte类型,计算结果提升为int类型
特殊:任何类型与String相加,实为拼接,结果都为String类型
控制台输入
先导入需要的类库:import java.util.Scanner;
在对类实例化:Scanner sc = new Scanner(System.in);
调用类中的函数:int input = sc.nextInt();
.nextInt(); :获得整数
.nextdouble(); :获得小数
.next(); :获得字符串
.next().charAt(0) :获得单个字符
.nextdouble(); :获得小数
.next(); :获得字符串
.next().charAt(0) :获得单个字符
函数
函数的概念:实现特定功能的一段代码,可反复使用。
定义语法
public static void 函数名(){
函数体;
}
函数体;
}
经验:将需要在多个位置重复使用的一-组代码,定义在函数内
函数定义位置:函数定义要与主函数并列
函数的调用:在需要执行函数代码的位置,通过函数名称进行调用
函数的参数·
形式参数
形式参数是在函数定义的时候写的,他没有具体的值
实际参数
实际参数是在函数调用的时候用到的,他需要和形式参数相对应并写入对应类型的值,具有实际值
特别增加
String类型用==是,比较的是地址而不是内容
equals
比较的是内容
使用方法
s1.equals(s2);
逻辑运算符非
相当于取反的意思
真的取反为假
假的取反威真
例子
s1.equals(s2);
意思为s1和s2内容相等吗
!s1.equals(s2);
意思为s1和s2内容不相等吗
函数的返回值以及返回值类型
public static 返回值类型 函数名(){
return 返回值;}
return 返回值;}
返回值类型可以是基本数据类型和引用类型
返回值和返回值类型相匹配
return关键字
应用在具有返回值类型的函数中:
return value; //表示结束当前函数,并伴有返回值,返回到函数调用处。
return value; //表示结束当前函数,并伴有返回值,返回到函数调用处。
应用在没有返回值类型(void) 的函数中:
return; //表示结束当前函数,直接返回到函数调用处。
return; //表示结束当前函数,直接返回到函数调用处。
函数的递归
何时使用递归?
当需要解决的问题可以拆分成若千个小问题,大小问题的解决方法相同。
有固定规律,函数中自已调用自已。
有固定规律,函数中自已调用自已。
如何正确使用递归?
设置有效的出口条件,避免无穷递归。
注意:所有能以递归解决的问题,循环都可以解决。当解决复杂问题时,递归的实现方式更为简单。
特别注意:递归应要注明出口条件
面向对象
程序和对象
程序是为了模拟现实世界、解决现实问题而使用计算机语言编写的指令集合。
程序员眼中,世界是由无数个对象组成的。
程序员眼中,世界是由无数个对象组成的。
对象的概念,特征和行为
任何对象,一定有自己的特征和行为。
特征:称为属性,一般为名词,代表对象都有什么。
行为:称为方法,一般为动词,代表对象能做什么。
行为:称为方法,一般为动词,代表对象能做什么。
一切客观存在的事物都是对象,万物皆对象。
初期:看得见、摸得着、并真实存在,都是对象。
初期:看得见、摸得着、并真实存在,都是对象。
程序中的对象
程序如何模拟现实世界
1). 现实世界中,都是对象,程序中也应有对象。
2). 程序当中必须具有和现实中相同的对象,用以模拟。
3). 使用程序中的对象,代表现实中的对象,并执行操作,解决现实问题。
2). 程序当中必须具有和现实中相同的对象,用以模拟。
3). 使用程序中的对象,代表现实中的对象,并执行操作,解决现实问题。
现实的对象从哪来
手机 -> 工厂 -> 图纸(模板)
现实与程序
1). 现实中的对象,来自于模板,通过模板造出来的实体,即是现实的对象。
2). 程序中的对象,来自于模板(“类”),通过类造出来的实体,即是程序中的对象。
2). 程序中的对象,来自于模板(“类”),通过类造出来的实体,即是程序中的对象。
定义类和对象
类名一定要清晰准确的表达出是什么类,
对象只是类的一个实例,可以new无限个
对象只是类的一个实例,可以new无限个
类与对象的关系
I. 类:定义了对象应具有的特征和行为,类是对象的模板。
II. 对象:拥有多个特征和行为的实体,对象是类的实例。
II. 对象:拥有多个特征和行为的实体,对象是类的实例。
PS:
属性、实例变量、成员变量,三者等价
实例方法、成员方法,二者等价
reference - 引用、句柄、指针
属性、实例变量、成员变量,三者等价
实例方法、成员方法,二者等价
reference - 引用、句柄、指针
实例变量与局部变量的区别
定义位置
实例变量定义在类的内部,方法的外部
局部变量定义在方法的内部
局部变量定义在方法的内部
默认值
实例变量默认值与数组相同
局部变量没有默认值
局部变量没有默认值
使用范围
实例变量本类有效
局部变量从定义行到包含其结构结束
局部变量从定义行到包含其结构结束
命名冲突
实例变量可与局部变量重名,局部变量优先
局部变量不允许重名
局部变量不允许重名
方法的重载
概念:在一个类中定义多个相同名称的方法。
1). 方法名称相同
2). 参数列表不同
3). 与访问修饰符、返回值无关
2). 参数列表不同
3). 与访问修饰符、返回值无关
1). 屏蔽用户的使用差异,方便。
可根据传入的参数不同调用不同的方法
可根据传入的参数不同调用不同的方法
构造方法
概念:类中的特殊方法,主要用于创建对象。将对象初始化
特点:1). 名称与类名完全相同(包括大小写)。
2). 没有返回值类型。
3). 创建对象时(new对象时),触发构造方法的调用,不可通过句点的形式手工调用。
2). 没有返回值类型。
3). 创建对象时(new对象时),触发构造方法的调用,不可通过句点的形式手工调用。
注意:(1)如果没有在类中显示定义过构造方法,则编译器默认提供无参构造方法。
(2):如果已经手动添加过有参构造方法,则无参构造方法不再默认提供,可结合需求自行添加。(建议,必须手动添加无参构造方法)
(2):如果已经手动添加过有参构造方法,则无参构造方法不再默认提供,可结合需求自行添加。(建议,必须手动添加无参构造方法)
this关键字
this代表“当前实例”,即是模板中的当前对象,模板服务与哪个对象,this就指向哪个对象。
用法
this第一种用法:调用本类中的实例属性、实例方法。例如:this.name、this.run()
this第二种用法:调用本类中的其他构造方法。例如:this()、this(实参)。注意:必须在构造方法的首行,并且必须在构造方法中使用。
对象的创建过程
内存中开辟对象空间
为各个属性赋予初始值
执行构造方法中的代码
[将对象的地址赋值给变量]
为各个属性赋予初始值
执行构造方法中的代码
[将对象的地址赋值给变量]
三大特性
封装
概念:尽可能隐藏对象的内部实现细节,控制对象的修改及访问的
private的访问修饰符,修饰属性,达到本类可见的效果。
get/set方法是外界访问私有属性的唯一通道,方法内部可对数据进行过滤。(可在set方法中添加过滤条件)
提供公共访问方法,以保证数据可以正常录入。
数据私有化行为公开化
继承
程序中的继承,是类与类之间特征和行为的一种赠与或获得。
类与类之间必须满足“is a”的关系。
类与类之间必须满足“is a”的关系。
父类的选择:功能越精细,重合点越多的,越接近直接父类。
父类的抽象:根据程序需要使用到的多个具体类,进行共性的提取,进而定义父类。
在一组相同或类似的类中,抽取出共性的特征和行为,定义在父类中,实现重用。
产生继承关系之后,子类可以使用父类中的属性和方法,也可定义子类独有的属性和方法。
完整的子类 = 父类共性 + 子类独有
父类的抽象:根据程序需要使用到的多个具体类,进行共性的提取,进而定义父类。
在一组相同或类似的类中,抽取出共性的特征和行为,定义在父类中,实现重用。
产生继承关系之后,子类可以使用父类中的属性和方法,也可定义子类独有的属性和方法。
完整的子类 = 父类共性 + 子类独有
好处:既提高代码的复用性,又提高代码的可扩展性。
Java为单继承,一个类只能有一个直接父类,但可以多级继承,属性和方法逐级叠加。
访问修饰符://其他:不在一个包中,还没有继承关系
继承中的不可继承
1). 父类的构造方法,子类不可继承。
2). 父类中由private修饰的成员,不可继承(不可见)。
3). 父类中由default修饰的成员,子类不在同包时,不可继承(不可见)。
2). 父类中由private修饰的成员,不可继承(不可见)。
3). 父类中由default修饰的成员,子类不在同包时,不可继承(不可见)。
继承中方法的重写/覆盖
当父类提供的方法无法满足子类需求时,可以在子类中定义和父类相同的方法进行覆盖。
要求
a). 方法名、参数表、返回值,必须与父类完全相同。
b). 访问修饰符应与父类相同或比父类更宽泛。
a). 方法名、参数表、返回值,必须与父类完全相同。
b). 访问修饰符应与父类相同或比父类更宽泛。
执行机制:子类覆盖父类方法后,优先执行子类覆盖后的方法版本。
定义语法
class 子类 extends 父类
多态
多态指允许不同类的对象(同一父类的子类对象)对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)同一类型变量(父类类型)在调用相同的方法(子类重写父类的方法)时结果不同。
概念:父类引用指向子类对象,从而产生多种形态。
构成多态的前提,二者之间必须具有直接或间接的继承关系,父类引用可指向子类对象,进而形成多态。
父类引用仅可调用父类中所声明的属性和方法,不可调用子类独有的属性和方法。
多态应用的两种场景
场景一:使用父类作为方法形参,实现多态
调用方法时,可传递的实参类型包括:本类型对象+其所有的子类对象。
调用方法时,可传递的实参类型包括:本类型对象+其所有的子类对象。
场景二。 使用父类作为方法返回值,实现多态。
调用方法后,可得到的结果类型包括:本类型对象+其所有的子类对象。
调用方法后,可得到的结果类型包括:本类型对象+其所有的子类对象。
装箱和拆箱
装箱:父类引用中保存真实子类对象,称为向上转型(多态核心概念)。
父类类型 变量名 = new 子类类型();
拆箱:将父类应用中的真实子类对象,强转回子类本身类型,称为向下转型。
子类类型 变量名 =(子类类型)父类类型的变量名;
注意:向下转型时,如果父类引用中的子类对象的类型与目标类型不匹配,则会发生类型转换异常。java.lang.ClassCastException
instanceof关键字
语法:父类引用 instanceof 类型(返回boolean类型的结果)
多态的作用
a). 屏蔽子类间的差异。
b). 灵活、耦合度低。
b). 灵活、耦合度低。
三大修饰符
abstract抽象
abstract的意思:抽象的,似是而非的,像,却又不是,具备某种对象的特征,但不完整。
abstract修饰类,意为“不够完整、不够具体,不该独立存在”
I. 即为抽象类,不能独立new对象。
II. 可被子类继承,对子类提供共性的属性和方法。
III. 可声明引用,更纯粹的使用多态。
IV. 抽象类的构造方法的作用:构建子类对象时,先构建父类对象,由父类共性+子类独有组成完整的子类对象。
II. 可被子类继承,对子类提供共性的属性和方法。
III. 可声明引用,更纯粹的使用多态。
IV. 抽象类的构造方法的作用:构建子类对象时,先构建父类对象,由父类共性+子类独有组成完整的子类对象。
抽象方法
1).抽象方法没有方法体连大括号都没有,只有声明部分加分号结束
2)有抽象方法的类一定是抽象类,抽象类不一定有抽象方法
3)抽象方法一定要在子类中重写抽象方法
2)有抽象方法的类一定是抽象类,抽象类不一定有抽象方法
3)抽象方法一定要在子类中重写抽象方法
static静态
静态与实例的区别:
实例属性是每个对象各自持有的独立空间(多份),对象单方面修改,不会影响其他对象。
静态属性是整个类共同持有的共享空间(一份),任何对象修改,都会影响其他对象。
静态的概念
I. static可以修饰属性和方法,即为静态属性(类属性)、静态方法(类方法)
II. 静态成员是全类所有对象共享的,全类只有一份,不因创建多个对象而产生多份。
III. 不必创建对象,也可通过类名,直接访问静态成员。
IV. 经验:访问静态属性和方法时,可直接通过“类名.静态属性名”以及“类名.静态方法名”(推荐)
II. 静态成员是全类所有对象共享的,全类只有一份,不因创建多个对象而产生多份。
III. 不必创建对象,也可通过类名,直接访问静态成员。
IV. 经验:访问静态属性和方法时,可直接通过“类名.静态属性名”以及“类名.静态方法名”(推荐)
静态的特点
I. 静态方法允许直接访问静态成员。
II. 静态方法不能直接访问非静态成员。
III. 静态方法中不允许使用this或super关键字。
IV. 静态方法可以继承,不能覆盖,没有多态。
II. 静态方法不能直接访问非静态成员。
III. 静态方法中不允许使用this或super关键字。
IV. 静态方法可以继承,不能覆盖,没有多态。
类加载
I.JVM首次使用某个类时,将该类的.class文件加载到内存中,进行保存。
II.加载时机:
1). 创建对象
2). 创建子类对象
3). 调用静态属性和方法
4). Class.forName(“全限定名”); //主动的加载一个类
1). 创建对象
2). 创建子类对象
3). 调用静态属性和方法
4). Class.forName(“全限定名”); //主动的加载一个类
静态代码块
I. 类加载时,触发静态代码块的执行(仅一次)。
II. 执行地位:静态属性初始化之后。
III. 作用:可为静态属性赋值,或必要的初始行为。
II. 执行地位:静态属性初始化之后。
III. 作用:可为静态属性赋值,或必要的初始行为。
总结
static修饰的成员为静态成员,无需创建对象,可直接通过类名访问。
静态方法不能直接访问非静态成员,非静态方法可以访问静态成员 。
静态方法中不能使用this或super。
静态方法可以继承、不能重写、没有多态。
静态代码块在类加载时被执行,且只执行一次。
静态方法不能直接访问非静态成员,非静态方法可以访问静态成员 。
静态方法中不能使用this或super。
静态方法可以继承、不能重写、没有多态。
静态代码块在类加载时被执行,且只执行一次。
final常量
I. 修饰类:此类不能被继承
II. 修饰方法:此方法不能被覆盖
II. 修饰方法:此方法不能被覆盖
III.修饰变量
1). 局部常量:显示初始化
2). 实例常量的赋值:显示初始化、动态代码块、构造方法。
要求:
a).实例常量赋值deadline:在构造方法完成之前,为实例常量赋值即可。
b).如果在构造方法中为实例常量赋值,必须保证所有的构造方法都可正确赋值。
要求:
a).实例常量赋值deadline:在构造方法完成之前,为实例常量赋值即可。
b).如果在构造方法中为实例常量赋值,必须保证所有的构造方法都可正确赋值。
3). 静态常量的赋值:显示初始化、静态代码块。
要求:
a). 静态常量赋值deadline:在类加载完成之前(通过类名调用之前),为静态常量赋值即可。
要求:
a). 静态常量赋值deadline:在类加载完成之前(通过类名调用之前),为静态常量赋值即可。
不同常量类型的特点:
1). 基本数据类型常量:值不可变。
2). 引用数据类型常量:地址不可变。
2). 引用数据类型常量:地址不可变。
接口
接口的语法:
I. 相当于特殊的抽象类,定义方式、组成部分,与抽象类类似。
II. 接口中只能定义公开静态常量(变量)
III. 接口中只能定义公开抽象方法(方法)
IV. 接口不是类
II. 接口中只能定义公开静态常量(变量)
III. 接口中只能定义公开抽象方法(方法)
IV. 接口不是类
接口与抽象类的异同:
相同:
1). 可以编译成字节码文件
2). 不能创建对象。(接口不是类,不是模板的概念,也没有构造方法)
3). 可以声明引用。
4). 具备Object定义的方法。
1). 可以编译成字节码文件
2). 不能创建对象。(接口不是类,不是模板的概念,也没有构造方法)
3). 可以声明引用。
4). 具备Object定义的方法。
不同:
1). 接口中的属性只能是公开静态常量(隐式使用public static final修饰)
2). 接口中的方法只能是公开抽象方法(隐式使用public abstract修饰)
3). 没有构造方法、没有动态代码块、没有静态代码块
1). 接口中的属性只能是公开静态常量(隐式使用public static final修饰)
2). 接口中的方法只能是公开抽象方法(隐式使用public abstract修饰)
3). 没有构造方法、没有动态代码块、没有静态代码块
接口的微观概念
I. 接口是种能力和约定
1). 接口的定义:能力
2). 方法的定义:约定
1). 接口的定义:能力
2). 方法的定义:约定
经验:Java为单继承,当父类的方法种类无法满足子类需求时,可实现接口扩充子类能力。
经验:接口支持多实现,可为类扩充多种能力。
接口的规范
I. 任何类在实现接口时,必须实现接口中所有的抽象方法,否则此类为抽象类。
II. 实现接口中的抽象方法时,访问修饰符必须是public。
接口引用
同父类一样,接口也可声明为引用,并指向实现类对象。
注意:
1). 仅可调用接口中所声明的方法,而不可调用实现类中独有的方法。
2). 可强转回实现类的本身类型,进行独有的属性和方法的调用。(强转前通过instanceof判断)
1). 仅可调用接口中所声明的方法,而不可调用实现类中独有的方法。
2). 可强转回实现类的本身类型,进行独有的属性和方法的调用。(强转前通过instanceof判断)
接口的多态
I. 不再关注具体的类型,而是关注行为
接口与类的常见关系:
I. 类与类:单继承,extends父类名称
II. 类与接口:多实现,implements 接口名称1,接口名称2,接口名称3
III. 接口与接口:多继承,extends 父接口名称1,父接口名称2
II. 类与接口:多实现,implements 接口名称1,接口名称2,接口名称3
III. 接口与接口:多继承,extends 父接口名称1,父接口名称2
常量接口:
将多个常用于表示状态和固定值的变量,以形态常量的形式定义在接口中统一管理,提高代码的可读性。
接口的宏观概念
I. 接口是一种标准。
II. 耦合度:模块与模块之间的关联程度,关联的越密切,耦合越高,关联的越松散,耦合越低。
II. 耦合度:模块与模块之间的关联程度,关联的越密切,耦合越高,关联的越松散,耦合越低。
接口的回调
1.class A实现接口CallBack callback——背景1
2.class A中包含一个class B的引用b ——背景2
3.class B有一个参数为callback的方法f(CallBack callback) ——背景3
4.A的对象a调用B的方法 f(CallBack callback) ——A类调用B类的某个方法 C
5.然后b就可以在f(CallBack callback)方法中调用A的方法 ——B类调用A类的某个方法D
2.class A中包含一个class B的引用b ——背景2
3.class B有一个参数为callback的方法f(CallBack callback) ——背景3
4.A的对象a调用B的方法 f(CallBack callback) ——A类调用B类的某个方法 C
5.然后b就可以在f(CallBack callback)方法中调用A的方法 ——B类调用A类的某个方法D
内部类和常用类
内部类
成员内部类
I. 成员:
1). 在类的内部定义,与实例变量、实例方法同级别的类。
2). 属于外部类的一个实例部分,创建内部类对象,必须依赖外部类对象。
3). Outer out = new Outer();
Outer.Inner in = out.new Inner();
4). 当外部类、内部类存在重名属性时,有限访问内部类属性,通过外部类类名.this.外部类实例属性
5). 成员内部类不能定义静态成员。
1). 在类的内部定义,与实例变量、实例方法同级别的类。
2). 属于外部类的一个实例部分,创建内部类对象,必须依赖外部类对象。
3). Outer out = new Outer();
Outer.Inner in = out.new Inner();
4). 当外部类、内部类存在重名属性时,有限访问内部类属性,通过外部类类名.this.外部类实例属性
5). 成员内部类不能定义静态成员。
静态内部类
II. 静态:
1). 不依赖外部类对象,可直接创建或通过类名访问,也可声明静态成员。
2). Outer.Inner.静态成员
Outer.Inner in = new Outer.Inner();
1). 不依赖外部类对象,可直接创建或通过类名访问,也可声明静态成员。
2). Outer.Inner.静态成员
Outer.Inner in = new Outer.Inner();
局部内部类
III. 局部:
1). 定义在外部类的方法中,作用范围和创建对象的范围仅限当前方法中。
2). 局部内部类访问外部类局部变量时,因无法保障变量的生命周期与自身相同,所以修饰为final。
3). 隐藏类的信息、限制类的使用范围。
1). 定义在外部类的方法中,作用范围和创建对象的范围仅限当前方法中。
2). 局部内部类访问外部类局部变量时,因无法保障变量的生命周期与自身相同,所以修饰为final。
3). 隐藏类的信息、限制类的使用范围。
匿名内部类
IV. 匿名:
1). 没有类名的局部内部类
2). 必须继承一个父类或实现一个接口。
3). 定义类、实现类、创建对象的语法合并,只能创建一个该类的对象。
4). 优:减少代码量,书写的思路流畅。
5). 劣:可读性较差。
1). 没有类名的局部内部类
2). 必须继承一个父类或实现一个接口。
3). 定义类、实现类、创建对象的语法合并,只能创建一个该类的对象。
4). 优:减少代码量,书写的思路流畅。
5). 劣:可读性较差。
1. 概念:在一个类的内部,再定义一个完整的类。
2. 特点:
I. 编译之后可生成独立的字节码文件。
II. 内部类可直接访问外部类的私有成员,而不破坏封装。
III. 可为外部类提供必要的内部功能组件。
I. 编译之后可生成独立的字节码文件。
II. 内部类可直接访问外部类的私有成员,而不破坏封装。
III. 可为外部类提供必要的内部功能组件。
常用类
Object类
getClass方法
1.getClass()方法
public final Class<?> getClas0{}
返回引用中存储的实际对象类型。
应用:通常用于判断两个引用中实际存储对象类型是否一致。
public final Class<?> getClas0{}
返回引用中存储的实际对象类型。
应用:通常用于判断两个引用中实际存储对象类型是否一致。
hashCade
2.hashCade()方法
public int hashCode0{}
返回该对象的十六进制的哈希码值。
哈希算法根据对象的地址或字符串或数字计算出来的int类型的数值。
哈希码并不唯一,可保证相同对象返回相同哈希码,尽量保证不同对象返回不同哈希码。
public int hashCode0{}
返回该对象的十六进制的哈希码值。
哈希算法根据对象的地址或字符串或数字计算出来的int类型的数值。
哈希码并不唯一,可保证相同对象返回相同哈希码,尽量保证不同对象返回不同哈希码。
3.toString()方法
子主题
(1)public String toString0{}
(2),返回该对象的字符串表示(表现形式)。
(3)可以根据程序需求覆盖该方法,如:展示对象各个属性值。
(2),返回该对象的字符串表示(表现形式)。
(3)可以根据程序需求覆盖该方法,如:展示对象各个属性值。
4.equals(Object obj)方法
(1)public boolean equals(Object obj){}
(2)默认实现为(this == obj),比较两个对象地址是否相同。
(3)可进行覆盖,比较两个对象的内容是否相同。
①先比较两个对象的地址是否相同,相同则返回true(地址一样说明是一块地方内容肯定也一样)
②在判断传入的对象是不是null
③然后判断两个对象的类型是不是相同,用getClass()方法获取对象类型,这一步就可以判断出传入的参数是当前对象相同的类型(也是本类类型)
④转型,将obj强转为当前对象的类型(但是可能存在向上造型的情况需要强转(向下造型))
⑤比较内容 String类型参数要用覆盖后的equals()判断
补充一点:== 是判断地址是否相同,equals方法的最大作用是判断地址不同内容相同的情况
(2)默认实现为(this == obj),比较两个对象地址是否相同。
(3)可进行覆盖,比较两个对象的内容是否相同。
①先比较两个对象的地址是否相同,相同则返回true(地址一样说明是一块地方内容肯定也一样)
②在判断传入的对象是不是null
③然后判断两个对象的类型是不是相同,用getClass()方法获取对象类型,这一步就可以判断出传入的参数是当前对象相同的类型(也是本类类型)
④转型,将obj强转为当前对象的类型(但是可能存在向上造型的情况需要强转(向下造型))
⑤比较内容 String类型参数要用覆盖后的equals()判断
补充一点:== 是判断地址是否相同,equals方法的最大作用是判断地址不同内容相同的情况
5.protected void finalize() throws Throwable //了解(面试题中可能有坑)
当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象,进入回收队列。
垃圾对象:没有有效引用指向此对象时,为垃圾对象。
垃圾回收: 由GC销毁垃圾对象,释放数据存储空间。
自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象。
手动回收机制:使用System.gc(); 通知JVM执行垃圾回收。
垃圾对象:没有有效引用指向此对象时,为垃圾对象。
垃圾回收: 由GC销毁垃圾对象,释放数据存储空间。
自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象。
手动回收机制:使用System.gc(); 通知JVM执行垃圾回收。
包装类
1. 概念:
I. 基本类型所对应的引用类型
II. Object可统一所有数据,包装类的默认值为null
III. 包装类中实际上就是持有了一个基本类型的属性,作为数据的存储空间(Byte中有一个byte属性),还提供了常用的转型方法,以及常量,
既可以存储值,又具备了一系列的转型方法和常用常量,比直接使用基本类型的功能更强大
IV. 包装类型中提供了若干转型的方法,可以让自身类型与其他包装类型、基本类型、字符串相互之间进行转换。
II. Object可统一所有数据,包装类的默认值为null
III. 包装类中实际上就是持有了一个基本类型的属性,作为数据的存储空间(Byte中有一个byte属性),还提供了常用的转型方法,以及常量,
既可以存储值,又具备了一系列的转型方法和常用常量,比直接使用基本类型的功能更强大
IV. 包装类型中提供了若干转型的方法,可以让自身类型与其他包装类型、基本类型、字符串相互之间进行转换。
转型方法:
java.lang.Number父类为所有子类分别提供了6个转型的方法,将自身类型转换成其他数字型。
byteValue(); shortValue(); intValue(); longValue(); floatValue(); doubleValue();
byteValue(); shortValue(); intValue(); longValue(); floatValue(); doubleValue();
parseXXX(String s) 静态转型方法,8种包装类型都有
parseByte("123");
parseShort("123");
parseInt("123");
parseDouble("123.45");
......
parseByte("123");
parseShort("123");
parseInt("123");
parseDouble("123.45");
......
valueOf(基本类型)、valueOf(字符串类型),静态转型方法,8种包装类型都有
Byte b1 = Byte.valueOf( (byte)10 );
Byte b2 = Byte.valueOf( "20" );
Byte b1 = Byte.valueOf( (byte)10 );
Byte b2 = Byte.valueOf( "20" );
注意:在使用字符串构建包装类型对象时,要保证类型的兼容,否则产生NumberFormatException。
特别留心........................
JDK5之后,提供自动装箱、拆箱,简化使用包装类的编程过程
Byte b4 = 40;//自动装箱,将基本类型直接赋值给包装类型
byte b5 = b4;//自动拆箱,将包装类型的值,直接赋值给基本类型
Byte b4 = 40;//自动装箱,将基本类型直接赋值给包装类型
byte b5 = b4;//自动拆箱,将包装类型的值,直接赋值给基本类型
自动装箱时,会调用valueOf方法,Byte、Short、Integer、Long,四种整数包装类型都提供了对应的cache缓冲区,将常用的256个数字提前创建对象并保存在数组中,实现复用。即在区间的复用已有对象,在区间外创建新对象。
自动拆箱,会调用xxxValue方法,看什么类型接受就调用哪个方法
String类
1.String类基础概念
字符串是常量,创建之后不可改变。
字符串字面值存储在字符串池中,可以共享。
Strings= "Hello";产生-一个对象,字符串池中存储。
String s = new String("Hello"); //产生两个对象,堆、池各存储-一个。而s存储的是堆中的地址。
字符串字面值存储在字符串池中,可以共享。
Strings= "Hello";产生-一个对象,字符串池中存储。
String s = new String("Hello"); //产生两个对象,堆、池各存储-一个。而s存储的是堆中的地址。
举例:
String a =”abc”;
a =”def”;
这种情况不是字符串改变了,而是变量a指向了另一个字符串地址
反编译 javap -verbose 字节码文件名(.class文件) > 字节码文件名.bytecode
String s1 = “abc”+”def”;这样和String s1 =”abcdef”一样就只创建一个对象
String s4 = new String(“Word”);//如果word首次出现并且直接赋值的,他是在String构造里面直接赋值的,所以他会在堆中和池中分别创建(查看String的构造源码)
String s1 = "abc";//1.直接声明&&2.首次出现(保存在池中)
String s2 = s1 + "def";//自动优化 StringBuilder.toString()得到的一个 new String(xxx,xxx,xxx) 堆new的是拼接好了的字符串所以def不会在池中创建
//s2.intern();
String s3 = "abcdef";//1.直接声明&&2.首次出现(保存在池中)
s2.intern();//手工向池中保存s2指向的字符串失败了
System.out.println(s2 == s3);//比较 s2指向堆中的"abcdef" s3所指向的池中的"abcdef"
String s4 = s2;//指向堆中,可变
String s5 = s2.intern();//指向池中,不变(如果池中已有s2所指向的"abcdef"的话,则返回池中的内容一样的常量的地址)
System.out.println(s4 == s3);
String a =”abc”;
a =”def”;
这种情况不是字符串改变了,而是变量a指向了另一个字符串地址
反编译 javap -verbose 字节码文件名(.class文件) > 字节码文件名.bytecode
String s1 = “abc”+”def”;这样和String s1 =”abcdef”一样就只创建一个对象
String s4 = new String(“Word”);//如果word首次出现并且直接赋值的,他是在String构造里面直接赋值的,所以他会在堆中和池中分别创建(查看String的构造源码)
String s1 = "abc";//1.直接声明&&2.首次出现(保存在池中)
String s2 = s1 + "def";//自动优化 StringBuilder.toString()得到的一个 new String(xxx,xxx,xxx) 堆new的是拼接好了的字符串所以def不会在池中创建
//s2.intern();
String s3 = "abcdef";//1.直接声明&&2.首次出现(保存在池中)
s2.intern();//手工向池中保存s2指向的字符串失败了
System.out.println(s2 == s3);//比较 s2指向堆中的"abcdef" s3所指向的池中的"abcdef"
String s4 = s2;//指向堆中,可变
String s5 = s2.intern();//指向池中,不变(如果池中已有s2所指向的"abcdef"的话,则返回池中的内容一样的常量的地址)
System.out.println(s4 == s3);
子主题
子主题
String类常用方法
public char charAt(int index) :根据下标获取字符。
public boolean contains(tring str) :判断当前字符串中是否包含str。
public charD toCharArray( ):将字符串转换成数组。
public int indexOf(String str) :查找str首次出现的下标,存在,则返回该下标;不存在,则返回-1。
public int lastIndexOf(String str) :查找字符串在当前字符串中最后一次出现的 下标索引。
public int length():返回字符串的长度。
public String trim():去掉字符串前后的空格。
public String toUpperCase():将小写转成大写。
public boolean endWith(String str):判断字符串是否以str结尾。
public String replace(char oldChar, char newChat);将旧字符串替换成新字符串
public boolean contains(tring str) :判断当前字符串中是否包含str。
public charD toCharArray( ):将字符串转换成数组。
public int indexOf(String str) :查找str首次出现的下标,存在,则返回该下标;不存在,则返回-1。
public int lastIndexOf(String str) :查找字符串在当前字符串中最后一次出现的 下标索引。
public int length():返回字符串的长度。
public String trim():去掉字符串前后的空格。
public String toUpperCase():将小写转成大写。
public boolean endWith(String str):判断字符串是否以str结尾。
public String replace(char oldChar, char newChat);将旧字符串替换成新字符串
public String] split(String str):根据str做拆分。
System.out.println( upperHi.equals(lowerHi) );//内容必须完全相同,包括大小写
System.out.println( upperHi.equalsIgnoreCase(lowerHi) );//内容必须完全相同,忽略大小写
String str = text.substring(0, 5); //获取字符串text的子串,传入的参数为截取开始下标和结束下标,截取的内容是开始下标值和结束下标值的前一个(左包右不包)
System.out.println( upperHi.equals(lowerHi) );//内容必须完全相同,包括大小写
System.out.println( upperHi.equalsIgnoreCase(lowerHi) );//内容必须完全相同,忽略大小写
String str = text.substring(0, 5); //获取字符串text的子串,传入的参数为截取开始下标和结束下标,截取的内容是开始下标值和结束下标值的前一个(左包右不包)
BigDecimal
位置: java.math包中。
作用:精确计算浮点数。
创建方式: BigDecimal bd=new BigDecimal(“1.0");
作用:精确计算浮点数。
创建方式: BigDecimal bd=new BigDecimal(“1.0");
方法:
BigDecimal add(BigDecimal bd) 加
BigDecimal subtract(BigDecimal bd) 减
BigDecimal multiply(BigDecimal bd) 乘
BigDecimal divide(BigDecimal bd) 除
BigDecimal add(BigDecimal bd) 加
BigDecimal subtract(BigDecimal bd) 减
BigDecimal multiply(BigDecimal bd) 乘
BigDecimal divide(BigDecimal bd) 除
BigDecimal除法
除法: BigDecimal(BigDecimal bd,int scal,RoundingMode mode)
参数scal :指定精确到小数点后几位。
参数mode :
指定小数部分的取舍模式,通常采用四舍五入的模式,
取值为BigDecimal.ROUND_HALF_UP。
除法: BigDecimal(BigDecimal bd,int scal,RoundingMode mode)
参数scal :指定精确到小数点后几位。
参数mode :
指定小数部分的取舍模式,通常采用四舍五入的模式,
取值为BigDecimal.ROUND_HALF_UP。
异常
异常的概念
I.程序在运行过程中出现的特殊情况。
II.异常处理的必要性:任何程序都可能存在大量的未知问题、错误;如果不对这些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。
异常的分类
ThrowableI-可抛出的,一切错误或异常的父类。位于java.lang包中。
ErrorJVM、硬件、执行逻辑错误,不能手动处理。
Exception程序在运行和配置过程中产生的问题,可处理。
RubtimeException
运行时异常,可处理,可不处理。
CheckedException
受查异常,必须处理。
异常的产生
自动抛出异常
I.当程序在运行时遇到不符合规范的代码或结果时,会产生异常。
手动抛出异常
throw new 异常类型("实际参数");
注意:一旦发生异常,会导致程序中断
异常的传递
I.按照方法的调用链反向传递,如果最终都没有处理异常,最终交由我们的JVM进行默认异常处理(打印堆栈跟踪信息)
II.受查异常:throws 声明异常,声明位置:修饰在方法参数列表的后端。(这个方法内的异常交给上一级处理假如这个方法没有上一级了就由JVM处理,而且上一级没有声明也没有处理的话就会编译不通过) 这个throws主要用来修饰非运行时的异常,也可以修饰运行时异常,但是没用。
运行时异常:因其可处理,可不处理,无需声明。
异常的处理
注意:try里面的内容是可能存在异常的逻辑代码,catch是异常处理,finally是不管代码有无异常都要在try-catch-finally结构结束前执行finally里面的代码
try-catch的几种写法:
1. try{}
catch(){}
catch(){}
2.try{}
catch(){}
catch(){}
......
catch(){}
catch(){}
......
3.try{}
catch(){}
finally{}
catch(){}
finally{}
4.try{}
catch(){}
catch(){}
finally{}
catch(){}
catch(){}
finally{}
5.try{}
finally{}
finally{}
注意:多重catch下,遵循从子到父的顺序,父类异常在最后捕获
自定义异常
I.继承Exception(受查异常)或Exception的子类。常用RuntimeException.(运行时异常)
II.必要提供的内容
(1).无参构造方法题
(2)String message参数的构造方法。定义异常原因信息
异常的方法覆盖
方法名,参数列表,返回值类型必须和父类一个样(遵循方法覆盖规则)
II.子类的访问修饰符和父类相同或比父类更宽泛
子类中的方法,不能抛出比父类更宽泛的异常。
子类中的方法,不能抛出比父类更宽泛的异常。
子类中的方法的异常声明可以声明多个异常,但是声明的异常必须要是父类或者接口声明的异常的本身或者其子类
线程与进程
进程
I.运行时的程序,称为进程。
II.单核CPU在任一时间点上,只能运行一个进程。
III.宏观并行、微观串行
IV. cpu get NumberOfCores 获得核心数
II.单核CPU在任一时间点上,只能运行一个进程。
III.宏观并行、微观串行
IV. cpu get NumberOfCores 获得核心数
初级多线程
概念
I.轻量级进程
II.程序中的一个顺序控制流程,也是CPU的基本调度单位。
II.程序中的一个顺序控制流程,也是CPU的基本调度单位。
III.进程可以由单个或多个线程组成,彼此间完成不同的工作,交替执行,称为多线程
IV.JVM虚拟机是一个进程,默认包含主线程(Main函数),可以通过代码创建多个独立线程,与Main线程并发执行。
IV.JVM虚拟机是一个进程,默认包含主线程(Main函数),可以通过代码创建多个独立线程,与Main线程并发执行。
组成
(1)CPU时间片:操作系统(OS)会为每个线程分配执行时间。
(2)运行数据:
①堆空间:存储线程需使用的对象,多个线程可以共享堆中的对象。
②栈空间:存储线程需使用的局部变量,每个线程都拥有独立的栈。
①堆空间:存储线程需使用的对象,多个线程可以共享堆中的对象。
②栈空间:存储线程需使用的局部变量,每个线程都拥有独立的栈。
(3) 线程的逻辑代码
创建
第一种方法
I.创建一个类继承Thread
II.根据需求覆盖run方法
III.创建继承Thread类的对象
IV.调用start()方法
II.根据需求覆盖run方法
III.创建继承Thread类的对象
IV.调用start()方法
.第二种方法
I.创建一个类实现Runnable接口
II.根据需求覆盖run方法
III.创建实现Runnable接口类的对象
IV.创建Thread将上一步创建的对象传入Thread有参构造
V.调用start()方法
II.根据需求覆盖run方法
III.创建实现Runnable接口类的对象
IV.创建Thread将上一步创建的对象传入Thread有参构造
V.调用start()方法
线程的基本状态
初始状态(new 线程对象)
就绪状态(执行start)
运行状态(竞争到时间片运行)
结束状态(线程运行完毕)
阻塞状态(线程未获得锁进入阻塞状态,获得锁之后进入运行状态)
限期等待
sleep休眠
无限期等待
join
JDK5之后统一把就绪状态和运行状态统一叫Runnable
线程的常用方法
休眠
public static void sleep(long millis)
当前线程主动休眠 millis 毫秒。 线程执行到sleep方法是,该线程如果还有剩余时间片,会释放剩余的时间片
sleep(0)表示立即放弃当前线程的时间片
当前线程主动休眠 millis 毫秒。 线程执行到sleep方法是,该线程如果还有剩余时间片,会释放剩余的时间片
sleep(0)表示立即放弃当前线程的时间片
放弃
public static void yield()
当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片。
当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片。
结合
例如:t1.join();这个语句假如是在main线程中书写的,意思为:在执行到这个语句后,t1线程不结束,main线程不能竞争时间片
线程的安全问题
I. 当多线程并发访问临界资源时,如果破坏了原子操作,可能会导致数据不一致。
II. 临界资源:共享资源(同一对象、堆空间),一次仅允许一个线程使用,才可保证其正确性
III.原子操作:不可分割的多步操作,被视作为一个整体,其顺序和步骤不能打乱或缺省。
II. 临界资源:共享资源(同一对象、堆空间),一次仅允许一个线程使用,才可保证其正确性
III.原子操作:不可分割的多步操作,被视作为一个整体,其顺序和步骤不能打乱或缺省。
synchronized 同步锁
I.每个对象都有一个互斥锁标记,用来分配给线程。
II.只有持有对象互斥锁标记的线程,才能进入对该对象加锁的同步操作中(同步方法、同步代码块)。
III.只有线程退出同步操作时,才会释放相应的锁标记
II.只有持有对象互斥锁标记的线程,才能进入对该对象加锁的同步操作中(同步方法、同步代码块)。
III.只有线程退出同步操作时,才会释放相应的锁标记
同步代码块
(1). synchronized(临界资源对象){
//原子操作
}
(1). synchronized(临界资源对象){
//原子操作
}
I.同步方法
(1). synchronized 返回值类型 方法名成(参数列表){
//原子操作
}
(1). synchronized 返回值类型 方法名成(参数列表){
//原子操作
}
同步规则
I.只有在调用包含同步代码块的方法或者是同步方法时,才需要对象的锁标记
II.如果调用的是不包含同步代码块的方法或普通方法时,则不需要锁标记,直接调用即可。
III.已知线程安全的内容:StringBuffer、Vector、Hashtable
II.如果调用的是不包含同步代码块的方法或普通方法时,则不需要锁标记,直接调用即可。
III.已知线程安全的内容:StringBuffer、Vector、Hashtable
死锁、生产者与消费者(详情见E盘千峰学习笔记.第六周.day4.com.qf.day4.t2.questions下面的代码)
线程通信
I.等待
(1)wait();
(2) 必须在对obj(对象)加锁的同步代码块(或同步方法)中,在一个线程执行期间,调用了obj.wait(),该线程会释放所拥有的锁标记。同时,进入到obj的等待队列中。等待唤醒
(2) 必须在对obj(对象)加锁的同步代码块(或同步方法)中,在一个线程执行期间,调用了obj.wait(),该线程会释放所拥有的锁标记。同时,进入到obj的等待队列中。等待唤醒
通知
(1).notify();、notifyAll();
(2).必须在对obj加锁的同步代码块(或同步方法)中,从obj的Waiting(等待队列)中随机唤醒一个等待的线程,去竞争锁
(2).必须在对obj加锁的同步代码块(或同步方法)中,从obj的Waiting(等待队列)中随机唤醒一个等待的线程,去竞争锁
高级多线程
线程池
线程池的概念:
线程池:
线程容器,可设定线程分配的数量上限。
将预先创建的线程对象存入池中,并重用线程池中的线程对象。
线程容器,可设定线程分配的数量上限。
将预先创建的线程对象存入池中,并重用线程池中的线程对象。
2.线程池的原理及获取(创建)
(1)原理:
线程池就是相当于之前字符串池,我们先创建好固定数量(也有动态线程池)线程的线程池,将任务提交给线程池,由线程池分配线程、运行任务,并在当前任务结束后复用线程
(2)获取(创建):
常用的线程池接口和类(所在包java.util.concurrent):
Executor:线程池的顶级接口。
ExecutorService:线程池接口,可通过submit(Runnable task) 提交任务代码。
Executors工厂类:通过此类可以获得一个线程池。
ExecutorService ex = Executors.newCachedThreadPool();//获取(创建)动态数量的线程池,如不够则创建新的,没有上限
ExecutorService ex = Executors.newFixedThreadPool(3); 获取固定数量的线程池。参数:指定线程池中 线程的 数量
Tack1 tack1 = new Tack1();任务对象
Executor:线程池的顶级接口。
ExecutorService:线程池接口,可通过submit(Runnable task) 提交任务代码。
Executors工厂类:通过此类可以获得一个线程池。
ExecutorService ex = Executors.newCachedThreadPool();//获取(创建)动态数量的线程池,如不够则创建新的,没有上限
ExecutorService ex = Executors.newFixedThreadPool(3); 获取固定数量的线程池。参数:指定线程池中 线程的 数量
Tack1 tack1 = new Tack1();任务对象
3.Callable<V>接口
public interface Callable<V>{
public V call() throws Exception;
}
JDK5加入,与Runnable接口类似,实现之后代表一个线程任务。
Callable具有泛型返回值、可以声明异常。
public V call() throws Exception;
}
JDK5加入,与Runnable接口类似,实现之后代表一个线程任务。
Callable具有泛型返回值、可以声明异常。
4.Future<V>接口
概念:异步接收ExecutorService.submit()所返回的状态结果,当中包含了 call()的返回值
方法:V get()以阻塞形式等待Future中的异步处理结果(call()的返回值)
方法:V get()以阻塞形式等待Future中的异步处理结果(call()的返回值)
线程的同步与异步
同步
形容一次方法调用,同步一旦开始,调用者需要等待方法返回才能继续向下执行
异步
形容一次方法调用, 异步- -旦开始, 像是一一次消息传递,调用者告知之后立刻返回。
二者竞争时间片,并发执行。
二者竞争时间片,并发执行。
Lock接口
JDK5加入,与synchronized比较,显示定义,结构更灵活。
提供更多实用性方法,功能更强大、性能更优越。
常用方法: void lock() //获取锁,如锁被占用,则等待。
boolean tryLock() //尝试获取锁(成功返回true。失败返回false,不阻塞),
void unlock() //释放锁
提供更多实用性方法,功能更强大、性能更优越。
常用方法: void lock() //获取锁,如锁被占用,则等待。
boolean tryLock() //尝试获取锁(成功返回true。失败返回false,不阻塞),
void unlock() //释放锁
重入锁
ReentrantLock:Lock接口的实现类,与synchronized一样具有互斥锁功能
读写锁(ReentrantReadWriteLock)
一种支持一写多读的同步锁,读写分离,可分别分配读锁、写锁。
支持多次分配读锁,使多个读操作可以并发执行。
支持多次分配读锁,使多个读操作可以并发执行。
互斥规则:
写-写:互斥,阻塞。
读-写:互斥,读阻塞写、写阻塞读。
读-读:不互斥、不阻塞。
在读操作远远高于写操作的环境中,可在保障线程安全的情况下,提高运行效率
读-写:互斥,读阻塞写、写阻塞读。
读-读:不互斥、不阻塞。
在读操作远远高于写操作的环境中,可在保障线程安全的情况下,提高运行效率
创建方式:
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
ReadLock read = rwl.readLock();获取读锁
WriteLock write = rwl.writeLock();获取写锁
ReadLock read = rwl.readLock();获取读锁
WriteLock write = rwl.writeLock();获取写锁
Collections中的工具方法
Collections工具类中提供了多个可以获得线程安全集合的方法。
public static <T> Collection<T> synchronizedCollection(Collection<T> c)
public static <T> List<T> synchronizedList(List<T> list)
public static <T> Set<T> synchronizedSet(Set<T> s)
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s)
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
public static <T> Collection<T> synchronizedCollection(Collection<T> c)
public static <T> List<T> synchronizedList(List<T> list)
public static <T> Set<T> synchronizedSet(Set<T> s)
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)
public static <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s)
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m)
创建方式:
例如;List<String> list = new ArrayList<String>();
List<String> safeList = Collections.synchronizedList(list);
它的使用和ArrayList一样,他只是在内部加了锁,synchronizedList他的add方法是用synchronized同步锁把ArrayList的add方法锁上了
List<String> safeList = Collections.synchronizedList(list);
它的使用和ArrayList一样,他只是在内部加了锁,synchronizedList他的add方法是用synchronized同步锁把ArrayList的add方法锁上了
其他方法追一下源码大同小异都是
9.CopyOnWriteArrayList
线程安全的ArrayList,加强版读写分离。
写有锁,读无锁,读写之间不阻塞,优于读写锁。
写入时,先copy一个容器副本、再添加新元素,最后替换引用。
使用方式与ArrayList无异(包括创建方式也一样)
写有锁,读无锁,读写之间不阻塞,优于读写锁。
写入时,先copy一个容器副本、再添加新元素,最后替换引用。
使用方式与ArrayList无异(包括创建方式也一样)
add的主要实现代码及描述:
我们创建它的对象时,会调用一个无参构造方法,方法内部是调用的setArray(new Object[0]);创建一个长度为0的数组,然后是我们调用他的add方法具体代码如下:
public boolean add(E e) {
final ReentrantLock lock = this.lock;//我们定义一个Lock对象,以便下面获取锁
lock.lock();//获取锁
try {
Object[] elements = getArray();//获取当前的数组
int len = elements.length;//获取当前数组长度
Object[] newElements = Arrays.copyOf(elements, len + 1);//将当前数组复制给比当前数组长度大1的新建数组,相当于给原来的数组扩容了1个位
newElements[len] = e;//将我们输入的对象放入当前数组的末尾(新数组最后一个元素下标就是len)
setArray(newElements);//将我们新的数组newElements覆盖以前的数组
return true;
} finally {
lock.unlock();//如果try代码出现异常,他都会执行finally内的代码,释放锁
}
}
public boolean add(E e) {
final ReentrantLock lock = this.lock;//我们定义一个Lock对象,以便下面获取锁
lock.lock();//获取锁
try {
Object[] elements = getArray();//获取当前的数组
int len = elements.length;//获取当前数组长度
Object[] newElements = Arrays.copyOf(elements, len + 1);//将当前数组复制给比当前数组长度大1的新建数组,相当于给原来的数组扩容了1个位
newElements[len] = e;//将我们输入的对象放入当前数组的末尾(新数组最后一个元素下标就是len)
setArray(newElements);//将我们新的数组newElements覆盖以前的数组
return true;
} finally {
lock.unlock();//如果try代码出现异常,他都会执行finally内的代码,释放锁
}
}
10.CopyOnWriteArraySet
线程安全的Set,底层使用CopyOnWriteArrayList实现。
唯一不同在于,使用addIfAbsent()添加元素,会遍历数组,
如存在元素,则不添加(扔掉副本)。
唯一不同在于,使用addIfAbsent()添加元素,会遍历数组,
如存在元素,则不添加(扔掉副本)。
add的实现方式:首先我们创建CopyOnWriteArraySet它的对象是,调用无参构造方法,方法内创建了一个CopyOnWriteArrayList对象,并赋值给了CopyOnWriteArraySet他的属性al。调用CopyOnWriteArraySet的add方法时他会调用用CopyOnWriteArrayList内部的addIfAbsent方法。主要实现代码如下:
//e是我们add内的参数
public boolean add(E e) {//CopyOnWriteArraySet下的add方法
return al.addIfAbsent(e);//调用的CopyOnWriteArrayList内部的addIfAbsent方法
}
//进入方法后
public boolean addIfAbsent(E e) {
Object[] snapshot = getArray();//获取了一个数组,相当于复制了一个数组,原数组没动
//下面代码的主要作用是去重,我们传入的e跟snapshot获取的数组内从下标0开始循环长度为数组长度,如果有跟我们传入的e相同的元素,则返回下标,如果没有返回-1(indexOf方法内部代码),然后根据返回的信息,重复的话就抛弃了传入的e不重复的话就吧e添加到了数组末尾(多追源码,清晰)
return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
addIfAbsent(e, snapshot);
}
public boolean add(E e) {//CopyOnWriteArraySet下的add方法
return al.addIfAbsent(e);//调用的CopyOnWriteArrayList内部的addIfAbsent方法
}
//进入方法后
public boolean addIfAbsent(E e) {
Object[] snapshot = getArray();//获取了一个数组,相当于复制了一个数组,原数组没动
//下面代码的主要作用是去重,我们传入的e跟snapshot获取的数组内从下标0开始循环长度为数组长度,如果有跟我们传入的e相同的元素,则返回下标,如果没有返回-1(indexOf方法内部代码),然后根据返回的信息,重复的话就抛弃了传入的e不重复的话就吧e添加到了数组末尾(多追源码,清晰)
return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
addIfAbsent(e, snapshot);
}
11.ComcurrentHashMap
初始容量默认为16段(Segment),使用分段锁设计。
不对整个Map加锁,而是为每个Segment加锁。
当多个对象存入同一个Segment时,才需要互斥。
最理想状态为16个对象分别存入16个Segment,并行数量16。
使用方式与HashMap无异
不对整个Map加锁,而是为每个Segment加锁。
当多个对象存入同一个Segment时,才需要互斥。
最理想状态为16个对象分别存入16个Segment,并行数量16。
使用方式与HashMap无异
版本差异:
JDK1.7版本
JDK1.7版本:他是对HashMap分的16段(Segment),每一段都加上锁了,put方法添加的键值对,会先用tryLock()方法尝试获取锁,如果获取失败,则有当前线程拿到锁正在运行,下一次获取不等待,如果获取成功,要先进入自己的段(根据hash算的16个段中的一个)中,先判断段是不是空的,如果是空的就把传入的键值对放在头部(第一个),如果不为空,则遍历段中的key值和当前传入key值比较相等不,不相等就吧当前传入的键值对放在最后一个键值对的next上,如果相等,就把相等的键值对给覆盖。
JDK1.8版本
CAS交换算法:V要更新的变量 E:期望值 N:新值 当V = E则V = N
JDK1.8版本:采用的是CAS交换算法和同步锁,实现方法主要为:我们put传入的键值对,先算一下自己的段,然后我们根据CAS交换算法,这时候期望值为NUll,如果段中有对象,则线程获取段的表头的锁,拿到锁的对象要先做节点遍历。查看有没有相同的key,相同覆盖,不同挂在节点的next上。同步锁锁的是表头对象,只要表头锁上了其余的线程也就进不来了。如果段中没有对象则我们自己new一个节点对象放在段的头部,代码如下( if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null))))判断段是否为空。注意:这里我说的段就是Hash表
JDK1.8版本:采用的是CAS交换算法和同步锁,实现方法主要为:我们put传入的键值对,先算一下自己的段,然后我们根据CAS交换算法,这时候期望值为NUll,如果段中有对象,则线程获取段的表头的锁,拿到锁的对象要先做节点遍历。查看有没有相同的key,相同覆盖,不同挂在节点的next上。同步锁锁的是表头对象,只要表头锁上了其余的线程也就进不来了。如果段中没有对象则我们自己new一个节点对象放在段的头部,代码如下( if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null))))判断段是否为空。注意:这里我说的段就是Hash表
Queue接口(队列)
Collection的子接口,表示队列FIFO(First In First Out)
常用方法:
抛出异常:
boolean add(E e) //顺序添加一个元素(到达上限后,再添加则会抛出异常)
E remove() //获得第一个元素并移除(如果队列没有元素时,则抛异常)
E element() //获得第一个元素但不移除(如果队列没有元素时,则抛异常)
boolean add(E e) //顺序添加一个元素(到达上限后,再添加则会抛出异常)
E remove() //获得第一个元素并移除(如果队列没有元素时,则抛异常)
E element() //获得第一个元素但不移除(如果队列没有元素时,则抛异常)
返回特殊值:推荐使用
boolean offer(E e) //顺序添加一个元素 (到达上限后,再添加则会返回false)
E poll() //获得第一个元素并移除 (如果队列没有元素时,则返回null)
E peek()//获取但不移除此队列的头,如果队列为空返回null;
boolean offer(E e) //顺序添加一个元素 (到达上限后,再添加则会返回false)
E poll() //获得第一个元素并移除 (如果队列没有元素时,则返回null)
E peek()//获取但不移除此队列的头,如果队列为空返回null;
ConcurrentLinkedQueue(Queue的实现类)
线程安全、可高效读写的队列,高并发下性能最好的队列。
无锁、CAS比较交换算法,修改的方法包含三个核心参数(V,E,N)
V:要更新的变量、E:预期值、N:新值。
只有当V==E时,V=N;否则表示已被更新过,则取消当前操作
无锁、CAS比较交换算法,修改的方法包含三个核心参数(V,E,N)
V:要更新的变量、E:预期值、N:新值。
只有当V==E时,V=N;否则表示已被更新过,则取消当前操作
13.BlockingQueue接口(阻塞队列)
Queue的子接口,阻塞的队列,增加了两个线程状态为无限期等待的方法。
方法:
void put(E e) //将指定元素插入此队列中,如果没有可用空间,则等待。
E take() //获取并移除此队列头部元素,如果没有可用元素,则等待。
可用于解决生产生、消费者问题。仔细品一品。
void put(E e) //将指定元素插入此队列中,如果没有可用空间,则等待。
E take() //获取并移除此队列头部元素,如果没有可用元素,则等待。
可用于解决生产生、消费者问题。仔细品一品。
实现类
ArrayBlockingQueue
创建方式
BlockingQueue <String> a = new ArrayBlockingQueue<String>(3);手工固定队列容量
LinkedBlockingQueue
创建方法跟上面一样,这个是无界限,最大值为Interger.MAX_VALUE
JDK8
1.lambda表达式
概念:允许把函数作为一个方法的参数。(函数作为参数传递到方法中)
结构:
<函数式接口> <变量名> = (参数1,参数2...) -> { //方法体 }
理解:函数式接口和变量名可以理解成为一个实现了“函数式接口”的类,他的对象名字为“变量名”,而等号右边的为该“函数式接口”的唯一方法的具体实现。用法:我们用“变量名”调用该“函数式接口”中定义的抽象方法名字。
注:函数式接口为只有一个方法的接口。变量名是接收实现接口方法的,就是将实现的方法存到了变量名中
<函数式接口> <变量名> = (参数1,参数2...) -> { //方法体 }
理解:函数式接口和变量名可以理解成为一个实现了“函数式接口”的类,他的对象名字为“变量名”,而等号右边的为该“函数式接口”的唯一方法的具体实现。用法:我们用“变量名”调用该“函数式接口”中定义的抽象方法名字。
注:函数式接口为只有一个方法的接口。变量名是接收实现接口方法的,就是将实现的方法存到了变量名中
注意事项:
新的操作符 ->(箭头操作符)
(参数1,参数2)->表示参数列表
->{ }方法体
形参列表的数据类型会自动推断
如果形参列表为空,只需保留()
如果形参只有1个,()可以省略,只要参数名字即可
如果执行语句只有1句,且无返回值,{}可以省略。
若有返回值,仍想省略{},return也省略。保证执行语句只有1句
Lambda表达式不会生成单独的内部类文件
lambda访问局部变量时,变量要修饰final,如果没加,会自动添加
新的操作符 ->(箭头操作符)
(参数1,参数2)->表示参数列表
->{ }方法体
形参列表的数据类型会自动推断
如果形参列表为空,只需保留()
如果形参只有1个,()可以省略,只要参数名字即可
如果执行语句只有1句,且无返回值,{}可以省略。
若有返回值,仍想省略{},return也省略。保证执行语句只有1句
Lambda表达式不会生成单独的内部类文件
lambda访问局部变量时,变量要修饰final,如果没加,会自动添加
函数式接口
如果一个接口只有一个抽象方法,则该接口称为函数式接口。
为了确保接口达到要求,可以添加@FunctionalInterface注解。
为了确保接口达到要求,可以添加@FunctionalInterface注解。
内置四个核心函数式接口:
Consumer<T> 消费型接口 void accept(T t);
Supplier<T> 供给型接口 T get();
Function<T,R> 函数型接口 R apply(T t);
Predicate<T> 断言型接口 boolean test(T t);
Supplier<T> 供给型接口 T get();
Function<T,R> 函数型接口 R apply(T t);
Predicate<T> 断言型接口 boolean test(T t);
方法引用
方法引用是Lambda表达式的一种简写形式,如果Lambda表达式方法体中只是 调用一个特定的已存在的方法,则可以使用方法引用
使用 :: 操作符将对象或类和方法名的名字分隔开来。
使用 :: 操作符将对象或类和方法名的名字分隔开来。
对象::实例方法 //含义:对象调用了他的一个实例方法,如果调用的实例方法有参数,我们在往下调用他的函数接口实现时会传入相应的参数如下:
Consumer<String> con2 =System.out::println;//对象System.out调用了他的一个实例方法println
con2.accept("嘿嘿嘿");//我们往println里面传入了参数(System.out::println为accept的具体实现)
con2.accept("嘿嘿嘿");//我们往println里面传入了参数(System.out::println为accept的具体实现)
类::静态方法 //含义:一个类调用了他的静态方法
Comparator<Integer> com = Integer::compare;
int result = com.compare(1, 2);
int result = com.compare(1, 2);
类::实例方法 //含义:一个类的对象调用他的实例方法,但是这个类的意思为,是这个类的对象调用的实例方法,后面我们要传入这个类的对象,具体代码如下
//Employee中有一个getName的方法,获取对象的姓名
Function<Employee,String> fun = Employee::getName;//方法引用
String name = fun.apply(e);//我们传入的e就相当于Employee,e.getName返回String,apply接受到了
目前来看要用类::实例方法,实例方法必须为没有参数的方法。
Function<Employee,String> fun = Employee::getName;//方法引用
String name = fun.apply(e);//我们传入的e就相当于Employee,e.getName返回String,apply接受到了
目前来看要用类::实例方法,实例方法必须为没有参数的方法。
类::new相当于类名::构造方法
Supplier<Employee> supp =Employee::new;//相当于new了一个Employee类的对象,并返回了
Employee emps = supp.get();//调用方法,获得Employee对象
Employee emps = supp.get();//调用方法,获得Employee对象
注意:调用的方法参数列表与返回值类型,要与函数型接口中的方法参数列表与返回值类型一致
Stream
Java8中处理数组,集合操作的抽象概念,可以执行复杂的查找,过滤,筛选,映射等操作
常用的方法(中间操作)
• Stream<T> filter(Predicate<? super T> predicate); 过滤
• Stream<T> limit(long maxSize); 截断,不超过给定数量
• Stream<T> distinct(); 筛选,利用hashCode和equals
• <R> Stream<R> map(Function<? super T, ? extends R> mapper); 根据Function传入的接口实现,将返回的R存入流中
• Stream<T> sorted(); 自然排序
• Stream<T> sorted(Comparator<? super T> comparator); 定制排序
• Stream<T> limit(long maxSize); 截断,不超过给定数量
• Stream<T> distinct(); 筛选,利用hashCode和equals
• <R> Stream<R> map(Function<? super T, ? extends R> mapper); 根据Function传入的接口实现,将返回的R存入流中
• Stream<T> sorted(); 自然排序
• Stream<T> sorted(Comparator<? super T> comparator); 定制排序
注意:以上所有的中间操作都是将括号内自己指定的规则,筛选过后存入到流中,然后在进行最终的操作(看返回值)
常用方法(终止操作)
• long count(); 返回流中元素的总个数
• void forEach(Consumer<? super T> action); 遍历
• boolean anyMatch(Predicate<? super T> predicate); 是否至少匹配一个
• boolean allMatch(Predicate<? super T> predicate); 是否匹配所有元素
• boolean noneMatch(Predicate<? super T> predicate); 是否没有匹配
• Optional<T> findFirst(); 返回第一个
• Optional<T> findAny(); 返回任意
• Optional<T> min(Comparator<? super T> comparator); 返回最小
• Optional<T> max(Comparator<? super T> comparator); 返回最大
• void forEach(Consumer<? super T> action); 遍历
• boolean anyMatch(Predicate<? super T> predicate); 是否至少匹配一个
• boolean allMatch(Predicate<? super T> predicate); 是否匹配所有元素
• boolean noneMatch(Predicate<? super T> predicate); 是否没有匹配
• Optional<T> findFirst(); 返回第一个
• Optional<T> findAny(); 返回任意
• Optional<T> min(Comparator<? super T> comparator); 返回最小
• Optional<T> max(Comparator<? super T> comparator); 返回最大
注意:看终止操作的返回值,那是最后得到的结果
常用方法补充
中间操作(延迟方法)
概念
方法的返回值是Stream类对象;支持链式编程。
Stream<T> limit(long maxSize)
获取流中前maxSize个元素
Stream<T> skip(long n)
获取跳过n个元素之后的元素
Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
将两个流合并成一个新的流
终止操作(终结方法)
概念
方法的返回值不是Stream类对象;不支持链式编程。
接口新特性
java8.0之前的接口组成
常量
抽象方法
java80接口组成
抽象方法
常量
静态方法
static方法
格式
public static 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2...){
方法体;
return 返回值;
}
方法体;
return 返回值;
}
注意事项
接口中的静态方法只能通过接口名调用,不能通过接口的实现子类对象调用
默认方法
default方法
作用
解决接口下不同实现子类的功能扩展问题
哪一个实现子类需要对功能进行扩展,就重写default方法
总结
default方法,用到就重写,用不到就不重写,也不会报错或强制重写
java9.0的接口组成
默认方法
子主题
静态方法
default方法
常量
抽象方法
private方法
枚举
概念
就是一个天然的多例设计模式
在数学和计算机科学理论中,一个集的枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。
设计模式
单例设计模式
public enum MySingleClass04 {
INSTANCE
}
INSTANCE
}
总结
枚举单例设计模式可以避免反射攻击
枚举单例设计模式既可以避免反射攻击,也可以避免序列化攻击
特点
- 效率高
- 线程安全
- 不支持懒加载
- 避免反射攻击
- 避免序列化攻击
- 线程安全
- 不支持懒加载
- 避免反射攻击
- 避免序列化攻击
程序的设计规则/原则
面向对象五大设计原则
简称
solid
单一职责原则
Single Responsibility Principle
每个模块、每个类、每个方法都只负责一件事情
开放关闭原则
Open Close Principle
里氏替换原则
Liskov Substitution Principle
接口隔离原则
Interface Segregation Principle
依赖倒置原则
Dependency Inversion Principle
总结
SOLID原则
设计模式六大原则
单一职责原则
Single Responsibility Principle
每个模块、每个类、每个方法都只负责一件事情
开放关闭原则
Open Close Principle
对功能扩展开放,对源码修改关闭
注意
作为开发者分为两类
使用者:代码是别人写的,自己只使用。就不能修改源码,只能进行扩展
作者:代码是自己写的。可以视情况修改源码。
里氏替换原则
Liskov Substitution Principle
概念
任何父类可以出现的地方,子类一定可以出现
LSP是继承的基石,只有当子类可以替换掉父类,软件单位的功能不受到影响时,父类才能真正被复用,而子类也 能够在父类的基础上增加新的行为。
子类可以无障碍地替换父类
注意
父类中能够正常使用的方法,子类也能正常使用,否则就违反了里氏替换规则
接口隔离原则
Interface Segregation Principle
概念
使用多个专门的接口比使用单一的总接口要好。
一个类对另外一个类的依赖性应当是建立在最小的接口上的。
一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形 成一个臃肿的大接口,这是对角色和接口的污染。
注意
接口的实现类要注意实现的接口功能会不会对代码造成污染
依赖倒置原则
Dependency Inversion Principle
要求面向抽象进行编程,不要面向具体进行编程,这样就降低了客户与实现模块间的耦合。
注意
所有的形参不要写的太具体,要不增加功能是就会因为耦合度太高,而变得很麻烦
还有尽量多应用多态,这样也会解耦
迪米特法则
Law of Demeter
概念
也叫最少知道原则
一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。
总结
类中公开的方法,或者属性要尽量少点,这会让使用者使用起来更加方便
对于某个操作,开发者尽量将多个连贯方法封装到一个对外公开的方法中
这样避免了,使用者使用时对开发者的代码使用更加方便
0 条评论
下一页