有关长度的方法
数组 | 字符串 | 集合 | 文件 |
---|---|---|---|
length | length() | size() | length() |
int | int | int | long |
了解JAVA及工具使用
java的特征
- 跨平台(JVM)
Classloader(类加载器)
ByteCode Verifier(字节码校验器)
Interfreter(解释执行器) - 安全 健壮
GC(garbage collection) 防止内存泄漏
exception:当代码出现不合适的地方会报告异常 等待程序员解决
没有指针 可以避免非法访问 - 免费 开源
- 简单
语法简单:指针 运算符重载 手动的垃圾回收
思想简单:面向对象的思想 = OO思想
面向过程的思想:需要人以计算机的角度去思考问题
面向对象的思想:需要拿着代码去模拟现实生活 - 动态更新
核心方法值保留一个指向关系
java开发环境
安装jdk
SDK = Software Development Kits = 软件开发工具包
JDK = Java Development Kit = java开发工具包
JRE = Java Runtime Environment = java运行环境
JVM = 类加载器 + 字节码校验器 + 解释执行器
JRE = JVM + API(核心类库)
JDK = JRE + BIN(常用的工具命令)
设置环境变量
PATH:让操作系统更加快捷的找到一个文件/一个文件夹
PATH=C:\Program Files\Java\jdk-10.0.1\bin
CLASSPATH:类加载器 让类加载器明确去哪里加载.class文件
一般不需要设置 默认值:.[当前目录]
JAVA_HOME:其它的程序使用(WEB)
set PATH=C:\Program Files\Java\jdk1.8.0_74\bin
环境变量的名字进行大写 %%: 表示取出中间环境变量的值
用 ; 分隔多个环境变量
我的电脑 -> 属性 -> 高级 -> 环境变量 -> 新建
java编译运行CMD命令
- javac (-d 目录) HelloWord.java (-d -> 自动创建包结构)
- java (目录) HelloWord (有包结构时)
- javadoc (-d 目录) HelloWord.java
- jar cvf (Hello.jar) HelloWord.class
Main-Class: HelloWord
端口被占用
netstat -ano | findstr 8080 ## 得到占用程序的pid
tasklist | findstr 14592 ## 得到占用程序的名称
taskkill /f /t /im javaw.exe ## 结束程序
Eclipse
编码设置
- General-> ContentTypes-> Text,Default encoding: utf-8-> update
- Text,jsp: utf-8
- 工作空间默认编码: General-> Workspace, Text file encoding-> other: utf-8
- 新建jsp默认编码: General->Files and Editors-> Jsp-> encoding: utf-8
优化
- 拼写检查: Editors Spelling-> 去掉Enable spell checking上面的对勾
- 显示行号: General-> Editors-> Text Editors, Show line numbers
- 字体: window-> Preferences-> General-> Appearance-> colors and Fonts, Basic-Text Font
- 代码提示: window-> Preferences-> java-> Editor-> Content Assist, Auto-Activation, Auto Activation triggers for java 改
.
为.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ([{,
单元测试
- 工程右键build path -> add libraies -> jUnit
- 单元测试的方法命名规则 -> public void 方法名(){}
@Test 表示这是一个用来测试待测试方法的方法。(重点掌握)
@Ignore 表示这个方法不执行,被忽略。
@Before 表示在每个方法之前都会执行该测试方法一次。
@After 表示在每个方法之后都会执行该测试方法一次。
SVN
Subversion简称,是一款 C/S结构的版本管理工具。主要用在多人开发的协同开发场景。
需要配置环境变量
cmd方式
创建代码仓库
svnadmin create D:\Repositories\book
监管代码仓库
svnserve -d -r E:\Repositories\demo
从SVN检出
svn checkout svn://localhost/test
添加到svn
svn add "demo.java"
svn commit "demo.java" -m "演示上传文件到svn"
关于SVNServer中的配置
修改Repositories/项目名/cconf/svnserve.conf下
- anon-access = read 匿名访问方式
- auth-access = write 用户访问方式
- password-db = passwd 修改用户和密码 格式 username = password
- authz-db = authz 给用户添加权限 格式 [/](可访问空间) username = rwx
在MyEclipse中添加SVN支持
site 目录下 features 和 plugins 文件夹覆盖到 MyEclipse 根目录
maven
依赖管理 -> 我们在项目中需要用到的jar包都交给maven统一管理,不用手动把jar包导入到工程中来。
目录结构
- Bin:可执行文件
- Boot:一个类加载器的框架
- Lib:存放各种maven需要的jar包
- Conf:maven的配置文件 settings.xml
- 修改本地仓库的位置 非必须 但是建议修改
<localRepository>E:\Service\maven\repository</localRepository>
- 添加国内镜像 (阿里云)
<mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror>
配置环境变量
- JAVA_HOME: JDK的安装目录
- MAVEN_HOME: maven家,bin目录的上一层
- Path: MAVEN的bin目录
Maven-helloworld
- mvn compile: 编译源代码,会在target目录生成.class文件
- mvn test: 执行单元测试 会在target中生成测试类的class文件和测试报告
- Mvn package: 打包 在target中生成一个jar包
- Mvn install: 安装 将jar包安装到本地仓库 执行install时会自动执行 compile->test->package
- 在执行compile \ test\ package\install 命令时,执行后边的命令会自动的执行前边命令。
- Mvn clean: 清空 清空target目录 不会执行其他命令
- 以上命令可以混合执行如: mvn clean test 或者mvn clean package
eclipse-maven
window -> preferences -> maven -> installations 添加bin目录的上一层
window -> preferences -> maven -> usersettings 添加conf\settings.xml
创建一个maven工程
- 加入jdk版本并强制更新 工程名 -> maven -> update project -> 勾选force update -> OK
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
- 添加web.xml
工程名 -> properties -> project facets -> Dynamic... -> runtimes -> 勾选部署的服务器 -> 下方配置xml -> src/main/webapp -> OK
- 如果maven没有部署 -> 找不到maven的jar
工程名 -> properties -> Deployment Assembly -> add -> java Build Path Entries -> maven
maven范围
compile(编译范围): 编译范围依赖在所有的classpath 中可用,同时它们也会被打包。
provided(已提供范围): provided 依赖只有在当JDK 或者一个容器已提供该依赖之后才使用。例如, 如果你开发了一个web 应用,你可能在编译 classpath 中需要可用的Servlet API 来编译一个servlet,但是你不会想要在打包好的WAR 中包含这个Servlet API;这个Servlet API JAR 由你的应用服务器或者servlet 容器提供。已提供范围的依赖在编译classpath (不是运行时)可用。它们不是传递性的,也不会被打包。
runtime(运行时范围): 依赖在运行和测试系统的时候需要,但在编译的时候不需要。
test(测试范围): 只有在测试编译和测试运行阶段可用。
system(系统范围): 与provided 类似,但是你必须显式的提供一个对于本地系统中JAR 文件的路径。这么做是为了允许基于本地对象编译,而这些对象是系统类库的一部分。这样的构件应该是一直可用的,Maven 也不会在仓库中去寻找它。如果你将一个依赖范围设置成系统范围,
你必须同时提供一个 systemPath 元素。注意该范围是不推荐使用的(你应该一直尽量去从公共或定制的 Maven 仓库中引用依赖)。
基础运算
进制转换
整数二进制转换
0 | 127 | -128 | -1 | 0 |
---|---|---|---|---|
00000000 | 01111111 | 10000000 | 11111111 | 00000000 |
0+num | -1-num |
浮点类型二进制转换
float x = 21.25F;
将两个部分全部转换成二进制
整数:21 = 16 + 4 + 1 = 10101
小数:0.25 * 2 * 2 = 01
21.25 = 10101.01
将上面的结果转换成二进制的科学计数法
10101.01 -> 1.010101 * 2(4)
对号入座
符号位1 | 幂指位8 | 数值位23 |
---|---|---|
0 | 10000011 | 01010100000000000000000 |
127+4 = 128+2+1= 10000011 01000001101010100000000000000000
强制类型转换
包含关系(范围)可以直接转换 类型范围大转类型范围小要强转
运算符
类型 | 包含 |
---|---|
分隔符 | {} [] () , ; |
单目运算符 | ++ -- ~ ! |
强制类型转换 | (int)(char) |
算术运算符 | */ % |
+- | |
移位运算 | << >> >>> |
关系运算 | > >= < <= |
等价运算 | == != |
按位运算 | & ^ | |
逻辑运算 | && |
|| | |
三目运算 | a?b:c |
赋值运算 | = += -= *= /= |
提高运行效率
- &(2^n -1) <===> %(2^n)
& 100......00
% 011......11 - 交换数值(不能交换浮点类型)
a = a ^ b;====>a=^
b = a ^ b;====>b=^+b=a
a = a ^ b;====>a=^+a=b
数据类型
基本数据类型
boolean | char | byte | short | int | long | float | double |
---|---|---|---|---|---|---|---|
16 | 8 | 16 | 32 | 64 | 32 | 64 |
char
char a = 'a';
char a = '中';
char a = 88; //ASCII编码
char a = '\u4e2d'; //Unicode编码
char a = '\t';
int
int num = 25; //十进制
int num = 0b1011; //二进制
int num = 025; //八进制
int num = 0x4e; //十六进制
float/double
float:符号位1 + 幂指位8 + 数值位23
double:符号位1 + 幂指位11 + 数值位52
3.2E4F
E:表示科学计数法 3.2*10(4)
F:表示float类型
封装类
Boolean | Character | Byte | Short | Integer | Long | Float | Double |
---|
String中常用方法
String StringBuffer StringBuilder
方法 | 备注 |
---|---|
length() | 字符长度 |
getBytes() | 得到字节数组 |
toCharArray() | 转化成字符数组 |
split(String) | 按照指定的内容劈开 |
equals(String) | 是否相同 |
equalsIgnoreCase(String) | 是否相同-忽略大小写 |
contains(String) | 是否含有指定的内容 |
startsWith(String) | 是否以指定的内容开头 |
endsWith(String) | 是否以指定的内容结尾 |
toUpperCase() | 全部大写 |
toLowerCase() | 全部小写 |
replace(String,String) | 全部替换 |
replaceAll(String,String) | 全部替换[支持正则表达式] |
replaceFirst(String,String) | 替换第一个 |
trim() | 去除前后空格 |
substring(int x,int y) | 截取数组下标x到下标y-1 |
substring(int x) | 截取数组下标x到最后 |
charAt(int x) | 找到指定下标对应的元素 |
indexOf(String) | 字符串所在下标 |
lastIndexOf(String) | 最后一次出现的下标 |
Integer中常用的方法
Integer num = new Integer(num);
Integer num = Integer.valueOf(num);
int x = Integer.parseInt(str);
//valueOf() : -128 到 127 常量缓冲池
数组
- 得到数组元素
数组对象[下标]
Arrays.toString(数组对象);(import java.util.Arrays;) - 数组大小
数组对象.length - 遍历复制
新数组 = 老数组.clone();
System.arraycopy(原数组, 原数组起始下标, 目标数组, 目标数组起始下标, 复制长度); - 冒泡排序
for(int i=0; i< data.length-1; i++){ //循环次数
for(int j=0; j< data.length-1-i; j++){ //两两比较 一个循环
if(错误的位置){
//交换 -> j
}
}
}
- 自动排序
Arrays.sort(数组对象); //从小到大
import java.util.*;
分支循环控制
- if else: 使用return ;简化代码 不要做if(boolean == true)这种低智商的判断
- switch case: for当循环体需要一个值,循环结束不需要这个值时,最好用for
- while
- do while
- continue: 跳过本次循环,开始下一次循环
- break: 表示跳出所在的循环
- a: 循环外设置,循环里面continue/break a:
修饰符
访问权限修饰符 | 作用范围 | 类 | 属性,方法 |
---|---|---|---|
public=>公共的 | 公开 | T | T |
protected=>受保护的 | 本包/子类 | O | T |
(default)=>默认的 | 本包 | T | T |
private=>私有的 | 本类 | O | T |
- static: 加载时执行一次
- final: 基本数据类型:数值不能改变 引用数据类型:地址不能改变
- abstract: 抽象类不能创建对象 但能构造方法 抽象方法不能具体实现
面向对象
类-Class
- Class类的实例代表正在运行的JAVA应用程序中的类和接口
- JVM创建一个类==>加载Class对象==>创建对象[类的信息都存放在Class对象中]
- 一个类的对象可以有很多个,但是Class对象只能有一个
- Class类没有公共的构造方法,Class类的对象是由JVM在加载类时自动构造的
- 所有具有相同元素类型和维数的数组都共享同一个Class对象
获得Class对象
- 类 类名字.class Classc= Student.class,Class cls = Emp.class
- 对象 Class cls = 对象.getClass()
- 类名字 Class cls = Class.forName(“类名字”)
创建对象的两个方式
- new();强类型。相对高效。能调用任何public构造。
- newInstance();弱类型。低效率。只能调用无参构造。
使用场景:运行时传入一个类的名字,创建实例===>newInstance()===>Class ===>Class.forName("");
newInstance()是实现IOC、反射、依赖倒置 等技术方法的必然选择,new 只能实现具体类的实例化,不适合于接口编程。类里面就是通过这个类的默认构造函数构建了一个对象,如果没有默认构造函数就抛出InstantiationException, 如果没有访问默认构造函数的权限就抛出IllegalAccessException
构造方法
super():首行默认执行父类无参构造方法
注意:父类没有无参却使用无参super就会编译报错
this():执行本类参数匹配的构造方法
super()/this()只能出现一个
成员变量/局部变量
- 定义的位置不同
- 作用域不同
成员变量:依赖于对象存在 只要对象没有被回收 都可以访问
局部变量:所在方法体内存在 一旦所在的方法体执行结束 局部变量立即消亡 - 默认值不同
成员变量:有默认值
局部变量:没有默认值 必须先赋值 - 重名时访问方式不同
直接访问该变量默认是局部变量
如果我们想要访问成员变量 需要加上this.
接口
类与类之间需要特定的接口协调,将一组类视为单一的类,调用者通过接口与这组类联系
属性默认存在三个修饰符:public static final
方法默认存在两个修饰符:public abstract
接口和抽象类之间的区别
- 分别表示java中两大类型
interface:接口,需要实现,用implement
abstract class:类,需要继承,用extends - 对属性的要求不同
接口里面的属性默认是静态的最终变量(public static final)
抽象类里面的属性就是普通属性 - 对方法的要求不同
interface是完全抽象的 只能声明方法 且不能定义方法体 子类必须实现
抽象类里面即可以定义抽象方法 又可以定义普通方法 子类可以有选择的实现 - 一个类可以实现多个interface
一个类只能继承一个abstract class - interface强调的是特定功能的实现,
abstract class强调的是从属关系
枚举
- enum java5.0之后
- 枚举不是类,但是可以将枚举看做一个类来使用
- 成员(,,,) + 属性(private) + 方法
public enum Color {
RED("红色",1),Yellow("黄色",2),Blue("蓝色",3);
private Color(String name, int num){
this.name = name;
this.num = num;
}
private String name;
private int num;
public String getName() {return name;}
public int getNum() {return num;}
@Override
public String toString(){
return name;
}
}
注解
annotation
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(value=RetentionPolicy.SOURCE)
public @interface Demo{
//只有属性是value时,赋值可以省略
String value() default "demo";
Color[] cs();
}
@Target:表示注解适用的程序元素。
- value=ElementType.METHOD:方法
- value=ElementType.TYPE:类
- value=ElementType.FIELD:属性
@Retention:标识注解可以保留多长时间
- Value=RetentionPolicy.SOURCE:注解信息保存在源码中
- Value=RetentionPolicy.CLASS:注解信息保存在class文件中 默认的
- Value=RetentionPolicy.RUNTIME:注解信息保留到运行期
封装继承多态
封装 private 属性,方法
隐藏实现细节 对外提供公共的访问方式
将属性都私有化,对外提供set、get方法来访问
- 提高了安全性。不允许直接访问细节 可以实现数据可控
- 提高了易用性。
- 提高了复用性。
- 隔离了变化。
继承extends 子类 extends 父类
java中的类只允许单根继承
私有属性在子类的内存空间里面存在
但是不能继续使用 所以不能算是继承得到
super访问父类同名变量
多态用父类型代指所有子类型(继承或者实现)
- 创建对象 (非重点)
- 放在参数中 解除代码之间的耦合度
优势:提高代码的扩展性
弊端:不能使用子类的特有方法
@overload
同类体内相同名称的方法 参数数量或者类型不同
方法重载对返回类型和修饰符没有要求
@override
访问权限修饰符 >= 父类的权限
返回类型 + 方法签名 相同
异常处理部分 <= 父类的异常(范围,和个数无关)
@Override:注解
数据共享
静态变量
返回类型:方法执行结束之后 返回给我们的数据
方法参数:方法执行的过程中 需要我们提供的数据
方法的定义三个部分:
修饰符 + 返回类型 + 方法签名(方法名 + 参数)
参数传递
内部类
定义在一个类类体当中的另一个类 被称作内部类
内部类的分类: 能够共享到外部类所有[静态+非静态]成员[属性+方法]
Outer.Inner in = new Outer().new Inner();
- 静态内部类: 能够共享到外部类所有静态成员[属性+方法]
Outer.Inner in = new Outer.Inner();
- 局部内部类: 外部类所有成员 [被定义在非静态方法中]
外部类静态成员 [被定义在静态方法中]
另外还有final修饰的局部变量 [8.0开始可以不加]
Inner in = new Inner();
- 匿名内部类:
//没有名字
new 父类/接口() { 完成方法覆盖; }
单例模式
- 私有化构造方法 ――>无法随意创建对象
- 创建一个私有的 静态的 对象 ――>private 外界无法创建 所以要在本类中创建一个对象
恶汉式:无论是否存在直接new 懒汉式:为null时new - 提供一个公共的 静态的 返回本类类型对象的方法
Object的一些方法
clone():"克隆"一个对象的方法
对clone方法进行方法覆盖
public 类名 clone()throws CloneNotSupportesdException{
Object x = super.clone();
return (类名)x;
当前的类需要实现接口
class 类名 implements Cloneable{}
main方法调用
finalize():对象的"遗言"方法
当一个对象要被回收的时候 gc会主动调用这个对象的finalize方法
toString():制定一个对象打印显示的内容
@Override
public String toString(){return ;}
equals():定义一个类型的比较规则
== 比较 变量(栈) 存放的 对象(堆) 的内存地址
equals 程序员自定义的比较规则
hashCode():定义一个对象的散列特征依据
Hashtable => 哈希表 => 散列表
所谓散列 指的是:将一大组数据分散排列成若干小组
集合
Java Collections Framework
Java集合框架
Collection Map
[单值类型集合] [键值对集合]
主键唯一
List Set
有序 不唯一 无序 唯一 SortedMap
SortedSet 主键有序 唯一
主键有序 唯一
- 集合中所有的"唯一"都是逻辑相等 是人们希望它相等而把它们算作相同 实际上它们并不是同一个
这也是 equals 和 == 的区别 - 散列表或者二叉树 不能 get(下标) 或者 remove(下标)
迭代器Iterator
for(Iterator<> iter = list.iterator(); iter.hasNext(); ){//存在下一个
iter.next();//下一个
iter.remove();//删除
}
迭代器使用过程中不允许使用集合增删操作,否则会触发并发修改异常ConcurrentModificationException
如果一定要删除,请使用迭代器自带的iter.remove;
若果一定要添加,请新建一个集合暂存
List
基本方法
//创建List集合
List<泛型类型> list = new ArrayList<>();
//添加元素
list.add(元素);
Collections.addAll(list,元素1,元素2);
//集合长度 有几个元素
list.size()
//根据下标获取元素
list.get(i)
遍历集合
- for + get(i)
- foreach
- Iterator
- lambda表达式(JDK8.0新特性)
删除元素
//根据下标删除元素
remove(int)
//删除指定Object元素
remove(Object)
//清空集合
clear()
- 如果要删除的是Integer对象
请务必保证remove()的参数是Integer而不是int - 尊重equals()比较的结果
- "谁主张 谁举证" 要被删除的那个对象主动调用equals()
数组扩容
如果知道数组长度 最好传参指定
因为数组扩容需要创建新数组 移动元素 删除旧数组
//确保底层数组能装指定的元素个数 - 扩容
list.ensureCapacity()
//将底层数组大小调整到跟真正元素个数一致 - 锁容
list.trimToSize()
四种List
Arraylist | LinkedList | Vector | Stack | |
---|---|---|---|---|
底层 | 数组 | 链表 | 数组 | 数组模拟栈结构 |
区别 | 连续存储 | 内存指向 |
ArrayList | JDK6.0及之前x*3/2+1 | JDK7.0及之后x+(x>>1) |
---|---|---|
Vector | new Vector(10) *2 |
new Vector(10,8) +8 |
stack
//向栈顶添加一个新元素<==>add()
push()
//从栈顶取走一个元素<==>get()+remove()
pop()
Set(HashSet)
完整比较流程 增删改都尊重这个流程
hashCode && (== || equals)
删除重复元素 后来的舍弃
修改参与排序的属性
- 删除 --> 可能比较器无法返回0 使用迭代器删除
- 修改属性
- 重新添加回集合 --> 也是重新排序的过程 需要注意迭代器遍历时不能对集合操作 建一个新的集合来暂存
HashSet构造方法的两个参数:int 分组组数,float 加载因子
//example
new HashSet<>(16,0.75F);
分组组数可以随意指定 但是最终一定是2的n次方数
阈值 = (int)(分组组数*加载因子); //12
阈值 = Threshold => hold住多少个元素
SortedSet(TreeSet)
TreeSet特有的方法,不能使用多态创建:first() last() pollFirst() pollLast()
TreeSet<Integer> set = new TreeSet<>();
Collections.addAll(set,55,33,44,11,22,22,22,22,22);
System.out.println(set.size());//唯一
System.out.println(set);//有序 从小到大排序
System.out.println(set.first());//得到第一个 也就是最小值
System.out.println(set.last());//得到最后一个 也就是最大值
System.out.println(set.pollFirst());//删除第一个并返回它本身 即返回11
System.out.println(set.pollFirst());//22
TreeSet必须要实现comparable接口或者参数传入实现comparator接口的比较器
Comparable compareTo(1)
Comparator compare(1,2)
多个属性综合形成排序规则
优先尊重什么属性 就先描述假如什么属性不同
修改参与排序的属性
- 删除 --> 可能比较器无法返回0 使用迭代器删除
- 修改属性
- 重新添加回集合 --> 也是重新排序的过程 需要注意迭代器遍历时不能对集合操作 建一个新的集合来暂存
Map/SortedMap
Map<K,V> map = new HashMap<>();
map.put(k,v);
map.putAll(另一个Map集合);
map.size();
map.get(k);
map.containsKey(k);//是否存在此主键 返回bool类型
map.containsValue(v);//是否存在此值 返回bool类型
map.remove(k);
重复元素处理添加元素时,主键相同(hashCode=1,equals return true)值不同,那么保留主键替换值
遍历Map
keySet() -> 得到所有主键对象组成的Set集合
values() -> 得到所有值对象组成的Collection集合
entrySet() -> 得到所有键值对对象(Map.Entry)组成的Set集合
getKey() getValue() setValue()
================================================
Map<String,Integer> map = new HashMap<>();
map.put("小翔",210); map.put("小俐",160); map.put("小黑",720);
Set<String> ks = map.keySet();//得到所有主键对象组成的Set集合
Collection<Integer> vs = map.values();//得到所有值对象组成的Collection集合
Set<Map.Entry<String,Integer>> es = map.entrySet();//得到所有键值对对象(Map.Entry)组成的Set集合
for(Map.Entry<String,Integer> e: es){
if(e.getKey()=="小翔") e.setValue(750);
System.out.println(e.getKey()+": "+e.getValue());
}
}
对上面得到的集合进行操作就是对Map进行操作
HashMap 和 HashTable的区别
- 同步特性
HashMap 同一时间允许多个线程进行操作 效率高 但是可能出现并发错误
Hashtable 同一时间只允许一个线程进行操作 效率低 但是不会出现并发错误
JDK5.0开始集合工具类Collections.synchronizedMap();
JDK5.0开始java.util.concurrent.ConcurrentHashMap支持并发的HashMap - 对于null的"态度"不同
HashMap 无论主键还是值 都允许存放null 只是主键要求唯一 所以只能有一个null
Hashtable 无论主键还是值 都不允许null出现 一旦出现null 则直接出现异常 - 底层实现有区别
HashMap 底层默认分为16个小组 分组组数可以随意指定 但是最终一定是2的n次方数 &(分组组数-1)
Hashtable 底层默认分为11个小组 它分组组数可以随意指定 %(分组组数) - 出现的版本不同
HashMap - since JDK1.2
Hashtable since JDK1.0 [集合两大鼻祖之一]
异常Exception
Throwable
Error Exception
底层硬件环境或者系统问题 运行过程出现的例外情况
RuntimeException
运行过程出现的例外情况
=================================================================
非运行时异常 编译时需要给出处理方案 否则无法编译
运行时异常 编译时无需给出处理方案 编译可以通过 但是后面的代码无法执行
两者都是在运行时出现!!!
处理异常
throws Exception
try(){ }catch(Exception1 | Exception2 | Exception3 ex){ex.printStackTrace()}finally{ }
throw //主动制造异常
- try()括号里的内容支持包括流以及任何可关闭的资源,数据流会在 try 执行完毕后自动被关闭
- 当try和catch中有return时,先把要返回的值保存起来,不管finally中的代码怎么样,返回的值都不会改变,仍然是之前保存的值,所以函数返回值是在finally执行前确定的;
- finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值
- 如果finally前有System.exit(0)结束java虚拟机,finally不会执行
实用技巧
全局变量赋值需要处理异常时可以在初始化块中try catch
运行时异常默认抛出 不抛出任何异常 也是抛出所有运行时异常
学会try catch finally嵌套使用
无论前面的资源关闭是否出现异常 都要尝试去关闭后面的资源
try的大括号当中定义的变量是特殊的局部变量 会在try的大括号结束的时候消亡
在某些场景下学会使用异常处理代替传统的分支流程 会有意想不到的好效果
线程Thread
新生 就绪 运行 消亡
Born Runnable Running Dead
等待池 锁池 阻塞 ====>都属于阻塞状态
wait pool lock pool Blocking
程序 -> 保存在物理介质中的代码片段
进程 -> 一旦程序运行起来 就变成了操作系统当中一个进程
线程 -> 一个程序当中一条独立的执行线索
线程章节所有主动进入阻塞状态的方法 都需要进行异常处理
线程章节所有静态方法 不要关注谁调用方法 而要关注调用出现在哪
调用出现在谁的线程体当中 就是操作那个线程
创建线程
extends Thread -> 线程对象.start()
@Override
public void run(){ ...; }
implements Runnable ->Thread xx = new Thread(线程对象) ->xx.start();
@Override
public void run(){ ...; }
implements Callable<XXX>
@Override
public XXX call(){ ...; }
它强化了Runnable接口中run()的两大不足
1st.run被定义为void方法 执行结束之后无法返回数据
2nd.run没有任何throws声明 但是call有
控制线程
setPriority(int) -> 优先级 默认5 可选范围10-1
static sleep(long) -> 让当前线程休眠指定的毫秒数
static yield() -> 让当前线程放弃时间片 返回到就绪
join() -> 让其他线程加入 并执行完成后再执行后面的语句
线程章节其它常用方法
setName() + getName() -> extends Thread 设置和得到线程的名字 不是类名
static activeCount() -> 程序当中所有活跃线程的总数 = 就绪 + 运行 + 阻塞
这个方法永远不可能返回0(主线程)
setDaemon(true) -> 设置线程成为守护线程
守护线程通常都是无限循环 防止过早消亡
设置成为守护线程要早于自己的start()
守护线程应当具有极低的优先级别
interrupt() -> 中断 打断线程的阻塞状态
让线程从阻塞状态 直接返回就绪
注意 会触发异常
static currentThread() -> 得到当前处于运行状态的线程对象
在主方法当中得到主线程的线程对象
在run()调用的其它方法中用来得到线程对象
它永远不会直接出现在run() 因为得到的对象等价于this
并发错误
多个线程共享同一个数据(对象)
时间片突然耗尽 线程中的代码未能连续执行
多个线程共享的那个对象 -> 临界资源
解决并发错误
- 互斥锁 = 互斥锁标记 = 锁旗标 = 锁标记 = 监视器 = Monitor
synchronized 同步的 修饰符 形容词 Modifier
synchronized特性 只对本类有效 隔代丢失
synchronized(临界资源){...}修饰代码块
public synchronized void add(Object obj){...}修饰方法
- Java包的工具包的并发包的锁包的可重入锁
lock() unlock();
java.util.concurrent.locks.ReentrantLock
死锁
互斥锁标记使用不当 两个线程各占有部分资源又去申请另一个线程已经持有的资源
从而双双进入对方资源的锁池当中====>引入等待池
锁池 要使用锁标记 在锁池内争夺锁的使用权
等待池 主动调用wait方法,休眠
===========================================================
wait(): 放弃锁标记 进入等待池
notify(): 从调用方法的对象等待池中随机唤醒等待池中一个线程
notifyAll(): 唤醒所有阻塞的线程
锁池/等待池
都是每个对象都有一份的空间 而且是存放线程的~
它们都属于阻塞状态
进入锁池不需要释放锁标记
进入等待池需要释放锁标记
锁池不需要 一旦锁标记再度可用 线程自动返回就绪
等待池必须要程序员调用notify() 或者 notifyAll()
离开锁池直接返回就绪
离开等待池直接前往锁池
线程池
一个线程的完整执行时间 = 创建 + 核心逻辑的执行 + 销毁
import java.util.concurrent.*;
ExecutorService es= Executors.newFixedThreadPool(2);//可重用的线程池
ExecutorService es= Executors.newCachedThreadPool();//缓存机制的线程池
ExecutorService es= Executors.newSingleThreadExecutor();//单一实例的线程执行器
es.submit(t1);
es.shutdown(); 将之前加入的线程全部完成后退出
es.shutdownNow(); 将已经在执行的全部完成后退出
- 提高资源利用率
- 提高响应速度
- 使线程具有可管理性
IO流
方向 -> 输入流 输出流 ==> 参照物是本身
单位 -> 字节流 字符流
功能 -> 节点流 过滤流(包装流、处理流)
new File(String 路径)
new File(String 父目录,String 文件名)
new File(File 父目录对象,String 文件名)
===========================================================
static listRoots() -> 列出当前计算机的所有根目录
String[] list() -> 得到一个目录当中所有的文件名字
File[] listFiles() -> 得到一个目录当中所有的文件对象
exists() -> 判断File对象指代的文件或者目录是否存在
isFile() -> 判断File对象代表的是不是一个文件
isDirectory() -> 判断File对象代表的是不是一个目录
length() -> 得到一个文件的字节个数
===========================================================
mkdirs() -> 创建多层不存在的目录结构
renameTo() -> 重命名文件或者目录
x.renameTo(y); x必须存在 y必须不存在
x和y可以在不同的目录结构 从而实现剪切移动
delete() -> 删除文件或者目录
它真的不懂什么叫做"回收站"
如果要删除的是一个目录 则必须保证目录为空
getName() -> 得到文件或者目录的名字
getParent() -> 得到文件或者目录的父目录
getAbsolutePath() -> 得到文件或者目录的绝对路径
setLastModified() -> 设置文件最后一次修改时间
lastModified() -> 得到文件最后一次修改时间
解析时间
java.util.Date
getYear() getMonth()+1 getDate()
getHours() getMinutes() getSeconds()
java.util.Calendar
get(1) get(2)+1 get(5) get(11) get(12) get(13)
java.text.SimpleDateFormat
"yyyy-MM-dd HH:mm:ss"
format()
parse()
包含子目录的递归遍历的攻略
- 我们需要一个专门用来过滤Dir的过滤器 最好使用单例模式[醉汉式]
- 我们需要一个专门用来过滤File的过滤器 最好使用单例模式[懒汉式]
- 这才是递归遍历的核心所在 一个递归调用的方法
这个方法需要一个File对象做参数 代表正要对付的那个目录
3.1. 利用1st开发完的过滤器 得到当前目录中所有子目录
3.2. 利用2nd开发完的过滤器 得到当前目录中所有File
3.3. 判断3-1和3-2得到的不是null 防止没有权限而导致的空指针异常
3.4. 遍历3-1得到的所有子目录 并且再次调用3rd
3.5. 遍历3-2得到的所有图片文件 进行对应的操作规则. 先进子目录,子目录全部遍历完成才会再进同级目录,然后再往上一层走 - 主方法当中创建一个File对象代表要对付的主目录 并且再次调用3rd方法
字节流
InputStream 所有字节输入流统一的父类 抽象类
int read()
int read(byte[] data)
int read(byte[] data,int off,int len)
OutputStream 所有字节输出流统一的父类 抽象类
write(int data)
write(byte[] data)
write(byte[] data,int off,int len)
Buffered = 缓冲 Data = 数据 Object = 对象 | File = 文件
FileInputStream 字节流 输入流 节点流
FileOutputStream 字节流 输出流 节点流
构造方法可以传入字符串或者文件对象只能连接文件 不能连接目录
FileOutputStream 自动创建对象 <==> createNewFile()
但是如果连接的目录结构都不存在 则直接抛出异常
FileOutputStream 是有杀伤力的 直接替换原文件
追加模式 new FileOutputStream("a.txt",true);
FileInputStream 以-1作为读取结束的标识
用完流请第一时间关闭流
BufferedInputStream 字节流 输入流 节点流
BufferedOutputStream 字节流 输出流 节点流
过滤流 给节点流添加缓冲空间 提高效率
不能直接连文件 第二个参数设置缓存空间大小 默认只有8192 也就是8K
BufferedInputStream read() -> 以-1为读取结束的标识
BufferedOutputStream write(int data)
DataInputStream
DataOutputStream
过滤流 给节点流添加读写基本数据类型的功能
DataInputStream 提供了一组readXxxx() -> 有返回值 -> 不再以-1作为读取结束的标识了
DataOutputStream 提供了一组writeXxxx() -> 要参数
到达文件结尾还尝试继续读取 出现EOFException => End of File
ObjectInputStream
ObjectOutputStream
过滤流 给节点流添加读写对象的功能
ObjectInputStream readObject(); ->不以-1作为读取结束的标识
ObjectOutputStream writeObject();
到达文件结尾还尝试继续读取 出现EOFException => End of File
只能将支持 java.io.Serializable 接口的对象写入流中 必须 implements Serializable
而且其中所有的属性的类型 也有序列化
如果某些属性无关紧要 可以transient => 不参与持久化
如果要持久化的是一个集合对象
则要求集合当中的元素的类型 也要实现序列化接口
如果要持久化的是一个使用了比较器的TreeSet或TreeMap
就连比较器的类型也要实现序列化接口
字符流
Reader 所有字符输入流统一的父类 抽象类
int read()
int read(char[] data)
int read(char[] data,int off,int len)
Writer 所有字符输出流统一的父类 抽象类
write(int data)
write(char[] data)
write(char[] data,int off,int len)
FileReader 字符流 输入流 节点流
FileWriter 字符流 输出流 节点流
构造方法可以传入字符串或者文件对象
只能连接文件 不能连接目录
FileWriter 自动创建对象 <==> createNewFile()
但是如果连接的目录结构都不存在 则直接抛出异常
FileWriter 是有杀伤力的 直接替换原文件
追加模式 new FileWriter("a.txt",true);
FileInputStream 以-1作为读取结束的标识
用完流请第一时间关闭流
BufferedReader 字符流 输入流 过滤流
BufferedWriter 字符流 输出流 过滤流
过滤流 给节点流添加缓冲空间
实现以行为单位读写
不能直接连文件
BufferedReader - String readLine() -> 以null代表读取结束 -> 不再以-1作为读取结束的标识了
BufferedWriter - write(String)
PrintStream
PrintWriter
和BufferedWriter相比较的优势:
- 既可以当做节点流 又可以当做过滤流
- 既可以连接字节流 又可以连接字符流
- 当做节点流使用 可以指定字符集
- 当做过滤流使用 可以指定自动清空缓冲
- println() = write() + newLine()
综上所述 今后如果需要写出文本文件 PrintWriter绝对是不二选择
InputStreamReader 桥转换器 能够将字节流转换成字符流
FileInputStream fis = new FileInputStream("abc.txt");
InputStreamReader r = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(r);
OutputStreamWriter 桥转换器 能够将字节流转换成字符流
FileOutputStream fos = new FileOutputStream("cba.txt");
OutputStreamWriter w = new OutputStreamWriter(fos);
BufferdWriter bw = new BufferedWriter(w);
因为PrintWriter的强大 让OutputStreamWriter几乎无用武之地
但是 其实幕后的英雄还是它
RandomAccessFile 构造方法第二个参数 请指定rw模式
setLength(long) -> 能够将连接的文件设定到指定的大小
反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射就是把java类中的各种成分映射成一个个的Java对象。
Class对象的由来是将class文件读入内存,并为之创建一个Class对象。
在运行期间,一个类,只有一个Class对象产生。
反射是框架设计的灵魂
获得类
类名.class
对象.getClass();
Class.forName("对象名");
通过class获取实例 无参
cls.newInstance();
获取构造方法
Constructor c = cls.getDeclaredConstructor();
Constructor[] cs = cls.getDeclaredConstructors();
............
通过构造方法获取实例 可以指定参
c.newInstance(obj...);
获得属性
Field f = cls.getField(String);本类和直接父类public的属性
Field[] fs = cls.getFields();
Field f = cls.getDeclaredField(String);本类的所有属性
Field[] fs = cls.getDeclaredFields();
属性名
f.getName();
修饰符 getModifies()->整数
Modifier.toString(f.getModifiers());
类型 getType->Class
f.getType().getName();
破封装 -> private
f.setAccessible();
对带有指定参数的指定对象设置field的值
field.set(instance,value);
获得方法
Method m = cls.getMethod(String);
ethod[] ms = cls.getMethods()
Method m = cls.getDeclaredMethod(String);
ethod[] ms = cls.getDeclaredMethods();
方法名
m.getName();
修饰符
Modifier.toString(m.getModifiers());
返回类型
m.getReturnType().getName();
method 由 instance 调用 参数 value 是框架的核心
method.invoke(instance,value);