Java学习路线
jie
2020-08-20
响应和提供数据
阻塞解除
导致阻塞事件
关系解析
存储数据
JVM调优
JVM解析程序时需要得到CLASSPATH支持
关系: JVM → CLASSPATH定义路径 → 加载字节码文件
文档注释里还有很多选项, 一般通过开发工具帮助实现
一般用有意义的单词
程序支持数据转换处理, 但不是必须的情况不建议转换
明确循环次数情况下优先选择for循环
不知道循环次数,但知道循环结束条件情况下优先使用while循环
在栈中开了一个内存空间, 还没有指向
在堆中开辟一个内存空间, 该对象在栈中有了地址
public ,abstract 写与不写都一样
主程序→
Java入门学习路线
Java编程入门
Java面向对象编程
Java语言高级特性
数据库开发
Java Web开发基础
子主题
Java开发框架
Java开发工具
Java面试技巧
Java语言基础
数据库及SQL/MySQ
JDBC数据库开发
数据库概述
Java应用于数据库的关系
安装MySQL
删除MySQL
MySQL启动(Window)
关系结构模型数据库
使用二维表格来存储数据
常见数据库
Oracle(甲骨文)
DB2(IBM)
SQL Server(微软)
Sybase(赛尔斯)
MySQL(甲骨文)
理解数据库
数据库泛指"关系型数据库管理系统"(RDBMS : Relation database management
system)
应用程序
操作和查询
数据库服务器
数据库
net start mysql
net stop mysql
MySQL服务端登录
mysqld -h 主机名 -u 用户名 -p
本机 : mysqld -u root -p
MySQL安装路径及配置信息
bin目录下
开启关闭服务器及登录退出客户端
SQL语言概述
mysqld.exe是服务端执行程序
mysql.exe是客户端执行程序
MySQL客户端登录
mysql -u用户名 -p密码 -h主机名
本机 : mysql -u用户名 -p密码 -hlocalhost
退出
exit和quit
DDL(数据定义语言)之操作数据库
结构化查询语言(Structured Query Language)
SQL作用
客户端使用SQL来操作服务器
启动mysql.exe连接服务器后, 就可以使用sql来操作服务器了
将来会使用Java程序连接服务器, 然后用sql操作
SQL 标准
有国际标准化组织(ISO)制定的, 对DBMS的统一操作方式(如mysql, oracle等)
注意
某种DBMS不会只支持SQL标准, 也会有自己的语法
SQL语法
SQL语句可以在单行或多行书写, 以分号结尾
可使用空格和缩进来增强语句的可读性, 换行符, 空格, tab 在SQL中不起作用
MySQL不区分大小写, 建议使用大写
SQL语句分类
DDL(Data Definition Language)
DML(Data Manipution Language)
DCL(Data Control Language)
DQL(Data Query Language)
数据定义语言, 用来定义数据库对象 : 库、表、列等
数据库或表的结构操作(创建. 删除, 修改)
数据操作语言, 用来定义数据库记录(数据)
数据控制语言, 用来定义访问权限和安全级别
数据查询语言, 用来查询记录(数据)
对表的记录进行更新(增, 删, 改)
alter user user() identified by "root";
s
创建数据库
CREATE DATABASE 数据库名;
DML (数据操作语言)之DELETE
DCL (数据控制语言)
DQL (数据查询语言)之基础查询之列控制
DQL (数据查询语言)之条件查询
DQL (数据查询语言)之模糊查询
DQL (数据查询语言)之排序
DQL (数据查询语言)之聚合函数
DQL (数据查询语言)之分组查询
DQL (数据查询语言)之limit方言
阿云产品简介:云数据库RDS MySQL版
阿里云数据库体验:数据库坛实战
DML (数据操作语言)之INSERT
查看所有数据库
SHOW DATABASES
选择要操作的数据库
USE 数据库名
删除数据库
DROP DATABASE 数据库名
注意 : 操作之前必须要选择数据库
官网
MySQL Workbench
图形化界面更方便管理数据库
MySQL Workbench
USE 数据库名称 ;
选中的数据库在SCHEMAS中会以粗体显示
也可以双击要选择的数据库
SELECT 列名称, 列名称
FROM 表名称 ;
从指定表里检索指定列
SELECT * FROM 表名称 ;
检索所有列
WHERE 布尔表达式(以列名称做比较) ;
获取指定列里是特定值的行数据
ORDER BY 列名称
以指定列升序排列
选择语句
注意 : 这些命令的顺续很重要, 不对会报错
列名称可接算数表达式
SELECT 列名称, 列名称+2
例 : SELECT last_name, points, points * 3
非数字的字符会变成数字, 数字中有其他数据类型会只保留数字, 然后运算
SELECT 列名称, 列名称+2 AS 新的列名称
赋予新的列名称
列名称例有空格需要加" "或' '
说明
SELECT DISTINCT 列名称
获得没有值重复的清单
比较 : >, >=, <, <=, =, !=, <>
除了数字, 还可以比较字符串, 日期等
逻辑 : AND( && ), OR( || ), NOT( ! )
第二章
IN运算符
WHERE 列名称 IN (值1, 值2, ...)
等同于: WHERE 列名称 = 值1 OR 列名称 = 值2 ...
第三章
内连接
子主题
BETWEEN运算符
子主题
主题
1.Java语言简介
2.搭建Java开发环境
3.初识Java开发
4.Java基本概念
5.Java数据类型划分
6.Java运算符
7.Java程序逻辑控制
8.方法的定义及使用
JDK简介
Java Development Kit, Java开发工具包
JDK版本更新
JDK下载
JDK安装与配置
安装JDK
环境变量配置
配置JDK路径: JAVA_HOME
配置PATH路径: %JAVA_HOME%\bin
配置CLASSPATH路径: .;%JAVA_HOME%\lib
Java编程起步
public class Hello {
public static void main(String args[]) {
System.out.println("public") ;
}
}
类的定义
可以定义多个class
public class 类名称 {}
class 类名称 {}
类名称首字母必须大写
主方法是程序执行的起点, 且必须定义在类中
JShell工具
CLASSPATH环境属性介绍
作用:可以在不同目录中加载 执行*.class文件
SET CLASSPATH = D:\Code\Java
SET CLASSPATH=.
CLASSPATH 和 PATH区别(面试题)
PATH 是操作系统提供的路径配置, 定义所有可执行程序的路径
CLASSPATH 是JRE提供,定义Java程序解析时加载路径
注释
本质: 程序编译时发现有注释内容将不对此部分进行编译
单行注释: //
多行注释: /* ....*/
文档注释: /** ...*/
标识符与关键字
在不同的结构一定要有不同的说明,结构的说明是有命名要求的
由字母, 数字, _ , $组成, 不能用数字开头
对一些关键字的简短说明
JDK1.4时有assert(断言)关键字, 用于异常处理上
JDK1.5时有enum(枚举)关键字, 用于枚举定义上
未使用到的关键字: goto, const
一些特殊含义的单词, 严格来讲不算是关键字: true, false, null
Java数据类型简介
基本数据类型
整数型
整型: byte, short, int, long
浮点型: float, double
引用数据类型
I.Java发展简介
II.Java语言特点
Sun公司开发的一套编程语言,但前身不是Java
网景公司推出HotJava浏览器
1995-5-23正式推出Java编程语言
1996年可以下载使用JDK1.0开发包
1997年传到中国
Java标准开发(J2SE,JAVA SE),:提供底层的支持,实现了桌面程序开发(单机程序)
SUN(Stanford University NetWork,斯坦福大学网络)
最早标志性作品:小型机
电子商务是IBM提出来的
后来被Oracle收购,但在Oracle收购前产品线上技术基础是Java
SUN没有通过Java赚到钱,真正赚到钱的是IBM和后来版权欺诈的Oracle
Java嵌入式开发(J2ME, JAVA ME):SUN公司最早想做嵌入式开发,但后来被Nokia
折腾够了,后来被Android替代了
Java企业开发(J2EE,JAVA EE):主要进行企业平台搭建,现在主要的开发是互联网平台
1.是一个行业内通用的技术实现标准
2.是一门面向对象编程语言
3.提供有方便的内存回收机制
4.避免了复杂的指针问题,使用简单的引用代替指针,引用难理解
5.Java是为数不多的支持多线程编程语言,多线程难理解,正确额多线程处理是提升性能
的核心所在
7.Java语言足够简单
6.Java具有良好的可移植性
JVM(Java虚拟机):一个由软件硬件模拟处理的计算机,不同系统有不同版本的JVM,
从而实现可移植性
Java应用程序运行机制
计算机高级编程语言类型:编译型,解析型
Java是两种语言的结合
编译命令:javac.exe
解析命令:java.exe
Java程序组成
用来解析的计算机就是Java虚拟机
Java源文件
字节码文件
机器码指令
由JVM执行肯定比会直接在操作系统上直接执行要慢
字节码class是通用的执行文件
Oracle官网
1995.05.23, JDK1.0开发包发布,96年正式提供下载
1998-12-04, JDK.2, Java更名为Java2
2005-05-23, JDK1.5, 这一版本决定了Java后续十年的技术核心
2014年, JDK1.8, 支持Lambda变大时, 可以使用函数编程
2017年, JDK1.9, 提升了稳定性
2018年, JDK1.10, 属于JDK1.9的稳定版, JDK1.11
2019年, JDK1.12, jDK1.13
2020年3月, JDK.14
Hello World程序
编译会生成多个*.class, 文件名是类名称, 但还是开发中一个*.java很少会定义多个
class, 一个public class就够了
公共类:类目称必须与文件名一致
主方法所在的类统一称主类, 都采用public class定义
public static void main(String args[]) {}
或:public static void main(String []args) {}
一个编写代码交互性工具,可直接运行核心代码,而不用编写结构,但实用性不高
从D:\Code\Java 加载类
默认当前目录加载
使用开发工具时, 单行注释会方便些, 对于一些重要的类, 方法一般使用文档注释
布尔型: boolean
字符型: char
默认值: 0
默认值: 0.0
默认值: false
默认值: 'u0000'
数组, 接口, 类
默认值: 0
数据类型的选择参考
描述数字首选int, double
进行数据传输或文字编码转换用byte(二进制处理操作)
处理中文最方便的是char(可选概念)
描述内存或文件大小, 描述主键列(自动增长)可以用long
数据类型可表示范围
int: 32位, -2,147,483,648~2,147,483,647
float: 32位, -3.4E38~3.4E38
double: 64位, -1.7E308~1.7E308
char: 16位, 0~65536
byte: 8位(一个字节), -128~127
long: 64位, -9,223,372,036,854,775,808(-2^63)
~9,223,372,036,854,775,807(2^63 -1)
short: 16位, -32768~32767
整形数据类型
浮点型数据
字符型
布尔型
String字符串
数字在进行处理时如果超过范围会循环,即数据溢出,int型 最大值+1=最小值(循环)
解决数据溢出
1.操作时预估数据范围,范围不够就使用更大范围
2.默认整数常量都是int型, 后面加"L"可以转换为long, 或在前面用"(long)"
强制类型转换
范围大的类型转小的类型
byte
Java对byte进行了处理, 如果int常量范围没超过byte, 会自动转为byte, 但是对于变
量, 还需要强制类型转换
byte num =20
小数默认都是double
定义float = 10.2, 需要使用强制类型转换
float = 10.2F;
float = (float)10.2;
计算时要注意选择的数据类型, 决定小数点的问题
任何编程语言中,char 都可以与 int 相互转换
编码范围
'A'(65)~'Z'(90)
'a'(97)~'z'(122)
0(48)~9(57)
Java中的char类型可以保存中文数据
注意:Java中不存在在用0表示false, 1表示true
要求使用双引号""描述
使用"+"进行字符串连接处理
str = "Hello";
str += "!!!";
自动类型转换
数据范围大的数据类型与范围小的数据类型计算时, 小自动转成大的
计算中如果有String字符串, 则所有类型无条件变为String, 此时"+"为字符型拼接
转义字符
TAB(\t)
" (\")
' (\')
换行 (\n)
\ (\\)
运算符简介
数学运算符
关系运算符
逻辑运算符
位运算
运算符里()优先级最高
不建议编写很复杂的运算, 简单易懂为主
简化运算占用内存会较少: 如"+="
"x++", 先计算在自增
"++y", 先自增再计算
"="表赋值, "=="才是关系运算
三目(赋值)运算符
关系运算 ? 关系满足时内容 : 关系不满足时内容
例: int max = x > y ? x : y;
指的是可以直接进行二进制数据的计算处理
与(&), 或(|), 异或(^), 反码(~)
移位运算
int x = 2;
x << 2(结果x = 8)
&& 运算: 如果前面条件返回false, 后面结果不再执行,结果为 false
|| 运算: 前面条件返回 true, 后面不再执行
If分支结构
Switch开关语句
while循环
for循环
循环控制
循环嵌套
使用的关键字: if, else
if(布尔表达式){
条件满足时执行;
}else if(布尔表达式){
条件满足时执行;
}else{
条件不满足时执行;}
执行多逻辑判断可以不写上else, 但好的习惯是写上else
switch(数据){
case 数值 : {
数值满足时执行 ;
[break ;]
}
case 数值 : {
数值满足时执行 ;
[break ;]
}
[default:
所有判断数值不满足时执行 ;
[break ;]
]
}
case后面如果没有break, 会继续执行后续代码,直到执行完毕遇见break
while循环
do ... while循环
while(布尔表达式){
条件满足执行 ;
修改循环条件 ;
}
do{
条件满足执行 ;
修改循环条件 ;
}while(布尔表达式);
for(定义循环的初始化数值 ; 循环判断 ;修改循环数据){
循环语句的执行 ;
}
两个控制语言语句: break, continue
break: 跳出循环
continue : 当前语句后续代码不再执行,直接执行后续判断
在一个循环语句里嵌套另一个循环
循环嵌套越多, 时间复杂度越高
在程序中可能需要重复执行的一些代码. 有些书把方法(method)叫函数(funtion)
方法重载
方法的递归调用
子主题
方法在主类中定义, 并且由主方法直接调用
方法的定义
public static 返回值类型 方法名称([参数类型 变量,....]) {
// 该方法要执行的代码
[return [返回值] ;]
}
没有返回值可以用void定义
如果返回值类型时void, 也可以用return结束调用
java中定义方法时一般不用太长, 对项目进行适当的拆分
同一个方法名称根据调用时传递的不同参数个数或类型实现不同的方法体调用,从而
实现方法重载的定义
例:
方法的重载与方法的返回值类型没有任何关系, 它只跟参数有关. 掌握一个基本的开
发原则 : 只要是方法重载建议其返回值类型相同
例如System.out.println()可以接收 不同数据类型, 就是一个方法重载
指的是一个方法自己调用自己的情况
一定要设置递归调用结束的条件
每一次调用一定要修改传递的参数条件
例: 累加
递归操作实际开发中很少出现递归情况, 处理不当会导致栈溢出
例 : 阶乘
JDK目录
bin目录, .exe可执行文件
lib目录, .jar类库文件
jre: java运行时环境目录
两个%表示引用"JAVA_HOME"的路径
常用DOS命令
dir(directory)
列出当前目录文件
md(make)
cd(change)
创建目录
rd(remove)
删除目录
进入指定目录
del
exit
cls(clear screen)
删除文件
推出DOC命令行
清屏
cd..
返回上一级目录
cd\
返回到根目录
其他
JRE(Java Runtime Environment)
JVM+lib(一些系统类库)
不能与关键字重名
命名要求
命名规范
类名: 首字母大写
变量名: 首字母小写, 后面单词首字母大写
方法名: 与变量名命名规则相同, 驼峰命名
常量名: 所有字母大写, 单词间_隔开
关键字 : 有53个, 51个在用
命名要用单词, 见名知意, 不可用拼音
! 非
>>>
无符号右移, 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移
动得到的空位以零填充。
赋值运算符
"=", "+=", "-=", "/=", "%="
<<=
左移位赋值运算符
>> =
右移位赋值运算符
&=
按位与赋值运算符
^ =
按位异或赋值操作符
| =
按位或赋值操作符
instanceof 运算符
该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类
型)
String name = "James";
boolean result = name instanceof String;
正整数的补码是其二进制表示,与原码相同
负整数补码 : 反码是原码取反, 补码是反码加1(带符号位二进制)
<< 左移
<< 右移
有符号
判断数据可以是String, char, int
方法的参数传递
形参 : 方法声明时的参数
实参: 方法调用时实际传给形参的参数值
Java中的值传递 : 用实际传递的参数值的副本(复制品)传入方法内, 参数本身不受影
响
1.类与对象
2.深入分析类与对象
3.MVC设计模式
4.this关键字
5.类的核心开发结构
6.static关键字
7.代码块
8.面向对象案例分析
9.数组的定义与使用
10.引用传递实际应用
11.数据表与简单Java类映射
12.String类特点分析
13.String类常用方法
14.继承的定义与使用
15.覆写(重写)
16.综合案例:继承分析
17.Annotation注解
18.多态性
19.Object类
20.抽象类的定义与使用
21.包装类
22.接口的定义与使用
23.综合案例:抽象类与接口
24.泛型
25.包的定义及使用
26.UML图形
27.单例设计模式
28.枚举
29.异常的捕获及处理
30.内部类
31.函数式编程
32.链表的定义与使用
33.Eclipse开发工具
34.IntelliJ IDEA开发工具
1.面向对象简介
3.类与对象的定义及使用
4.对象内存简单分析
5.对象引用分析
6.引用与垃圾产生分析
2.类与对象简介
Java最大的特点是面向对象的编程设计
核心本质 : 在整个面向对象的设计里面考虑的是一份标准的模块化设计, 使用时根据
标准进行拼装
三个主要特征
封装性
继承性
多态性
内部的操作对外不可见, 当内部的操作都不可以直接使用时才是安全的
在已有结构的基础上继续进行功能扩充,
是在继承的基础上扩充而来的概念, 指的是类型的转换处理
面向对象程序开发一般三个步骤 :
OOA (Object-Oriented Analysis): 面向对象分析
OOD (Object-Oriented Design): 面向对象设计
OOP (Object Oriented Programming): 面向对象编程
类是对某一类事物的共性的抽象概念, 而对象描述的是一个具体的产物, 是一个类的
实例, 有方法(行为)和属性(状态)
类是一个模板, 而对象才是类可以使用的实例, 先有类再有对象
类; 一般有两个组成
成员属性(Field)
操作方法(Method)
Java中类是一个独立的结构体
要用对象调用类,
声明对象
实例化对象
对象名称 = new 类名称();
调用
调用类中的属性
调用类中的方法
对象名称.属性名称
对象名称.方法名称()
类名称 对象名称;
类名称 对象名称 = new 类名称();
Java中类属于引用数据类型, 困难之处在于内存管理, 操作中也会发生内存关系变化
堆内存:
栈内存
通过地址找到堆内存, 再找到对象内容
程序里堆内存空间的开辟是通过new()完成的
栈内存
per(0x00001)
堆内存
Animal()
Peson()
name = "张三"
age = 18
Person per = new Person() ;
Animal an = new Animal() ;
per.name = "张三" ;
per.age = 18 ;
保存的是对象的具体信息
保存的是一堆内存地址
an(0x00002)
.......
.......
错误
......java.lang.NULLPointerException
......JavaDemo.java:[行数]
NULLPointer即指向异常, 没有开辟堆内存产生的问题(没有为对象实例化, 无法调
用),
只有引用数据类型存在此错误
内存引用传递的本质: 同一块内存空间可以被不同的栈内存指向
Person per = new Person ;
person per2 = per ;
可以利用方法实现引用传递处理
Person类的实例化对象(内存地址, 数值)per可传递到方法中, 即可做形参
方法执行完毕后, 形参temp会断开连接
引用传递发生在方法上, 要注意方法的参数类型, 执行过程
引用传递使用不当会造成垃圾产生
Person per1 = new Person() ;
Person per2 = new Person() ;
这会在堆开辟两块内存空间
per1 = per2 ;
这时per2指向改变, 但原来指向的堆空间还存在, 成为垃圾
垃圾空间
指没有任何栈内存指向的对内存空间
垃圾都将被GC(Garbage Collection)回收并释放内存空间, 该过程需要不少时间, 程
序开发中要尽量减少GC触发
成员属性封装
1.用private定义属性(对外部不可见)
3.设置属性的方法
4.获取属性的方法
public void setName(String n) ;
public String getName() ;
一般方法都是对外提供的,不做封装处理, 而属性需要较高的安全性, 往往采用封装性
对其保护
没有封装处理外部可以修改属性, 可能会导致属性是错误的数据
封装方式
2.java封装setter开发标准 :setXxxxx(), getXxxx()
5.例 :
开发中, 类中的所有属性都必须用private封装(98%), 这是标准做法
该方法里可以对属性值进行限制
构造方法与匿名对象
通过构造方法实现实例化对象中的属性初始化处理, 只有在关键字new时使用构造方
法
构造方法定义要求
构造方法名称必须与类名称保持一致
构造方法不允许设置任何返回值类型
构造方法在使用关键字new'实例化对象时自动调用
定义构造方法
class Person {
public Person (String n, int a){ //定义有参构造
name = n ;
age = a ; //为类中的属性赋值(初始化)
}
}
public class JavaDemo {
public static void main(String args[]){
Person per = new Person("张三", 18) ;//声明并实例化对象
}
}
一个类至少存在一个构造方法,
构造方法相关疑问
为什么构造方法不能用void
编译器根据代码结构编译处理,
如果构造方法用void则如普通方法相同
构造方法与普通方法区别
构造方法是在类对象实例化时调用的, 普通方法是在类对象实例化产生之后调用的
构造方法重载
方法重载建议根据参数个数升序排列
匿名对象
new Person("张三", 10).方法名称() ;
对方法进行了调用, 但没有任何引用
this关键字
this调用本方法
三类描述
当前类中属性: this.属性
当前类中方法: this.方法()
当前对象
建议开发时, 只要是访问本类中属性,就加this
构造方法调用 this()
普通方法调用 this.方法()
构造方法重载里 , 可以用this([参数名称], .....) 调用本类中其他参数个数不同的方法,
(构造方法的互相调用), 以减少代码重复
例
目的: 减少代码重复
this()语句只允许放在构造方法首行
构造方法互相调用时注意避免死循环
类名称一定要有意义, 可以明确描述某一类事物
类中所有属性都必须使用private封装, 封装后必须提供setter(), getter()方法
类中可以有很多个构造方法, 且必须保留有无参构造方法
类中不允许出现输出语句, 所有输出内容的获取必须返回
[非必须]可以提供一个获取对象信息的方法, 暂时将此方法定义为getInfo()
训练: 建议写一个简单Java类, 囊括以上构造方法, 方法重载, this关键字等全部知识
点
将属性修改为公共属性, 存放在全局数据区
static属性可以由类名称直接调用
static虽定义在类中, 但不受到实例化对象影响, 不用实例化也可调用
首选非static, 考虑到公共信息存储时才使用static属性
声明static属性
声明static方法
限制: static方法里只能调用static属性, 方法; 要调用普通方法需要先实例化该普通
方法
static应用
子主题
普通代码块
构造代码块
静态代码块
同步代码块
多线程里的
定义在一个方法中的代码块, 即用{ } 括起来
作用: 防止相同变量名称带来的影响( 一个方法里不同的代码块可定义相同变量名称,
即全局, 局部变量)
特点: 实例化时执行, 构造块会先执行于构造方法
在类中{ }括起来的代码块
在类中用 static { } 定义的代码块
特点: 先执行于构造块, 无论实例化几次, 静态块都只执行一次
主要功能: 在类中为static属性初始化
注意: 静态代码块优先于主方法先执行
数组的基本定义
数组引用传递分析
foreach输出
数组动态初始化
数组静态初始化
数组类型 数组名称 [] = new 数据类型 [长度] ;
数组类型 [] 数组名称 = new 数据类型 [长度] ;
简化格式
数组类型 数组名称 [] ={ 数据1, 数据2, 数据3, ...} ;
完整格式
数据类型 数组名称 [] = new 数据类型 [] { 数据1, 数据2, 数据3, ...} ;
error
ArrayUndexOutOfBoundsException
数组越界异常(脚标超出范围)
常用
数组名称.length
获取数组长度
常用for循环控制数组
建议用完整格式定义
初始值为该数据类型对应的初始值
数组本身时引用数据类型, 可发生引用传递, 即一个堆内存被多个栈内存所指向
NullPointerException
空指向错误, 没有实例化new开辟堆内存空间
自动获取数组中每一个元素, 避免下标访问
语法
for (int temp : data) { } ;
二维数组
数组与方法
数组动态初始化
数组静态初始化
数组类型 数组名称 [][] = new 数据类型 [行数][列数] ;
数据类型 数组名称 [][] = new 数据类型 [][] { {数据, 数据, ...}, {数据, 数据, ...}, ...} ;
二维数组是数组的嵌套, 数组名称.length是行数, 数组名称[x].length是列数
public static int[] array() {
int arr[] = new int[] {3, 4, 5, 6} :
return arr ; // arr是地址
}
案例分析
数组冒泡排序
数组转置
数组相关类库
java.util.Arrays.sort(数组名称)
数组升序排序
System.arraycopy(源数组, 源数组开始点, 目标数组, 目标数组开始点, 拷贝长度)
数组拷贝
方法可变参数
pubilc static int sum(int ... data){
for(int temp : data) {
}
}
本质还是数组
对象数组
Java程序本身的各种数据类型都可以成为数组类型, 类也可以成为数组类型, 称为对
象数组
动态初始化
类 对象数组名称[] = new 类 [长度], 每一个元素的内容都是null
静态初始化
类 对象数组名称[] = new 类 [] {实例化对象, 实例化对象...} ;
所有开发都离不开对象数组
缺陷: 长度是固定的, 一旦确定不可更改
好处: 数据线性保存, 根据索引范围, 速度较快, 时间复杂度为"1"
存在堆内存中的对象是栈内存里的对象的名称引用??
类关联结构
自身关联
合成设计模式
例:
例 :
都是类中常用的逻辑关系
人类的产品都是可以拆分,再重新组合的
数据表与简单的Java类映射转换
一对多映射
多对多映射
复杂多对多映射
String类简介
字符串比较
字符串常量
String类对象两种实例化方式比较
String对象常量池
字符串修改分析
主方法组成分析
JavaDoc文档简介
字符串与字符
字符串比较
字符串查找
字符串替换
字符串拆分
字符串截取
字符串格式化
其他操作方法
继承问题引出
继承的实现
子类对象实例化流程
继承定义限制
简单Java类定义往往根据数据表的结构来实现的
基本映射关系
数据实体表设计 = 类的定义
表中的字段 = 类的成员属性
表的一行记录 = 类的一行实例化对象
表的多行记录 = 对象数组
表的外键关联 = 引用关联
映射解决步骤
写出类的基本组成
通过引用配置关联字段关系
例: 图书 → 不同书籍
例: 用户 → 商品 → 商品属性
例: 用户授权管理
用户 → 所有角色 → 所有权限信息 → 所有用户信息
字符串不是一种基本数据类型
String这个类里定义的字符串 每一个字符是保存在一个数组里
JDK1.9后 String类的数组用的是bype类型(字节), JDK1.8以前用的是字符数组
不能用"=="准确判断
要用equals()比较
"=="是数值比较, 如果用于对象比较, 比较的是两个内存的地址值
是类提供的比较方法, 可以直接进行字符串内容判断
描述的是String类的匿名对象
strA.equals(strB) ; //返回布尔值
注意: strA不能是null, strB可以
所以要把字符串常量写在前面
String str = "mind" ; //直接赋值
String str = new String("mind") ; //构造方法实例化
即strA, strB两个对象指向的堆内存是同一个(数据共享), 对象重用
String strA = "mind" ;
String strB = "mind" ;
System.out.println(strA==strB); //地址[按段, 输出True
堆内存会提供一个"String对象池", 定义strB时首先会查找池
在堆内存中开辟新的内存空间, 不会自动保存到字符串池
也可以实现手动入池 : String str = new String("mind").intern() ;
一般建议用直接赋值
目的 : 实现数据的共享处理
分两种
静态常量池
运行时常量池
在 *.class加载时自动将程序里保存好的字符串, 普通常量, 或者类, 普通方法等等. 全
部进行分配
*.class加载后, 里面可能有些变量, 这时提供的常量池
字符串内容不可修改
字符串"+="拼接时只是生成新的内容空间, 并且对象改变指向, 原本的字符串成为垃
圾
开发中String类不要进行频繁修改, 会产生很多垃圾
String str = "a" + "b" + "c" ;
这会保存成一个静态值, 不是频繁修改, 不会产生垃圾
for(int x = 0; x<1000; x++){
str += x ;
}
此程序将会产生1000多个垃圾空间
public static void main(String args[]) ;
public
描述的是一种访问权限, 主方法时一切的开始点, 一定是公共的
static
程序执行通过类名称完成, 所以此方法是由类直接调用
void
主方法是一切的开始, 一开始就没有返回的可能了
main
String args[]
是一个系统定义好的方法名称
字符串数组, 可以实现程序启动参数的接收
程序执行时可以设置参数, 每个参数以空格分隔,
如参数本身有空格, 必须使用""包装
例 : java StringDemo first second
public class StringDemo{
public static void main(String args[]){
for(String arg : args){
System.out.println(arg) ;
}
}
}
可以暂时通过这种启动参数实现数据的输入模拟
开发中要大量使用Java的API文档
JDk1.9之前, Java中常用类库会在JVM启动时全部加载, 性能会有所下降
1.9后模块(Module)化设计, 模块中包含大量程序开发包,
如 要打开String类的相关定义, 可以打开java.lang这个包, 里面有个String类
类页面
类的完整定义
Class String
类相关说明信息
成员属性摘要(Field Summary)
构造方法摘要(Constructor Summary)
看见有"Deprecated"描述的方法不建议使用
方法摘要(Method Summary)
对方法和成员的详细说明, 有返回值, 方法名称和相应的参数
注意 别用自动翻译的文档, 要看英文的
str.charAt(index)
获取指定索引位置的字符, 下标是从0开始的
str.toCharArray()
将字符串变为字符数组
new String(数组名称), 可将字符数组变为String
new String(数组名称, 0, 5), 从下标0开始取5个变为String
字符串与字节
字符串与字节转换, 主要目的是为了进行二进制的数据传输或者编码转换
getBytes()
字符串变为字节数组
equals(String anObject)
区分大小写的相等判断
equalsIgnoreCase(String anotherString)
不区分大小写的相等判断
compareTo(String anotherString)
字符串大小比较, 返回 int类型
返回值: 大于(>0), 小于(<0), 等于(=0)
compareToIgnoreCase(String anotherString)
不区分大小写的字符串大小比较
public boolean contains(String str)
判断字符串是否存在(1.5之后才有的)
public int indexOf(String str)
从头查找字符串位置, 找不到返回 -1
indexOf()
public int indexOf(String str, int fromIndex)
从指定位置开始查找字符串位置
public int lastIndexOf(String str)
由后向前查找指定字符串位置
public int lastIndexOf(String str, int fromIndex)
从指定位置由后向前查找指定字符串位置
public boolean startsWith(String prefix)
判断是否以指定字符串开头
public boolean startsWith(String prefix, int toffset)
由指定位置判断是否以指定字符串开头
public boolean endsWith(String suffix)
判断是否以指定字符串结尾
字符串位置的查询, 在一些开发中可以利用此进行索引的确定
public String replaceAll(String regex, String replacement)
全部替换, regex(正则表达式)
public String replaceFirst(String regex, String replacement)
替换首个
public String[] split(String regex, int limit)
按照指定字符串全部拆分
public String[] split(String regex, int limit)
按照指定字符串拆分指定个数, 后面不拆了
拆分时遇见拆不了的情况(涉及正则表达式(regex)的问题),
最简单的理解是使用"\\"进行转义
public String subString(int beginIndex)
从指定位置截取到结尾
public String subString(int beginIndex, int endIndex)
截取指定索引范围的字符串
subString()
开发中开始或结束索引往往是通过indexOf()来的
JDK1.5开始提供, 类似c语言的格式化输出语句, 利用占位符输出,
如字符串(%s), 整数(%d)等等
public static String format(String format, 各种类型 ... args)
根据指定结构进行文本格式化显示
(有static即可以直接调用, String fomat())
例 :
public boolean isEmpty()
""和null, 一个表示有实例化对象, 一个表示没有实例化对象
判断字符串的内容, 一定要在有实例化对象的时候进行调用
判断是否为空字符串(是"", 不是null)
public String concat(String str)
字符串连接,跟"+"的区别是这个定义的字符串没有入池(好像没什么用处)
public int length()
计算字符串长度
public String intern()
让字符串入池
public String trim()
去除字符串左右的空格信息(有空格时字符串查找可能会出现错误)
public String toUpperCase()
public String toLowerCase()
转大写
转小写
自定义实现首字母大写的方法(官方没提供)
扩充已有类的功能, 解决代码重复问题
依靠extends关键字
class 子类 extends 父类 {}
有时会把子类称为派生类, 父类称为超类(SuperClass)
子类实例化时一定要先实例化父类
super()表示子类构造调用父类构造的语句, 只允许放在子类构造方法首行,
super()默认调用父类无参构造,但若父类没有无参构造, 要用super()明确调用有参构
造
super()
即使没有实例化父类, 系统也会自动实例化父类 (注意会调用父类的构造方法)
目的是为了实现所有的属性 空间的分配
super()与this (this是调用本类构造) 都必须在构造方法首行, 所以两个语句不允许
同时出现
方法覆写
方法覆写限制
属性覆盖
final关键字
Java中不允许多重继承, 只允许多层继承
class A{}
class B{}
class C extends A, B{}
多重继承
多层继承
多重继承时希望同时继承多个类的方法
多层继承是希望扩展已有类的功能
class A{}
class B extends A{}
class C extends B{}
理论上层次不应该超过三层
子类不能直接访问父类的private属性(隐式继承)
子类定义了与父类方法一样的方法
覆写是为了优化父类的功能
子类中调用父类方法, 方法前一定要追加"super."
权限 : public > default(不写) > private
子类覆写方法权限不能低于父类
父类的private方法不能被覆写, 子类如果定义了同样的方法, 则这是一个新的方法
建议方法都用public
子类定义了与父类相同名称的属性
描述的是终接器的概念, 定义不能被继承的类, 不能被覆写的方法, 常量
final class Person{}
该类不能被继承
public final void connet() {}
不能被覆写的类
可用final定义常量
final String str = "mind" ; //常量
public static final int ON =1 ; //全局常量, 每个字母必须大写表示
Annotation简介
准确覆写
过期声明
压制警告
程序 维护时的一些常量可能需要更改
最初时开发人员修改源代码, 后来引入配置文件(配置文件暴多), 到现在的注解(又把
配置文件放回代码中, 并让其与代码分离)
如果全部使用注解, 难度太高, 所以现在的开发基本使用配置文件 + 注解
几个基本注解
@Overrde
@Deprecated
@SuppressWarnings
明确表示该方法是一个覆写方法, 写在方法上方(不是方法里),
旨在防止由于疏忽 方法没有覆写成功, 但是程序认为这是一个新方法, 没有报错,
是个结构性的注解
表示这是一个旧的方法, 不要用
用于代码升级过渡, 因为旧的方法不能马上全部换掉
不显示,提示, 警告 (如果你已经明确指导错误在哪里)
例 :@SuppressWarnings({"deprecation"})
多态性简介
对象向上转型
对象向下转型
instanceof关键字
在继承的基础上扩展出来的, 可以实现父子类之间的互相转换处理
两种实现模式
方法的多态性
对象的多态性
方法的重载, 重载就是一种多态性
方法的覆写
父类 父类实例 = 子类实例()
自动完成转换, (大多数情况)
子类 子类实例 = (子类)父类实例()
强制转换,(很少用)
作用 : 让父类可以调用子类覆写的方法, 注意不能调用子类特有的方法
实现参数的统一
要转型的对象原本就是子类对象通过向上转型得到的, 否则
会"ClassCastException"异常
例 ;
例 :
判断对象是否是此类,或此类的子类 , 为了保证向下转型的正确性
例 :
Object类的基本概念
取得对象信息
对象比较
java中只有一个类是没有继承关系的, 这个类就是Objec类
例 : class Person extends Object { }
Object obj = new int[] {2, 3, 4} ;
Object是一个万能的数据类型, 开发时用可以用Object接收任意数据类类
toString
编写简单java类是要获取对象信息 覆写toString即可
是Object自带的一个方法
例 :
public boolean equals(Object obj)
比较两个对象的内容是否完全一致
默认情况该方法只是进行了两个对象的地址判断
要判断内容需要对该方法覆写
例 :
抽象类的基本概念
抽象类的相关说明
模板设计模式
实际开发中很少继承已经完善的类, 进行父类设计时应优先考虑抽象类
主要作用 : 对子类中覆写方法进行约定, 定义一些抽象方法,
使用原则 :
抽象类必须有子类
抽象类的子类(不是抽象类)一定要覆写抽象类的全部抽象方法
抽象类的对象实例化可以利用对象多态性通过子类向上转型完成
使用absract 定义抽象类和抽象方法
使用问题
抽象类不能直接实例化
使用抽象类时往往时是为了解决代码重复的问题
不能用final关键字定义 (抽象类必须有子类, final不能有子类)
抽象类的组成是在普通类的基础上扩展的, 提供构造方法, 也允许没有构造方法
抽象类中可以有static方法, 该方法不受抽象类局限, 可以用类名称进行调用
实际应用
定义一个抽象类, 有"机器人" , "人", "猪" 三个字类, 抽象类定义"eat"抽象方法,
"人"的eat()跟"机器人"的eat()行为是不一样的, 在各自的类中写eat(), (即对一样抽
象的东西进行统一处理)
抽象类好处
对子类方法统一管理
自身可以提供一些普通方法, 普通方法可以调用抽象方法, 这些抽象方法再有子类提
供实现时才会生效
基本数据类型进行包装处理后可以像对象一样引用传递
包装类实现原理
包装类对象型(Object直接子类)
包装类数值型(Number直接子类)
Boolean, Character
Byte, Short, Integer, Long, Float, Double
public byte byteValue()
从包装类获取byte基本数据
public short shortValue()
public abstract int intValue()
public abstract long longValue()
public abstract float floatValue()
public abstract double doubleValue()
Number类中的方法
装箱与拆箱
Integer obj = new Integer(10) ; //装箱
int num = obj.intValue() ; //拆箱
以int 和 Interger为例
JDK1.9后, 所有包装类中提供的构造方法变为了过期处理, 不建议用户继续使用了,
因为JDK1.5后提供了自动的装箱与拆箱处理
Integer obj = 10 ; //自动装箱,拆箱, 不再关心构造方法
Object obj = 19.2 ; //double自动装箱为Double, 向上转型为Object
double num = (Double) obj ; //向下转型为包装类, 再自动拆箱
自动装箱最大好处
注意
相等判断包装类相等判断要用equals()完成
接口的基本定义
抽象类与普通类相比最大的优势在于: 可以实现对子类覆写方法的控制,但是在抽
象类里面可能依然保留有一些普通方法, 而普通方法里面可能会涉及到一-些安全或
者隐私的操作问题,开发中如果要对外部隐藏一些细节,则就可以通过接口来进行
描述。
Java中接口主要用interface关键字定义
interface IMessage { //定义了一个接口(接口名称前通常加入字母"I"以区分接口)
public abstract String getInfo() ; //可以不用加abstract, public, 默认是此类型
}
class MessageImpl implements IMessage { // 实现接口
public String getInfo() { } //必须要覆写抽象方法
}
使用原则
接口必须要被子类实现(implements), 一个子类可以实现多个接口
子类(如果不是抽象类)一定要覆写接口中的全部抽象方法
接口对象可以利用子类对象的向上转型进行实例化
子类可继承抽象类并且实现接口(要先继承再实现)
一个接口可以继承若干个父接口
重要说明
接口可以通过Object接收
接口中的所有抽象方法的访问权限都是public
接口定义加强
JDK1.8之前, 最初不会让子类直接实现接口, 而是在中间追加一个过渡的抽象类(因
为不能保证接口的完善, 如果接口改动, 所有子类覆写的方法都要改)
全部由抽象方法和全局常量组成
JDK1.8之后, 为了解决以上缺陷, 允许接口中定义普通方法或static方法
接口中的普通方法必须用default声明
但还是该操作属于挽救方法, 不是必须不建议使用
接口开发中应该奉行 : 接口就是抽象方法
使用接口定义的标准
工厂设计模式
代理设计模式
抽象类与接口区别
例如 usb键盘接口, usb鼠标接口, 电脑不管插入的是键盘还是鼠标,只要符合usb标
准, 都能正常识别
所有子类都放在Factory类里, 在一个类里实现所有功能, 主类(客户端)只关注IFood,
而不关注Food是Bread还是Milk
Ieat eat = new EatProxy(new Eat()) ;
eat.get() ; //吃东西
EatProxy()包括准备食材, 做饭, 收拾碗筷等方法, 但主类只关心是不是真的Eat()了,
而不关心"Eat的代理"
代理主题负责真实主题的准备业务与收尾, 没有代理主题无法实现真实主题
定义关键字
abstract class 抽象类名称 {}
interface 接口名称 {}
组成
抽象类 : 构造, 普通方法, 静态方法, 静态常量, 普通成员
接口 : 抽象方法, 全局常量, 普通方法, static方法
权限
子类使用
抽象类 : 可以使用各种权限定义
接口 : 只能使用public
抽象类 : 子类通过extends关键字可以继承一个抽象类
接口 : 子类使用imprements关键字可以实现多个父接口
两者关系
使用
抽象类可以实现若干个接口
接口不允许继承抽象类, 但是允许继承多个父接口
抽象类或接口必须定义子类
子类一定要覆写抽象类或接口中的全部抽象方法
通过子类的向上转型实现抽象类或接口对象的实例化
两者都能使用的情况下优先考虑接口, 因为接口可以避免子类的单继承局限,
另外也需要先从接口进行整体设计
JDK1.5后, 泛型是为了解决"ClassCastException"的问题(对象向下转型的风险)
泛型问题的引出
Object范围太广了, 是造成泛型产生的主要依据
泛型的基本定义
参数的返回值类型可以由对象实例化时动态决定, 需要在类定义时定义占位符(泛型
标记)
如果未设置泛型类型会自动使用Object作为类型, 但编译时会提示警告信息
泛型定义完成后可以在实例化时进行泛型类型的设定
如 : Point<Interger> point = new Point<interger>() ; //必须用包装类, 不能用
int
这样point对象里所有泛型都会是Int类型(仅局限与此对象当中)
JDK1.7后, 可以简化为 :Point<Interger> point = new Point<>() ;
注意 : 不能局限数据类型对程序很危险, 开发时一般使用泛型操作, 不用Object
泛型通配符
可以接收所有的泛型类型, 并且不能修改里面的数据(允许获取),通配符"?"
例 :
?extends 类 : 设置泛型的上限
?extends Number 表示该泛型类型只能设置Number或Number的子类
?super 类 : 设置泛型的下限
?extends String表示该泛型只能用String或其父类
例 :
例 :
泛型接口
泛型也可以在接口中定义
两种实现方式
class MessageImpt implements IMessage<String> {}
interface IMessage<T> { }
class MessageImpt<S> implements IMessage<S> {}
例 :
例 :
泛型方法
泛型方法不一定要在泛型类中
例 :
public static <T> T fun(T temp) { }
利用包实现类的包装, 实际开发中, 所有的类都必须放在包里面
包的定义
包的导入
静态导入
生成jar文件
系统常用包
访问控制权限
为了类的方便管理, 而且很难包证类的不重复, 所以将类放在不同的目录中, 这个目
录就是包
package cn.mldn.demo ;
打包编译处理 javac -d . Demo.java
将 *.class文件保存在定义的目录中
"-d": 表示要生成的目录, 目录的结构就是package定义的结构
"." : 表示程序类文件生成在当前目录中
定义包, 点表示分割子目录(子包)
java cn.mldn.demo.Demo
带着包执行程序类
不同包中的类存在有互相调用的关系, 这时就需要用import语句来导入其他包中的
程序类
例 :
package cn.mind.util ;
public class Message {
public String getContent() {
return "这是一条消息" ;
}
}
package cn.mind.demo ;
import cn.mind.util.Message ;
//导入其他包的类
public class Demo {
public static void main(String args[]) {
Message msg = new Message() ;
System.out.println(msg.getContent()) ;
}
}
javac -d . *.java
编译所有文件, 自动决定编译顺序
注意public class与class区别
public class
一个*.java文件里只允许有一个public class, 定义为public class才能被其他包使用
class
类名称可以与文件名称不一致, *.java里可以有多个, 但是外包无法访问
开发标准 : 一个*.java里只提供一个程序类
包名称必须用小写
还有一个形式 : import cn.mind.util.*
" 包.* "的导入形式并不是全部加载, 只会加载有被调用的包
".*"的方式只导入下一级的类, 再下一级的类要另外导入
用包.*和用具体的类性能是相同的
不同的包有同名的类时会出现引用不明确
解决 : 调用时用完整名称,
cn.mind.util.Message msg = new cn.mind.util.Message()
JDK1.5后对于全是static方法的类可用静态导入
import static cn.mind.util.Message.* ;
作用 : 该类中的static方法可由主方法直接调用
但是很少有人这么写, 很不方便
一个项目有大量的*.class文件, 把相关的文件用文件管理打包成一个压缩文件结构,
这样的结构就是jar文件
jar -cvf demo.jar cn
"-c" : 创建一个新的jar文件
"-v" : 得到一个详细输出
"-f" : 设置要生成的jar名称(demo.jar)
jar的使用
每个jar文件都是一个独立的文件路径
SET CLASSPATH = . ;D:\Code\Java\demo.jar
我的电脑不知道为什么没其作用?
cmd窗口配置临时环境变量(窗口关闭会恢复默认)
编译时会从demo.jar目录里查找*.class文件
*.jar没有配置正确会出现错误
java.lang.ClassNotFoundException: cn.mind.demo.Demo
JDK1.9后的模块化操作(了解概念)
JDK1.9之前提供的是一个所有类的*.jar文件(rt.jar、tools.jar, 需要在CLASSPATH
里配置这两个文件), 那么启动Java虚拟机就需要加载这两个几十兆的类文件
JDK1.9后的模块化(Module)设计 : 启动时根据程序加载指定的模块(模块中有包),
启动速度变快了
Java自身提供的(除了JDK提供类库外还会有有一些标准)
第三方厂商提供的
常见
java.lang
String, Number,Object等类里面, 该包自动默认导入
java.lang.reflect
反射机制处理包, 所有的设计由此开始
java.util
工具类的定义, 包括数据结构的定义
java,io
java.net
输入与输出流操作的程序包
网络程序开发的程序包
Java.sql
进行数据库编程的开发包
java.applet
Java最原始的使用形式, 直接嵌套在网页上执行的程序类
现在的程序已经以Application为主了(有主方法的程序类)
java.awt, javax.swing
java的图形界面开发包(GUI), 其中awt是属于重量级的组件, swing是轻量级组件
private
default(缺省(早期直译), 即不写)
protected
public
同一包中的同一类, 同一包中的不同类
同一包中的同一类
同一包中的同一类, 同一包中的不同类, 不同包的子类
同一包中的同一类, 同一包中的不同类, 不同包的子类, 不同包的所有类
共有四种权限
权限使用参考方案
属性定义全部使用private
方法定义全部使用public
类图
时序图
用例图
UML类图是统一的建模语言, 本质是利用图形化的形式来实现程序类关系的描述(现
在很多人都不使用类图了,都是写完程序再转换出来)
往往三层结构
类名称
属性
方法
普通类直接编写, 抽象类使用斜体, 往往再加上"abstract"
使用"访问权限 属性名称 : 属性类型" 的格式
访问权限的描述: public(+), protected(#), private(-)
使用"访问权限 方法名称(): 返回值" 的结构描述
工具
可以使用PowerDesigner
描述代码的执行流程
描述的是程序的执行分配(不同用户具备不同功能)
项目设计过程中出现得比较多
单例设计
多例设计
要求一个类只允许提供一个实例化对象
例 :
懒汉式
饿汉式
特点 : 构造方法私有化, 类内部提供static方法获取实例化对象
在系统加载类时就会自动提供类的实例化对象, 之前定义类都是懒汉式
后面要考虑线程同步问题
可以保留多个实例化对象, 构造方法也是私有化
例 :
Java在JDK1.5后才提出枚举, 主要作用是用于定义有限个对象的一种结构, 枚举就属
于多例设计, 并且比多例设计简单(enumeration [ɪˌnuːməˈreɪʃn] )
定义枚举类
enum关键字
例 :
switch中的枚举项判断
例 :
Enum类
定义枚举结构
枚举应用案例
JDK1.5后提供的关键字用于定义枚举类
是一个抽象类, 使用enum关键字定义的类就默认继承了此类
public final String name()
public final int ordinal()
方法
获得对象名字
获得对象序号
例 :
与正常类一样可以定义私有属性, 构造方法, 也可以实现接口, 覆写方法等等
不一样的是枚举可以直接定义抽象方法, 要求每个枚举对象都要独立覆写此抽象方
法
但是这个好像没什么用处
枚举的定义非常灵活, 但是更多时候建议使用它的正确用法, 就是定义一个范围, 实
例对象即可
其实不用枚举也能实现
认识异常对程序的影响
处理异常
可处理多个异常
异常处理流程
thows关键字
throw关键字
异常处理模型
RuntimeException
自定义异常类
assert断言
异常指导致程序中断执行的指令流
出现错误会中断程序执行
try, catch, finally几个关键字
基本处理结构
例 :
printStackTrace()方法可以获得完整异常信息
产生异常
自动实例化相关异常对象
存在异常处理?
true
false
try捕获实例化对象
catch匹配?
true
false
处理异常
catch 2匹配?
true
false
打印异常信息
程序中断执行
处理异常
执行final代码
以处理?
Stop
true
false
其他代码
内存简单分析
new
per, an
person, Animal
内存空间
Error
Exception
程序未执行出现的异常, 开发者无法处理
程序执行中出现的异常, 开发者可处理
可用Exception处理所有异常
catch (Exception e) { }
但是Exception描述的异常信息不明确
一般将捕获范围大的异常类型放后面
是在方法上定义使用的, 将此方法可能产生的异常告诉使用者, 由使用者处理
public void fun() throws Exception { }
在代码块中使用的, 手工产生一个异常类的实例化对象, 并且进行异常的抛出处理处
理
try {
throw new Exception("抛出的异常信息") ;
} catch (Exception e) { }
与Exception区别
RuntimeException是Exception子类
RuntimeException标注的异常不需要强制性处理, 而Exception必须强制处理
常见RuntimeException异常
NumberFormatException, ClassCastException, NullPointException
开发中只要是用throws定义的方法都必须要求开发中进行手工处理, 这样编写太麻
烦了, 所以提供灵活可选的异常处理父类"RuntimeException", 该类的子类不需要
强制性处理
两种方案
继承Exception
继承RuntimeException
例 :
JDK1.4后追加的功能, 确定代码执行到某一行时所期待的结果, 程序中没有强制执
行, 只是一种检测手段
要想执行断言, 运行要时加 "-ea"
java -ea Demo
例 :
内部类的基本概念
内部类的相关说明
static定义内部类
方法中定义内部类
匿名内部类
在一个类的内部定义其他的类, 这样的类成为内部类
例 :
目的是为了让内部类可以直接访问外部类的私有属性, (如果写在外部,则需要实例化
外部类, 调用getter方法才能访问私有属性,比较麻烦)
同样外部类也可以轻松访问内部类的私有属性
在外部也可以产生内部类的实例化对象, 格式 :
外部类.内部类 内部类对象 = new 外部类().new 内部类() ;
编译完会形成一个 "外部类$内部类.class" 类文件
因为内部类可以访问外部类的私有属性, 内部类实例化时一定要保证外部类已经实
例化了
让内部类只允许外部类访问
使用private定义类
内部接口
抽象类与接口中都可以定义内部接口
JDK1.8后, 接口中追加了static, 不受实例化对象的控制, 可以实现内部 利用类实现
接口
Outer.Inner inner = new Outer.Inner() ;
看到这个应该立即想到是static内部类
static定义内部接口(比static定义内部类常用)
用static定义内接口部是因为这些接口时一组相关的定义, 可以更明确的描述出这些
接口的主要目的, 功能(方便做统一管理)
例 :
例 :
JDK1.8后内部类中才可以直接访问方法中的参数, 之前必须给参数加final, 取消这样
的限制是为了其扩展的函数式编程准备的
一种简化的内部类的处理形式, 主要在抽象类和接口上使用的, 是一个没有名字只能
使用一次,且结构固定的子类操作
如果一个子类只需要使用一次, 那么没必要定义成一个单独的类, 只需使用匿名内部
类
例1 :
例2(为了更方便的体现出匿名内部类的使用) :
JDK1.8开始引入的, 函数式编程可以避免一些面向对象编程中一些繁琐的处理问题
Lambda表达式
方法引用
内建函数式接口
说明
比较著名的函数式编程语言
haskell
Scala
可以简化代码
实现要求
SAM(Single Abstract Method), 即只允许一个抽象方法
格式
方法没有参数 : () ->{ } ;
方法由参数 : (参数, 参数) ->{ } ;
如果只有一行语句返回 : (参数, 参数) ->语句 ;
JDK1.8后提供的, 不同的方法名称可以描述同一个方法, 但必须是函数式接口
引用静态方法
类名称 :: static 方法名称
引用某个实例对象的方法
引用形式
实例化对象 :: 普通方法
引用特定类型的方法
特定类 :: 普通方法
引用构造方法
类名称 :: new
为了方便直接引用系统中提供的函数式接口
java.util.function开发包
功能型函数式接口()
例 :
消费型函数接口
只能进行数据处理操作, 而没有任何的返回
例 :
供给型函数式接口
没有接收参数, 但是有返回值
例 :
Supplier<T>
T get()
Consumer<T>
void accept(T t)
Function<T,R>
R apply(T t)
有接收参数, 也有返回
断言型函数式接口
进行判断处理
例 :
Predicate<T>
链表实现简介
数据增加
获取集合个数
空集合判断
返回集合数据
根据索引取得数据
链表(修改指定索引数据)
链表(判断数据是否存在)
链表(数据删除)
链表(清空链表)
链表的本质是一个动态的对象数组, 它可以实现若干个对象的存储, 利用引用的逻辑
关系来实现类似于数组的数据处理操作
由于传统的数组长度是固定的, 依赖于角标的控制, 应用很有限(数组的接收及循环处
理)
例(过程) :
数组根据索引获取数据的时间复杂度是1, 而链表为n, 见例
例 :
Eclipse简介
使用JDT开发Java程序
代码调试
junit测试工具
bin
保存所有的*.class文件, 这些文件会自动进行编译处理
src
保存所有*.java源文件
切换UTF-8编码
Window → Preference → Workspace
工作空间
常用快捷键
Ctrl + 1
代码纠正提示
Alt + /
进行代码提示
Ctrl + /
单行注释
Ctrl + Shift + O
自动导入需要的包
Ctrl + Shift +
查看快捷键
source菜单栏
包括自动生成setter, getter方法
覆写toString
......
将类导出为*.jar文件
File → Export
导入*.jar文件
项目上右键 → 属性 → JavaBuid Path → Libraries → ClassPath
设置断点
使用调试模式
调试工具
F5 : 单步跳入
F6 : 单步跳过
F7 : 单步返回
F 8 : 恢复执行
白盒测试和黑盒测试之外, 还有用例测试 ,JUnit就是用例测试
......
类变量也称为静态变量,在类中以 static 关键字声明,但必须在方法之外
例 :
实现思路
1.定义接口ILink<E>, 添加操作链表的各种方法
2.创建类LinkImple<E>实现接口ILink<E>
3.创建私有内部类Node<E>用于保存数据E data;, 和下一个节点Node next;
4.ILink<E>创建用于操作链表的方法(以add(E data)为例)
1.判断data是否为null
2.实例化一个Node, newNode
3.根节点root保存
4.内部类Node里创建方法addNode(Node newNode)用于保存节点
简单工厂设计模式
工厂方法设计模式
抽象工厂设计模式
例 :
例 :
例 :
1、抽象产品
2、具体产品
3、具体工厂
4、产品使用者
抽象产品类
具体产品类
抽象工厂类
具体工厂类
角色:和工厂方法一样
同一种类型的一组数据, 按照一定顺序排列, 只有一个名字, 按照编号方式管理数据
创建数组开辟一整块连续空间, 数组名指向该空间首地址(多维数组即一个数组里存
放另一个数组的首地址)
byte : 0 ; int : 0 ; boolean : false ; char : "\u0000"(空字符) ; 引用数据类型 : null
;
例 :
二维数组遍历
例 :
可以 : 数组类型 数组名称 [][] = new 数据类型 [行数][] ;
//只固定行数
数组类型 [] 数组名称 [] = new 数据类型 [行数][列数] ;
二维数组打印杨辉三角形
例 :
其他
面向过程(POP), Procedure Oriented Programming
是一种以过程为中心的编程思想, 就是分析出解决问题所需要的步骤,然后用函数
把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
7.其他
高内聚
尽可能类的每个成员方法只完成一件事(最大限度的聚合)
低耦合
减少类内部,一个成员方法调用另一个成员方法。
MVC是常用的设计模式之一,将整个程序分为三个层次:视图模型层,控制器层,
与 数据模型层。
数据模型层
Model 主要处理数据
数据对象封装 : model.bean/domain
数据库操作类 : model.dao
数据库 : model.db
视图层
View 显示数据
相关工具类 : view.utils
自定义view : view.ui
控制层
Controller 处理业务逻辑
应用界面相关 : controller.activity
存放fragment : controller.fragment
显示列表的适配器 : controller.adapter
服务相关的 : controller.service
抽取的基类 : controller.base
JavaBean
JavaBean是一种Java语言写成的可重用组件, 是一个类(就是一个简单的类标准起了
个名叫JavaBean)
标准
类是公共的
有一个无参的公共的构造器
有属性,且有对应的get、set方法
常用于数据库的对接
例 :
View → Controller → Model → DataBase
例
controller
model
view
UserService
User
UserManager
Test
UserView
注意
不要仅为了获取其他类的某个功能而继承, 要考虑其中关系
同一个工程
同一个包, 不同子类
同一个包
Java只支持单继承
子类不能访问父类中的private属性和方法
导入第三方开发包
Project → Properties(属性) → Java Build Path → Libraries → ClassPath →Add
External JARs
子类抛出的异常级别不能高于父类抛出异常
例 :
返回值
父类返回引用数据类型, 子类只能返回其引用数据类型及其子类
父类是基本数据类型, 子类返回值类型必须相同
引用父类属性, 父类构造, 父类方法
访问属性
如果本类中没有, 则从父类中查找
访问方法
如果本类中没有, 则从父类中查找
父类的引用指向子类的对象
例 :
Java引用变量有两个类型
编译时类型
运行时类型
属性是在编译时确定的(声明的类型),而方法的调用是在运行时确定的(new出的类)
动态绑定
虚拟方法调用
只有等到方法调用的那一刻,解释运行器才会确定所要调用的具体 方法,这称“动
态绑定”
静态绑定
对于重载而言,在方法调用之前,编译器就已经确定了所要调用的方法, 这称“静
态绑定”
面试题 : 覆写与重载区别
对File, String, Data, 以及包装类(Wrapper Class)来说, 比较的是内容而不考虑是否
是同一个对象, 因为在这些类中重写了Object中的equals方法
equals()覆写步骤
2.判断是否属于要进行比较的类, instanceof
3.判断是否为null
4.强制类型向上转换, 并比较所有属性是否都相等
1.判断两个对象的地址值是否相同, 是就返回true
面试题 "==" 与equals区别
"=="是一个, equals是一个方法
"=="可以比较的数据的值, 也可以比较引用数据类型, equals()只可以比较引用数据
类型(地址值)
子主题
重载和重写都是实现多态的方式, 重载实现编译时的多态性, 重写实现运行时的多态
性
重载发生一个类里面, 同名的方法有不同的参数列表(参数数量, 参数类型)
重写发生在子类和父类之间, 子类重写的方法与父类的方法有相同的返回值类型,
修饰符的访问权限要大于被重写的方法
重写方法抛出的异常不能比父类抛出的要宽泛
方法
clone()
hashCode()
两个对象hashCode()相等, 这两个对象equals()..
......
finalize()
notifyAll()
notify()
Object o = true?new Integer(1):new Double(2.0); //编译时"1"就转为了Double
//打印o为1.0
Java多线程编程
线程常用操作方法
线程的同步与死锁
综合实战:“生产者消费者模型
多线程深入话题
多线程综合案例
Java基础类库
数字操作类
日期操作类
正则表达式
国际化程序实现
开发支持类库
比较器
类库使用案例分析
文件操作
字节流与字符流
I0操作深入
输入与输出支持
对象序列化
JavalO编程案例
认识反射机制
反射应用案例
反射与类操作
反射与简单Java类
ClassLoader类加载器
反射与代理设计模式
反射与Annotation
类集框架简介
List集合
Set集合
集合输出
Map集合
集合工具类
Stream数据流
网络编程
Java数据库编程基础操作
Statement数据库操作接口
PreparedStatement数据库操作接口
进程与线程
Thread类实现多线程
Runnable接口实现多线程
Thread与Runnable关系
Callable接口实现多线程
多线程运行状态
线程的命名和取得
线程休眠
线程中断
线程强制运行
线程礼让
线程优先级
同步问题引出
线程同步处理
线程死锁
生产者与消费者基本程序模型
解决生产者-消费者同步问题
利用Object类解决重复操作
优雅的停止线程
后台守护线程
volatile关键字
数字加减
生产电脑
竞争抢答
StringBuffer类
CharSequence接口
AutoCloseable接口
Runtime类
System类
Cleaner类
对象克隆
Math数学计算类
Random随机数生成类
大数字处理类
Date日期处理类
SimpleDateFormat类日期处理类
认识正则表达式
常用正则标记
String类对正则的支持
java. util.regex包支持
国际化程序实现原理
Locale类
ResourceBundle读取资源文件
实现国际化程序开发
格式化文本显示
UUID类
Optional类
ThreadLocal类
定时调度
Base64加密与解密
比较器问题引出
Comparable比较器
Comparator比较器
二叉树结构简介
二叉树基础实现
二叉树数据删除
红黑树原理简介
StringBuffer使用
随机数组
Email验证
扔硬币
IP验证
HTML拆分
国家代码
学生信息比较
File类基本操作
File类操作深入
获取文件信息
综合案例:列出目录结构
综合案例:文件批量更名
流的基本概念
OutputStream字节输出流
InputStream字节输入流
Writer字符输出流
Reader字符输入流
字节流与字符流的区别
转换流
综合实战:文件拷贝
字符编码
内存操作流
管道流
RandomAccessFile
打印流
System类对IO的支持
BufferedReader缓冲输入流
Scanner扫描流
对象序列化基本概念
序列化与反序列化处理
transient关键字
数字大小比较
文件保存
字符串逆序显示
数据排序处理
数据排序处理深入
奇偶数统计
用户登录.
投票选举
反射机制简介
Class类对象的三种实例化模式
反射实例化对象
反射与厂设计模式
反射与单例设计模式
反射获取类结构信息
反射调用构造方法
反射调用普通方法
反射调用成员
Unsafe工具类
传统属性赋值弊端
属性自动赋值实现思路
单级属性赋值
ClassLoader类载器简介
自定义ClassLoader处理类
静态代理设计模式
动态代理设计模式
CGLIB实现代理设计模式
反射取得Annotation信息
自定义Annotation
工厂设计模式与Annotation整合
类集框架简介
Collection接口简介
List接口简介
ArrayList子类
ArrayList保存自定义类对象
LinkedList子类
Vector子类
Set接口简介
HashSet子类
TreeSet子类
分析TreeSet子类排序操作
分析重复元素消除
Iterator迭代输出
ListIterator双向迭代输出
Enumeration枚举输出
foreach输出
Map接口简介
HashMap子类
LinkedHashMap子类
Hashtable子类
Map.Entry内部接口
利用Iterator输出Map集合
自定义Map的key类型
Stack栈操作
Queue队列
Properties属性操作
Collections工具类
Stream基本操作
MapReduce基础模型
网络编程简介
Echo程序模型
BIO处理模型
UDP程序
JDBC简介
连接Oracle数据库
Statement接口简介
Statement实现数据更新
Statement实现数据查询
Statement问题分析
PreparedStatement接口简介
使用PreparedStatement实现数据查询操作
进程
线程
传统的DOS中如果出现病毒, 所有程序将无法执行, 因为用的是单进程处理
后来Windows的时代开启了多进程的设计, 所有进程轮流抢占执行, 但同一时间
点只会有一个进程执行
线程是在进程的基础上创建的, 依赖于进程,但线程启动速度比进程快很多
Java是多线程的编程语言,所以Java在进行并发访问处理时可以得到更高的处理性
能
需要有一个线程的主体类来实现多线程的定义,该定义必须要实现特定的接口或继
承特定的类
Java中有java.lang.Thread程序类,一个类只要继承了此类就表示这个类为线程的
主体类
实现
继承Thread类
覆写Thread类中的run()方法(这个就是线程的主方法)
用Thread类中的start()方法调用run(), 要实现多线程不能直接调用run()方法, 因为
这里涉及到系统调用的问题
例 ;
new MyThread("线程A").start();
如果是new MyThread("线程A").run(); 则会按顺序执行
执行顺序是交替的, 不可控的
注意
每个线程类的对象值允许启动一次, 如果重复启动则抛出异
常"java.lang.illegalThreadStateException"
Thread的执行分析
在开发中对于多线程的实现, 优先考虑Runnable接口实现, 然后通过Thread类对象
启动多线程
例 :
由于只是实现了Runnable接口对象, 此时线程主体类没有单继承的局限, 这样的设
计才是一个标准型设计
Runnable接口使用了函数式接口定义, 所以也可以直接利用Lambda表达式进行线
程类定义
public Thread(Runnable target)
Runnable有一个缺点 : 线程执行完后没有返回值(run()方法没有返回值), JDK1.5后
就提出了一个新的线程实现接口 : java.util.concurrent.Callable 接口
Callable定义时可设置一个泛型
所有多线程的实现都要通过Thread类中的start()方法
Thread接收Runnable对象
面试题 : Runnable于Callable的区别
Runnable是在JDK1.0时提出的接口, Callable时在1.5后提出的
java.lang.Runnable接口中值提供一个run()方法, 没有返回值
java.util.concurrent.Callable接口提供有call()方法, 可以有返回值
例 :
创建
public class Thread extends Object implements Runnable
Thread 是Runnable的子类
多线程设计中使用了代理设计模式, 用户自定义的线程主体只是负责项目核心功能
的实现, 而所有的辅助功能全交由Thread处理
通过Thread类实现Runnable接口对象时, 该接口对象会被Thread中的target属性保
存 : 在start()方法执行时会调用Thread中的run()方法, 而这个run()方法会调用
Runnable接口子类覆写过的run()方法
start()
就绪状态
← 调度 →
运行状态
终止
阻塞状态
构造方法
public Thread(Runnable target,
String name)
设置名字
取得名字
public final String getName()
public final void setName(String name)
如果没有设置则会自动生成一个不重复的名字"Thread-编号"
关系
FutureTask(Callable<V> callable)
FutureTask类接收Callable对象, Callable有个call()方法, Future(FutureTask的实
现接口)的get()返回call()方法返回值
Thread和FutureTask都是Runnable的子类
public interface RunnableFuture<V>
extends Runnable, Future<V>
Future<V>里有个 get()方法
//由get()获得Callable对象里call()的返回值
public class FutureTask<V>
extends Object
implements RunnableFuture<V>
简化 : FucturetTask接收到Callable,再传递到Thread里实现调用
可以这样记 : Thread接收的参数都是Runnable接口的子类对象
返回正在执行的线程对象
public static Thread currentThread()
例 : Thread.currentThread().getName() 返回当前线程名字
发现主方法是个名字为"main"的线程
说明
java命令执行程序启动时就启动了一个JVM进程, 一台电脑可以同时启动多个JVM
进程
任何开发中, 主线程可以创建若干个子线程, 创建子线程的目的是为了将一些复杂比
较耗时的逻辑交由子线程处理
public static void sleep(long millis) throws InterruptedException
public static void sleep(long millis, int nanos) throws InterruptedException
millis(毫秒)
中断异常 "InterruptedException"必须被处理
特点 : 定时自动实现线程的唤醒
多个线程对象休眠是有轮流的, 并不是同步的
public boolean isInterrupted()
检测线程是否被中断
public void interrupt()
中断线程执行
例 :
让某一个线程可以独占资源, 一直执行, 直到结束
public final void join(long millis) throws InterruptedException
超时设为0,或不填,表示永远等待
例 :
public static void yield()
每一次调用yield()方法都只会礼让一次当前的资源
线程的优先级越高越有可能先执行(越有可能先抢占资源)
public final void setPriority(int newPriority)
priority(优先)
public final int getPriority()
参数 : MAX_PRIORITY(10), NORM_PRIORITY(5), MIN_PRIORITY(1)
主方法和默认创建的线程都是中等优先级
例 :
Runnable描述多个线程的操作资源, 而Thread描述每一个线程对象, 多个线程访问
同一资源时处理不当会产生数据的错误操作
例 :
解决同步问题的关键时锁, 即当某一线程正在执行时其他线程外面等待
同步代码块
synchronized(同步对象){
同步代码操作 ;
}
例 :
注意 : 同步实际上会造成性能的下降
同步方法
两种方案
例 : public synchronized void 方法名(){ }
系统中许多同步处理用的都是同步方法
死锁指的是若干个线程彼此互相等待的状态
例 :
public final void wait() throws InterruptedException
等待线程,直到被notified(唤醒)或interrupted
public final void wait(long timeoutMillis) throws InterruptedException
public final void wait(long timeoutMillis, int nanos) throws
InterruptedException
等待线程
设置等待时间
唤醒
public final void notify()
唤醒第一个等待线程, 其他的继续等待
public final void notifyAll()
唤醒所有等待线程, 线程优先级高级有可能先执行
例 :
设计更改某一属性就能让线程退出, 或其他方式, 让线程运行完毕, 而不是强制停止
主线的程序或其他的线程还在执行时, 守护线程将一直存在, 并且运行在后台状态,
如果用户线程结束, 守护线程也将结束, JVM里最大的守护线程就是GC线程
public final void setDaemon(boolean on)
public final boolean isDaemon()
设置守护线程
判断是否时守护线程
在属性定义上使用, 表示此属性为直接数据操作, 而不进行副本的拷贝(不要将其错误
地理解为同步属性) ,
正常变量处理步骤 : 获取变量原有数据内容→利用副本为变量进行数学计算→将计
算后的变量保存到原始空间之中
作用 : 更快地进行变量修改处理
append()
insert()
public StringBuffer delete(int start, int end)
删除指定范围数据
public StringBuffer replace(int start, int end, String str)
替换指定范围字符串
public StringBuffer reverse()
字符串内容反转, StringBuffer的最大特征
调用wait()的方法需是synchronized的, 用super.wait()或wait()
例
面试题 : String, StringBuffer, StringBuilder类最大区别
String类是字符串的首选类型, 最大特点是内容不允许修改
StringBuffer与StringBuilder类的内容允许修改
StringBuffer是在JDK1.0的时候提供,属于线程安全的操作, 而StringBuidler是
JDK1.5后提供的,属于非线程安全操作
描述字符串结构的接口, String, StringBuffer和StringBuffer都实现了该接口
方法
char charAt(int index)
CharSequence subSequence(int start, int end)
int length()
获取字符串长度
获取指定索引字符串
截取字符串
实现资源的自动关闭, 释放资源
JDK1.7后提供的, 只有提供有一个方法
void close() throws Exception
描述的是运行时的状态, 是唯一一个与JVM运行状态有关的类,并且默认提供有一个
实例化对象
每一个JVM进程里只允许提供有一个Rnutime对象(单列设计模式)
public static Runtime getRuntime()
获取Runtime实例化对象
public static void arraycopy(Object src, int srcPos, Object dest, int destPos,
int length)
public int availableProcessors()
获取本机中的CPU内核数
例 :
内核数决定了最佳并发访问量
public long maxMemory()
返回最大可用内存空间, 默认配置为本机系统内存的1/4
public long freeMemory()
返回可用空闲内存空间, 默认配置为本机系统内存的1/64
public long totalMemory()
返回全部可用内存空间
public void gc()
手工GC处理
面试题 :
GC(Garbage Collector)垃圾收集器, 可以由系统自动调用的垃圾释放功能 或由
Runtime类中的GC()手工调用
public static long currentTimeMillis()
数组拷贝
返回当前时间戳, 可用于计时
public static void gc()
进行垃圾回收(这个gc()是调用了Runtime类中的gc操作:
Runtime.getRuntime().gc() ;)
JDK1.9之后提供的一个对象清理操作, 替代之前的finalize()方法(对象回收前的收尾
操作)
JDK1.9之后建议使用AutoCloseable()或者使用java.lang.ref.Cleaner类进行回收处
理(Cleaner类也支持AutoCloseable处理)
例 :
新版本的对象回收前的处理通常单独通过一个线程完成,以防止由可能造成的延迟处
理, 以提高进程的整体执行性能
指对象的复制, 创建一个新的对象
protected Object clone() throws CloneNotSupportedException
被克隆的对象要求实现Cloneable接口(该接口描述的是"能力", 没有方法,是一个表
示接口)
例 :
实际开发中很少会用到对象克隆需求
public final class Math
extends Object
Math提供有很多计算的基础公式,具体看JavaDoc
自定义一个四舍五入功能
public int nextInt(int bound)
返回一个int类型随机数,bound: 上限
例 :
超过double范围的数字处理
BigInteger类
BigDecimal类
public BigInteger add(BigInteger val)
加法
public BigInteger subtract(BigInteger val)
相减
public BigInteger multiply(BigInteger val)
相乘
public BigInteger divide(BigInteger val)
相除
......
例 :
大数字的计算过程是很缓慢的
public BigInteger[] sqrtAndRemainder()
求余除法, 返回第一个是商, 二是余数
public BigInteger[] divideAndRemainder(BigInteger val)
开根
小数计算, BigInteger是整数计算, 注意这个涉及到进位问题
......
将long(时间戳)转为日期
public Date(long date)
public long getTime()
将日期转为时间戳
例 : System.out.println(new Date().getTime());
S例 : ystem.out.println(new Date(1594566383));
对日期显示格式进行格式化处理
public final String format(Date date)
构造方法 : public SimpleDateFormat(String pattern)
public Date parse(String source) throws ParseException
将日期格式化
将字符串转为日期,parse(解析)
--日期格式: 年(yyyy), 月(MM), 日(dd), 时(HH),分(mm), 秒(ss), 毫秒(SSS)
其他看JavaDoc
例 :
设置日期格式
字符串格式为设置的日期格式
如定义格式时时间日期超过合理范围, 则会自动进行进位处理
其他 : 数字也可格式化, NumberFomat类
JDK1.4后正则已经默认被JDK支持
特点 : 方便进行验证处理, 以及复杂字符串的修改处理
java.util.regex(regular expression)包里的Pattern类定义有所有支持的正则标记
字符匹配(单个)
任意字符
\\ : 表示"\"
\n : 匹配换行
\t : 匹配制表符
字符集(单个)
可以从里面任选一个
[abc] : 表示可能是a, b, c中的任意一个
[^abc] : 表示没有有a,b,c中的任意一个
[a-zA-Z] : 表示有一个字母组成, 不区分大小写
[0-9] : 表示由一位数字组成
单个数量
. : 表示任意一个字符
\d : 表示一个数字, 等价于[0-9]
\D : 表不是一个数字, 等价于[^0-9]
\s : 匹配任意一个空格, 可以是换行符, 制表符
\w : 匹配任意字母, 数字, 下划线,等价于[a-zA-Z_0-9]
\W : 匹配非字母,数字, 下划线
^ : 匹配边界开始
边界匹配
$ : 匹配边界结束
数量表示
默认情况下只有添加了数量单位才可以匹配多位字符
表达式? : 该正则可以出现0次或1次
表达式* : 该正则可以出现0次, 1次或多次
表达式+ : 该正则可以出现1次或多次
表达式{n} : 表达式长度为n
表达式{n,} : 表达式长度为n个次以上
表达式{n, m} : 表达式长度n~m次
逻辑表达式
可以连接多个正则
XY : 表达式X紧跟表达式Y,
X|Y : 有一个表达式满足即可
(X) : 为表达式X设置整体描述, 可以为整数描述设置数量单位
public boolean matches(String regex)
matcher类 : public boolean matches()
例 : str.matches("[abc]")
大部分正则操作用的都是String类
将指定字符串进行正则判断
public String replaceAll(String regex, String replacement)
public String replaceFirst(String regex, String replacement)
public String[] split(String regex, int limit)
public String[] split(String regex)
替换全部
替换第一个
正则拆分指定个数
正则拆分
简单例 :
验证邮箱格式 :
这个包定义有两个类 : Pattern(正则表达式编译), Matcher(匹配)
public static Pattern compile(String regex)
将正则表达式编译成pattern
public String[] split(CharSequence input)
也提供字符串拆分, 但是String类的正则拆分更方便
public Matcher matcher(CharSequence input)
如果只是拆分, 替换, 匹配三种操作, 只用String类就可以实现了
Pattern类提供的方法, 获得Matcher类对象
Pattern类
Matcher类
public String replaceAll(String replacement)
字符串替换
public boolean matches()
正则匹配
String类不具备的功能
分组, 例 :
专门描述区域和语言的类
public Locale(String language)
构造方法
public Locale(String language,
String country)
public Locale(String language,
String country,
String variant)
中文 : zh_CN, 美国 : en_US
public static Locale getDefault()
获取默认语言环境
Locale.CHINA ;
常量, 方便使用
例 :
public abstract class ResourceBundle extends Object
是一个抽象类
public static final ResourceBundle getBundle(String baseName)
获取ResourceBundle类对象
baseName : 描述的是资源文件的名称,但是没有后缀
根据key读取资源内容
public final String getString(String key)
属性文件 : *.properties
以key = values格式存储文件
一般这个文件作为一些参数的存储, 有利于以后的代码重构,维护
用于适应多语言环境,随着系统的语言环境的变化,读取不同的属性文件,显示对
应语言的UI
例 : info=jerrys
读取时key一定要存在, 否则会出现以下异常
java.util.MissingResourceException
读取顺序 : 指定区域的资源文件>默认的本地资源>公共资源(没有区域设置)
Message_zh_CN.properties
Message_en_US.properties
指定国家的区域资源文件
baseName是"Message"时,会读取系统默认区域的文件(根据文件名末尾区域代码)
可用Locale修改当前Locale环境
例 :
例 :
Message.properties
公共资源
info=欢迎{0}, date : {1}
有需要可以继续添加{2},{3}...
要将占位符的信息读取出来, 要利用MessageFormat类进行格式化处理
public static String format(String pattern, Object... arguments)
例 :
Object... arguments用逗号分隔, 依次对应{0}, {1}, {2} ...
开发中看到资源文件有"{0}", "{1}"的结构表示的都是占位符, 该信息一定要进行格式
化处理
universally unique identifier(通用唯一标识符), 生成无重复字符串的程序类
public static UUID randomUUID()
获取UUID对象, 返回的是UUID类型, 一般用toString()输出字符串类型
public static UUID fromString(String name)
根据字符串获取UUID内容
对一些文件自定命名处理的情况下, UUID非常好用
主要进行null的处理
public static <T> Optional<T> empty()
返回空的数据
public T get()
获取数据
public static <T> Optional<T> of(T value)
保存数据, 不允许出现空
如果保存数据时存在空,会抛出"NullPointerException"
public static <T> Optional<T> ofNullable(T value)
保存数据, 允许为空
public T orElse(T other)
空的时候返回其他数据
解决核心资源与多线程并发访问的情况
public ThreadLocal()
构造方法, 创建一个新的对象
public T get()
设置数据
public void set(T value)
取出数据
public void remove()
删除数据
例 :
每一个线程通过ThreadLocal只允许保存一个数据
进行定时任务的处理, 这种任务处理只实现了一种间隔触发的操作
需要一个定时操作的主体类, 以及一个定时任务的控制
public abstract class TimerTask
extends Object
implements Runnable
public class Timer
extends Object
设置定时任务处理
进行任务的启动, 启动的方法
public void schedule(TimerTask task, long delay)
任务启动, delay : 延迟(毫秒)
public void scheduleAtFixedRate(TimerTask task, long delay, long period)
间隔触发, period: 间隔时间(毫秒)
Base64.Decoder类
Base64.Encoder类
进行解密处理
进行加密处理, Encoder(编码器)
public byte[] encode(byte[] src)
public byte[] decode(byte[] src)
由于这是一个公版的算法, 直接对数据加密并不安全, 可使用盐值操作, 并且多次加
密。最好把盐值也给加密了, 同时使用几种加密程序, 找到一种不可解密的加密算法
例 :
public static Base64.Encoder getEncoder()
public static Base64.Decoder getDecoder()
Base64类
例 :
进行大小关系的确定判断,
使用java.util.Arrays的操作类完成, 这个类里提供有对象数组的排序支持
public static void sort(Object[] a)
例 :
int compareTo(T o)
public interface Comparable<T>
o: 要比较的对象 ; return: 当前数据比对象小返回负数, 大于则返回整数, 等于返回0
例 :
实现了comparable的类可以实现排序, 有对象数组的排序需求就用comparable
定义排序规则
程序开发时没考虑对象数组的排序, 后面需要排序对象又不能修改类时使用,
Comparator是一种挽救排序规则, 尽可能用comparable,不用comparator
public interface Comparator<T>
int compare(T o1, T o2)
例 :
与Comparable区别
java.lang.Comparable 主要用于定义排序规则, 只有一个compareTo()方法
java.util.Comparator 是挽救的比较操作, 需要定义单独的比较器规则类实现排序,
里面有compare()方法
以尽可能减少检索次数为出发点进行设计, 进行数据检索时要进行每个节点的判断,
但它的判断时区分左右的, 那么它的时间复杂度时O(logn)
原理 : 取第一个数据为保存的根节点, 取小于等于根节点的数据放在节点的左子树,
而大于节点的数据放在节点的右子树
数据获取有三种形式
前序遍历(根-左-右)
中序遍历(左-根-右)
后续遍历(右-根-左)
思路
创建BinaryTree<T>类 继承 Comparable<T>类(用于比较数据)
创建内部类Node(Comparable<T> data), 定义有父接点Node parent, 右子树
Node right, 左子树
创建功能实现方法,add(E data)为例
在Node类里创建addNode(Node newNode)方法用于保存节点在合适位置
如果待删除节点没有子节点,那么直接删掉即可;
如果待删除节点只有一一个子节点,那么直接删掉,并用其子节点去顶替它
如果待删除节点有两个子节点,这种情况比较复杂: 首选找出它的后继节点,然后处
理“后继节点”和"被删除节点的父节点”之间的关系,最后处理“后继节点的子节
点”和 "被删除节点的子节点”之间的关系。
要达到良好的查询效果的二叉数应该是个平衡二叉树, 同时所有节点的层次深度应
该相同
红黑树本质上是一种二叉查找树,但它在二叉查找树的基础上额外
添加了一个标记(颜色) , 同时具有一定的规则。这些规则使红黑
树保证了一种平衡,插入、删除、查找的最坏时间复杂度都为
O(logn)。
public class File
extends Object
implements Serializable, Comparable<File>
public File(String pathname)
构造方法
public File(String parent,
String child)
设置父路径与目录
public boolean createNewFile() throws IOException
创建新文件
public boolean exists()
判断文件是否存在
public boolean delete()
删除文件
Window分隔符 "\" , Linux分隔符 "/"
提供separator分隔符常量解决此问题
new File("D:"+File.separator+"textFile.txt")
new File("D:\\textFile.txt")
例 :
分隔符问题
但是随着系统的发展, 现在分隔符"\", "/" 也通用了
程序 → JVM → 操作系统函数 → 文件处理
注意 :
在进行同一文件复制删除或创建的时候可能会右延迟的问题的时候, 所以最好的方
案是别重名
文件操作时文件的父路径必须存在
获取文件父路径
public File getParentFile()
public boolean mkdirs()
创建多级目录
这样反复判断会影响一点性能, 最好是保证目录存在, 少做判断
例 :
public boolean canRead()
public boolean canWrite()
判断文件是否可读
判断文件是否可写
public long length()
返回文件大小(字节长度)
public long lastModified()
返回最后一次日期时间(时间戳)
public boolean isFile()
判断是否是文件
public boolean isDirectory()
判断是否是路径
public File[] listFiles()
列出目录内容, 返回Filie对象数组
例 :
例 :
例 :
更改目录下所有文件后缀名, 包括子目录
数据流指的是字节数据(二进制数据)
java.io包提供两类支持
字节处理流
OutputStream, InputStream
字符处理流
Writer, Reader
流操作步骤(以文件处理为例)
1.通过File类找到一个文件路径
2.通过字节流或字符流的子类为父类对象实例化
3.利用字节流或字符流中的方法实现数据的输入与输出操作
4.流的操作属于资源操作, 必须进行关闭处理
public abstract class OutputStream
extends Object
implements Closeable, Flushable
public void write(byte[] b) throws IOException
输出一组字节数据
public abstract void write(int b) throws IOException
输出单个字节数据
public void write(byte[] b, int off, int len) throws IOException
输出部分数据(off: 开始点, len: 长度)
方法
public class FileOutputStream
extends OutputStream
OutputStream属于抽象类, 需要通过子类向上转型获得实例
构造方法
public FileOutputStream(File file)
throws FileNotFoundException
public FileOutputStream(File file, boolean append)
throws FileNotFoundException
覆盖
追加
例 :
public FileInputStream(File file)
throws FileNotFoundException
public abstract class InputStream
extends Object
implements Closeable
方法
public abstract int read() throws IOException
读取当个字节数据 , 如果读取到底返回-1
public int read(byte[] b) throws IOException
读取一组字节数据,保存在字节数组b中, 并返回读取的个数, 读取到底则返回-1
public int read(byte[] b, int off, int len) throws IOException
读取部分数据(off: 开始点, len: 长度)
public byte[] readAllBytes() throws IOException
可以直接读取所有字节数据, 但是如果读取文件过大不能用
例 :
public void write(char[] cbuf) throws IOException
输出字符数组
public void write(String str) throws IOException
输出字符串
方法
public abstract class Writer
extends Object
implements Appendable, Closeable, Flushable
public class FileWriter
extends OutputStreamWriter
public class OutputStreamWriter
extends Writer
例 :
public abstract class Reader
extends Object
implements Readable, Closeable
方法
public int read(char[] cbuf) throws IOException
public abstract int read(char[] cbuf, int off, int len) throws IOException
public class FileReader
extends InputStreamReader
public class InputStreamReader
extends Reader
public int read() throws IOException
返回单个字符
读取字符数组保存到cbuf, 并且返回字符数组长度
读取部分字符数组(off: 开始点, len: 长度)
例 :
使用OutputStream和Writer时 最后都使用了close()方法
OutputStream没有用close()方法关闭输出流, 依然可以实现正常的输出, Writer不
行, 因为Writer使用了缓冲区
Close()方法会强制刷新缓存区, 想在不关闭的情况下输出全部内容, 可以使用flush()
方法强制清空缓存区
字节流没有使用缓冲区, 字符流使用了缓冲区, 使用缓冲区的字符流更适合中文数据
的处理
指实现字节流与字符流的功能转换
java.io包里提供右两个类
InputStreamReader
OutputStreamWriter
public class OutputStreamWriter
extends Writer
public class InputStreamReader
extends Reader
构造方法
public OutputStreamWriter(OutputStream out)
构造方法
public InputStreamReader(InputStream in)
例 : Writer writer = new OutputStreamWriter(out)
接收到的字节流对象通过向上转型变成字节流对象
字节流转字符流的继承结构
例 :
上例是最原始的拷贝实现, 而从JDK1.9开始InputStream和Reader类追加了数据转
存的处理方法 transferTo(), 该方法性能更高
public long transferTo(Writer out) throws IOException
InputStream:
public long transferTo(OutputStream out) throws IOException
Reader:
TransferTo() 例 :
最终代码(包括目录拷贝)
该程序是IO的基础核心, 要理解
常用编码
GBK/GB2312
国标编码, 可以描述中文信息, GB2312只有简体, GBK有简,繁
ISO8859-1
国际通用编码, 可以描述所有字母信息, 如果是象形文字则需要进行编码处理
UNICODE编码
采用十六进制的方式存储, 可以描述所有文字信息
UTF编码
象形文字部分使用十六进制编码, 普通字母采用ISO8859-1编码, 适合快速传输, 节
约带宽, UTF-8是我们开发中的首选编码
前面使用的都是文件操作流, 现在要进行IO操作, 又不希望产生文件(临时文件), 就以
内存为终端进行处理
字节内存操作流
字符内存操作流
public class ByteArrayOutputStream extends OutputStream
public class ByteArrayInputStream extends InputStream
public class CharArrayWriter extends Writer
public class CharArrayReader extends Reader
构造方法
构造方法
public ByteArrayInputStream(byte[] buf)
public ByteArrayOutputStream()
public byte[] toByteArray()
获取数据
例 :
实现两个线程之间的IO处理操作
OutputStream
Writer
连接()
InputStream
Reader
发送消息线程对象
(Runnable)
← 管道 →
接收消息线程对象
(Runnable)
字节管道流
字符管道流
public class PipedInputStream
extends InputStream
public class PipedOutputStream
extends OutputStream
public void connect(PipedInputStream snk) throws IOException
连接处理
public void connect(PipedWriter src) throws IOException
public class PipedReader
extends Reader
public class PipedWriter
extends Writer
public void connect(PipedReader snk) throws IOException
public void connect(PipedOutputStream src) throws IOException
例 :
public class RandomAccessFile
extends Object
implements DataOutput, DataInput, Closeable
可以由用户定义读取的位置, 数据可以按照固定的长度进行保存
根据实例化对象反推出其类型
"正"
1.导入程序需要的包
2.通过类产生实例化对象
3.根据对象调用类中的方法
"反"
1.获取Class类信息(根据实例化信息)
public final Class<?> getClass()
public final class Class<T> extends Object
implements Serializable, GenericDeclaration, Type, AnnotatedElement,
TypeDescriptor.OfField<Class<?>>, Constable
构造方法
public RandomAccessFile(File file, String mode)
throws FileNotFoundException
mode: 读写状态, "r", "rw, "rws", "rwd"
public int skipBytes(int n) throws IOException
public void write(byte[] b, int off, int len) throws IOException
跳过第n个字节开始操作
public void seek(long pos) throws IOException
回到第n个字节开始读取(设置指针偏移量)
例 :
public int read(byte[] b, int off, int len) throws IOException
从第off个字节开始写入len字节(覆写原位置内容)
......
标准输出(显示器)
public static final PrintStream out
错误输出
标准输入(键盘)
public static final InputStream in
public static final PrintStream err
System.out和System.err都是统一种类型, 在Eclipse中System.err会输出红色字体
可以修改输出位置
public static void setOut(PrintStream out)
public static void setErr(PrintStream err)
可以输出到文件里, 但一般不这么做, 没什么用
例 :
缺陷: 如果长度不足, 只能接收部分内容, 一般情况不这样输入
提供的是一个缓存字符输入流的概念, 可以利用这个类实现键盘输入数据的标准化
定义
public String readLine() throws IOException
读取一行数据
public class BufferedReader
extends Reader
例 :
java.util.Scanner, JDK1.5之后追加的类, 目的为了解决输入流的访问问题, 比
BufferReader方便点
实际开发中输入的一般是字符串
public Scanner(InputStream source)
构造 :
public boolean hasNext()
判断是否有数据
public String next()
取出数据
public Scanner useDelimiter(String pattern)
设置分隔符
例 :
Scanner最大特点是可以进行正则验证
public boolean hasNext(String pattern)
例 :
程序需要输出数据使用打印流, 输入数据使用Scanner(首选)或BufferReader
OutputStream输出功能有限: public void write(byte[] b) throws IOException,
开发中往往自定义一些功能类
打印流实现 例 :
设计思想 : 提高已有类的功能, 即"装饰设计模式"
在java.io包里提供有打印流: PrintStream(字节流), PrintWriter(字符流)
public class PrintWriter
extends Writer
public class PrintStream
extends FilterOutputStream
implements Appendable, Closeable
构造方法
public PrintStream(OutputStream out)
......
构造方法
public PrintWriter(OutputStream out)
......
public PrintWriter(Writer out)
public PrintWriter printf(String format, Object... args)
格式化输出
例 :
只要是进行内容输出, 全部使用打印流
指将内存中保存的对象以二进制数据流的形式进行处理, 可以实现对象的保存或网
络传输
堆内存中对象经二进制转换保存位置
文件中
服务器
数据库里(SQL)
Java中强制性要求
要序列化的对象要实现java.io.Serializable父接口, 作为序列化的标记(这个接口没
有方法, 只是描述了这个类的能力)
public class ObjectOutputStream
extends OutputStream
implements ObjectOutput, ObjectStreamConstants
序列化
public class ObjectInputStream
extends InputStream
implements ObjectInput, ObjectStreamConstants
反序列化
public ObjectInputStream(InputStream in) throws IOException
构造方法
构造方法
public ObjectOutputStream(OutputStream out) throws IOException
public final void writeObject(Object obj) throws IOException
public final Object readObject() throws IOException,
ClassNotFoundException
Java中的对象序列化处理必须使用内部提供的对象操作流, 因为牵扯到对象的二进
制处理。实际开发中很少能见到ObjectOutputStream, ObjectInputStream的直
接使用, 会有其他容器帮助完成
例 :
类中有一些属性不需要序列化处理, 可以使用transient关键字
private transient String name ;
在进行序列化的时候那么属性的内容不会被保存下来
由于开发中大部分被序列化的类往往都是简单的java类, 所以这一关键字出现的频率
不高
Class类
Object类
public final Class<?> getClass()
例 :
JVM支持 "类.class" 形式实例化
第一种
第二种
例 :
public static Class<?> forName(String className)
throws ClassNotFoundException
通过类名称(字符串) 获得类对象, 并且不需要import语句
第三种
Class<? extends Person> cls = per.getClass() ;
Class<? extends Person> cls = Person.class ;
例 :
Class<?> cls = Class.forName("cn.exercise.test.Person");
获取Class对象之后最大的意义不是在于对象的实例化操作形式, 更重要的是Class类
里提供有对象的反射实例化方法(代替了关键字new)
JDK1.9以前的实例化
@Deprecated(since="9") public T newInstance() throws
InstantiationException, IllegalAccessException
JDK1.9之后
public Constructor<?>[] getDeclaredConstructors() throws
SecurityException
例 :
实例化对象 关键字new 与 反射的选择
简单工厂设计模式
例 :
这种属于静态工厂设计模式, 每追加一个子类工厂就要追加判断
工厂设计模式要解决的是子类与客户端的耦合问题, 该例子中Factory要进行修改,
实际开发中要求Factory满足所有子类的修改
解决方案 : 不使用关键字 new, 因为new使用的时候要有一个明确的类存在,
newInstance()方法只需要一个表示类名称的字符串即可应用
例 :
小数高精度计算
public T newInstance(Object... initargs) throws InstantiationException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException
java.lang.reflect.Executable.Construtor<T>类
利用反射机制实现的工厂设计模式, 对于接口子类的扩充不会影响到工厂类
只有一个接口
例 :
有多个接口
先从简单的看起容易理解
上述例子中如果要定义其他接口, Factory还是要修改, 解决方案 : 用泛型 (客户端即
主方法要知道要使用的接口和方法名称)
例 :
这样的工厂设计模式才是真正实用的
单例设计模式本质在于 : 类内部的构造方法私有化, 在类的内部产生实例化对象后通
过static方法获取实例化对象进行类中的结构调用(本次只谈论懒汉式)
没考虑多线程的 例 :
单例设计最大特点是在运行过程中只允许产生一个实例化对象, 但是在使用多线程
时可以实例化多个, 此时就不是单例设计模式了
解决方案 : 进行同步处理, 在getInstance()方法加Synchronized可以解决, 但是这
样的效率太低, 实际上只有instance实例化对象部分需要同步处理
并发编程的3个基本概念
原子性
定义 : 即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打
断,要么就都不执行。
可见性
定义:指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程
能够立即看得到修改的值。
有序性
定义:即程序执行的顺序按照代码的先后顺序执行。
锁的两种主要特性
(1)互斥即一次只允许一个线程持有某个特定的锁,一次就只有一个线程能够使
用该共享数据。
(2)可见性要更加复杂一些,当一条线程修改了共享变量的值,新值对于其他线
程来说是可以立即得知的。
可见性(visibility)
互斥(mutual exclusion)
要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
a.对变量的写操作不依赖于当前值。
b.该变量没有包含在具有其他变量的不变式中。
???
例 :
面试题
编写一个饿汉式的单例设计模式, 并实现构造方法私有化
在Java中那里使用了单例设计模式 : Runntime类 ; Spring框架
懒汉式单例设计模式的问题
标准单例设计模式
获取类的基本信息(父类, 父接口)
类名.class, class.forName(), getClass()区别
其他
子主题
1.类名.class 说明: JVM将使用类装载器, 将类装入内存(前提是:类还没有装
入内存),不做类的初始化工作.返回Class的对象
2.Class.forName("类名字符串") (注:类名字符串是包名+类名) 说明:装入类,
并做类的静态初始化,返回Class的对象
3.实例对象.getClass() 说明:对类进行静态初始化、非静态初始化;返回引用运行
时真正所指的对象(因为:子对象的引用可能会赋给父对象的引用变量中)所属的类的
Class的对象
Class类
public Package getPackage()
获取指定类的包定义
public String getName()
获得包名称
public Class<? super T> getSuperclass()
获得父类信息
public Class<?>[] getInterfaces()
获取实现接口
.......
获取一个Class类后可以获取这个类的一切继承结构信息
例 :
Class类
public Constructor<?>[] getDeclaredConstructors()
throws SecurityException
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes
throws NoSuchMethodException, SecurityException
获取所有构造方法
获取指定构造方法, 要用Class定义参数类型, (包括public和非public)
建议反射的类中最好有无参构造, 因为这样的实例化可以达到统一性
例 :
通过反射获取类中的全部方法, 前提条件是类中要提供实例化对象
Class类
public Method[] getMethods()
throws SecurityException
获取全部方法(包括父类的方法)
例 :
public Method getDeclaredMethod(String name, Class<?>...
parameterTypes) throws NoSuchMethodException, SecurityException
获取指定的方法(包括父类), 权限包括public和非public
public Method getMethod(String name, Class<?>... parameterTypes) throws
NoSuchMethodException, SecurityException
获取本类指定方法(权限是public的)
public Method[] getDeclaredMethods()
throws SecurityException
获取本类全部方法
public Object invoke(Object obj, Object... args) throws
IllegalAccessException, IllegalArgumentException,
InvocationTargetException
Method类
不导入指定类开发包的情况下实现属性配置
例 :
这里的输出是通过Method的toString方法完成的
public Class<?> getReturnType()
Executable类
public abstract int getModifiers()
返回修饰符的整形类型, 可通过Modifier.toString(int param)转字符串
自定义方法信息输出
例 :
了解可以根据反射获取方法结构即可, 与开发关联不大
例 :
没有明确的类对象产生, 都是通过反射机制处理的, 避免了与某一个类的耦合问题
Class类
public Field getDeclaredField(String name) throws NoSuchFieldException,
SecurityException
public Field[] getDeclaredFields() throws SecurityException
获取全部成员属性
获取指定成员属性
public Field getField(String name) throws NoSuchFieldException,
SecurityException
获取指定父类成员属性
public Field[] getFields() throws SecurityException
获取全部父类成员属性
例 :
但是Field类里最重要的操作形式不是获取全部成员, 而是以下几个
Field类
public void set(Object obj, Object value) throws IllegalArgumentException,
IllegalAccessException
设置属性内容
public Object get(Object obj) throws IllegalArgumentException,
IllegalAccessException
获取属性内容,
public void setAccessible(boolean flag)
解除封装, 虽然允许, 但是不建议去解除
public Class<?> getType()
获取成员类型, 开发中最常用的方法
开发中进行反射处理的时候, 往往会利用Field, Method类实现setter方法的调用
public Constructor<T> getConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException
获取指定构造方法, 只返回制定参数类型访问权限是public的构造器。
例 :
特点 : 可以用反射类获取对象, 并且直接使用底层的C++来代替JVM执行(即绕过
JVM的对象管理机制, 无法使用JVM的内存管理机制以及垃圾回收机制)
不建议使用
sun.msic.Unsage, 找不到这个包.......
设置多种数据类型
级联对象实例化
级联属性赋值
简单java类有过多的setter, getter方法, 代码存在有大量的重复操作
解决方案 : 反射机制, 可以根据自身特点实现相同功能类(Object类的直接操作, 可直
接操作属性和方法)的重复操作的抽象处理
属性自动设置解决方案 :
采用字符串 : "属性: 内容|属性: 内容"
类的基本结构 : 由一个专门的ClassInstanceFactory类负责所有的反射处理, 接收反
射对象于要设置的属性内容, 同时可以获取指定类的实例化对象
设计的基本结构:
需要通过反射进行指定类对象的实例化处理 ; 进行内容的设置(Field属性类型、方
法名称, 要设置的内容)
例 :
应该使用"."作为级联关系的处理
例(难点) :
实现自动实例化类(包括它的级联对象) 和设置属性
JVM里面可以根据类加载器, 而后进行指定路径中的类加载(JVM提供的环境变量
CLASSPASH)
public ClassLoader getClassLoader()
获得类加载器
public final ClassLoader getParent()
Class类
ClassLoder类
获取其父类的ClassLoder
AppClassLoader
应用程序加载器
PlatformClassLoader
平台类加载器, JDK1.8及以前为扩展类加载器
ExtClassLoad(JDK1.8及以前)
开发包里有ext文件夹, 可以将"*.jar"文件拷贝到目录里面, 可以直接执行。
但是这样并不安全, 所以从JDK1.9开始将其废除了,同时为了保证系统类加载器和
应用类加载器的平衡, 提供平台类加载器
Bootstrap
系统类加载器
类加载器
获得了类加载器后可以利用类加载器来实现类的反射加载类处理
自定义的类加载器执行顺序是在所有系统类加载器最后
作用 :可以由开发者任意指派类加载位置,( 系统类加载器都是由CLASSPATH定
义的), 类文件从磁盘加载, 也可以通过网络进行加载(最终都是用字节数组来加载)
protected final Class<?> defineClass(String name, byte[] b, int off, int len)
throws ClassFormatError
将字节数据转换为要实例化的类对象
类集就是一套动态对象数组的实现方案
重要的两个结构
困难
数据结构的代码实现困难
对于链表或二叉树更新处理的时候维护麻烦
对于链表或二叉树要尽可能保证其操作性能
链表 与 树
因为以上原因, JDK1.2开始引入了类集, 对常见的数据结构进行完整的实现包装. 并
且提供了一系列接口与实现子类来减少困难
几个核心接口
Collection, List, Set, Map, Iterator, Enumeration, Queue
java.util.Collection是单值集合操作的最大父接口
方法
boolean add(E e)
增加单个数据
boolean addAll(Collection<? extends E> c)
增加一组数据
void clear()
清空集合, 让根节点为空 , 同时执行GC处理
boolean contains(Object o)
查询数据是否存在, 需要equals()方法支持
boolean remove(Object o)
数据删除, 需要wquals()方法支持
int size()
获取数据长度
Object[] toArray()
将集合变成对象数组返回
Iterator<E> iterator()
将集合变为Iterator接口返回(数据输出)
子接口
List<E>
Set<E>
允许重复
不允许重复
public interface List<E> extends Collection<E>
方法
E get(int index)
获取指定索引上的数据
E set(int index, E element)
修改指定索引对象的数据
ListIterator<E> listIterator()
返回ListIterator接口对象
List本身依然属于一个接口, 接口要想使用则一定要使用子类来完成定义
三个常用子类
ArrayList
LinkedList
Vector
大部分情况首选(90%)
......
JDK1.9开始List子接口里面追加有一些static方法, 以方便用户的处理
观察List中的静态方法
static <E> List<E> of(E... elements)
例 :
因为是JDK1.9后开始提供的, 不兼容以前的版本, 开发的时候一般都用传统方法
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
例 :
保存的顺序就是其存储顺序
List集合里面允许存在重复数据
这个例子 集合的输出是利用每一个类提供的toString()方法实现的,
public void forEach(Consumer<? super E> action)
为了方便进行输出处理, 在JDK1.8之后Iterable父接口定义有一个forEach()进行输
出(不是标准输出)
ArrayList操作封装的是一个数组
例 :
构造
public ArrayList()
public ArrayList(int initialCapacity)
public ArrayList(Collection<? extends E> c)
initial(初始), capacity(容量)
JDK1.9之后 ArrayList默认的构造指挥使用默认的空数组, 使用的时候才会开辟数组,
默认的开辟长度为10
JDK1.9之前 ArrayList默认的构造实际上就会默认开辟大小为10的数组
实例化ArrayList类对象的时候如果没有传递初始化的长度, 默认使用空数据, 如果增
加的时候容量不够了, 使用较大的数值(成倍的方式)进行新的数组开辟
所以如果数据量超过10个, 使用有参构造方法进行创建, 以避免垃圾数组的空间产生
保存自定义对象时如果需要用到contains(), remove()方法进行查询与删除的时候
一定要保证类已经成功覆写了equals()方法
例 :
双亲加载机制 : 如果自定义类加载器与系统类同名, 则为了保证系统的安全性不会加
载
代理设计模式是开发中使用最多的, 核心是有真实业务实现类与代理业务实现类, 代
理实现类要完成比真实业务实现类有更多的操作
传统代理设计模式弊端
例 :
标准代理设计(基础模式)
调用要知道接口, 代理类和业务类,
客户端的接口与子类产生了耦合问题, 实际开发时最好引入工厂设计模式进行代理
对象的获取
静态代理设计, 一个代理类只为一个接口服务
为所有功能一致的业务操作接口提供有统一的代理处理操作
InvocationHandler接口
public Object invoke(Object proxy, Method method, Object[] args)
代理方法调用, 代理主题类里面执行的方法最终都是此方法
参数 :
Proxy类
public static Object newProxyInstance(ClassLoader loader, Class<?>[]
interfaces, InvocationHandler h)
创建代理对象
参数 :
loader : 当前主体类ClassLoader ; interfaces : 真实主体类的接口信息 ;
h : 代理处理的方法
proxy 要代理的对象 ; method 要执行的接口方法名称 ; args 传递的参数
例 :
一些开发者认为不应该强迫性的基于接口实现代理设计模式, 所以开发者就开发出
了CGLIB开发包(第三方程序包)来实现类的代理设计
看教程使用并不比官方的代理设计方便......由空对比下优缺点
建议还是用接口设计比较合理
java.lang.reflect.
AccessibleObject类
public Annotation[] getAnnotations()
获取全部Annotation信息
public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
获取指定Annotation信息
例 :
不同的Annotation有它的不同存在范围
@FunctionalInterface
@SuppressWarnings
源码里有@Retention(RetentionPolicy.RUNTIME),
RetentionPolicy.RUNTIME : 即运行时生效, 程序运行时可以获取此Annotation
@Retention(RetentionPolicy.SOURCE)
RetentionPolicy.SOURCE : 源代码编写时有效
@Retention
RetentionPolicy.class : 类定义时有效
RetentionPolicy.RUNTIME : 即运行时生效,
RetentionPolicy.SOURCE : 源代码编写时有效
描述Annotation的运行策略, Retention policy(保留策略)
使用"@interface"来定义Annotation
例 :
自定义Annotation最大特点是可以结合放射机制实现程序的处理
public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, Serializable
继承关系
LinkedList
AbstractSequentialList {abstract}
List<E> <<interface>>
Deque<E> <<interface>>
队列
Queue<E> <<interface>>
双端队列
AbstractList<E> {abstract}
AbstractCollection<E> {abstract}
Collection<E> <<interface>>
Iterable<E> <<interface>>
例 :
这块操作只看功能跟ArrayList是一样的, 但实现机制是完全不同的
跟ArrayList区别
LinkedList构造方法里面没有像ArrayList那样初始化大小的方法, 只提供无参构造
LinkedList是链表实现的集合操作, ArrayList是数组实现的集合操作
使用get()方法根据索引获取数据时, ArrayList的时间复杂度为O(1), LinkedList为
O(n), n是集合的长度
ArrayList如果长度不足会以2倍的长度增加, 保存大数据量的时候会产生垃圾数组及
性能的下降, 这时可以用LinkedList来保存
Vector [ˈvektər] 矢量, 向量
public class Vector<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
继承结构与ArrayList相同
Vector无参构造会开辟长度为10的数组, 其余操作与ArrayList是相同的
Vector类中的操作方法采用的都是synchronized的同步处理, 在多线程访问的时候
属于线程安全的, 但性能不如ArrayList高
与ArrayList区别
Set集合最大特点是不允许保存重复元素
JDK1.9以前Set集合与Collection集合的定义并无差别, Set继续使用了Collection
定义的方法
JDK1.9之后, Set集合也像List集合一样扩充了一写static方法
public interface Set<E> extends Collection<E>
没有像List集合扩充了许多的新方法, 无法使用List集合中的get()方法, 无法实现指
定索引数据的获取
两个常用子类
HashSet, TreeSet
Set接口里使用最多的子类, 最大的特点是保存的数据是无序的, 且不允许保存重复
的元素(Set接口定义的)
public class HashSet<E> extends AbstractSet<E>
implements Set<E>, Cloneable, Serializable
与HashSet最大的区别是TreeSet集合的数据是有序的(升序)
例 :
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, Serializable
继承结构
TreeSet<E>
NavigableSet<E> <<interface>>
SortedSet<E> <<interface>>
Set<E> <<interface>>
......
允许使用自定义类进行排序, 但是这个类必须实现Comparable接口, 只有实现这个
接口才能确认对象的大小关系
TreeSet本质是利用TreeMap子类实现集合数据的存储, 而TreeMap需根据
Comparable确定大小关系
例 :
TreeSet需要将类中所有信息进行比对, 实现难度大, 开发中首选HashSet子类进行
存储
HashSet判断重复元素用的是Object类提供的方法hashCode()和equals(),
只有在需要排序的情况下(TreeSet)才会利用Comparable接口来实现
public int hashCode()
对象编码, 编码作用: 快速定位信息。
public boolean equals(Object obj)
对象比较
先进行编码匹配, 如果编码不存在, 则对象不存在, 如果编码存在, 则进一步进
行对象比较处理, 如果发现对象存在了,此数据不允许保存
开发工具可以生成hashCode()和equals()方法
例 :
JDK1.8开始在Iterable接口之中提供的forEach()方法并不是标准的集合输出形式,
并且也很难在实际的开发中出现
概述
用得最多的
非常少用
用得比较多
比较少用
Collection接口从JDK1.5开始多继承了一个Iterable父接口, 这个接口的iterator()方
法可以获取Iterator接口对象(JDK1.5前这个方法是定义在Collection中的)
Iterator<T> iterator()
boolean hasNext()
获取Iterator接口对象
判断是否有数据
E next()
取出当前数据
default void remove()
删除(不是必须不要使用, Iterator是输出类)
方法
在迭代过程中如果使用Collection中的remove()方法删除会出现并发更新的异常
此时就只能利用Iterator中的remove()方法删除
Collection.remove()与Iteration.remove()区别
Iterator迭代输出只能向后输出, 如果需要双向迭代输出则要使用Iterator的子类
ListIterator实现
public interface ListIterator<E> extends Iterator<E>
方法
boolean hasPrevious()
判断是否有前一个元素
E previous()
由后向前取出数据
例 :
public interface Enumeration<E>
方法
boolean hasMoreElements()
E nextElement()
判断是否由下一个元素
获取当前元素
例 :
对Vector进行输出
该方法时间比较久远, 有些方法只能用Enumeration, 现在大多数都能使用Iterator
输出了
例 :
在Collection保存的数据是单个对象, 实际上可以进行二元偶对象(key:value)的形
式存储, 其核心意义在于需要通过key获取对应的value
开发中Collection集合保存数据的目的是为了输出, Map集合保存数据的目的是为
了进行key的查找
概述
Map接口是二元偶对象保存的最大父接口
public interface Map<K,V>
方法
V put(K key, V value)
向集合中保存数据
V get(Object key)
根据key查询数据
Set<Map.Entry<K,V>> entrySet()
将Map转为Set集合
boolean containsKey(Object key)
查询指定key是否存在
Set<K> keySet()
将Map集合中的key转为Set集合
V remove(Object key)
根据key删除掉指定数据
key是不允许重复的, 在Map中数据的保存按照key = value的形式存储的, 使用of()
操作的时候如果重复会出现"IllegalArgumentException"异常
key值
key值不能为null, 否则会出现"NullPointerException"异常
例 :
Map接口中最为常见的一个子类, 该类的主要特点是无序存储
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
public V put(K key, V value)
向集合中保存数据, 返回值 : 重复key时返回旧的value
方法
public V get(Object key)
获取集合数据
HashMap的put()方法是如何实现容量扩充的
HashMap类里面提供有一个"DEFAULT_INITIAL_CAPACITY"常量, 默认值16
当保存的内容超过了阈值(DEFAULT_LOAD_FACTOR = 0.75f), 相当与"容量 * 阈
值" = 12, 保存12个元素的时候就会进行容量的扩充
进行扩充的时候HashMap采用的是成倍的扩增模式
HashMap的工作原理
JDK1.8后开始的, 在HashMap中进行数据存储的依然是利用了Node类完成的, 这
种情况下能使用的结构只有链表(时间复杂度"O(n)")和 二叉树("O(logn)")
JDK1.8开始, HashMap的实现发生了改变, 因为要适合大数据时代的大量数据存储
如果保存的数据没有超过阈值(TREEIFY_THRESHOLD = 8), 会按照链表的形式进行
存储, 如果超过了阈值则会将链表转为红黑数以实现树的平衡, 并且利用左旋与右旋
保证数据的查询性能
如果要Map集合中保存的数据为其添加顺序, 可以更换为子类LinkedHashMap(基
于链表实现的), 使用LinkedHashMap类时数据量不要特别大, 会造成时间复杂度攀
升
public class LinkedHashMap<K,V> extends HashMap<K,V> implements
Map<K,V>
例 :
操作方法与HashMap类似
public class Hashtable<K,V> extends Dictionary<K,V>
implements Map<K,V>, Cloneable, Serializable
例 :
Hashtable设置的key和value都不允许为null
HashMap与Hashtable的区别
HashMap中的方法都属于异步操作(非线程安全, HashMap允许保存null数据)
Hashtable中的方法都属于同步方法(线程安全), Hashtable不允许保存null, 否则会
出现NullPointerException
HashMap源码里 :
static class Node<K,V> implements Map.Entry<K,V>
public static interface Map.Entry<K,V>
方法
V getValue()
K getKey()
获取value
获取key
JDK1.9之后Map中追加了一个新的方法
static <K,V> Map.Entry<K,V> entry(K k, V v)
创建Map.Entry对象
作用 : 作为key和value的包装类型使用, 默认数据存储时会将key和value包装为一
个Map.Entry对象使用
例 :
Set<Map.Entry<K,V>> entrySet()
将Map集合转为Set集合, 返回一组Map.Entry接口对象(包装key和value)
Set<Map.Entry<K,V>> entrySet()
例 :
将Map集合转为Set集合, 返回一组Map.Entry接口对象(包装key和value)
过程
用Map接口中的entrySet()方法将Map集合转为Set集合
用Set集合中的Iterator()方法将Set集合转为Iterator集合
用Iterator迭代输出每一个Map.Entry对象, 可用getKey()和getValue()方法获取key
和value
要覆写hashCode()和equals()方法, 否则无法查找到key
注意
实际开发中key常用数据类型 String, Long, Integer
HashMap进行数据操作时出现Hash冲突(Hash码相同), HashMap是如何解决的
为了保证程序的正常执行, 会在冲突的位置上将所有Hash冲突的内容转为链表保存
因为根据key获取数据的时候要将传入的key通过hash()方法来获取对应的hash码,
即要先用hashCode()来进行数据查询
例 :
栈是一种先进后出的数据结构
方法
public class Stack<E> extends Vector<E>
虽然继承了Vector, 但用的不是Vector提供的方法
public boolean empty()
判断栈是否为空
public E push(E item)
推入元素
public E peek()
peek(窥视), 查看栈顶的元素
public E pop()
抛出栈顶元素(删除), 如果栈已经空了, 会抛出"EmptyStackException"异常
例 :
队列的特点是先进先出的操作形式
public interface Queue<E> extends Collection<E>
方法
boolean add(E e)
boolean offer(E e)
E poll()
E element()
E peek()
向队列中追加数据
弹出后(返回值)删除(先进的)数据
向队列中提供数据(添加)
返回首个元素
查看首个元素
子类 :
LinkedList
PriorityQueue
例 :
优先级队列(有排序)
例 :
根据功能要求选择使用
public class Properties extends Hashtable<Object,Object>
方法
public Object setProperty(String key, String value)
设置属性
public String getProperty(String key)
获取属性, 如果key不存在返回null
public String getProperty(String key, String defaultValue)
获取属性, 如果key不存在返回默认值
public void store(OutputStream out, String comments) throws IOException
输出属性内容
public void load(InputStream inStream) throws IOException
通过输入流读取属性内容
Properties可以像Map一样进行数据操作, 区别是Properties只能操作String类型
Properties类可以进行输入流和输出流输出读取属性,
例 :
Collections是一组集合数据操作工具类
方法
public static <T> boolean addAll(Collection<? super T> c, T... elements)
public static void reverse(List<?> list)
追加数据
实现数据反转
......
例:
public static <T> int binarySearch(List<? extends Comparable<? super T>>
list, T key)
二分查找
Collection与Collections区别
Collection是集合接口, 允许保存单值对象
Collecttions是集合操作工具类
default Stream<E> stream()
获取Stream接口对象
Collection接口
方法
Stream<T> filter(Predicate<? super T> predicate)
Stream<T> limit(long maxSize)
设置取出的最大的数据量
Stream<T> skip(long n)
跳过指定数据量
Predicate: 断言型的函数式接口
例 :
分两部分 : Map处理部分, Reduce分析部分
例 :
这些分析操作只是JDK本身提供的支持, 而实际中不会这样, 因为面对大数据的环境,
不能将所有数据都保存在内存里面
两种模型
C/S(Client/Server), 客户端与服务器端, 这种开发可以由开发者自定义传输协议, 并
且使用一些比较私密的端口, 安全性比较高, 但是开发与维护成倍较高
B/S(Browse/Server, 浏览器与服务器端) : 只开发一套服务器端程序, 浏览器作为客
户端, 这种开发维护成倍较低(只有一套程序), 但使用的是公共的HTTP协议和80端
口,安全性较差, 现在的开发基本上以"B/S"结构为主
C/S程序模型
TCP(可靠的数据连接)
UDP(不可靠的数据连接)
TCP程序基本实现
核心特点使用两个类实现数据的交互处理 : ServerSocket(服务器端), Socket(客户
端)
ServerSocket
主要目的是设置服务器的监听端口
Socket
要指明要连接的服务器地址与端口
telnet指令
open localhost 端口
进行服务器端的连接
检查是服务器端还是客户端出错
例 :
服务器端
客户端
服务器上启动多个线程, 每个线程单独为一个客户端实现Echo服务支持
服务器是单线程, , 占用着的端口其他程序不能用了, 只能提供一个Echo服务
例
服务器端
客户端
基于datagram(数据报)的网络编程实现, 数据报客户端是否接收与发送者无关
两个类
DatagramPacket
DatagramSocket
数据内容
网络的发送与接收
例 :
服务端
客户端
Java Database Connectivity(Java数据库连接)
java.sql模块
DriverManager类
一些接口 : Connection, Statement, PreparedStatement, ResultSet
对数据库访问几种形式
JDBC-ODBC桥连接
利用微软的ODBC技术进行数据库的连接, 而后再利用JDBC技术访问ODBC技术进
行数据库的开发, Java默认支持的技术, 不需要任何额外配置就可实现
处理流程: 程序 → JDBC → ODBC → 数据库
性能很差, 没有人用
JDBC连接
程序 → JDBC → 数据库
这种连接一般只连接本地数据库
JDBC网络连接
通过特点的网络协议连接指定的数据库服务
程序 → JDBC → 网络数据库(IP地址, 端口号)
JDBC的协议连接
自己编写指定的协议操作实现数据库的访问
Oracle驱动配置
使用记事本编写的话用Oracle文件路径配置到CLASSPATH中
用Eclipse开发, 要在JavaBuilderPath上配置驱动程序
步骤
通过反射机制加载数据库驱动程序类
oracle.jdbc.driver.OracleDriver
地址结构
jdbc:oracle:thin:@主机名称:端口号:SID
用户名 :
密码 :
java.sql.DriverManager类
获取Connection接口对象
public static Connection getConnection(String url, String user, String
password) throws SQLException
例 :
Created With
MindMaster