本文只列举了一些大纲,如果需要细节知识的读者请移步《Java编程思想》
,这也是我的入门书籍,它给了我很大的帮助
Java 学习路线图
Java 核心
类和对象
类、对象关系
什么是类
类是对某一种事物的抽象描述,是具备某些共同特征的实体的集合,它是一种抽象的数据类型,它是对所具有相同特征实体的抽象
什么是对象
对象是类的实例,是一个真实世界中的实体,对象与实体是一一对应关系的,意思就是现实世界的每一个实体都是一个对象,所以对象是一个具体的概念。对象是一种个性的表示,表示一个独立的个体,每个对象拥有自己独立的属性,依靠属性来区分不同对象。
对象与类的关系
类是对象的模版,对象是类的实例
创建对象的几种方式
- 使用
new
关键字 - 使用反射机制
- 使用
clone
方法 - 使用反序列化
类的成员变量和方法
成员变量
成员变量定义在类中
成员变量随着对象的创建而创建,随着对象的消失而消失,存在对象的堆内存中
这里可以联想到动态数组,如果一个动态数组中的一个元素引用了一个对象,但是在扩容是放弃了之前的使用过的内存,那么这块变量很有可能还是存在堆内存当中
成员变量有默认的初始值
方法
类的构造函数
Object
类Object
类是所有类的父类封装、继承、多态
- 封装
- 定义:隐藏对象的属性和实现的细节,仅仅对外公开接口,控制在程序中的属性的读和修改的访问级别
- 目的:增强安全性和简化编程
- 封装的基本要求,把所有对象私有化,对应该暴露的属性使用
getter setter
方法,如果类有带参数的构造方法,那么一定要重写一个不带参数的构造方法.
- 继承
- 定义:当多个类具有相同特征和行为时,可以把多个类的相同部分抽取出来放在一个类中作为父类,其它的类继承这个类
- 目的:提高代码的复用
- 多态
- 定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
- 目的:消除类型之间的耦合关系
- 封装
JDK常用的类
System
类 慎用
System.out.printf
System.out.println
System.arraycopy(Object src, int srcPos,Object dest, int destPos,int length)
基础类型的包装类
Integer
Long
Byte
String StringBuilder StringBuffer
类
String
每一个new出来的对象都是不一样的,即使你使用了相同的字面量equals
方法public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
split
方法:用于字符串切割contains
方法:是否包含子字符replace
方法:字符串替换subString
方法:剪切字符串trim
方法:去除空格
StringBuilder
使用了内部数组保存数据,内部数组如果不指定则有一个默认的大小,如果超出了内部数组的容量则会扩容append
方法:往内部数组中添加元素toString
方法,根据内部数组保存的内容转化为一个String
对象
为什么要使用
StringBuilder
StringBuilder
一般使用在有字符串拼接的情况下,如果使用String
则会产生大量无用的对象,而使用StringBuilder
则不会StringBuffer
类StringBuffer
与StringBuilder
功能类型,可以看到StringBuffer
和StringBuilder
都继承了AbstractStringBuilder
类,并且都基本上只使用了父类的方法,StringBuffer
只是在方法上面增加了一个synchronized
关键字,这个关键字的作用是给方法加锁,表示同一个时间端只能有一个线程访问这个方法,如此就可以做到线程安全
正则表达式类
Date
类
构造函数
public Date(long date)
根据Unix
时间戳来生成Date
对象- 无参构造函数:生成当前时间的
Date
对象,实际上是调用了Date(System.currentTimeMillis())
这也是多态的一个体现 after(Date when)
如果调用此方法的Date
对象在指定日期之后返回true
before(Date when)
如果调用此方法的Date
对象在指定日期之前返回true
SimpleDateFormat
类- 指定时间生成字符串
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String s = sdf.format(date)
- 生成指定时间的
Date
对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = sdf.parse("2006-01-02 15:03:04")
Random
类
math
包中的random
方法,只能生成double
类型的0~1
之间的随机数Random
类
Math
类
round(double x)
返回x的四舍五入的值ceil(double x)
向上取整floor(double x)
向下取整abs()
Scanner
类
看看就好
抽象类
抽象类规则:
- 抽象类不能被实例化
- 抽象类中的方法可以包含方法体也可以不包括方法体
- 构造方法、静态方法不能声明为抽象方法
接口
接口的特性
- 接口中的每一个方法也是隐式抽象的,接口中的方法会饿毙隐式指定为
public abstract
- 接口中可以包含变量,接口中的变量会被隐式指定为
public static final
- 接口可以多继承、多实现
在JDK 1.8+
接口可以有静态代码块和方法体,定义方法体使用了预留关键字default
异常
Java
异常框架
,---------.
|Throwable|
|---------|
|---------|
`---------'
^
|
----------
| |
| |
,-----. ,---------.
|Error| |Exception|
|-----| |---------|
|-----| |---------|
`-----' `---------'
^
|
-------------------
| |
| |
| |
,-----------. ,----------------.
|IOException| |RuntimeException|
|-----------| |----------------|
|-----------| |----------------|
`-----------' `----------------'
异常通常被分为三类:
- 错误:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
- 运行时异常:运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
- 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
集合
Java
中的集合框架大致可以分为Collection
和Map
类,两者的区别如下:
- Collection是单列集合;Map是双列集合
- Collection中只有Set系列要求元素唯一;Map中键需要唯一,值可以重复
- Collection的数据结构是针对元素的;Map的数据结构是针对键的。
Collection
体系
Collection
包含了两大体系:List
、Set
List
存取有序,有索引,可以根据索引来取值,元素可以重复Set
存取无序,元素不可重复
List
List
主要学习以下两种:ArrayList
、LinkedList
ArrayList
底层使用了数组实现,所以查询速度是O(1)
,所以查询速度快,但是增删速度慢
LinkedList
是基于双向循环链表结构实现的,所以查询速度为O(n)
,但是增加删除速度快
Set
Set
集合的特点:元素不会重复,存取是无序的,无下标Set
集合下面有:HashSet LinkedHashSet TreeSet
LinkedHashSet
是基于链表和hash
表共同实现的,所以具有存取有序,元素唯一的特点
TreeSet
: 存取无序,元素唯一,可以进行排序(排序是在添加的时候进行排序)
Map
体系
Map
是一个双列集合,其中保存的是键值对,键要求保持唯一性,值可以重复,
Map
最重要的一个结构就是HashMap
课后习题
- 实现一个简单的
ArrayList
和LinkedList
,LinkedList
可以考虑使用双向循环链表作为低层实现,存储的数据类型可以只考虑int
类型
范型
范型的意思就是就可以编写模版代码来适应任意类型
- 范型类
// 定义一个泛型类
public class Generator<T> {
T item;
}
- 范型方法
public class Generator<T> {
T item;
// 定义一个泛型方法
public T getItem(){
return this.item;
}
}
- 范型接口
//定义一个泛型接口
public interface Generator<T> {
public T next();
}
课后习题
- 使用范型支持
ArrayList
多类型存储
注解
注解可以理解其为标签,标签本身并没有什么用处,但是我们可以给这个标签赋予含义
注解的声明和元注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
}
我们使用@interface
声明了一个注解,并使用@Target
注解传入ElementType.METHOD
参数来表示这个注解只能应用在方法上,@Retention(RetentionPolicy.RUNTIME)
则用来表示改注解生存期是在在运行时.
其中@Target
和@Retention
是由Java
提供的元注解,元注解的意义在于标注其它注解
@Target
注解
@Target
可以用来约束任何可以应用的地方,其中ElementType
是一个枚举类型
如果一个注解未指定@Target
注解则表示可以应用在任意元素上
@Retention
注解
@Retention
用来约束注解的生命周期,分别有三个值,源码级别(source
),类文件级别(class
)或者运行时级别(runtime
),其含有如下:
SOURCE
:注解将被编译器丢弃(该类型的注解信息只会保留在源码里,源码经过编译后,注解信息会被丢弃,不会保留在编译好的class文件里)
CLASS
:注解在class
文件中可用,但会被JVM
丢弃(该类型的注解信息会保留在源码里和class
文件里,在执行的时候,不会加载到虚拟机中),请注意,当注解未定义Retention
值时,默认值是CLASS
,如Java内置注解,@Override
、@Deprecated
、@SuppressWarnning
等
RUNTIME
:注解信息将在运行期(JVM
)也保留,因此可以通过反射机制读取注解的信息(源码、class
文件和执行的时候都有注解的信息),如SpringMvc
中的@Controller
、@Autowired
、@RequestMapping
等。
文件、IO
文件IO操作是重点中的重点,Java中的IO是以流为基础进行输入输出的
IO流的划分
IO流我们可以使用两种形式来划分:
- 输入输出流:程序从外部读取数据使用输入流(
InputStream、Reader
),程序向外部写数据使用输出(OutputStream、Writer
) - 字节流、字符流:这是按照流中最小数据单元来区分的,字节流以8位作为一个数据单元,字符流以16位作为一个数据单元,其中字节流命名主要以
InputStream、OutputStream
为后缀,而字符流主要以Reader、Writer
为后缀
主要的类和方法
IO的最基本的四个类为:InputStream、OutputStream、Reader、Writer
,这四个类均为抽象类,我们具体使用的时候更多的是使用它们的子类,而使用它们作为声明,比如:InputStream inputStream = new FileInputStream(file)
,(想想这里是为什么)
下面列举了基本的方法
InputStream
类
方法 | 方法介绍 |
---|---|
public abstrcat int read() | 读取一个字节的数据,返回值为所对应的ANSCii码值 |
public int read(byte b[]) | 读取b.length 个字节的数据填充到数组中,返回具体读了多少字节的数据,如果到了文件末尾则返回-1 |
public int read(byte b[], int off, int len) | 从第 off 位置读取 len 长度字节的数据放到 byte 数组中,流是以 -1 来判断是否读取结束的 |
public long skip(long n) | 跳过多少个字节不被读取 |
public int available() | 返回有多少个字节可被读取 |
public void close() | 关闭流,释放资源 |
public synchronized void mark(int readlimit) | 标记读取位置,下次还可以从这里开始读取,使用前要看当前流是否支持,可以使用 markSupport() 方法判断 |
public synchronized void reset() | 重置读取位置为上次 mark 标记的位置 |
public boolean markSupported() | 判断当前流是否支持标记流,和上面两个方法配套使用 |
OutputStream
方法 | 方法介绍 |
---|---|
public abstract void write(int b) | 写入一个字节 |
public void write(byte b[]) | 写入b数组中的数据 |
public void flush() | 把缓冲区中的数据刷入文件中 |
public void close() | 关闭流 |
Reader
类
与InputStream
类似
Writer
类
与OutputStream
类似,多出
方法 | 方法介绍 |
---|---|
public Writer append(char c) | 追加一个字符 |
常用的类
FileInputStream、FileOutputStream
,文件读写BufferedInputStream、DataInputStream、BufferedOutputStream、DataOutputStream
用作缓冲区ByteArrayOutputStream
常用缓存FileReader、FileWriter
文件读写BufferedWriter、BufferReader
用作缓冲区
课后习题
- 使用流进行文件的拷贝
- 使用流进行图像的翻转
线程
线程和进程的区别
进程是程序的一次动态执行过程,而线程是进程的一个执行单元,一个进程可以拥有多个线程,多个线程之间可以共享一个进程的资源
为什么需要多线程
可以发挥多处理的强大功能,简单来说就是为了加快程序的运行效率
Java实现多线程的几种方式
- 实现
Runnable
接口,实现run
方法 - 继承
Thread
类,实现run
方法,其中Thread
也是实现了Runable
类 - 实现
Callable
接口,实现call
方法
线程状态的变化
任何线程一半具有5种状态,即为创建、就绪、运行、阻塞、终止
- 创建状态:当程序中用构造方法创建了一个线程对象之后,新的线程就处于创建状态,此时它已经有了对应的内存空间和其它的资源,但是还是处于不可运行的状态
- 就绪状态:新建线程对象之后,调用该线程的
start()
方法就可以启动一个线程,线程进入就绪状态,此时线程就可以进去线程队列,可以抢占CPU了 - 运行状态:当就绪状态的线程获取到了CPU资源的时候,线程就进入了运行状态,CPU会自动调用该线程的
run
方法进行操作 - 阻塞状态:一个处于运行状态的线程由于某些特殊的原因,放弃CPU暂时中止自己的运行,在运行过程中,调用
sleep() wait()
方法会使程序进入阻塞状态 - 死亡状态:调用
stop()
方法或者run()
方法执行结束后线程处于死亡状态
线程状态转化图如下
Java锁
课后习题
- 实现生产者消费者模型
网络编程
类加载和反射机制
JDBC
编码规范
Java Web
基础
JSON
https://www.json.org/json-en.html
json解析库:fastjson
、gson
json使用{}
表示一个对象,使用[]
表示一个数组
HTTP 协议
请求报文
一个HTTP请求报文分为四个部分:请求行、请求头、空行、请求数据,这四个部分排列顺序是固定的!!!
请求行:请求行主要由请求方法字段、URL字段和HTTP协议版本字段三个字段组成,他们分别用空格分割开来,一个最经典的请求报文的请求行就是
GET / HTTP/1.1
请求头:HTTP客户端程序向服务器请求是必须指明请求类型:如
GET POST
,如有必要,也可以选择发送其它的请求头,大多数请求头不是必须的,但是Content-Length
除外,对于POST
请求来说,Content-Length
是必须出现的.常见的请求头字段含义:Accept
:浏览器可以接受的MIME类型Content-Length
:表示请求报文的正文长度Host
:客户急通过这个告诉服务器想要访问的主机名,Host
头域指定请求资源的Intenet
主机和端口号,必须表示请求URL的原始服务器或者网关地址,HTTP/1.1
请求必要包含主机头域,不然系统会以400状态码返回User-Agent
:这里面的内容包含发出请求的用户信息、浏览器类型.(这个爬虫非常有用)Cookie
:客户端通过这个头像服务器发送数据,Cookie
是Session
的基础Connection
:处理完这次请求释放断开连接还是继续保持连接,其中Keep-Alive
是持久连接Content-Type
:表示请求数据的类型
空行:即使空了一行,可以告诉服务器头部到此为止
请求数据:这个部分是携带的数据
响应报文
一个HTTP响应报文也主要分为四个部分:响应行、响应头、空行、数据行
响应行:这个主要行扩了三个部分:协议类型和版本号、状态码、状态码的描述信息
这里主要叙述HTTP状态码,HTTP状态码主要分为五大类
- 100~199 (信息性状态码)
- 200~299(成功状态码)
- 300~399(重定向状态码)
- 400~499(客户端错误状态码)
- 500~599(服务端错误状态码)
响应头部
重要的几个:
- Set-Cookie:在客户端设置数据
- Warning:比原因短语更详细的一些的警告报文
空行
数据行
RESTFul
我们可以通过HTTP方法来对资源进行CURD
GET: 我们使用GET来进行查询,如
GET /user 查询所有用户的信息 GET /user/1 查询指定用户ID为1 的用户信息 GET /user/1/age 查询指定用户ID为1 的用户信息的年龄
POST: 创建单个资源
POST /user 新增一个用户 POST /user/1/teacher 为用户ID为1 的用户新增家教
PUT: 更新单个资源
PUT /user/1 更改用户为1 的用户信息
DELETE 删除某个资源
DELETE /user/1 删除ID为1 的用户信息,不过删除操作一半是把数据库的is_del字段置为true