学习顶层,使用底层
1.学习顶层:学习顶层接口/抽象类中共性的方法所有的子类都可以使用
2.使用底层:顶层不是接口就是抽象类无法创建对象使用,需要使用底层的子类创建对象使用
常用关键字
final:最终、不可改变的
-
可以用来修饰一个类:表示此类不可继承
-
可以用来修饰一个方法:表示此方法不可覆盖重写
-
还可以用来修饰一个变量:变量变为常量
- 对于基本类型来说,不可变说的是变量当中的数据不可改变
- 对于引用类型来说,不可变说的是变量当中的地址值不可改变
常用类
String:字符串
注意:字符串是常量;它们的值在创建之后不能更改,字符串的底层是一个被final修饰的数组,不能被改变
常用string方法
valueOf('基础数据类型') // 将基础类型数据的文本转换为字符串
substring(int beginIndex) // 返回一个新的字符串,它是此字符串的一个子字符串。
getBytes(String charset) // 将string转换为byte 数组。
toLowerCase() // 将此 String 中的所有字符都转换为小写。
toUpperCase() // 将此 String 中的所有字符都转换为大写。
replace(char oldChar, char newChar)
// 返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
trim() // 返回字符串的副本,忽略前导空白和尾部空白。
isEmpty() // 当且仅当 length() 为 0 时返回 true。
// 在字符串中查询指定子字符串的位置
charAt(int index) // 返回指定索引处的 char 值。
indexOf(string) // 返回指定字符在此字符串中第一次出现处的索引。
// 返回指定字符或字符串出现的索引位置
lastIndexOf(int ch) // 返回指定字符在此字符串中最后一次出现处的索引。
lastIndexOf(int ch, int fromIndex)
// 返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。
// 比较两个string类型内容
contains(CharSequence s) // 判断字符串是否包含指定的 char 值,返回 true。
equals(Object anObject) // 将此字符串与指定的对象比较。
equalsIgnoreCase(String anotherString) // 将此 String 与另一个 String比较,不考虑大小写。
// 判断是否以指定字符开头或者结尾
endsWith(String suffix) // 判断此字符串是否以指定的后缀结束。
startsWith(String prefix) // 判断此字符串是否以指定的前缀开始。
// 将字符串转换为字符数组,和字节数组
format(Locale l, String format, Object... args)
// 格式字符串和参数返回一个格式化字符串。
getBytes(String charset) // 将string转换为byte 数组。
getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
// 将string转换为字符数组
toCharArray() // 将此字符串转换为一个新的字符数组。
// 正则表达式
matches(String regex) // 告知此字符串是否匹配给定的正则表达式。
replaceAll(String regex, String replacement)
// 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
replaceFirst(String regex, String replacement)
// 使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
split(String regex) // 根据给定正则表达式的匹配拆分此字符串。
StringBuilder
注意:底层也是个数组,,但是没有被final修饰, 可以改变长度
append 方法始终将这些字符添加到缓冲区的末端;而 insert
方法则在指定的索引下添加字符。
StringBuffer(String str)// 构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容。
append(基础类型数据 b) // 将 基础类型的字符串表示形式追加到序列后面。
charAt(int index) // 返回此序列中指定索引处的 char 值。
delete(int start, int end) // 移除此序列的子字符串中的字符。
deleteCharAt(int index) // 移除此序列指定位置的 char。
insert(int offset, 基础类型数据 b) // 将基础类型参数的字符串表示形式插入指定位置中。
toString() // 返回此序列中数据的字符串表示形式。
StringBuffer
StringBuffer是线程安全的,性能低于StringBuilder
// 构造函数
StringBuffer()
// 构造一个字符串缓冲区,其中没有字符,初始容量为16个字符。
StringBuffer(CharSequence seq)
// 构造一个包含与指定字符相同的字符串缓冲区。
StringBuffer(int capacity)
// 构造一个字符串缓冲区,其中没有字符,但是包含指定的初始容量capacity。
StringBuffer(String str)
// 构造一个指定字符串内容的字符串缓冲区。
// +方法
StringBuffer append(boolean b)
// 将boolean参数的字符串表示形式追加到序列中。
StringBuffer append(char c)
// 将char参数的字符串表示形式追加到此序列。
StringBuffer append(char[] str)
// 将char数组参数的字符串表示形式追加到此序列。
StringBuffer append(char[] str, int offset, int len)
// 将char数组参数的子数组的字符串表示形式追加到此序列。
StringBuffer append(CharSequence s)
// 将指定的内容附加CharSequence到此序列。
StringBuffer append(CharSequence s, int start, int end)
// 将指定的子CharSequence序列追加到此序列。
StringBuffer append(double d)
// 将double 参数的字符串表示形式追加到此序列。
StringBuffer append(float f)
// 将float 参数的字符串表示形式追加到此序列。
StringBuffer append(int i)
// 将int 参数的字符串表示形式追加到此序列。
StringBuffer append(long lng)
// 将long 参数的字符串表示形式追加到此序列。
StringBuffer append(Object obj)
// 附加Object参数的字符串表示形式。
StringBuffer append(String str)
// 将指定的字符串追加到此字符序列。
StringBuffer append(StringBuffer sb)
// 将指定的内容附加StringBuffer到此序列。
StringBuffer appendCodePoint(int codePoint)
// 将codePoint参数的字符串表示形式追加到此序列。
int capacity()
// 返回当前容量。
char charAt(int index)
// 返回char指定索引处的此序列中的值。
int codePointAt(int index)
// 返回指定索引处的字符(Unicode代码点)。
int codePointBefore(int index)
// 返回指定索引之前的字符(Unicode代码点)。
int codePointCount(int beginIndex, int endIndex)
// 返回此序列的指定文本范围内的Unicode代码点数。
StringBuffer delete(int start, int end)
// 删除此序列的子字符串中的字符。
StringBuffer deleteCharAt(int index)
// char按此顺序删除指定位置。
void ensureCapacity(int minimumCapacity)
// 确保容量至少等于指定的最小值。
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
// 字符从此序列复制到目标字符数组中dst。
int indexOf(String str)
// 返回指定子字符串第一次出现的字符串中的索引。
int indexOf(String str, int fromIndex)
// 从指定的索引处开始,返回指定子字符串第一次出现的字符串中的索引。
StringBuffer insert(int offset, boolean b)
// 将boolea参数的字符串表示形式插入此序列中。
StringBuffer insert(int offset, char c)
// 将char参数的字符串表示形式插入此序列中。
StringBuffer insert(int offset, char[] str)
// 将char数组参数的字符串表示形式插入此序列中。
StringBuffer insert(int index, char[] str, int offset, int len)
// 将str数组参数的子数组的字符串表示形式插入到此序列中。
StringBuffer insert(int dstOffset, CharSequence s)
// 将指定的内容CharSequence插入此序列中。
StringBuffer insert(int dstOffset, CharSequence s, int start, int end)
// 将指定的子CharSequence序列插入此序列中。
StringBuffer insert(int offset, double d)
// 将double参数的字符串表示形式插入此序列中。
StringBuffer insert(int offset, float f)
// 将float参数的字符串表示形式插入此序列中。
StringBuffer insert(int offset, int i)
// 将第二个int 参数的字符串表示形式插入到此序列中。
StringBuffer insert(int offset, long l)
// 将long参数的字符串表示形式插入此序列中。
StringBuffer insert(int offset, Object obj)
// 将Object 参数的字符串表示形式插入此字符序列。
StringBuffer insert(int offset, String str)
// 将字符串插入此字符序列。
int lastIndexOf(String str)
// 返回指定子字符串最后一次出现在字符串中的索引。
int lastIndexOf(String str, int fromIndex)
// 返回指定子字符串最后一次出现在字符串中的索引。
int length()
// 返回该字符串的长度(字符数)。
int offsetByCodePoints(int index, int codePointOffset)
// 返回此序列中与代码点给定index的偏移量的索引codePointOffset。
StringBuffer replace(int start, int end, String str)
// 用指定的字符替换此序列的子字符串中的字符String。
StringBuffer reverse()
// 返回此字符序列的反向替换。
void setCharAt(int index, char ch)
// 指定索引处的字符设置为ch。
void setLength(int newLength)
// 设置字符序列的长度。
CharSequence subSequence(int start, int end)
// 返回一个新的字符序列,它是该序列的子序列。
String substring(int start)
// 返回一个新的String,包含此字符序列中当前包含的字符的子序列。
String substring(int start, int end)
// 返回一个新的String,包含此序列中当前包含的字符的子序列。
String toString()
// 返回表示此序列中数据的字符串。
void trimToSize()
// 尝试减少用于字符序列的存储空间。
Math 数学工具类
static double abs(double num) // 获取绝对值
static double ceil(double num) // 向上取整
static double floor(double num) // 向下取整
static long round(double num) // 四舍五人
Ranom随机数
//获取0-9之间的随机数
int number = r.nextInt(10);
System.out.println(number);
//获取1-10之间的随机数
int num = r.nextInt(10)+1;
System.out.println(num);
date:日期和时间
-
毫秒值的作用:可以对时间和日期进行计算,可以日期转换为毫秒进行计算,计算完毕,在把毫秒转换为日期:(1000毫秒
== 1秒) -
把毫秒转换为日期:1天=24x 60 x 60 = 86400秒=86400 x 1000 = 86400000毫秒
方法:
new Date() // 获取当前系统的日期和时间
new Date(long date) // 传递毫秒值,把毫秒值转换为Date日期
Long getTime() // 把日期转换为毫秒值(相当于System. current TimeMillis()方法)
返回自1970年1月1日00:00:00 GMT以来此Date对象表示的毫秒数。
after(Date when) // 测试此日期是否在指定日期之后。
before(Date when) // 测试此日期是否在指定日期之前。
setTime(long time) // 设置此 Date 对象,以表示 1970 年 1 月 1 日 00:00:00 GMT 以后 time 毫秒的时间点。
toString()
// 把此 Date 对象转换为以下形式的 String: dow mon dd hh:mm:ss zzz yyyy 其中: dow是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat)。
Calendar 日期工具类
1、获取Calendar实例
Calendar cal= Calendar.getInstance();
2、初始值
代码如下,值得指出的是由于我们的时区设置是GMT+8,所以打印格林威治时间得到的是1970-01-01
08:00:00.
Calendar cal = Calendar.getInstance();//得到当前时间
cal.setTimeInMillis(0);//转换成格林威治时间
3、获取值
cal.get(Calendar.YEAR);//年
cal.get(Calendar.MONTH) + 1;//月(必须要+1)
cal.get(Calendar.DATE);//日
cal.get(Calendar.HOUR_OF_DAY);//时
cal.get(Calendar.MINUTE);//分
cal.get(Calendar.SECOND);//秒
cal.get(Calendar.DAY_OF_WEEK);//星期(Locale.ENGLISH情况下,周日是1,剩下自己推算)
注意:如果拿时间不是为了计算而是展示出来,肯定用SimpleDateFormart了,模式为yyyy-MM-dd
HH:mm:ss
4、设置值
cal.set(2013, 5, 4, 13, 44, 51);//年月日时分秒(月份0代表1月)
cal.set(Calendar.YEAR, 2014);//年
cal.set(Calendar.MONTH, 7);//月(月份0代表1月)
cal.set(Calendar.DATE, 11);//日
cal.set(Calendar.HOUR_OF_DAY, 15);//时
cal.set(Calendar.MINUTE, 33);//分
cal.set(Calendar.SECOND, 32);//秒
cal.getTimeInMillis() // 获取Calendar对象的毫秒值
5、运算值
cal.add(Calendar.YEAR, 1);//年
cal.add(Calendar.MONTH, 1);//月
cal.add(Calendar.DATE, 1);//日
cal.add(Calendar.HOUR_OF_DAY, -1);//时
cal.add(Calendar.MINUTE, 1);//分
cal.add(Calendar.SECOND, 1);//秒
cal.add(Calendar.DATE, 7);//周
DateFormat日期格式化抽象类
作用:格式化 (也就是日期-> string、解析(string->日期)
日期格式模式: yyyy年M月dd日 EEEE(星期) H时mm分ss秒
-
String format(Date date)
: 将Date日期,格式化为符合模式的字符串 -
Date parse(String source)
: 将字符串,解析为Date日期
DateFormat是一个抽象类需要使用,子类SimpleDateFormat 类创建对象
SimpleDateFormat(String pattern) // SimpleDateFormat 构造pattern
:传递指定的模式,
y 年 M 月 d 日 EEEE (星期) H 时 m 分 s 秒
//1.创建s impLeDateFormat对象构造方法中传 递指定的模式
SimpleDateFormat sdf = new SimpleDateFormat( pattrn: "yyyy年M月dd日 HH时mm分ss秒");
//2.调用SimpleDateFormat对象中的方法format,按照构造方法中指定的模式,把Date日期格式化为符合模式的字符串(文本)
// String format(Date date)按照指定的模式,把Date日期,格式化为符合模式的字符串
Date date = new Date();
String d = sdf.format(date); // 将日期转换为string类型
System.out.println(date);//Sun Aug 08 15:51:54 CST 2088
System.out.println(d); //2088年08月08日15时51分54秒
Date类型之间的比较
@Test
public void test02(){
Date date1 = new Date();
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR,2019);
Date date2 = calendar.getTime();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd EEEE HH:mm:ss");
String format1 = format.format(date1);
String format2 = format.format(date2);
/* format1.compareTo(format2) = 1 表示date1时间大于date2
* format1.compareTo(format2) = 0 表示两个时间一致
* format1.compareTo(format2) = -1 表示date1小于date2
* */
System.out.println(format2.compareTo(format1));
}
System类
1. public static long currentTimeMillis()
// 返回以事秒为单位的当前时间。
2. static void arraycopy(object src, int srcPos, object dest, int destPos, int length)
// 将数组中指定的数据拷贝到另-个数组中。
/**
src:源数组
srcPos:源数组中的起始位置(起始索引)。:
dest :目标数组。
destPos:目标数据中的起始位置。
Length:要复制的数组元素的数量。
**/
Arrarys 数组工具类
-
static String toString(数组对象)
按照默认格式,输出数组对象 -
static void sort(数组对象)
按照升序,进行排序
集合
学习集合的目标:
1.会使用集合存储数据,2.会遍历集合,把数据取出来,3.掌握每种集合的特性
集合框架的学习方式:
-
学习顶层:学习顶层接口/抽象类中共性的方法所有的子类都可以使用
-
使用底层:顶层不是接口就是抽象类无法创建对象使用,需要使用底层的子类创建对象使用
Collection接口:单列集合父类s
所有单列集合的共性方法,此接口没有索引
boolean add(E e): //把给定的对象添加到当前集合中。
void clear() //清空集合中所有的元素。
boolean remove(E e) : //把给定的对象在当前集合中删除。
boolean contains(E e) : //判断当前集合中是否包含给定的对象。
boolean isEmpty() : //判断当前集合是否为空。
int size() : //返回集合中元素的个数。
object[] toArray() : //把集合中的元素,存储到数组中。
List:接口
List接口的特点:
-
有序的集合,存储元素和取出元素的顺序是一致的(存储123 取出123)
-
有索引,包含了一些带索引的方法
-
允许存储重复的元素
list接口中带索引的特有方法
void add(int index, E element):// 将指定的元素,添加到该集合中的指定位置上。
E get(int index) :// 返回集合中指定位置的元素。
E remove(int index): // 移除列表中指定位置的元素, 并返回被移除的元素。
E set(int index, E element):
// 用指定元素替换集合中指定位器的元素,返回值的更新前的元素。
注意:操作索引的时候,一定要防止索引越界异常
子类ArrayList
ArrayList
集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合。
子类Linkedlist
-
java.util.Linkedlist集合数据存储的结构是链表结构。增删快,查询慢
-
注意:使用此方法不可以使用多态,多态是看不到子类特有方法的
LinkedList集合特有方法
public void addFirst(E e) ;// :将指定元素插入此列表的开头。
public void addLast(E e) // :将指定元素添加到此列表的结尾。
public E getFirst() // :返回此列表的第一个元素。
public E getlast() // :返回此列表的最后一个元素。
public E removeF irst() // :移除并返回此列表的第一个元素。
public E removelast() :// 移除并返回此列表的最后一个元素。
public E pop() :// 从此列表所表示的堆栈处弹出一个元素。
public void push(E e) // :将元素推入此列表所表示的堆栈。
public boolean isEmpty() // :如果列表不包含元素,则返回true。
set:接口
Set接口的特点:
-
不允许存储重复的元素
-
没有索引,没有带索引的方法,也就不能使用普通的for循环遍历
子类:HashSet
哈希表=数组+链表+红黑树(提高查询的速度) 哈希表的特点:速度快
HashSet特点:
-
不允许存储重复的元素,没有索引,没有带索引的方法,也不能使用普通的for循环遍历需要使用迭代器Iterator接口,或者使用正确for循环
-
是一个无序的集合,存储元素和取出元素的顺序有可能不一致
-
给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法
,建立自己的比较方式,才能保证HashSet集合中的对象唯一
Map<k, v>接口:双列集合父类
Map(也称为字典、关联数组)是用于保存具有映射关系的数据,保存两组值,key和value,这两组值可以是任何应用类型的数据。
Map的key不允许重复(底层Map的keySet()返回的是key的Set集合,所以key不会重复),即Map中对象的任意两个key通过equals()方法得到的都是false。而,Map的value值是可以重复的(Map的底层values()方法返回类型是Collection,可以存储重复元素),通过key总能找到唯一的value,Map中的key组成一个Set集合,所以可以通过keySet()方法返回所有key。Set底层也是通过Map实现的,只不过value都是null的Map来实现的。
int size(); // 返回Map的key-value对的长度。
boolean isEmpty(); // 判断该Map是否为空。
boolean containsKey(Object key); // 判断该Map中是否包含指定的key。
boolean containsValue(Object value); // 判断该Map是否包含一个或多个value。
V get(Object key); // 获取某个key所对应的value;若不包含该key,则返回null。
V put(K key, V value); // 向Map添加key-value对,当Map中有一个与该key相等的key-value对,则新的会去覆盖旧的。
V remove(Object key); // 移除指定的key所对应的key-value对,若成功删除,则返回移除的value值。
void putAll(Map<? extends K, ? extends V> m); // 将指定的Map中的key-value对全部复制到该Map中。
void clear(); // 清除Map中的所有key-value对。
Set<K> keySet(); // 获取该Map中所有key组成的Set集合。
Collection<V> values(); // 获取该Map中所有value组成的Collection。
Set<Map.Entry<K, V>> entrySet();: // 获取到Map集合中所有的键值对对象的集合(Set集合)。
boolean remove(Object key, Object value): // 删除指定的key-value对,若删除成功,则返回true;否则返回false
Map实现类
Map典型的实现类是HashMap、Hashtable(HashMap子类还有LinkedHashMap)、SortedMap子接口及实现类TreeMap、WeakHashMap、IndentityHashMap等。
Map有一个内部类Entry,该类封装了key-value对,有如下三个方法:
K getKey(); // 获取Entry中的key值;
V getValue(); // 获取Entry中的value值;
V setValue(V value); // 设置Entry中的value值,并返回新设置的value值。
子类:HashMap集合
HashMap底层是数组+链表的形式,实现Map.Entry接口,数组是Entry[]数组,是一个静态内部类,Entry是key-value键值对(类似json对象),持有一个指向下一个元素的next引用,这就构成链表(单向链表)。
HashMap底层是数组和链表的结合体。底层是一个线性数组结构,数组中的每一项又是一个链表。当新建一个HashMap的时候,就会初始化一个数组。数组是Entry[]数组,静态内部类。Entry就是数组中的元素,每个
Map.Entry
其实就是一个key-value对,它持有一个指向下一个元素的引用next,这就构成了链表。根据指定的hash值找到在table中的索引;HashMap底层数组的长度是2^n,默认是16,负载因子为0.75,所以最大容量阈值threshold
= (int)(capacity *
loadFactor);16*0.75=12,当超过这个阈值的时候,开始扩容,即每次扩容增加一倍。
- HashMap存储自定义类型键值,Map集合保证key是唯一的:作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一
String 类重写hashCode方法和equals方法,可以保证key唯一
value 可以重复(同名同年龄的人视为同一个)
LinkedHashMap
LinkedHashMap是HashMap的子类,使用双向链表维护key-value对的顺序(只是关注key的顺序),迭代顺序和key-value插入Map中的顺序保持一致。
子类:HashTable集合
Hashtable是和HashMap一样,属于Map典型的实现类,区别于Hashtable是线程安全的Map实现,但是性能低。Hashtable不允许使用null作为key和value;若将null值存入Hashtable,会抛出NullPointerException异常;而HashMap可以使用null作为key或value。
Properties
Properties类是Hashtable类的子类。通常作为处理属性配置文件比较好。可以将Map对象中的key-value配置写入到属性文件中,反之,也可以将属性文件中的key=value加载到Map对象中。注意,属性文件中的属性key-value只能是字符串类型。提供以下几个方法来操作Properties
synchronized Object setProperty(String key, String value)
// 设置属性值,底层是通过put来实现。
String getProperty(String key):
// 获取指定属性名的属性值,底层是通过Map的get(Object key)来实现。
String getProperty(String key, String defaultValue):
// 类似于getProperty(String key)方法,在此基础上多一个功能是党Properties中不存在指定的key时,该方法指定默认值去获取。
synchronized void load(InputStream inStream) throws IOException:
// 从属性文件以输入流的方式加载key-value对,并将这些key-value追加到Properties中。
void store(OutputStream out, String comments):
// 将Properties中的key-value对以输出流的方式输出到指定的属性文件中。
Collections:集合工具类
常用方法
- static <T> boolean addAll(需要添加元素的集合对象,Jπ… elements)
往集合中添加一些元素。
static void shuffle(List<?> list) 打乱顺序:打乱集合顺序。
static <T> void sort(List<T> list) :将集合中元素按照默认规则排序。
static <T> void sort(List<t> list, Comparator<? super T> ) :
将集合中元素按照指定规则排序。
Iterator接口:迭代器
-
Collection接口中有一个方法,叫iterator(),这个方法返回的就是选代器的实现类对象,所有集合对象都有此方法
iterator() 返回Iterator接口对象 -
boolean hasNext() :如果仍有元素可以迭代,则返回true。
-
next() : 取出下一个元素。
集合线程安全问题
Vector、HashTable、Properties是线程安全的;
ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等都是线程不安全的。
值得注意的是:为了保证集合是线程安全的,相应的效率也比较低;线程不安全的集合效率相对会高一些。
enum枚举
public class ProductConstant {
// 定义一个简单枚举
public enum AttrEnum{
ATTR_TYPE_BASE(1,"基本属性"),
ATTR_TYPE_SALE(0,"销售属性");
private int code;
private String msg;
AttrEnum(int code,String msg){
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
}
面向对象
1 Java中有四种权限修饰符
public 公共的 > protected 不同包子类 > (default) 同一个包中 > private
同一个类中
注意事项: (default)并不是关键字“default”,而是根本不写。
2 this:本类
-
在本类的成员方法中,访问本类的成员变量。
-
成员方法中,访问本类的另一个成员方法。
-
本类的构造方法中,访问本类的另一个构造方法。
在第三种用法当中要注意:
A:this(… )调用也必须是构造方法的第一一个语句,唯一一个。
B:super和this两种构造调用,不能同时使用。
3 super:父类
-
在子类的成员方法中,访问父类的成员变量。
-
在子类的成员方法中,访问父类的成员方法。
-
在子类的构造方法中,访问父类的构造方法。
4 extends:继承
继承:子类共性抽取形成父类或者是接口(注意:在继承中只有子类知道父类是谁,父类并不知道他的子类是谁)
-
在Java中一个子类的直接父类是唯一的,但是一个父类可以拥有很多个子类,和父类。
-
注意:一个子类继承父类后,父类的所有都是子类的。
-
成员变量不能覆盖重写
5 abstract:抽象类,抽象方法
-
抽象类:在类名前加abstract关键字,可以定义抽象方法,和普通方法,和属性
-
抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束。抽象方法必须在抽象类中,
-
抽象类不能直接创建抽象对象,必须用一个子类来继承抽象父类,然后向上转型为父类对象(抽象对象)。
6 interface:接口
public interface 接口名称{
接口内容可以包含(抽象方法[abstract],常量[final],静态方法[static])
}
-
接口就是多个类的公共规范。
-
接口当中的抽象方法,修饰符必须是两个固定的关键字: public abstract,可以省略
-
不可以直接new一个接口对象,必须利用子类向上转型为接口对象,实现接口必须实现接口的抽象方法
-
接口是没有静态代码块或者构造方法的。
-
implement:实现接口实现接口必须覆写接口中的全部抽象方法
-
一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。接口之间用逗号分隔。
-
如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
-
如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象
类, -
如果实现类所实现的多个接口当中,
存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。 -
类与接口之间是多实现的。一个类可以实现多个接口,接口与接口之间是多继承的。一个接口可以继承多个接口
-
多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写,(
而且带着default关键字)
default:接口的默认方法
- 从Java 8开始,接口里允许定义默认方法。
格式:
public default 返回值类型 方法名称(参数列表) { 方法体 }
- 默认方法不需要子类覆写,但是会被子类继承此方法,并且可以在子类覆盖重写,默认方法主要用于接口的升级
static:接口的静态方法
- 从Java 8开始,接口当中允许定义静态方法。
格式:
public static 返回值类型 方法名称(参数列表) { 方法体 }
- 直接使用接口 类名称.静态方法()调用接口静态方法
private:接口的私有方法
-
我们需要抽取一个共有方法,用来解决接口中,两个默认方法之间重复代码的问题。但是这个共有方法不应该让实现类使用,应该是私有化的。
-
从Java 9开始,接口当中允许定义私有方法。
-
.private普通私有方法,解决多个默认方法之间重复代码问题
格式:
private 返回值类型 方法名称(参数列表) { 方法体 }
- .private static静态私有方法,解诀多个静态方法之间重复代码问题
格式:
private static 返回值类型方法名称(参数列表) { 方法体 }
public static final:接口中的全局常量
-
接口当中也可以定义“成员变量”,但是必须使用public static
final三个关键字进行修饰,可以省略。全局变量名称使用大写字母 -
直接使用接口名.接口全局常量名
7 多态
- 代码当中体现多态性,其实就是一句话: 父类引用指向子类对象
格式:
-
父类名称 对象名= new 子类名称();
-
接口名称 对象名= new 实现类名称();
-
对象名.方法名()
->优先调用覆写的方法,没有则向上查找,不能调用子类特有方法,只能调用父类拥有的方法,或者子类覆写的此父类的方法, -
对象名.属性名 ->直接调用对象的属性,没有则向上查找
-
好处:无论右边new的时候换成哪个子类对象,等号左边调用方法都不会变化。
instanceof对象和类型的判断
- instanceof通过返回一个布尔值来,判断一个对象是否是指定类的对象,用要用来判断一个对象是否可以向下转型我其他类型
用法:
对象 instanceof 类型
:这将会得到一个boolean值结果,也就是判断前面的对象能不能当做后面类型的实例。
内部类
1 成员内部类
成员内部类:在一个类中,方法外,再定义一个类为成员内部类
-
注意:内用外,随意访问;外用内,需要内部类对象。
-
创建内部类对象
外部类名称.内部类名称对象名 = new 外部类名称()。new 内部类名称();
- 内部类调用外部类属性或者方法
外部类名称。this。属性 | 方法()
局部内部类
如果一个类是定义在一个方法内部的,那么这就是一个 局部内部类。
-
“局部内部类”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。
-
局部内部类,如果希望访问所在方法的局部变量,那么这个局部变量必须是[有效final的]。原因:
new出来的对象在堆内存当中,局部变量是跟着方法走的,在栈内存当中,方法运行结束之后,立刻出栈,局部变量就会立刻消失。但是new出来的对象会在堆当中持续存在,直到垃圾回收消失,因此局部内部类会复制一份在内部类中需要使用的在方法中的变量,以需后用,因此方法中的变量必须使用final关键字定义(java1.8后不写以可以)
3 匿名内部类
如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,那么这种情况下就可以省略掉该类的定义,而改为使用[匿名内部类]。
匿名内部类的定义格式:
接口名称 对象名 = new 接口名称() {
//覆盖重写所有抽象方法
};
- 匿名内部类是省略了[实现类/子类名称],但是匿名对象是省略了[对象名称],两者不一样
多线程
线程常用方法
static void **sleep**(long millis) // 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
static Thread currentThread() // 返回对当前正在执行的线程对象的引用。
string getName() // 返回该线程的名称。
setName(线程名字) // 设置线程的名称
object支持线程方法
-
static wait(等待时间)
不输入参数,线程则进入无限等待状态 -
static notify()
使线程进入唤醒状态(首先进入堵塞状态,然后进入运行状态)
Thread:线程类
实现步骤:
-
创建一个Thread类的子类,并重写Thread类中的run方法,设置线程任务(开启线程要做的内容)
注意:run方法在线程对象调用start方法后触发执行 -
创建Thread类的子类对象,调用Thred类中的方法start方法,开启新的线程,执行run方法
Runnable:线程接口
实现步骤:
-
创建一个Runnable接口的实现类
-
在实现类中重写Runnable接口的run方法,设置线程任务
3.创建一个Runnable接口的实现类对象
4.创建Thread类对象,构造方法中传递Runnable接口的实现类对象
5.调用Thread类中的start方法,开启新的线程执行run方法
Callable 接口
(1)实现Callabel接口
(2)执行线程对象,并获取返回结果
线程池(最优)
注意:以上三种方法,都太浪费系统资源,在业务代码里面,以上三种启动线程的方式都不能不用。[将所有的多线程异步任务都交给线程池执行]
CompletableFuture 异步编排(重点)
CompletableFuture的优点:
●异步任务结束时,会自动回调某个对象的方法
●异步任务出错时,会自动回调某个对象的方法
●主线程设置好回调后,不再关心异步任务的执行
基本使用
(2)从线程池中获取线程,并感知异常,但是不能修改返回的数据
修改线程返回结果以及异常信息
(2) 从线程池中获取线程,并感知异常,而且可以修改线程返回的信息
线程串行化方法
线程安全问题(核心)
- 多个线程同时访问同一资源,会出现线程安全问题
- 使用Lock锁接口
ReentrantLock implements Lock接口
使用步骤:
-
在成员位置创建一个ReentrantLock对象
-
在可能会出现安全问题的代码前调用Lock接口中的方法lock()获取锁
-
在可能会出现安全问题的代码后调用Lock接口中的方法unlock()释放锁
- 使用同步方法
使用步骤:
-
把访问了共享数据的代码抽取出来,放到一个方法中
-
在方法上添加synchronized修饰符
使用同步代码块
synchronized(锁对象){
可能会出现线程安全问题的代码(访问了共享数据的代码)
}
注意:
1、通过代码块中的锁对象,可以使用任意的对象,只能锁住同一个锁对象实例的线程,否则无法锁住
2、但是必须保证多个线程使用的锁对象是同一个
3、锁对象作用:把同步代码块锁住,只让相同锁对象实例的,一个线程在同步代码块中执行,其他线程则等待,
IO编程
File类:文件,文件夹
- 重点: file:表示文件 directory:表示,文件夹/目录 path:表示路径
路径是不区分大小写windows使用反斜杠,反斜杠是转义字符,两个反斜杠代表一个普通的反斜杠
创建删除功能的方法
File(String pathname) // 通过将给定路径名(字符串)创建一个新File 实例。
boolean createNewFile() // 不存在此文件,则创建一个新的空文件,不能创建文件夹
boolean delete()// 删除由此File表示的文件或目录。
boolean mkdirs() // 创建由此File表示的目录,包括任何必需但不存在的父目录。
注意:在创建文件和文件夹创建文件,的路径和名称在构造方法中给出(构造方法的参数)
获取功能的方法
-
string getAbsolutePathQ() :返回此File的绝对路径名字符串。
-
string getPath() : 将此File转换为路径名字符串。
-
string getName() : 返回由此File表示的文件或目录的名称。
-
long length() 返回由此File表示的文件的长度。
判断功能的方法
-
boolean exists() :此File表示的文件或目录是否实际存在。
-
boolean isDirectory() : 此File表示的是否为目录。
-
boolean isFile() : 此File表示的是否为文件。
目录的遍历
-
String[] list() : 返回一个String数组,表示该File目录中的所有子文件或目录。
-
File[] listFiles() : 返回一个File数组,表示该File目录中的所有的子文件或目录。
注意:list方法和ListFiles方法遍历的是构造方法中给出的目录,如果构造方法中给出的目录的路径不存在,会抛出空指针异常,如果构造方法中给出的路径不是一个目录,也会抛出空指针异常
OutputStream抽象类:字节输出流
- 流:数据(字符,字节) 1个字符=2个字节,1个字节=8个二进制位
注意:OutputStrem抽象类:是所有字节输出流的父类
定义了一些子类共性的成员方法:
-
void close() : 关闭此输出流并释放与此流相关联的任何系统资源。
-
void flush() :刷新此输出流并强制任何缓中的输出字节被写出。
-
void write(byte[] b):将b.length字节从指定的字节数组写入此输出流。
-
void write(byte[] b, int off, int len)
:从指定的字节数组写入Len字节,从偏移量off开始输出到此输出流。 -
abstract void write(int b) : 将指定的字节输出流。
FileOutputStream:子类
字节输出流的使用步骤(重点):
-
创建一个File0utputStream对象,构造方法中传递写入数据的目的地
-
调用FileoutputStream对象中的方法write,把数据写入到文件中
-
释放资源(流使用会占用一一定的内存,使用完毕要把内存清空,提供程序的效率)
构造方法:创建FileOutputStream对象
-
FileoutputStream(String name
)创建一个向具有指定名称的文件中写入数据的输出文件流。 -
FileoutputStream(File file) 创建一个向指定File
对象表示的文件中写入数据的文件输出流。
追加写/续写:使用两个参数的构造方法
-
FileoutputStream(String name, boolean append) 创建一个向具有指定 name
名的文件中写入数据的输出文件流,并设置是否可以进行续写 -
FileoutputStream(File file, boolean append) 创建一个向指定File
对象表示的文件中写入数据的文件输出流,并设置是否进行续写
InputStream抽象类:字节输入流
注意:InputStream是所有输入流的父类
定义了所有子类共性的方法:
-
int read( ) 从输入流中读取数据的下一个字节。
-
int read(byte[] b) 从输入流中读取的字节保存在数组b中。
注意:没有数据后返回-1,否则返回读取到的字节
- void close() 关闭此输入流并释放与该流关联的所有系统资源。
FileInputStream:子类
构造方法:
-
FileInputStream(String name) 接收需要读取的文件路径,
-
FiLeInputStream(File file) 接收一个File对象,创建对象
Reader抽象类:字符输入流
-
public void close() ;关闭此流并释放与此流相关联的任何系统资源。
-
public int read()]: 从输入流读取一个字符,没有数据返回-1
-
public int read(char[] cbuf):
从输入流中读取一些字符,并将它们存储到字符数组cbuf中。没有数据返回-1
需要使用FileReader子类实例化对象
Writer抽象类:字符输出流
共性的成员方法:
-
void write(int c) 写入单个字符。
-
void. write(char[] cbuf)写入字符数组。
-
abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分,
off数组的开始索引,len写的字符个数。 -
void write(String str)写入字符串。
-
void write(Sstring str, int off, int len)
写入字符串的某一部分,off字符串的开始索引,len写的字符个数。 -
void flush( )刷新该流的缓冲。
-
void close() 关闭此流,但要先刷新它。
Filewriter类构造方法:
-
Filewriter(File file )根据给定的File 对象构造一-个FileWriter 对象。
-
Filewriter(String fileName) 根据给定的文件名构造一个Filewriter 对象。
续写,使用两个参数的构造方法
-
Filewriter(String fileName,boolean append) append指定是否续写
-
Filewriter(File file, boolean append) true为续写
Properties:集合
- Properties集合extends Hashtable<k, v> implements Map<k, v>
Properties类表示了一一个持久的属性集。Properties
可保存在流中或从流中加载,Properties集合是一个双列集合,key和value默认都是字符串
- void store(Writer writer,String null)
把集合中的临时数据,持久化写入到硬盘中存储
- load(Reader red, String null),
把硬盘中保存的文件(键值对),读取到集合中使用
-
object setProperty(String key, String value) 添加数据
-
string getProperty(String key) 通过key找到value值,
-
Set<String> stringPropertyNames() 返回此属性列表中的key集合,
PrivateStream:打印流
构造方法:
-
Printstream(File file):输出的目的地是一个文件
-
Printstream(outputstream out ) :输出的目的地是一个字节输出流
-
Printstream(String fileName) :输出的目的地是一个文件路径
JDBC数据库编程
DriverManager :驱动管理对象
-
Class.forName(数据库驱动) 加载驱动
-
获取数据库连接:
方法: static Connection getConnection(String url, String user, string
password)
参数:url :指定连接的路径(jdbc:mysql://ip地址(域名) :端口号/数据库名称)
user:用户名,
password:用户密码
例子: jdbc:mysql://localhost :3306/db3
Connection :数据库连接对象
-
获取执行sq1的对象
Preparedstatement prepareStatement(String sql)
-
管理事务:
setAutoCommit( boolean autoCommit)
: 参数为false,即开启事务 -
提交事务: commit() 回滚事务: rollback()
ResultSet :结果集对象
-
Boolean next(): 游标向下移动一行,并判断当前行是否是最后一行
-
get数据类型(字段名|数据集合索引) :
通过索引(从1开始),或者字段名获取数据,
preparedstatement :执行sq1的对象
-
注册驱动,获取数据库连接对象Connection
-
定义sql,注意:sql的参数使用?作为占位符。
如: select * from user where username = ? and password = ?;
- 获取执行sql语句的对象
Preparedstatement Connection对象.prepareStatement(String sql)
-
给?赋值: Preparedstatement对象。set数据类型(int,值)
-
执行sql,接受返回结果,不需要传递sq1语句
-
处理结果
-
释放资源
DataSource接口:数据库连接池
注意:一般我们不去实现它,由数据库厂商来实现
连接池:1. C3P0 :数据库连接池技术,2. Druid
:数据库连接池实现技术,由阿里巴巴提供的
-
getConnection() 获取连接:
-
归还连接:如果连接对象Conpection是从连接池中获取的,那么调用Connection对象。close()方法,
则不会再关闭连接了。而是归还连接
使用Druid :数据库连接池
-
导入jar包druid-1.0.9.jar
-
定义配政文件:
是properties形式的
可以叫任意名称,可以放在任意目录下
- 获取数据库连接池对象:通过工厂来来获取
DruidDataSourceFactory
- 获取连接: getConnection
Java8 新特征
(一)Lambda表达式
面向对象的思想:做一件事情,找一个能解决这个事情的对象调用对象的方法,完成事情.
函数式编程思想:只要能获取到结果,谁去做的,怎么做的都不重要,重视的是做什么,而不是怎么做(将关注点从”怎么做”回归到"做什么”的本质上)
使用Lambda表达式
- Lambda表达式的标准格式:
(参数列表) -> {一些重写方法的代码};
a.一些参数,b.一个箭头,c.一段代码
解释说明格式: (必须为函数式接口才可以使用Lambda表达式)
():接口中抽象方法的参数列表,没有参数就空着;有参数就写出参数,多个参数使用逗号分隔
-> :传递的意思,把参数传递给方法体{}
{}:重写接口的抽象方法的方法体
函数式接口
注意:函数式接口:有且只有一个抽象方法的接口,称之为函数式接口,当然接口中可以包含其他的方法(默认静态,私有)
@FunctionalInterface注解:作用:可以检测接口是否是一个函数式接口
函数式编程
可以使用Lambda作为方法的参数和返回值
- Lambda表达式的标准格式: (参数列表) -> {一些重写方法的代码};
-
方法的参数类型是一个函数式接口, 所有我们可以传递一个Lambda表达式
-
方法的返回值类型是一个函数式接口,所有我们可以返回一个Lambda表达式
Consumer<T> :消费型接口
void accept(T t);
Supplier<T> :供给型接口
T get();
Function<T, R> :函数型接口
R app1y(T t);
Predicate<T> :断言型接口
boolean test(T t);
(二)方法引用
方法引用:若Lambda体中的内容有方法已经实现了,我们可以使用"方法引用"
(可以理解为方法引用是Lambda表达式的另外一种表现形式)
(三)Stream API步骤
流(Stream)到底是什么呢:是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。“集合讲的是数据,流讲的是计算!”
注意:
①stream自己不会存储元素。
②Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream。,
③Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
1、创建Stream
Stream主要用来操作集合,数组的
2、中间操作
filter 过滤
- 接收lambda表达式,从流中排除不符合条件的元素
limit(n) 截断流
- limit 方法可以对流进行截取,只取用前n个
skip(n) 跳过元素
- 返回一个过滤前n个,诺流中元素不足n个,则返回一个空流对象
distinct 筛选
- 通过流所生成元素的hashCode()和equals()方法进行去重操作
map 映射(重要)
- map:接收Lambda表达式,将元素提取到流中。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap:接收一个函数作为参数, 将流中的每个值都换成另一个流,
然后把所有流连接成一个流
/*审核人封装*/
public List<Map<String, Object>> index4(ProcessList process) {
/*从数据库获取数据*/
List<Reviewed> revieweds = redao.findByReviewedTimeNotNullAndProId(process);
/*获取集合流*/
List<Map<String, Object>> relist = revieweds.stream()
.map(r -> { /*使用map映射,表示集合中的每一个元素都会执行代码块中的操作*/
Map<String, Object> result = new HashMap<>();
User u = udao.findById(r.getUserId().getUserId()).get();
Position po = pdao.findById(u.getPosition().getId()).get();
SystemStatusList status = sdao.findById(r.getStatusId()).get();
result.put("poname", po.getName());
result.put("username", u.getUserName());
result.put("retime", r.getReviewedTime());
result.put("restatus", status.getStatusName());
result.put("statuscolor", status.getStatusColor());
result.put("des", r.getAdvice());
result.put("img", u.getImgPath());
result.put("positionid", u.getPosition().getId());
return result; /*将每一个元素,返回出去*/
}).collect(Collectors.toList()); /*将流生成为list集合*/
return relist;
}
sorted 排序
(1)sorted() 自然排序(按照compareto()方法进行排序)
流元素必须实现Comparable接口,
(2)sorted(Comparator com) 定制排序
concat 组合
- 如果有两个流,希望合并成为一个流,那么可以使用 Stream 接口的静态方法 concat
:
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T>
b)
总结
logger.warn("*********************过滤*********************");
all.stream()
.filter(a -> a.geteId() > 2) /*过滤id大于2的元素*/
.forEach(System.out::println); /*遍历输出*/
logger.warn("*********************获取指定数量的元素*********************");
all.stream()
.filter(a -> a.geteId() > 5) /*过滤*/
.limit(2) /*收集的元素数量*/
.forEach(System.out::println);
logger.warn("*********************跳过几个元素*********************");
all.stream().filter(a -> a.geteId() >2) /*过滤*/
.skip(2) /*过滤后,再跳过几个元素*/
.forEach(System.out::println);
logger.warn("*********************去重*********************");
all.stream().distinct() /*必须实现hashCode和,equals方法*/
.forEach(System.out::println);
查找与匹配
匹配
allMathch 检查是否匹配所有元素
anyMatch 检查是否至少匹配一个元素
noneMatch 检查是否没有匹配的元素
查找
findFirst 返回第一个元素
findAny 返回当前流中任意的元素
count 返回流中元素总数
max 返回流中最大值
min 返回最小值
reduce归约
reduce(起式值,运算式)
collect 收集 (重要)
logger.warn("--------------获取用户数据集合--------------------");
List<Employee> all = mapper.findAll();
logger.warn("--------------将用户名收集到list集合中--------------------");
List<String> strings = all.stream() /*将对象转换为流*/
.map(e -> e.geteName()) /*将name属性提取到流中*/
.collect(Collectors.toList()); /*将name属性收集进list集合中*/
logger.warn(strings);
logger.warn("--------------将用户名收集到set集合中--------------------");
Set<String> dateSet = all.stream()
.map(Employee::geteName) /*将name属性提取到流中*/
.collect(Collectors.toSet()); /*将流中的属性保存进set集合中*/
logger.warn(dateSet);
logger.warn("--------------将用户名收集到HasSet集合中--------------------");
HashSet<String> hashSet = all.stream()
.map(Employee::geteName)
.collect(Collectors.toCollection(HashSet::new)); /*将流中对象收集进HasSet中*/
logger.warn(hashSet);
logger.warn("-----将用户Id,作为key,用户名作为value,收集到Map集合中,默认使用HasMap实例化---------");
Map<Integer, String> collect =
all.stream().
collect(Collectors.toMap(a -> a.geteId(), /*将流中对象的id作为key*/
a -> a.geteName())); /*将流中对象的name属性作为value收集进Map集合中*/
logger.warn(collect);
logger.warn("--------将用户Id,作为key,用户对象作为value,收集到Map集合中,默认使用HasMap实例化------");
Map<Integer, Employee> employeeMap =
all.stream()
.collect(Collectors.toMap(Employee::geteId, /*将流中对象的id作为key*/
Function.identity())); /*将流中对象作为value,收集进map集合中*/
logger.warn(employeeMap);
Collectors.toMap 有三个重载方法:
(1)toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper);
(2)toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,BinaryOperator<U> mergeFunction);
(3)toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper,BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier);
keyMapper:Key 的映射函数
valueMapper:Value 的映射函数
mergeFunction:当 Key 冲突时,调用的合并方法
mapSupplier:Map 构造器,在需要返回特定的 Map 时使用
示例:如果 List 中 userId 有相同的,使用上面的写法会抛异常:
List<User> userList = Lists.newArrayList(
new User().setId("A").setName("张三"),
new User().setId("A").setName("李四"), // Key 相同
new User().setId("C").setName("王五")
);
userList.stream().collect(Collectors.toMap(User::getId, User::getName));
// 异常:
java.lang.IllegalStateException: Duplicate key 张三
// 这时就需要调用第二个重载方法,传入合并函数,如:
userList.stream().collect(Collectors.toMap(User::getId, User::getName, (n1, n2) -> n1 + n2));
/**
输出结果
A-> 张三李四
C-> 王五
**/
// 第四个参数(mapSupplier)用于自定义返回 Map 类型,比如我们希望返回的 Map 是根据 Key 排序的,可以使用如下写法:
List<User> userList = Lists.newArrayList(
new User().setId("B").setName("张三"),
new User().setId("A").setName("李四"),
new User().setId("C").setName("王五")
);
userList.stream().collect(
Collectors.toMap(User::getId, User::getName, (n1, n2) -> n1, TreeMap::new)
);
/**
A-> 李四
B-> 张三
C-> 王五
**/
其他操作(重)
logger.warn("*************从数据库中获取员工数据*************");
List<Employee> all = mapper.findAll();
logger.warn("*************获取员工总数*************");
Long aLong = all.stream() /* 将集合转换为stream流 */
.collect(Collectors.counting()); /*从流中获取员工总数*/
logger.warn(aLong);
logger.warn("*************获取员工薪水的平均值*************");
Double aDouble = all.stream().
collect(Collectors.averagingDouble(Employee::getSalary)); /*从流中获取薪水的平均值,注意:获取平均值必须为数值类型才可以*/
logger.warn(aDouble);
logger.warn("*************获取员工薪水的最大值,最小值等等*************");
DoubleSummaryStatistics statistics = all.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
logger.warn(statistics);
// 输出的结果:DoubleSummaryStatistics{count=14, sum=66888.400000, min=4000.000000, average=4777.742857,max=7000.000000}
logger.warn("*************获取员工薪水进行分组*************");
Map<Double, List<Employee>> collect = all.stream()
.collect(Collectors.groupingBy(Employee::getSalary)); /*从流中,根据员工薪水进行分组*/
collect.forEach((k, v) -> logger.warn("key=" + k + " value=" + v));
// 输出结果
// *************获取员工总数*************
// 14
// *************获取员工薪水的平均值*************
// 4777.742857142856
// *************获取员工薪水总和*************
// DoubleSummaryStatistics{count=14, sum=66888.400000, min=4000.000000, average=4777.742857, max=7000.000000}
// *************获取员工薪水进行分组*************
// key=5888.4 value=[Employee{eId=14,eName='zs', postId=3, date=2020-11-19 08:00:00, salary=5888.4, mgrPid=null, departmentId=null}]
// key=5000.0 value=[Employee{eId=3,eName='ls', postId=2, date=2020-10-25 08:00:00, salary=5000.0, mgrPid=1, departmentId=2},
// Employee{eId=5, eName='zl', postId=2, date=2020-10-25 08:00:00, salary=5000.0, mgrPid=1, departmentId=4}]
// key=6000.0 value=[Employee{eId=8,eName='zs1', postId=3, date=2020-10-25 08:00:00, salary=6000.0, mgrPid=4, departmentId=3},
// Employee{eId=11, eName='zl1', postId=3, date=2020-10-25 08:00:00, salary=6000.0, mgrPid=3, departmentId=2}]
// key=7000.0 value=[Employee{eId=10,eName='ww1', postId=3, date=2020-10-25 08:00:00, salary=7000.0, mgrPid=2, departmentId=1}]
// key=4000.0 value=[Employee{eId=1,eName='zxm', postId=1, date=2020-10-25 08:00:00, salary=4000.0, mgrPid=null, departmentId=1},
// Employee{eId=2, eName='zs', postId=2, date=2020-10-25 08:00:00, salary=4000.0, mgrPid=1,departmentId=1},
// Employee{eId=4, eName='ww', postId=2, date=2020-10-25 08:00:00, salary=4000.0,mgrPid=1, departmentId=3},
// Employee{eId=6, eName='qq', postId=3, date=2020-10-25 08:00:00, salary=4000.0, mgrPid=2, departmentId=1},
// Employee{eId=7, eName='zb', postId=3, date=2020-10-25 08:00:00,salary=4000.0, mgrPid=3, departmentId=2},
// Employee{eId=9, eName='ls1', postId=3, date=2020-10-2508:00:00, salary=4000.0, mgrPid=5, departmentId=4},
// Employee{eId=12, eName='qq1', postId=3,date=2020-10-25 08:00:00, salary=4000.0, mgrPid=4, departmentId=3},
// Employee{eId=13, eName='zb1',postId=3, date=2020-10-25 08:00:00, salary=4000.0, mgrPid=5, departmentId=4}]
根据true,false分组
获取对薪水的总数,平均数,等等
连接
3、终止操作
终结方法:返回值类型不再是 Stream 接口自身类型的方法,因此不再支持类似
StringBuilder 那样的链式调 用。本小节中,终结方法包括 count 和 forEach 方法。
非终结方法:返回值类型仍然是 Stream
接口自身类型的方法,因此支持链式调用。(除了终结方法外,其余
方法均为非终结方法。)
(四)反射机制
获取字节码Class对象
-
Class.forName(“包点类名”);
-
实例对象名.getClass()方法
-
Class类名.class属性
创建对象的方式。
- 使用反射无参:创建对象只需要一个类名创建Class对象然后通过Class对象的newInstance()方法创建目标对象
public class ServiceFactoy {
public static IService getIserviceimpl(String clsString) throws Exception {
Class cls = Class.forName(clsString);
Constructor ctr = cls.getConstructor();
return (IService)ctr.newInstance();
}
}
- 使用反射有参:使用Class对象的getConstuctor()方法拿到构造器(Constutor对象),然后通过构造器的newIntansce()方法实例化并初始化对象
public class DAOFactory {
public static DAO<Student> StudentDAOimplFacotry(String claString,Connection conn) throws Exception {
// 根据传入的目标对象的包。类名创建改对象的Class对象
Class cls = Class.forName(claString);
// 通过Class对象获取,目标对象的构造方法,并获得构造器对象
Constructor cst = cls.getConstructor(Connection.class);
// 通过构造器对象实例化目标对象
return (DAO<Student>)cst.newInstance(conn);
}
}
Class 类中方法详解
1、获取成员变量
-
Field[] getFields() 获取public的所有成员变量
-
Field getField(String name) 获取public的指定名称变量
-
Field[] getDeclaredFields() 获取全部成员变量,不考虑修饰符
-
Field getDeclaredField(string name )
获取public的指定名称变量,不考虑修饰符
Filed成员对象方法
-
set(对象,属性值) 为指定的对象设置属性值
-
get()对象 获取指定对象的属性值
-
setAccessible(true); 可以访问私有的属性或者方法
2.获取构造方法
-
Constructor<?>[] getConstructors() 获取public无参的构造器
-
Constructor<T> getConstructor(Class<?>… parameterTypes)
获取public有参的构造器,需要传递对应参数的Class对象,
如:String则要传递String.class
-
Constructor<T> getDeclaredConstructor(Class<?>… parameterTypes)
获取有参的构造器,不考虑修饰符,需要传递对应参数的Class对象, -
Constructor<?>[] getDeclaredConstructors()
获取无参的构造器,不考虑修饰符
Constructor构造器对象方法
- newInstance(obj… 参数);
构造方法有参数则传递对应类型的参数,没有参数则不用传参,返回该类对象
3.获取成员方法们:
-
Method[] getMethods() 获取所有的public方法
-
Method getMethod(string name, Class<?>… parameterTypes)
参数:方法名,参数列表的Class对象,获取指定名称,和指定参数列表的方法
-
Method[] getDeclaredMethods()
-
Method getDeclaredMethod(String name,Class<?>… parameterTypes)
Method方法对象:方法
-
invoke(对象,args)
调用方法,有参数需要传递指定的参数类型并需要传递调用此方法的对象 -
getName() 获取方法名
注解:@注解名称
JDK中预定义的一些注解
-
@Override :检测被该注解标注的方法是否是继承自父类(接口)的
-
@Deprecated:该注解标注的内容,表示已过时
-
@SuppressWarnings:压制警告
自定义注解
格式:public @interface 注解名称{}
- 本质:注解本质上就是一个接口,该接口默认继承Annotation接口
public interface 自定义注解类 extends Annotation {}
-
属性:接口中的抽象方法
-
.属性的返回值类型有下列取值:基本数据类型,string,枚举,注解,以上类型的数组
-
定义了属性,在使用时需要给属性赋值
-
如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
-
如果只有一个属性需要赋值,例如:属性的名称是value,则value可以省略,
直接定义值即可 -
数组赋值时,值使用{}包裹。如果数组中只有一个值,则{ }省略
-
-
元注解
元注解:用于描述注解的注解
- @Target:描述注解能够作用的位置
El ementType取值:
-
TYPE :可以作用于类上
-
METHOD:可以作用于方法上
-
FIELD :可以作用于成员变量上
-
@Retention:描述注解被保留的阶段、
- @Retention( RetentionPolicy . RUNTIME)
:当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
- @Retention( RetentionPolicy . RUNTIME)
-
@Documented: 描述注解是否被抽取到api文档中
-
@Inherited: 描述注解是否被子类继承
解析注解
项目实战(DAO => 基于Oracle)
学员编号 int primary key
班级 varchar2(10) not null
学员姓名 varchar2(10)
性别 varchar2(4) check(“男” and “女”)
年龄 int check (>0 < 50)
出生日期 date
家庭住址 varchar2(40)
1、创建数据库表 设置主键
create table student(
stu_bh int primary key,
stu_bj varchar2(10) not null,
stu_name varchar2(20) not null,
stu_sex varchar2(4) check(stu_sex = '男' or stu_sex = '女'),
stu_nl int check(stu_nl \> 0 and stu_nl \< 50),
stu_date varchar2(30),
stu_jt varchar2(50)
);
2、创建序列自增
create sequence user_Sequence
increment by 1 -- 每次加几个
START WITH 1 -- 从1开始计数
NOMAXVALUE -- 不设置最大值
NOCYCLE -- 一直累加,不循环
CACHE 100;
create sequence stu_seq
increment by 1
START WITH 1
NOMAXVALUE
NOCYCLE
CACHE 100;
附 删除序列: DROP SEQUENCE user_Sequence
3、实际开发中创建触发器实现自增! 创建触发器
create or replace trigger 触发器名
before insert on 表名 /*触发条件:当向表dectuser执行插入操作时触发此触发器*/
for each row /*对每一行都检测是否触发*/
begin /*触发器开始*/
select 序列名.nextval into :new.列名 from dual; /*触发器主题内容,即触发后执行的动作,*/
end; /*在此是取得序列dectuser_tb_seq的下一个*/
/ /*值插入到表dectuser中的userid字段中*/
create or replace trigger stu_trigger
before insert on student
for each row
begin
select stu_seq.nextval into :new.stu_bh from dual;
end;
/
附 删除触发器:drop trigger users_trigger;
4、测试数据
insert into student values(1,'x1809','张三','男',20,'1997-12-13','湖北荆州');
insert into student(stu_bj,stu_name,stu_sex,stu_nl,stu_date,stu_jt)
values('x1809','李四','男',20,'1997-12-13','湖北荆州');
5、创建JDBC连接
public class DatabaseConnection {
private static String USERNAMR = "scott";
private static String PASSWORD = "tiger";
private static String DRVIER = "oracle.jdbc.OracleDriver";
private static String URL = "jdbc:oracle:thin:@localhost:1521:orcl";
private Connection conn = null;
public DatabaseConnection() {
try {
Class.forName(DRVIER);
this.conn = DriverManager.getConnection(URL, USERNAMR, PASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("連接成功:"+conn);
}
public Connection getConn() {
return this.conn;
}
public void close() {
try {
if(this.conn!=null) {
this.conn.close();
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
5.1、创建Student学生类(VO)
public class Student implements Serializable {
private Integer stu_bh;
private String stu_bj;
private String stu_name;
private String stu_sex;
private Integer stu_nl;
private String stu_date;
private String stu_jt;
/***
*实现属性的seter和geter方法
*/
}
6、实现数据层接口(DAO)
public interface DAO<T> {
/***
* 新增數據
* @return 新增是否成功,成功返回true
* @throws Exception
*/
public boolean Insert(T t)throws Exception;
/***
* 刪除數據
* @return 刪除成功返回true
* @throws Exception
*/
public boolean Delete(Integer[] ids)throws Exception;
/***
* 數據更新
* @return 更新成功返回true
* @throws Exception
*/
public boolean Update(T t)throws Exception;
/***
* 查詢全部
* @return 返回查詢數據
* @throws Exception
*/
public List<T> fildAll()throws Exception;
/***
* 根據Id查詢數據
* @param id
* @return
* @throws Exception
*/
public T fildId(Integer id)throws Exception;
/***
* 登陸驗證
* @param user
* @param pass
* @return 登陸成功返回true
* @throws Exception
*/
public boolean Login(String user,String pass)throws Exception;
/***
* 條件查詢,根據條件與值進行查詢
* @param v1 條件
* @param v2 值
* @return
* @throws Exception
*/
public List<T> fildS(String v1,String v2)throws Exception;
}
7、实现数据层(DAOimpl)
/***
* 数据层主要用于处理原子操作,对数据库进行操作
* @author ssa
*
*/
public class StudentDAOimpl implements IDAO<Student> {
private Connection conn = null;
/***
* 在构造方法中获取连接对象
* @param conn
*/
public StudentDAOimpl(Connection conn) {
this.conn = conn;
}
/***
* 添加数据
*/
@Override
public boolean Insert(Student t) throws Exception {
try {
String sql = "insert into student values(?,?,?,?,?,?,?)";
PreparedStatement premt = conn.prepareStatement(sql);
premt.setString(1, t.getStu_bh().toString());
premt.setString(2, t.getStu_bj().toString());
premt.setString(3, t.getStu_name());
premt.setString(4, t.getStu_sex());
premt.setString(5, t.getStu_nl().toString());
premt.setString(6, t.getStu_date().toString());
premt.setString(7, t.getStu_jt());
return premt.executeUpdate()>0;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/***
* 删除数据
*/
@Override
public boolean Delete(Integer[] ids) throws Exception {
try {
StringBuffer sBuffer = new StringBuffer("Delete student where stu_bh in(");
for(int i = 0 ; i < ids.length ; i++ ) {
sBuffer.append(ids[i]).append(",");
}
sBuffer.delete(sBuffer.length()-1, sBuffer.length()).append(")");
PreparedStatement parmet = conn.prepareStatement(sBuffer.toString());
return parmet.executeUpdate()>0;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/***
* 更新数据
*/
@Override
public boolean Update(Student t) throws Exception {
try {
String sql = "update student set stu_bj = ? ,stu_name=?,stu_sex = ?,stu_nl = ?,stu_date = ?,stu_jt = ? where stu_bh = ?";
PreparedStatement premt = conn.prepareStatement(sql);
premt.setString(1, t.getStu_bj().toString());
premt.setString(2, t.getStu_name());
premt.setString(3, t.getStu_sex());
premt.setString(4, t.getStu_nl().toString());
premt.setString(5, t.getStu_date().toString());
premt.setString(6, t.getStu_jt());
premt.setInt(7, t.getStu_bh());
return premt.executeUpdate()>0;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/***
* 查询全部数据
*/
@Override
public List<Student> fildAll() throws Exception {
List<Student> all = new ArrayList<Student>();
Student stu = null;
try {
String sql = "select * from student";
PreparedStatement parmet = conn.prepareStatement(sql);
ResultSet rSet = parmet.executeQuery();
while (rSet.next()) {
stu = new Student();
stu.setStu_bh(rSet.getInt(1));
stu.setStu_bj(rSet.getString(2));
stu.setStu_name(rSet.getString(3));
stu.setStu_sex(rSet.getString(4));
stu.setStu_nl(rSet.getInt(5));
stu.setStu_date(rSet.getString(6));
stu.setStu_bj(rSet.getString(7));
all.add(stu);
}
return all;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/***
* 根据id进行查询
*/
@Override
public Student fildId(Integer id) throws Exception {
Student stu = null;
try {
String sql = "select * from student where stu_bh = ?";
PreparedStatement parmet = conn.prepareStatement(sql);
parmet.setInt(1, id);
ResultSet rSet = parmet.executeQuery();
while (rSet.next()) {
stu = new Student();
stu.setStu_bh(rSet.getInt(1));
stu.setStu_bj(rSet.getString(2));
stu.setStu_name(rSet.getString(3));
stu.setStu_sex(rSet.getString(4));
stu.setStu_nl(rSet.getInt(5));
stu.setStu_date(rSet.getString(6));
stu.setStu_bj(rSet.getString(7));
}
return stu;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/***
* 条件查询
*/
@Override
public List<Student> fildS(String v1, String v2) throws Exception {
List<Student> all = new ArrayList<Student>();
Student stu = null;
try {
String sql = "select * from student where ? = ?";
PreparedStatement parmet = conn.prepareStatement(sql);
parmet.setString(1, v1);
parmet.setString(1, v2);
ResultSet rSet = parmet.executeQuery();
while (rSet.next()) {
stu = new Student();
stu.setStu_bh(rSet.getInt(1));
stu.setStu_bj(rSet.getString(2));
stu.setStu_name(rSet.getString(3));
stu.setStu_sex(rSet.getString(4));
stu.setStu_nl(rSet.getInt(5));
stu.setStu_date(rSet.getString(6));
stu.setStu_bj(rSet.getString(7));
}
return all;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
7.1、实现数据层工厂类(DAOFactoy)
public class DAOFactory {
public static DAO<Student> StudentDAOimplFacotry(String claString,Connection conn) throws Exception {
// 根据传入的目标对象的包。类名创建改对象的Class对象
Class cls = Class.forName(claString);
// 通过Class对象获取,目标对象的构造方法,并获得构造器对象
Constructor cst = cls.getConstructor(Connection.class);
// 通过构造器对象实例化目标对象
return (DAO<Student>)cst.newInstance(conn);
}
}
8、实现业务层(Service)
/***
* 业务层主要用来调用数据层的处理逻辑
* @author ssa
*
*/
public class StudentServiceimpl implements IService<Student> {
private DatabaseConnection dbc = new DatabaseConnection();
private String claString = "cn.mldn.lxh.dao.impl.StudentDAOimpl";
public StudentServiceimpl() {
// TODO Auto-generated constructor stub
}
@Override
public boolean Add(Student t) throws Exception {
try {
if(DAOFactory.getDAOimpl(claString, dbc.getConn()).fildId(t.getStu_bh())==null) {
return DAOFactory.getDAOimpl(claString, dbc.getConn()).Insert(t);
}
System.out.println("也存在ID为:"+t.getStu_bh());
} catch (Exception e) {
e.printStackTrace();
}finally {
dbc.close();
}
return false;
}
@Override
public boolean Remove(Integer[] ids) throws Exception {
try {
return DAOFactory.getDAOimpl(claString, dbc.getConn()).Delete(ids);
} catch (Exception e) {
e.printStackTrace();
}finally {
dbc.close();
}
return false;
}
@Override
public boolean Replace(Student t) throws Exception {
try {
if(DAOFactory.getDAOimpl(claString, dbc.getConn()).fildId(t.getStu_bh())!=null) {
return DAOFactory.getDAOimpl(claString, dbc.getConn()).Update(t);
}
System.out.println("不存在ID为:"+t.getStu_bh());
} catch (Exception e) {
e.printStackTrace();
}finally {
dbc.close();
}
return false;
}
@Override
public List<Student> SelectAll() throws Exception {
try {
return DAOFactory.getDAOimpl(claString, dbc.getConn()).fildAll();
} catch (Exception e) {
e.printStackTrace();
}finally {
dbc.close();
}
return null;
}
@Override
public Student SelectId(Integer id) throws Exception {
try {
if(DAOFactory.getDAOimpl(claString, dbc.getConn()).fildId(id)!=null) {
return (Student)DAOFactory.getDAOimpl(claString, dbc.getConn()).fildId(id);
}
System.out.println("不存在ID为:"+id);
} catch (Exception e) {
e.printStackTrace();
}finally {
dbc.close();
}
return null;
}
@Override
public boolean Login(String user, String pass) throws Exception {
// TODO Auto-generated method stub
return false;
}
@Override
public List<Student> SelectS(String v1, String v2) throws Exception {
try {
if(v1!=null&&v2!=null) {
return DAOFactory.getDAOimpl(claString, dbc.getConn()).fildS(v1, v2);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
dbc.close();
}
return null;
}
}
8.1、实现业务层工厂类(ServiceFactory)
public class ServiceFactoy {
public static IService getIserviceimpl(String clsString) throws Exception {
Class cls = Class.forName(clsString);
Constructor ctr = cls.getConstructor();
return (IService)ctr.newInstance();
}
}
9、Oracle分页参考
分页查询
参考
select * from ( select rownum rn, e.* from ( select * from EMP) e ) where rn > pageSize * (page - 1) and rn <= pageSize * page
select * from ( select rownum rn, e.* from ( select * from EMP) e )where rn > 9 * (page - 1) and rn <= 9 * page
注意:
pageSize:表示每页最大显示数量
page:表示显示第几页、
分析源码:
我们选定每页(pageSize)为5。那么EMP表目前共有三页,1~5行为1页;6~10行为1页;1~15行为1页(缺第15行,那么第3页就显示4行记录)
页面从第1页开始。
我们要查询第2页的记录,那么page = 2。
那么第2页是由第6,7,8,9,10行记录形成的。
ete(ids);
} catch (Exception e) {
e.printStackTrace();
}finally {
dbc.close();
}
return false;
}
@Override
public boolean Replace(Student t) throws Exception {
try {
if(DAOFactory.getDAOimpl(claString, dbc.getConn()).fildId(t.getStu_bh())!=null) {
return DAOFactory.getDAOimpl(claString, dbc.getConn()).Update(t);
}
System.out.println("不存在ID为:"+t.getStu_bh());
} catch (Exception e) {
e.printStackTrace();
}finally {
dbc.close();
}
return false;
}
@Override
public List<Student> SelectAll() throws Exception {
try {
return DAOFactory.getDAOimpl(claString, dbc.getConn()).fildAll();
} catch (Exception e) {
e.printStackTrace();
}finally {
dbc.close();
}
return null;
}
@Override
public Student SelectId(Integer id) throws Exception {
try {
if(DAOFactory.getDAOimpl(claString, dbc.getConn()).fildId(id)!=null) {
return (Student)DAOFactory.getDAOimpl(claString, dbc.getConn()).fildId(id);
}
System.out.println("不存在ID为:"+id);
} catch (Exception e) {
e.printStackTrace();
}finally {
dbc.close();
}
return null;
}
@Override
public boolean Login(String user, String pass) throws Exception {
// TODO Auto-generated method stub
return false;
}
@Override
public List<Student> SelectS(String v1, String v2) throws Exception {
try {
if(v1!=null&&v2!=null) {
return DAOFactory.getDAOimpl(claString, dbc.getConn()).fildS(v1, v2);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
dbc.close();
}
return null;
}
}
## 8.1、实现业务层工厂类(ServiceFactory)
```java
public class ServiceFactoy {
public static IService getIserviceimpl(String clsString) throws Exception {
Class cls = Class.forName(clsString);
Constructor ctr = cls.getConstructor();
return (IService)ctr.newInstance();
}
}
9、Oracle分页参考
分页查询
参考
select * from ( select rownum rn, e.* from ( select * from EMP) e ) where rn > pageSize * (page - 1) and rn <= pageSize * page
select * from ( select rownum rn, e.* from ( select * from EMP) e )where rn > 9 * (page - 1) and rn <= 9 * page
注意:
pageSize:表示每页最大显示数量
page:表示显示第几页、
分析源码:
我们选定每页(pageSize)为5。那么EMP表目前共有三页,1~5行为1页;6~10行为1页;1~15行为1页(缺第15行,那么第3页就显示4行记录)
页面从第1页开始。
我们要查询第2页的记录,那么page = 2。
那么第2页是由第6,7,8,9,10行记录形成的。