JAVA基础
JAVA基础
命名规范
项目名 全小写
包 全小写 域名反写:从大到小
类 大驼峰命名:每个单词首字母大写,其他字母小写
方法 小驼峰命名
变量 小驼峰命名:第一个单词全小写,第二个开始每个单词首字母大写
包和类的关系
类对应一个源代码,源文件 xxx.java
包就是文件夹,就是对类进行分类管理
package声明包,必须在源代码的第一条语句。告诉系统当前类所在的包的位置
import导入包,当前类要使用其它类不在同一包,要告诉系统,要使用的类的包的所在位置
不需要导入的情况
同一个包的类
java.lang包中类会自动导入
JDK JRE JVM的区别和联系
JDK
JDK是Java Development Kit的缩写,是Java的开发工具包。
包括了Java运行环境(JRE),Java工具(javac/java/jdb等)和Java基础的类库(即Java API )。
JRE
JRE(Java Runtime Environment,Java运行环境),包含JVM标准实现及Java核心类库。 JRE是Java运行环境,并不是一个开发环境,所以没有包含任何开发工具(如编译器和调试器),只是针对于使用Java程序的用户。
JVM
JVM(Java Virtual Mechinal),Java虚拟机,是JRE的一部分。它是整个java实现跨平台的最核心的部分,负责解释执行字节码文件,是可运行java字节码文件的虚拟计算机。
JDK=JRE+开发工具
JRE=JVM+类库(系统封装好的类,API)
JVM实现跨平台
环境变量的配置
环境变量
JAVA_HOME
D:\develop\Java\jdk1.8.0_221
Path
%JAVA_HOME%bin
idea 和eclipse的区别
eclipse | 免费 | 一个窗口同时展示多个项目 | ||
---|---|---|---|---|
idea | 收费 | 一个窗口只能展示一个项目 一个项目下创建多个模块 | 功能强大 | 机器硬件要求高 |
数据类型和变量
基本数据类型
byte(-128----+127) short int long ---整型
float double ---浮点型
char ---字符型
boolean ---布尔型
引用数据类型
类
自定类
JRE类库中的系统类 String Scanner
数组
抽象 具体
数据类型 变量
类 对象
类就是对象的数据类型
对象就是类的一个实例
分析设计系统
对象-----抽象-----类
编码
定义类----创建对象
类型转换
兼容数据类型
隐式转换(自动转换)
小的赋值给大的
char byte short,参与运行,结果会自动为int
要一个大的类型,参与,结果会转成这种类型
char byte short---int---float---double
显示转换(强制类型转换)
大的赋值给小的
问题:精度丢失
//常量:字面值常量,整数默认都是int,小数默认都是double
// double d=1.1;
// float f=1.1F;
// long i=1111111111111L;
//字面值常量,int,没用超过类型的范围,可以赋值
byte b1=127;
//上面的规则对变量无效
int i=127;
byte b2=i;
标识符
变量名
命名规范
语法规范
数字,字母,_,$
数字不能开头
不能使用系统关键字和保留字
关键字:这些单词用来构成程序的特殊语法结构
保留字:候选关键字,Java底层C语言 goto和const
向下转型
Aaa aaa =new Aaa;
Bbb bbb =new Bbb;
//a是父类对象,指向子类对象的地址
//假转型
aaa=bbb;
bbb=(Bbb)aaa;
//真转型 会报错,编译器可以运行,但运行时出错
bbb=(Bbb)aaa;
静态方法是属于类的
非静态方法
运算符
算术运算符 + - * / % ++ --
赋值运算符 = +=
关系运算符 > >= != ==
逻辑运算符 && || !
三目运算符 条件? 值1:值2
优先级 ()最高
流程控制
三种
顺序
选择
循环
选择结构
单分支
if(条件){
代码块;
}
if()
只有一条语句可以省略{}
二选一
if(条件){
代码块1;
}else{
代码块2;
}
多选一
if(条件1){
代码块1;
}else if(条件2){
代码块2;
}else if(条件3){
代码块3;
}else if(条件4){
代码块4;
}else{
代码块5;
}
程序流程图
switch(变量/表达式){
case 常量1:
代码块1;
break; //编码case穿透
case 常量2:
代码块2;
break;
case 常量3:
代码块4;
break;
defalut:
代码块4;
break;
}
switch-case缺点
变量能够匹配的类型有限制
JDK1.5之前 byte short char int
JDK1.5开始 枚举类型
JDK1.7开始 String
等值匹配,区间范围比较不灵活
switch-case优点
执行性能比多重if块
循环
1.while(循环条件){
循环体;
}
2.do{
循环体;
}while(循环条件);
3.for(表达式1;表达式2;表达式3){
循环体;
}
表达式1:循环变量初始值
表达式2:循环条件
表达式3:修改循环变量的值,使循环结束
break 结束整个循环
continue 结束本次循环
双重循环
类和对象
增删改都不需要返回值
查需要返回值
抽象类
抽象方法
final
多态
使用步骤
子类重写父类方法
子类对象赋给父类
父类调用方法执行的子类方法
典型应用
父类类型做参数
父类类型做返回值
访问修饰符
访问修饰符
本类 同包 子类 其它
private Y
默认(不写) Y Y
protected Y Y Y
public Y Y Y Y
单例:无论调用多少次创建对象的方法,内存中只分配一个对象
饱汉/懒汉
public class Singleton{
private static Singleton singlton;
private Singleton(){}
public static Singleton getInstance(){
if(singlton==null){
singlton=new Singleton();
}
return singleton;
}
}
饿汉
public class Singleton{
private static Singleton singlton=new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return singleton;
}
}
重载:同一个类,方法名相同,参数不同(参数个数,参数类型)
重写:子类,和父类的方法签名一般完全相同
增强父类的功能
访问修饰符 返回值类型 方法名 参数 抛出异常
重写 不能比父类更严格 父类返回值类型及其子类类型 相同 相同 有要求
抽象类
抽象
对象---->类---->父类----->父类......----->抽象类
抽象类
一般位于继承层级结构的上层节点,类似于一个骨架。定义所有子类公有的行为,这些行为的具体实现有子类自己完成,抽象类没有必要实现。
定义类中使用abstract关键字
抽象方法只定义,不实现。
声明方法使用abstract关键字,没有方法体{}
public abstarct class 类名{
public abstract 返回值 方法名(参数列表);
}
抽象方法所在的类必须是抽象类
抽象类中可以不定义抽象方法
子类继承抽象类,必须重写抽象类的抽象方法,除非这个类也是抽象类
抽象类不能实例化
Object
Object类是所有类的父类,为什么这个类的方法不是抽象方法
自定义输出:重写toString()
自定义相等的比较规则:重写equals()
如果是抽象方法,增加使用的麻烦
Java是单继承
面向对象是一种设计思想,不同的编程语言都支持
C++ Java C#
C++支持多继承,一个类可以同时继承多个父类
Java、C#都是单继承, 一个类只能有一个直接父类
继承:
子类共有的属性,封装到父类。子类继承父类的属性,也可以扩展自己的属性。
父类可以定义子类共有的行为,父类可以实现,也可以不实现。子类可以直接使用,也可以重写,可以扩展父类没有的行为
优点:
节省代码,减少冗余。方便修改扩展
缺点
低耦合(依赖性),高内聚(独立性)
继承是高耦合
final关键字
final:最终的,不变
修饰变量,就是常量
public static void main(String[] args) {
int a=1;
a=4;
a=5;
//可以修饰局部变量
final int b=5;
//赋值以后不能修改
//b=6;
System.out.println("b="+b);
}
class Ddd{
int a;
//声明成变量必须赋值
final int b=5;
void test(){
//不能修改
//b=6;
System.out.println(b);
}
}
class Eee{
//可以在构造方法中修改
final int b;
public Eee(int b){
this.b=b;
}
void test(){
//error
//b=6;
}
}
class Fff{
//最常见的用法,静态常量,一般都用大写。 MY_NAME_XXX
public static final int MAX=123;
}
public class Test03 {
public static void main(String[] args) {
System.out.println(Fff.MAX);
}
}
修饰方法,不能被重写
修饰类,不能被继承
String类能不能继承
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
}
设计模式
设计模式,一类问题的一种解决方案。软件开发的经验总结。
单例:对象只创建一个
简单工厂
一个父类 Car 抽象产品
若干子类 Benz BMW 实体产品
工厂类 CarFactory 实体工厂
工厂方法
抽象工厂
类型转换
向上转型,安全的
父类对象=子类对象
向下转型,不安全
真转型 运行异常
子类对象=父类对象
假转型 安全的
父类对象已经指向了子类对象
子类对象=父类对象
instanceof
对象 instanceof 类型
多态的优缺点
优点:代码灵活,方便扩展
父类类型 对象=new 子类构造器();
缺点:
不能通过父类类型调用子类的特有方法
重写equals()方法,实现自定义对象,自定义比较相对的规则
//自定义两个学生对象的相等比较规则:所有属性值都相同,就是同一个学生
// public boolean equals(Object obj) {
// if(obj==null){
// return false;
// }
// if(obj instanceof Student){
// //如果比较的对象是学生,才按照学生的属性比较
// //假转型
// Student other= (Student) obj;
// return this.id==other.id
// &&this.name.equals(other.name)
// &&this.age==other.age;
// }
// return false;
// }
@Override
public boolean equals(Object o) {
//地址相同,属性值相同
if (this == o) return true;
//参数为null,或者和当前对象不是同一个数据类型
if (o == null || getClass() != o.getClass()) return false;
//向下转型,假转型
Student student = (Student) o;
return id == student.id && age == student.age && Objects.equals(name, student.name);
}
接口
接口是一种数据类型(抽象类型),是抽象方法的集合,接口使用interface关键字。
一个类通过继承接口的方式,从而来继承接口的抽象方法
类描述对象的属性和方法。接口则包含类要实现的方法。
接口是一组规范,主要是用来规范行为,功能,方法
接口中定义成员变量,默认就是public static final
接口中的方法只定义不实现(JDK1.8之前),定义方法可以不写访问修饰符,默认就是public
接口不能实例化,可也通过多态的使用方法,将接口的实现类对象,赋给接口的实例变量
一个类实现接口必须实现接口中的所有方法,除非这个类也是抽象类
Java是单继承,一个类只能有一个直接父类。一个类可也同时实现多个接口。父类在前,接口在后。
public class 实现类 extends 父类 implements 接口1,接口2
---------------------------------------------------------------------------
接口是对单继承的一种扩展,接口间接实现了多继承。实现接口的耦合度比继承父类的耦合度小。
JDK1.8扩展了接口的功能:
接口的方法可以实现,使用static或者default关键字。
接口中的方法有默认实现,实现类实现接口的方法时可也按需选择实现重写,减少代码。
接口可也继承接口,可也继承多个。实现类似功能组合的作用。将几个基础的接口整合成一个功能更复杂的接口。
定义 成员变量
抽象类 abstract class 访问修饰符任意,是否静态任意,是否常量任意
接口 interface 默认都是public static final
方法
抽象类 访问修饰符任意,是否静态任意,有没有抽象方法任意
接口 默认public JDK1.8之前不能写方法体 JDK1.8以后可以使用static和default关键字定义有方法体的方法
子类继承抽象类
实现类实现接口
Comparable 语法
Comparable 语法
首先实现接口
public class Student implements Comparable
然后重写compareTO方法将
public int compareTo(Object o) {
if (o instanceof Student){
Student other=(Student) o;
return this.age-other.age;
}
return 0;
}
才能调用方法Arrays.sort(students);
comparator
先定义一个比较器,实现方法
public class AgeDesc implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o2.getAge() - o1.getAge();
}
}
调用方法
Arrays.sort(students,new AgeDesc());
匿名内部类
Comparator comparator=new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge()-o2.getAge();
}
};Arrays.sort(students);
匿名-例子
1创建另一个类来实现接口,通过另一个类来实现
interface Interface1{
void aaa();
}
class Class1{
public void test(Interface1 interface1){
interface1.aaa();
}
}
class Class2 implements Interface1{
@Override
public void aaa() {
System.out.println("实现匿名内部类");
}
}
public class MyInterface {
public static void main(String[] args) {
Class1 class1=new Class1();
class1.test(new Class2());
}
}
如果不想创建类,实现接口,就使用匿名内部类
interface Interface1{
void aaa();
}
class Class1{
public void test(Interface1 interface1){
interface1.aaa();
}
}
public class MyInterface {
public static void main(String[] args) {
new Class1().test(new Interface1() {
@Override
public void aaa() {
System.out.println("实现匿名内部类");
}
});
}
}
两种比较器例子
1、使用两种比较器实现自定义对象数组的自然排序和自动规则排序
comparable
public class Student implements Comparable{
private String name;
private int id;
private int age;
public Student(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
public Student(){}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public int compareTo(Object o) {
if (o instanceof Student){
Student other=(Student) o;
return this.age-other.age;
}
return 0;
}
}
import java.util.Arrays;
public class Test1 {
public static void main(String[] args) {
Student[] students =new Student[3];
students[0]=new Student("zs",1,18);
students[1]=new Student("ls",2,12);
students[2]=new Student("ww",3,14);
System.out.println("排序前"+Arrays.toString(students));
Arrays.sort(students);
System.out.println("排序后"+Arrays.toString(students));
}
}
comparator
import java.util.Comparator;
public class AgeDesc implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o2.getAge() - o1.getAge();
}
}
public class Test1 {
public static void main(String[] args) {
Student[] students =new Student[3];
students[0]=new Student("zs",1,18);
students[1]=new Student("ls",2,12);
students[2]=new Student("ww",3,14);
System.out.println("排序前"+Arrays.toString(students));
Arrays.sort(students,new AgeDesc());
System.out.println("排序后"+Arrays.toString(students));
}
}
2、Comparotor使用匿名内部类实现
import java.util.Arrays;
import java.util.Comparator;
public class Test1 {
public static void main(String[] args) {
Student[] students =new Student[3];
students[0]=new Student("zs",1,18);
students[1]=new Student("ls",2,12);
students[2]=new Student("ww",3,14);
System.out.println("排序前"+Arrays.toString(students));
Comparator comparator=new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge()-o2.getAge();
}
};Arrays.sort(students);
System.out.println("排序后"+Arrays.toString(students));
}
}
3、主方法中添加代码,调用test()方法
interface Interface1{
void aaa();
}
class Class1{
public void test(Interface1 interface1){
interface1.aaa();
}
}
interface Interface1{
void aaa();
}
class Class1{
public void test(Interface1 interface1){
interface1.aaa();
}
}
public class MyInterface {
public static void main(String[] args) {
new Class1().test(new Interface1() {
@Override
public void aaa() {
System.out.println("实现匿名内部类");
}
});
}
}
4、输入一个字符串,统计数字,大写字母,小写字母各有多少个。
import java.util.Scanner;
public class TongJi {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
System.out.println("输入一个字符串");
String str = scanner.next();
int up=0;
int low=0;
int num=0;
for (int i = 0; i <str.length() ; i++) {
char c=str.charAt(i);
if (c>='A'&&c<='Z'){
up++;
}
else if (c>='a'&&c<'z'){
low++;
}else if (c>'0'&&c<'9'){
num++;
}
}
System.out.println("大写字母:"+up);
System.out.println("小写字母:"+low);
System.out.println("数字:"+num);
}
}
5、字符串反转:输入abcefg,输出gfecba
public class FanZhuan {
public static void main(String[] args) {
String str="abcefg";
for (int i = str.length()-1; i>=0; i--) {
System.out.print(str.charAt(i));
}
}
}
6、字符串查找子串”abcwonxiuydewonxiuyfghiwonxiuyjklmwonxiuyl”,统计”woniuxy”出现的次数
public class SearchSonString {
// 字符串查找子串"abcwonxiuydewonxiuyfghiwonxiuyjklmwonxiuyl",统计"woniuxy"出现的次数
public static void main(String[] args) {
String str="abcwonxiuydewonxiuyfghiwonxiuyjklmwonxiuyl";
String[] strings=str.split("woniuxy");
int count =strings.length-1;
System.out.println("woniuxy出现的次数为:"+count);
}
}
集合
Collection
Collection 单列集合
List 有顺序的,可重复的 顺序是添加顺序
ArrayList 底层是数组,可以进行下标操作(一般都是使用ArrayList集合)
Linkedlist 底层是双向链表
Vector 底层是数组
10 后面是*1.5
Set 不重复
HashSet 无序 hash表:数组+链表
扩容: 16 后面是*0.75
去重: hashcode()equals(
根据hash值来确定顺序,所以无序
LinkedHashSet 有序 hash表保证不重复 链表保证有序
TreeSet 有序 红黑树
去重+排序 comparable +comparator
set都是map的
Map
Map 双列集合
HashMap
LinkedHashMap
TreeMap
数组和链表的区别
数组 内存中分配的是一段连续的空间
查询快:数组通过下标访问,只要知道首地址,就可以快速计算出任何一个元素的地址
增删慢:增或删都要进行数组的扩容或缩容,操作起来比较麻烦。
链表 内存中不是连续的空间,每个节点会记录前一个和下一个元素的地址
查询慢:
增删快;
linkedList
Arraylist的方法都有,底层实现不同
有专门操作头尾元素的方法
getFirst() getLast()
addFirst() addLast()
removeFirst() removeLast()
Vector
ArrayList 线程不安全,效率高
Vector 加了锁的,线程安全,效率低
HashSet
不重复:添加元素会自动去重判断
无序:添加的顺序和内存中的顺序不一致
HashSet底层
hash表:元素是链表的数组,相同HashCode的对象,在同一个数组的下标位置,通过单向链表关联在一起的
JDK1.7 数组+链表
JDK1.8 数组+链表+红黑树
HashSet去重原理
hashCode()+equals()
hashCode()方法
Object:默认实现:根据对象的内存地址使用Hash散列算法,计算出来的一个整数
String类重写:安装字符串中每个字符的编码做了一个累加
自定义类:使用所有的属性值做一个*固定数累加
HashSet去重判断相等
先判断hashCode()
hashCode()不同,属性值一定不同,直接添加
hashCode()相同,属性值可能相同,也可能不同
判断equals()
equals()相同,不添加
equals()不相同,添加
自定义类型去重:重写equals()和hashCode()
扩容
初始化没有指定长度,默认是0,第一添加,初始16个。加载因子0.75;
实际数据容量到16*0.75=12,扩容,原来的2倍 32
32*0.75=24 扩容,64
树化:链表转成红黑数:容量>=64链表的长度>=8
下标位置:
二次hash
HashMap
HashSet就是HashMap的key
Map接口的实现类,每一个元素由两个部分组成。键值对:key-value
key必须唯一
通过key获取value
key和value可以是任意类型,都支持泛型
添加
V put(K key, V value);
通过key获取Value值
V get(Object key);
删除所有元素
void clear();
通过key删除元素
V remove(Object key);
是否存在指定的key
boolean containsValue(Object value);
是否存在指定的value
boolean containsValue(Object value);
获取所有key的集合,key不重复,所有定义成Set<K>
Set<K> keySet();
获取所有value的集合,value可以重复,所有定义成Collection<V>
Collection<V> values();
//entrySet() entry的set集合
//Set<Map.Entry<Integer, Student>> set集合,集合中的元素是Map.Entry<Integer, Student>
//Map.Entry<Integer, Student>是一种数据类型 Map接口.Entry接口
//一个Entry就是一个键值对
Set<Map.Entry<K, V>> entrySet();
LinkedHashSet
Set 不重复
HashSet 不重复,无序
LinkedHashSet 不重复,有序( 遍历的顺序和添加顺序一致)
LinkedHashSet:
使用Hash表保证不重复 保证添加元素不重复:equals 和 hashCode
使用链表保证有序
TreeSet
Set 不重复
HashSet 不重复,无序
LinkedHashSet 不重复,有序
TreeSet 不重复,有序,自定义排序
底层是红黑树
数据结构
线性表
图
树 根节点 叶子节点
二叉树
平衡树: 左边分支的元素,比右边小,两边的层高最多差一层(所有数据查询,都是相同的查询效率)
红黑树: 不是严格平衡树,在查询平均性能和添加删除效率上做了一个折中的设计
根节点是黑色的
叶子节点也是黑色的,都是null
红色节点的子节点必须是黑色
任何一个节点到叶子节点的所有路径中,经过的黑色节点的个数必须相同
https://www.cs.usfca.edu/~galles/visualization/RedBlack.html
public TreeSet()
底层使用自然排序Comparable
public TreeSet(Comparator<? super E> comparator)
底层使用自定义排序Comparator
保证添加元素不重复:
comparable或comparator
正数 >
负数 <
0 ==
LinkedHashMap
LinkedHashSet就是LinkedHashMap的key
LinkedHashMap:key不重复,有顺序
TreeMap
TreeSet就是TreeMap的key
数据持久化
我们前的集合和数组,数据都在内存中
数据持久化,我们要把数据永久保存,数据持久化存储到硬盘中:
文件
读数据、写数据(I/O流)
学习File 异常处理
数据库 CRUD
File
一切皆对象
File 文件和目录路径(文件夹)名的抽象表示形式。
Java 文件和文件夹封装成一个类
C# File Directory
构造器
public File(String pathname)
创建目录
public boolean mkdir() 上级目录必须存在
public boolean mkdirs() 无论多少层目录会自动创建
创建文件
public boolean createNewFile()
递归
方法自己调用自己,避免栈溢出
递归
递推:将复杂的问题,往简单的情况退,推到最简单情况,可也得到一个已知值
回归:再从这个已知值,往回算
如求1加5的值
递推:
sum(5)=sum(4)+5 15
sum(4)=sum(3)+4 10
sum(3)=sum(2)+3 6
sum(2)=sum(1)+2 3
sum(1)=1 1
回归
斐波拉契数列
1,1,2,3,5,8,13,21...
n>2 f(n)=f(n-1)+f(n-2)
n=1 n=2 f(n)=1
f(5)=f(4)+f(3)
f(4)=(f3)+f(2)
f(3)=f(2)+f(1)
f(2)=1
f(1)=1
BigInteger
解决整数运算超出范围
大整数运算
BigDecemal
解决小数运算的范围和精度问题
小数的精确计算
Date
JDK提供的一个日期时间类,JDK1.8以后新增了很多其它的
new Date()
new Date(时间毫秒)
DateFormat
public final String format(Date date)
日期转字符串
public Date parse(String source)
字符串转日期
异常处理
语法错误:编译错误,不能运行
逻辑错误:正常运行,期望的结果和运行结果不同
异常:程序运行时出错
Throwable
Error 错误,不需要程序员处理。Error一般是系统级别的问题。
Exception
异常,出现异常,程序必须处理,如果程序员不处理,虚拟机处理。虚拟机遇到异常,挂了,停止运行。
处理异常的基本结构
try{
//可以能会发生异常的代码
}catch(异常类型 变量){
//发生异常以后要执行的代码
}finally{
//有没有异常都会执行的代码,一般做资源的清理
}
一个try可以配多个catch,父类在后,子类在前
异常分类
受查异常 checked exception
编译异常
编译检查代码中的异常有没有处理,没有处理,编译报错
除了RuntimeException及其子类
非受查异常
运行异常
编译时,不检查
RuntimeException及其子类
throw
写在代码中
throw 异常对象
只有执行这句话一定会抛出异常
throws
写在方法声明后面 方法名() throws 异常类{}
是一种处理异常的语法:就是告诉编译器这方法可能有异常,要求调用方法的调用者来处理异常
方法重写(增强)
最常见的形式:方法签名一致
方法名 相同
参数 相同
访问修饰符 不能比父类更严格
返回值 父类方法返回值的类型或者子类类型
throws 子类重写父类方法不能抛出比父类更大的异常
I/O流
数据持久化:文件,数据库
输入流
读数据:文件的数据读入内存
输出流
写数据:内存的数据写入文件
字节流
操作字节
XxxxxInputStream XxxxOutputStream
字符流
操作字符
XxxxReader XxxxWriter
字节流
字节流是功能最强大的,可以读写任何文件。
其它的流,底层都是靠字节流的基本功能实现的。
操作字符麻烦。
操作字节
XxxxxInputStream XxxxOutputStream
OutputStream 抽象类
FileOutputStream
public abstract void write(int b) 一次写一个字节
public void write(byte b[]) 一次写一个字节数组
InputStream 抽象类
FileInputStream
public int read() 一次读一个字节
public int read(byte b[]) 一次读一个字节数组
标准的异常处理
public static void main(String[] args) {
OutputStream os=null;
try {
os=new FileOutputStream("z:\\a.txt");
os.write("abcdef中文".getBytes());
} catch (IOException e) {
e.printStackTrace();
}finally {
if(os!=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
InputStream inputStream=null;
try{
inputStream=new FileInputStream("a.txt");
byte[] bytes=new byte[1024];
int length;
while((length=inputStream.read(bytes))!=-1){
System.out.println(new String(bytes,0,length));
}
}catch (IOException ex){
ex.printStackTrace();
}finally {
if(inputStream!=null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
复制文件
一个流读取文件,一个流写入
带缓冲区的字节流
InputStream
FileInputStream
FilterInputStream
BufferedInputStream
BufferedOutputStream
读写数据的时候,底层添加了一个数据缓冲区,读写性能块
字符流
字节流功能是最强的,操作中文不方便
字符流底层还是字节流
字符流底层就是:字节流+编码表
编码表:内存中的一串01编码和现实中一个字符的对应关系
ASCII 一个字节 256中编号
ISO-8859-1 拉丁编码
GB2312/GBK/GB18030 简体中文
BIG5 大五码,繁体中文
Unicode utf-8
乱码,编码和解码使用的码表不同
编码:字符--->字节
解码:字节--->字符
使用字符流,一次读取一个字符或者字符数组(字符串)
转换流
Writer
OutputStreamWriter
Reader
InputstreamReader
复制文件:
字节流任何文件都可以
记事本显示是乱码的文件,不能用字符流
转换流可以使用各种编码,我们在编程环境中一般还是使用默认编码
FileReader,FileWriter这两个流就是转换流的简化写法,不能更改编码,只能使用当前环境的默认编码。使用简单
带缓存区的字符流
BufferedReader
public String readLine() 一次读取一行数据
BufferedWrite
public void newLine() 换行,规避不同平台的底层指令不同的问题
换行输入:
操作系统底层使用转义字符
Windows \r\n
Unix Linux \n
Mac \r
三层架构
/**
* @author woniuxy
* @date 2000-1-1
* @version 1.1
*/
public class Test01 {
static Scanner scanner=new Scanner(System.in);
public static void main(String[] args) throws IOException {
addStudent();
getAllStudent();
}
private static void getAllStudent() throws IOException {
}
private static void addStudent() throws IOException {
}
/**
* 查询所有学生信息
* @return 学生集合
*/
public static List<Student> selectAllStudents() throws IOException {
}
/**
* 添加学生
* @param student 学生对象
* @throws IOException 异常
*/
public static void insertStudent(Student student) throws IOException {
}
}
UI:User Interface:用户的操作界面:和用户交互的一个界面:负责和用户交互,接受用户输入,展示结果
main()
程序入口
getAllStudent()
用户选择要执行的功能,显示查询的结构
addStudent()
用户选择要执行的功能,输入数据,执行添加操作
-------------------------------------------------------
数据操作:执行数据的CRUD
selectAllStudents()
I/O操作查询文件
insertStudent(Student student)
I/O操作添加文件
单一职责:一个类功能是单一
分类
UI类
学生数据数据操作类
学生类
处理学生数据还有别的数据:教师数据,班级数据,成绩数据,课程数据
UI类
学生数据数据操作类
教师数据数据操作类
班级数据数据操作类
.....
学生类
教师类
班级类
.....
类都在一个包下,分包
表示层:界面操作相关的类
业务逻辑层:放业务逻辑处理(业务处理)
业务操作:
银行:存取,取钱,贷款,查询账号
图书管:借书,还书,查询图书
酒店:预定,入住,结账
数据访问层:数据操作(学生数据操作)
实体层(实体类):基础的数据类(学生):数据载体
命令规范
实体层
包 com.woniuxy.xxx.entity
类 Student Teacher Score
数据访问层
包 com.woniuxy.xxx.dao
接口
StudentDao TeacherDao ScoreDao
实现类
创建一个子包 com.woniuxy.xxx.dao.impl
类 StudentDaoImpl TeacherDaoImpl ScoreDaoImpl
业务逻辑层
包 com.woniuxy.xxx.service
接口
StudentService TeacherService ScoreService
实现类
创建一个子包 com.woniuxy.xxx.service.impl
类 StudentServiceImpl TeacherServiceImpl ScoreServiceImpl
为什么要写接口
没有接口
Dao
XxxDaoImpl (文件实现)
XxxDaoImplDb(数据库实现)
Service
调用Dao
XxxDaoImpl xxxDao=new XxxDaoImpl();
xxxDao.方法();
XxxDaoImplDb xxxDao=new XxxDaoImplDb();
xxxDao.方法();
有接口
Dao
XxxDao
XxxDaoImpl (文件实现)
XxxDaoImplDb(数据库实现)
Service 可以使用多态
调用Dao
XxxDao xxxDao=new XxxDaoImpl();
xxxDao.方法();
XxxDao xxxDao=new XxxDaoImplDb();
xxxDao.方法();
命名规范
Dao
Service
UI
三层调用
复习集合api
基础语法,逻辑流程
面向对象
语法
设计
API
集合
Collection
List
ArrayList
数组 查询快,增删慢
扩容:
LinkedList
链表 增删快,查询慢
Vector
Set
HashSet
hash表:数组+链表
数组+链表+红黑数
去重 hashCode() equals()
扩容
LinkedHashSet
hash表保证不重复
链表保证有序
TreeSet
红黑树
去重+排序 Comparable Comparator
Map
HashMap
LinkedHashMap
TreeMap
异常
try{
}catch(){
}finally{
}
throws
throw 代码块
I/O
自定义异常
自定义异常
Exception
RuntimeException
NullPointerException
IndexOutofBoundsException
xxx1(){
if(){
throw new NullPointerException();
}
}
xxx2(){
if(){
throw new IndexOutofBoundsException();
}
}
xxx1(){
if(){
throw new RuntimeException("空指针");
}
}
xxx2(){
if(){
throw new RuntimeException(“数组下标越界”);
}
}
异常就是一个名字,JDK定义的所有异常,就是名字不同,里面都是构造器
自定义异常就是根据自己的项目需要,自己给某种情况的异常指定一个自定义名。继承自Exception或者RuntimeException.
三层异常处理
Dao
public List<Student> selectAllStudents() {
List<Student> students = new ArrayList<>();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("student.txt"));
//读取文件,每一行数据,转换成学生对象,存入集合
String line;
while ((line = reader.readLine()) != null) {
String[] strs = line.split("-");
int id = Integer.parseInt(strs[0]);
String name = strs[1];
int age = Integer.parseInt(strs[2]);
Student student = new Student(id, name, age);
students.add(student);
}
return students;
} catch (IOException e) {
e.printStackTrace();
throw new DaoException("Dao文件操作错误");
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Service
public List<Student> getAllStudents() {
try {
return studentDao.selectAllStudents();
} catch (DaoException e) {
e.printStackTrace();
throw new ServiceException("业务处理错误,联系管理员,稍后重试");
}
}
UI
public static void getAllStudents() throws IOException {
try{
System.out.println(studentService.getAllStudents());
}catch (ServiceException e){
e.printStackTrace();
System.out.println(e.getMessage());
}
}
异常分类
Throwable 是所有异常的根
Error 错误信息
Exception 异常信息
CheckedException 受查异常 除了RuntimeException异常都是受查异常
RuntimeException 非受查异常
三层异常的操作流程
1.先自定义异常
如果是受查异常可以直接 throws 抛出
如果是非受查异常
在三层架构中
1.自定义异常
定义DaoException的异常,继承非受查异常,下面定义的是DaoException的构造器
定义ServiceEXception异常继承非受查异常
2.在Dao的实现类里面进行try catch的操作 在Dao里面catch捕获的是ioexception,throw new DaoException
3.在service里面进行try catch的操作 在catch里面捕获DaoException ,throw new ServiceEXception
1.DaoException异常自定义
package com.woniuxy.exception;
//自定义异常 类似于自己
public class DaoException extends RuntimeException{
public DaoException() {
}
public DaoException(String message) {
super(message);
}
public DaoException(String message, Throwable cause) {
super(message, cause);
}
public DaoException(Throwable cause) {
super(cause);
}
public DaoException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
2.ServiceEXception异常自定义
2.在Dao的实现类里面进行try catch的操作 在Dao里面catch捕获的是ioexception,throw new DaoException
package com.woniuxy.dao.impl;
import com.woniuxy.dao.StudentDao;
import com.woniuxy.entity.Student;
import com.woniuxy.exception.DaoException;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class StudentDaoImpl implements StudentDao {
@Override
public List<Student> selectAllStudents() {
List<Student> students=new ArrayList<>();
BufferedReader reader=null;
try {
reader=new BufferedReader(new FileReader("students.txt"));
String line;
while ((line=reader.readLine())!=null){
String[] strs=line.split("-");
int id = Integer.parseInt(strs[0]);
String name=strs[1];
int age= Integer.parseInt(strs[2]);
Student student =new Student(id,name,age);
students.add(student);
}
}catch (IOException e){
e.printStackTrace();
throw new DaoException();
}finally {
if (reader!=null){
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return students;
}
@Override
public void insertStudent(Student student) {
BufferedWriter writer =null;
try {
writer=new BufferedWriter(new FileWriter("students.txt", true));
writer.write(student.getId()+"-");
writer.write(student.getName()+"-");
writer.write(student.getAge()+"");
writer.newLine();
writer.flush();
}catch (Exception e){
e.printStackTrace();
throw new DaoException("Dao文件操作错误");
}finally {
if (writer!=null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.在service里面进行try catch的操作 在catch里面捕获DaoException ,throw new ServiceEXception
package com.woniuxy.service.impl;
import com.woniuxy.dao.StudentDao;
import com.woniuxy.dao.impl.StudentDaoImpl;
import com.woniuxy.entity.Student;
import com.woniuxy.exception.DaoException;
import com.woniuxy.exception.ServiceEXception;
import com.woniuxy.service.StudentService;
import java.io.IOException;
import java.util.List;
public class StudentServiceImpl implements StudentService {
public StudentDao studentDao=new StudentDaoImpl();
@Override
public void addStudent(Student student) {
try {
studentDao.insertStudent(student);
} catch (DaoException e) {
e.printStackTrace();
throw new ServiceEXception("Service操作错误,addStudent使用错误");
}
}
@Override
public List<Student> getAllStudents() {
try {
studentDao.selectAllStudents();
return studentDao.selectAllStudents();
} catch (DaoException e) {
e.printStackTrace();
throw new ServiceEXception("Service操作错误,getAllStudents错误");
}
}
@Override
public void removeStudent(int id) {
try {
studentDao.deleteStudent(id);
} catch (DaoException e) {
e.printStackTrace();
throw new ServiceEXception("Service操作错误,removeStudent错误");
}
}
}
ui 捕获的ServiceEXception 直接打印错误信息
package com.woniuxy.ui;
import com.woniuxy.entity.Student;
import com.woniuxy.exception.ServiceEXception;
import com.woniuxy.service.StudentService;
import com.woniuxy.service.impl.StudentServiceImpl;
import javax.script.ScriptContext;
import java.io.IOException;
import java.util.List;
import java.util.Scanner;
public class App {
static Scanner scanner =new Scanner(System.in);
static StudentService studentService=new StudentServiceImpl();
public static void main(String[] args) throws IOException {
getAllStudents();
// addStudent();
}
private static void addStudent() throws IOException {
try {
System.out.println("添加学生");
System.out.println("请输入学号");
int id = scanner.nextInt();
System.out.println("请输入姓名");
String name =scanner.next();
System.out.println("请输入年龄");
int age = scanner.nextInt();
Student student=new Student(id,name,age);
studentService.addStudent(student);
} catch (ServiceEXception e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
}
private static void getAllStudents() {
try {
System.out.println(studentService.getAllStudents());
} catch (ServiceEXception e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
e.getMessage是输出字符串里面的信息 类似下面这个
删除
删除:I/O的API没有直接删除文件的方法
Dao
delete(){
//读数据
//删除数据
//写数据覆盖
}
Dao
读所有数据,转成集合
批量添加:将集合数据写入文件覆盖
Service
删除(){
dao.读所有
dao.批量添加()
}
修改
service
modify(Student student){
//dao.读所有
修改集合的元素
dao.批量添加()
}
添加用户不能添加相同的id
ui
输入数据
展示
service
业务层执行添加:
判断id是否存在,存在才添加
dao
基本的CRUD
根据id查询
Student getStduentById(int id);
没有:null
有: new Student(xxx,xxx,xxx);
List<Student> getAllStudents();
添加
登录
表示层
输入用户名,密码
业务逻辑层
Admin login(String name,String pwd){
//dao查询
//判断用户名密码是否正确
//错误提示: 用户名不存在;密码错误
if(){
new exception("用户名不存在")
}
if(){
new exception("密码错误")
}
retrun admin;
}
Dao
//根据用户名查询密码
String selectPwdByName(String name){
}
//根据主键查询管理员
Admin selectAdminById(int id){
}
//根据用户名键查询管理员
Admin selectAdminByName(String name){
}
常见问题
Dao+Service
接口+实现类,没有静态方法
UI
静态方法,为了方便,以后的web都没有static
业务逻辑层,不会有输入输出的相关代码,这些代码都是UI
Dao
List<Student> getAllStudents(){
//查询所有
}
Student getStudentById(int id){
//根据id查询指定的学生
}
List<Student> getStudentsByFamilyName(String name){
//读取每行文件,匹配相同的姓氏,封装对象,存入集合返回
}
LoginService
public class AdminServiceImpl implements AdminService {
AdminDao adminDao=new AdminDaoImpl();
@Override
public Admin login(String name, String pwd) {
//根据用户名查询,返回密码
try{
Admin admin=adminDao.selectAdminByName(name);
if(admin==null){
throw new ServiceException("用户名不存在");
}
if(!admin.getPwd().equals(pwd)){
throw new ServiceException("密码错误");
}
return admin;
}catch (DaoException e){
throw new ServiceException("联系管理员");
}
}
}
序列化和反序列化
序列化:对象存储到存储介质中
反序列化:将存储介质中的数据还原成对象
使用默认的二进制序列化必须实现接口Serializable
ObjectOutputStream
直接将对象按照二进制格式写入文件
public final void writeObject(Object obj)
ObjectInputStream
读取序列化的二进制文件,还原成对象
public final Object readObject()
序列化结果有不同的形式
二进制
XML
JSON
Exception in thread "main" java.io.InvalidClassException: com.woniuxy.io.Student; local class incompatible: stream classdesc serialVersionUID = -7256004073868010986, local class serialVersionUID = 6570981750800506245
序列化以后的文件,会记录这个保存的属性值以及这个类的所有属性的类型信息
反序列化的时候会检查文件中对应的类型,和要还原的类型是否一致,计算两边的serialVersionUID,不一致,反序列化失败
类中添加一个固定的值
transient关键字:定义属性时,使用这个关键字,序列化时,该属性的值,不会保存
Properties
Properties是一个集合类,我们一般都是结合IO一起使用,在程序中,用它来充当配置文件。
Properties可以看出K和V都是String的Map
配置文件:将程序中要用到配置参数(固定的数据),手动写好一个文件。程序中需要使用这个数据,我们读取文件中的数据。
//取Properties集合中的key对应的value值
public String getProperty(String key)
//一般都是加载我们手动写好的配置文件
public void load(Reader reader)
//set用的少
public Object setProperty(String key, String value)
//基本上不用
public void store(Writer writer, String comments)
装饰者模式
设计模式:
软件开发的经验总结
一类特定问题的一种解决方案
设计模式:可复用面向对象软件的基础
GoF 总结了23个经典的设计模式
简单工厂:破坏了开闭原则
一个父类,若干子类
工厂类,静态方法,通过参数返回不同的子类对象
单例
只创建一个对象
装饰者
增强类的功能
增强类的功能
继承:
Coffee
MilkCoffee
SugarCoffee
SaltCoffee
MilkSugarCoffee
//组合类型多,子类多
多线程
进程
一个运行的程序就是一个进程
线程
一个进程中的一条执行路径
如果一个进程只有一条执行路径,就是单线程的程序
如果一个进程只有多条执行路径,就是多线程的程序
Windows是多任务的操作系统 多个进程同时运行,并发执行
并行
物理上的概念,同一时刻(时间点),多个任务同时执行
并发
逻辑上的概念,一个时间段,多个任务同时执行
启动线程的四种方式
继承Thread类
实现Runnable接口
实现Callable接口
使用线程池
继承Thread类
1.自定义类,继承Thread类
2.重写run()方法
3.调用start()方法 //调用一个start()就开一个线程
start()底层使用多线程的方式调用run()
不要直接调用run(),是单线程
MyThread t1=new MyThread();
MyThread t2=new MyThread("MyThread02");//重写构造器 可以自定义名字
t1.setName("MyThread01");//使用setname定义名字
t1.start();
t2.start();
实现Runnable接口
优点: java中的语法是单继承 ,多接口 如果已经继承了其他类就无法继承Thread类,使用可以实现Runnable接口。
1.自定义类实现Runnable接口,
2.重写run方法
3.MyRunnable myRunnable=new MyRunnable();
Thread t1=new Thread(myRunnable);
Thread t2=new Thread(myRunnable);
t1.start();
t2.start();
常用API
public final String getName()
获取当前线程名
public static native Thread currentThread()
获取当前线程对象
public void setName(String name)
设置当前线程名,也可以定义带参构造器
public static void sleep(long millis)
线程休眠
Lambda表达式
lambda 方法的参数式接口
方法(new 接口(){
重写方法(){
}
})
方法(()->{//实现代码})
public static <T> void sort(List<T> list, Comparator<? super T> c)
//public static <T> void sort(List<T> list, Comparator<? super T> c)
//语法糖:这个方法的第二个参数Comparator接口的实现类对象
//关键就是实现接口中的方法,接口确定,重写的方法也就确定,这些都是可以推断出来的
//Lambda表达式,就是对匿名内部类的进一步简化
//(参数)->{方法体}
//方法的参数类型可以省,如果方法体只有一条语句,retrun {}和;都可以省
//只有个一个参数,()可以
序列化和反序列化例子
package com.woniuxy.io;
import com.sun.corba.se.pept.encoding.OutputObject;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class Test01 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
saveStudent();
loadStudent();
saveStudents();
loadStudents();
}
private static void loadStudents() throws IOException, ClassNotFoundException {
ObjectInputStream oos=new ObjectInputStream(new BufferedInputStream(new FileInputStream("students.bin")));
List<Student> students= (List<Student>) oos.readObject();
System.out.println(students);
oos.close();
}
private static void saveStudents() throws IOException {
List<Student> students=new ArrayList<>();
students.add(new Student(1,"zs",12));
students.add(new Student(2,"ls",11));
students.add(new Student(3,"ww",13));
ObjectOutputStream oos=new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("students.bin")));
oos.writeObject(students);
oos.close();
}
private static void loadStudent() throws IOException, ClassNotFoundException {
ObjectInputStream oos =new ObjectInputStream(
new BufferedInputStream(new FileInputStream("student.bin")));
Student student= (Student) oos.readObject();
System.out.println(student);
oos.close();
}
private static void saveStudent() throws IOException{
ObjectOutputStream oos=new ObjectOutputStream(
new BufferedOutputStream(new FileOutputStream("student.bin")));
oos.writeObject(new Student(1,"zs",12));
oos.close();
}
}
Properties
package com.woniuxy.io;
import javax.naming.Name;
import java.io.*;
import java.util.Properties;
import java.util.Set;
public class Test02 {
public static void main(String[] args) throws IOException {
test02();
}
private static void test03() throws IOException {
Properties properties=new Properties();
properties.setProperty("name", "zs");
properties.setProperty("age", "12");
properties.setProperty("email", "xxx@qq.com");
//将properties集合中的key和value写入properties文件
properties.store(new BufferedWriter(new FileWriter("xxx.properties" ) ),"自定义信息" );
}
private static void test02() throws IOException {
Properties properties=new Properties();
//properties.load是加载文件,读取配置信息
properties.load(new BufferedReader(new FileReader("myproperties.txt")));
System.out.println(properties.getProperty("id"));
System.out.println(properties.getProperty("name"));
System.out.println(properties.getProperty("age"));
System.out.println(properties.getProperty("email"));
//如果properties.getProperty("k") 是文件里面没有的,会输出空值
//如果有着输出key对应的value
}
private static void test01() {
//添加元素
Properties properties=new Properties();
properties.setProperty("id", "1");
properties.setProperty("name", "zs");
properties.setProperty("age", "12");
//读取元素
System.out.println(properties.getProperty("name"));
//properties.stringPropertyNames()这个取的是所有的key的集合,
//遍历key,通过properties.getProperty(key)可以获得所有value
Set<String> strings = properties.stringPropertyNames();
for (String str : strings) {
System.out.println(str+"----"+ properties.getProperty(str));
}
}
}
Lambda –创建线程写法
package com.woniuxy.io;
import java.util.Collections;
public class Test05 {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + "---" + i);
}
// Thread第一种写法
Thread t1 = new Thread() {
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + "---" + i);
}
}
};
t1.start();
//Thread第二种写法 匿名内部类
new Thread() {
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + "---" + i);
}
}
}.start();
//Runnable第一种写法
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + "---" + i);
}
}
}).start();
//Runnable第二种写法lambda 写的一定是接口
new Thread(() -> {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + "---" + i);
}
}).start();
}
}
lambda–Compartor集合排序
package com.woniuxy.io;
import java.sql.SQLOutput;
import java.util.*;
import static java.util.Comparator.*;
class StudentNameAsc implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.getName().compareTo(o2.getName());
}
}
public class Test06 {
public static void main(String[] args) {
List<Student> students=new ArrayList<>();
Student s1=new Student(1,"zs",12);
Student s2=new Student(2,"ls",11);
Student s3=new Student(3,"ww",13);
students.add(s1);
students.add(s2);
students.add(s3);
System.out.println(students);
//自定义类实现comparator接口,然后使用实现类进行升序排序
Collections.sort(students, new StudentNameAsc());
System.out.println(students);
//使用匿名内部类进行 降序排序
//语法糖,这个方法的第二个参数Comparator接口的实现类对象
//关键就是实现接口中的方法,接口确定,重写的方法也就确定,
//lambda表达式,就是对匿名内部类进一步简化
Collections.sort(students, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getName().compareTo(o1.getName());
}
});
System.out.println(students);
// lambda表达式 (参数)->{方法体}
Collections.sort(students, (Student o1, Student o2)-> {
return o2.getName().compareTo(o1.getName());
});
System.out.println(students);
//lambda表达式 (参数)->{方法体}
//参数类型也可以省略,如果方法体只有一条语句,return {} 和;都可以省。
Collections.sort(students, (o1, o2) -> o2.getName().compareTo(o1.getName()));
System.out.println(students);
//函数式编程
//Comparator compare(T t1, T t2);
}
}
lambda–Collection.removeIf(Predicate)
package com.woniuxy.io;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class Test07 {
public static void main(String[] args) {
List<Student> students=new ArrayList<>();
students.add(new Student(1,"zs",12));
students.add(new Student(2,"ls",13));
students.add(new Student(3,"ww",11));
System.out.println(students);
students.removeIf(new Predicate<Student>() {
@Override
public boolean test(Student student) {
//false 都不删 true 都删了
//可以自定义想删什么就删什么
return student.getId()>=2;
}
});
students.removeIf(student -> student.getId() >= 2);
// students.removeAll(students);
System.out.println(students);
}
}
装饰者例子
package com.woniuxy.model;
//父类
class Coffee{
public String getCoffee(){
return "coffee";
}
}
//MilkCoffee子类继承父类Coffee
class MilkCoffee extends Coffee {
//父类成员变量
Coffee coffee;
public MilkCoffee(Coffee coffee) {
this.coffee = coffee;
}
//装饰一下 z
public String getCoffee() {
return coffee.getCoffee() + "+milk";
}
}
class SugarCoffee extends Coffee {
Coffee coffee;
public SugarCoffee(Coffee coffee) {
this.coffee = coffee;
}
public String getCoffee() {
return coffee.getCoffee() + "+Sugar";
}
}
class SaltCoffee extends Coffee{
Coffee coffee;
public SaltCoffee(Coffee coffee) {
this.coffee = coffee;
}
public String getCoffee(){
return coffee.getCoffee()+"+salt";
}
}
public class Test01 {
public static void main(String[] args) {
Coffee coffee=new Coffee();
System.out.println(coffee.getCoffee());
//sout coffee
MilkCoffee coffee1=new MilkCoffee(coffee);
System.out.println(coffee1.getCoffee());
//sout coffee+milk
SugarCoffee coffee2=new SugarCoffee(coffee1);
System.out.println(coffee2.getCoffee());
//sout coffee+milk+Sugar
}
}
1207
线程的启动执行具有随机性
多线程,获取cpu的执行权,
轮询机制:平均分配,轮流执行
java使用的抢占式:
线程有优先级,获取cpu的执行概率大些
局部变量是安全的,每个都是自己的
影院卖票
不能超卖
不能重复卖票
为什么会出问题
cpu一次只能保证一次执行一个完整的指令
num--;一条语句的底层都对应多条语句
一个线程抢到cpu,不能保证一个方法一次能从头到尾全部执行完,执行的过程中,可能被其他线程抢走cpu
如何判断多线程环境是否具有数据安全性问题
1、多线程
2、共享数据
3、是否有语句修改共享数据
sout(num);
如何解决
加锁 synchronized 加在方法上面
同步代码块
多个线程,使用同一个锁对象
synchronized(锁对象){
//代码块
}
同步方法
public synchronized void sellTicket(){}
不想要指定锁对象,有默认的
非静态方法:就是this
静态方法:就是类的二进制字节码对象 对象.getClass() 类.class() 以后反射讲
单例设计多线程环境
饿汉 安全
static Singleton singleton=new Singleton() 没问题
饱汉 不安全
public class Singleton {
private static Singleton singleton;
private Singleton(){}
//double check 双重判断检查
public static Singleton createInstance(){
if(singleton==null){
synchronized (SingletonRunnable.class){
if(singleton==null){
singleton=new Singleton();
}
}
}
return singleton;
}
}
线程的生命周期
线程的生命周期包含5个阶段,包括:新建、就绪、运行、阻塞、死亡。
新建: 就是刚使用 new 方法,new 出来的线程;
Thread t1 = new Thread();
就绪: 就是调用的线程的 start() 方法后,这时候线程处于等待 CPU 分配资源阶段,谁先抢到 CPU 资源,谁开始执行;
t1.start()
运行: 当就绪的线程被调度并获得 CPU 资源时,便进入运行状态,run() 方法定义了线程的操作和功能;
阻塞: 在运行状态的时候,可能因为某些原因导致运行状态的线程变成了阻塞状态,比如 sleep()、wait() 之后线程就处于了阻塞状态,这个时候需要其他机制将处于阻塞状态的线程唤醒,比如调用 notify 或者 notifyAll() 方法。唤醒的线程不会立刻执行run 方法,它们要再次等待 CPU 分配资源进入运行状态;
死亡:线程会以以下三种方式之一结束,结束后就处于死亡状态:
run()方法执行完成,线程正常结束。
线程抛出一个未捕获的Exception或Error。
直接调用该线程的stop()方法来结束该线程——该方法容易导致死锁,通常不推荐使用。
数据库
数据库就是数据的仓库,存储数据库。
底层还是按照一定格式存储到文件,使用记事本查看,乱码
数据库提供一套操作数据的编程语句SQL(Structured Query Language)机构化的查询语言
优点:保存大量数据
操作数据方便CRUD 增加(Create)、读取(Retrieve)、更新(Update)和删除(Delete)
保证数据的一致性和完整性 创建约束
给不同用户分配不同的操作权限
数据库技术的发展
文件
层次数据库
网状数据库
关系型数据库 常用的
支持面向对象的数据库 只有Oracle支持,一般都不会用,
常见的数据库
产品 公司
Oracle Oracle
SQLServer Microsoft
MySQL MySQL AB-->SUN-->Oracle
DB2 IBM
Sybase Sybase
下载
5.7
8.0
官网
https://dev.mysql.com/downloads/mysql/
国内镜像网站
https://developer.aliyun.com/mirror/
windows安装数据库
安装版:
.mis .exe安装程序,下一步安装,指定安装路径(主要的文件安装以后都储存在这个位置,有些文件会保存到系统的指定目录,写入注册表)
安装失败,卸载,重装
绿色版
解压使用,添加一些配置信息
安装失败,删了重装
进入服务 win+R services.msc
没有安装过数据库 端口默认3306
装了一个之后,配置端口为3307