Java8帮助API文档:
https://docs.oracle.com/javase/8/docs/api/?xd_co_f=278ba860ac89178ee421598661572254
三大版本
javaSE:标准版,基础、核心(控制台开发、桌面程序)
javaEE:企业级开发,广泛应用(web端,服务器开发)
javaME:嵌入式开发,基本没人使用。(手机、小家电)
JDK/JRE/JVM
JDK:java development kit。 java开发环境。
JRE:java runtime environment。java运行环境。
JVM:java virtual machine。 java虚拟机(模拟了一个虚拟机专门运行java程序,屏蔽了底层操作系统的差异)
JDK包含JRE,JRE包含JVM。JDK ( JRE (JVM) )
java结构图: https://docs.oracle.com/javase/8/docs/
程序运行的两种机制
- 编译型compile,预先翻译好。(c、c++)
- 解释型,随着运行随着翻译。(javascript等)
因为现在电脑性能比较高,所以解释型编译型的效率差距无关痛痒。
java两者兼而有之,先javac编译成class文件,再在jvm中解释class文件。
环境
安装
- 下载jdk7 / jdk8
- 配置环境变量
- JAVA_HOME F:\xxxx\jdk1.8*
- PATH %JAVA_HOME%\bin 和 %JAVA_HOME%\jre\bin
- %是应用变量的意思
- java -version 发现java已经安装
卸载
- 删除java安装目录
- 删除环境变量:JAVA_HOME / path下java相关
- java -version 发现java已经被卸载
jdk目录简介
bin 可执行文件,比如javac
include jdk使用c编写,此处是c引用的头文件
jre java的运行环境
lib java开发用到的库文件
src java资源类文件(java基础类的源代码)
hello word
1 | // HelloWord.java |
cmd编译执行1
2
3
4
5# 编译(编译得到.class文件)
javac HelloWord.java
# 运行(运行编译出来的.class文件)
java HelloWord
注意:
- java大小写敏感
- java名尽量英文
- 文件名和类名必须一致
操作符
所有操作符基本只能操作基础类型,但有如下特例:
操作所有对象
- =
- ==(只能判断引用地址,不能判断内容)
- !=(只能判断引用地址,不能判断内容)
操作String对象
- +
- +=
“+”操作符作用
- 字符串拼接
- 字符串转换
- 数值计算
“=”操作符作用
- 基本类型=>深度复制
- 对象类型=>指向同一对象(仅复制引用地址,并没有复制对象本身内容)
判断内容相等
基本类型
- ==
- !=
对象
equals
自定义类需要在类中覆盖
1
2
3public boolean equals(Object obj) {
return (this == obj);
}
String
- 当作基本类型赋值,则可以使用 == 或 equals。如String str1 = “Str123”;
- 当作对象赋值,则使用equals。如String str3 = new String(“Str123”);
- 建议使用equals。
幂运算
- 2^3 = 2的3次方
- Math.pow(2, 3)
逻辑运算
- && 与
- || 或
- ! 非
- 短路运算,如果前面的逻辑能够得到结果,后续运算不再执行。
位运算
符号 | 说明 | |
---|---|---|
& | 与,两者皆1,才1 | |
\ | 或,两者有1,就1 | |
^ | 异或,两者不同,则1 | |
~ | 取反 | |
>> | 左移4位,每移1位除以2 | |
<< | 右移4位,每移1位乘以2。16=1<<4 | |
>>> |
取反
int型,4字节。最高位为符号位,0为正数,1为负数。
原码
1 | 正数 3的二进制:00000000 00000000 00000000 00000011 |
反码
- 正数,反码就是原码。
- 负数,反码是将原码除符号外的位取反。
1 | 正数 3的反码二进制:00000000 00000000 00000000 00000011 |
补码
- 正数,补码就是原码
- 负数,补码是反码+1
1 | 正数 3的补码二进制:00000000 00000000 00000000 00000011 |
取反
计算机中,都是用补码存储整数,取反是对补码取反。
- ~3,得到 - 4
- ~-3,得到2
1 | 正数 3的补码二进制:11111111 11111111 11111111 11111100 |
包package
- 用来区别类名和命名空间。
- 一般用公司域名倒置作为包名。
1 | 定义包名: |
JavaDoc
编写说明
1 | package com.baidu; |
生成文档
命令行方式
1 | javadoc -encoding UTF-8 -charset UTF-8 Base.java |
Idea导出
1 | Gerenate JavaDoc |
查看文档
- 打开index.html
Scanner
- 可以用来获取用户输入。
- 在Java5引入的的工具类。
类
1 | import java.util.Scanner; |
关键方法
next
- next();
- hasNext();
- 一直读取到【有效字符】才可以结束
- 在【有效字符】前遇到的【空白】,直接去掉
- 在【有效字符】后遇到的【空白】,作为分隔符或结束符
- 不能得到带有【空白】的字符串
nextLine
- nextLine();
- hasNextLine();
- 以【回车enter】作为结束符
- 可以获得【空白】
1 | package com.luxia.scanner; |
数组
- 元素是相同类型的、有序的一组数据。
- 元素可以是基本类型,也可以是引用类型。
- 长度是确定的,一旦创建,不可改变
- 引用类型(引用地址-栈,实质存储空间-堆)。
- 数组一经分配空间,他的每一个元素也都被隐式的初始化。
- int默认初始化为0
- String默认初始化为nulld等
声明
1 | // 常用 |
初始化(分配了堆空间))
静态初始化
1 | int[] ages = new int[]{2,3, 4, 5}; |
动态初始化
1 | int[] ages = new int[4]; //仅分配空间 |
取值
1 | // 总长度 |
多维数组
数组内部的元素也是个数组。
1 | int[][] a1= new int[3][2]; |
Arrays类
数组的工具类java.util.Arrays
- fill 给数组赋值
- sort 给数组升序
- equals 比较数组元素
- binarySearch 搜索,对排序后的数组,进行二分查找
- asList 转换为List类型
- Arrays.toString()
- copyOf()
稀疏数组
当二维数组中,很多默认值是0,会记录没有意义的数据,可以用稀疏数组。
- 记录数组一共有几行几列,有多少个不同值
- 把不同值的行列及值记录在一个小规模的数组中,减少程序规模
类
本质:抽象。以类的方式组织代码,以对象组织(封装)数据。
三大特性
- 封装 (隐藏数据,属性私有:高内聚,低耦合,如get/set)
- 继承 (extends / super)
- 多态 (基类)
封装
- 保护属性,提高程序的安全性/可维护性
- 隐藏代码细节
- 统一接口
继承
- 所有类的基类是Object。
- 先执行父类,再执行子类。
super
- super只能在子类的方法或构造器中
- super() 调用父类的构造器,必须出现在构造器的最开始
- super(参数)
this
- 本类
- this 调用本类的方法或属性
- this() 本类的构造器,也必须出现在构造器的最开始。所以this()和super()不能同时调用
- this(参数)
1 | // extends |
idea的ctrl + H,可以查看当前类的父祖类。
####
多态
重写
指的是,子类继承父类,子类想重写父类的方法。
- 静态方法,是类的方法。静态方法,不能重写。
- 普通方法,是对象的方法。普通方法才能重写。
重写和重载的区分:
- 重写:①必须有继承关系,子类重写父类;②修饰符可以扩大范围(不能缩小);③方法名、参数列表,必须相同;④抛出的异常可以缩小范围(不能扩大)。只有方法体不同。
- 重载:方法名相同,参数、返回值等不同。
1 | class Person { |
多态
多态是方法的多态,属性没有多态性。
即,同一方法,根据发送对象的不同,而有不同的行为方式。
存在条件:有继承关系,子类方法重写父类方法,父类引用Person指向子类对象Teacher。
1 | Person teacher = new Teacher(); |
instanceOf
object instanceOf Class
object 是Class的子孙类对象或对象,返回true,否则返回false
1 | Person teacher = new Teacher(); |
类型转换
1 | // 子类-->父类(直接转换) |
class 类(抽象)
new 对象(实例化)
new创建对象时,①分配内存空间,②初始化对象(值),③调用类的构造器
初始值:
- 数字: 0 0.0
- char: u0000
- boolean: false
- 引用类型: null
构造器
使用new实例化对象,本质是在调用构造器。
构造器可以用来初始化对象的值。
- 必须和类名相同
- 必须没有返回类型,也不能写void
- 如果自定义了构造器,隐式默认构造器会失效
抽象类
abstract / extends
- abstract class 抽象类
- abstract 方法 抽象方法
抽象类和接口,都是一种顶层的约束规则,不负责真正的实现。只能依靠子类,或者接口实现类去实现。
因为抽象类不负责实现,所以不能new这个抽象类。但是抽象类是有构造器滴!
1 | // 抽象类 |
接口
interface / implements
接口,就是规范!一般会先把接口设计好,再去实现。
- 类:只负责具体实现。
- 抽象类:有具体的实现,也有抽象的规则。本质是类,只能单继承。
- 接口:只有约束规则。一个类,可以实现多个接口!(类似多继承)
接口的方法,默认就是【public + 抽象】的(实际编程中,缩略不写)
接口的属性,默认都是【public + static + final 常量】!
1 | public interface InterfaceTest { |
内部类
在一个类A的内部,定义一个类B。B是内部类,A是外部类。
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
成员内部类
1 | import java.util.UUID; |
静态成员内部类(static class)
1 | package com.luxia.base; |
局部内部类(方法内部)
1 | public class InnerClassTest { |
匿名内部类
初始化类时,不指定名字。不用将实例保留到变量中。
内存分析
栈
- 存放基本变量(包括基本类型的值)
- 引用对象的变量(存放这个引用在堆里面的具体引用地址)
堆
- 存放new的对象和数组的实质内容。
- 可被所有线程共享。
方法区(属于堆)
- 存放所有的class和static变量
- 可被所有线程共享。
示例
int[] myList = new int[4];
static
静态属性
多用于多线程。
1 | public class StaticTest { |
静态方法
1 | public class StaticTest { |
静态代码块
1 | public class CodeBlock { |
结果
1 | 静态代码块 |
静态导入包
1 | // 常规调用: |
方法
Java中,参数只有值传递
只不过对于对象参数,【值的内容】是【对象的引用】
静态方法
- 非静态方法,可调用静态方法,或普通方法。
- 静态方法,只能调用静态方法,不能调用普通方法。因为类创建时,静态方法已经创建,而普通方法还没有被创建(在实例化对象时才被创建)
可变参数
- jdk1.5开始,可以传递同类型的、可变参数。
- 类型后面加省略号(…)
- 可变参数只能是最后一个参数
1 | // 调用 |
命令行传参
1 | public class CmdLine { |
idea传参
命令行
- javac CmdLine.java 生成.class
- java com.example.base.CmdLine 运行.class
for
增加型for循环,java5引入,多用于集合、数组。
1 | int[] counts = {1, 2, 3, 4, 5}; |
switch
- byte
- short
- int
- char
- String(JavaSE7)(字符的本质还是数字)
- 枚举
字符的本质是数字
idea反编译演示——
编译: .java => .class。从如下目录找到编译后的class文件
反编译:.class 。将.class用idea打开,可以看到,将字符串转换成了数字。
枚举
switch判断枚举值的时候,①枚举的是枚举类型本身;②case后的枚举类型,不能加枚举前缀(An enum switch case label must be the unqualified name of an enumeration constant)。
1 | TypeEnum typeEnum = TypeEnum.GOOD; |
String[]和List相互转换
1 | // String[] 转换为 List<String> |
取最大值最小值
获取List中的最大最小值
List< Integer > 或者 List< double >
注意不能有null元素
1 | Collections.min(Arrays.asList(1,2,3,4)) |
List< 实体类>
1 | // 自己写for寻找 |
异常
exception。
java把异常当做对象处理,java.lang.Throwable
是所有异常的基类。
异常类分为两类:
- 错误Error
- 由java虚拟机生成并抛出
- OutOfMemoryError 内存溢出
- NoClassDefFoundError 类定义错误
- LinkageError 链接错误
- 大多数错误,与代码开发者所执行的操作无关
- 灾难性,致命,无法控制和处理,当发生时,JVM一般会终止线程
- 由java虚拟机生成并抛出
- 异常Exception
- RuntimeException 运行时异常(由逻辑引起,是不检查异常,程序中可以自己选择是否捕获、是否处理)
- 数组下标越界
- 空指针
- 算术异常
- 丢失资源
- ClassNotFoundException 找不到类
- 检查异常
- 可以被程序处理,在程序中应该尽可能的去处理。
- RuntimeException 运行时异常(由逻辑引起,是不检查异常,程序中可以自己选择是否捕获、是否处理)
分类
类别 | 特点 |
---|---|
检查性异常 | 编译时。 |
运行时异常 | 运行时(编译时被忽略) |
错误ERROR | 错误,不是异常。如当栈溢出,发生错误,编译时无法检查到。 |
异常处理的方法
ctr alt t
使用异常处理后,碰到异常,会正常执行,而不会终止。
try/catch 捕获
1 | // 可多个catch |
throws 在方法上抛出异常
如果本方法无法处理异常,可以抛出异常到方法外。
1 | void test() throws ArrithmeticException{ |
throw 方法中主动抛出异常
一般在方法中使用,在方法中抛出。
1 | void test(){ |
#####
自定义异常
只需要继承exception类。
1 | public class MyException extends Exception { |
时间
新老版本
Java原本自带时间类(单线程不会有问题,多线程有风险,且使用困难)
- java.util.Date;(JDK1.1已经被弃用)
- java.sql.Date是其子类
- java.util.Calendar;(JDK1.1推出)
Java8增加的时间类
- java.time(基于Joda-Time库)
繁琐程度对比
1 | // 旧版本 |
线程对比
1 | // 旧版本,全局共享的是同一个calendar对象,如果没有线程同步措施,会造成线程安全问题 |
Calendar避免直接使用数字,而应该使用枚举常量
1 | Calendar calendar = Calendar.getInstance(); |
Java8时间类API
java.time中的类
类 | 描述 |
---|---|
Instant | 时间戳。作为中间类转换。 |
Duration | 时间间隔,秒、纳秒,适合处理较短、较精确 |
Period | 一段时间,年月日 |
LocalDate | 不可变,日期,年月日 |
LocalTime | 不可变,时间,时分秒 |
LocalDateTime | 不可变,日期+时间,年月日时分秒 |
ZonedDateTime | 不可变,具有时区的日期+时间 |
java.time中的类都不生成不可变实例,也不提供公共构造函数,没办法通过new的方式直接创建,需要采用工厂方法实例化。
now方法获取当前时间
1 | Instant instant = Instant.now(); |
of方法获取指定时间
1 | LocalDate localDate = LocalDate.of(1991, 11, 23); |
时区
1 | // 全部时区列表 |
Date获取年月日等方法被弃用
1 | Date date1 = new Date(); |
方法一:Calendar类
1 | Calendar calendar = Calendar.getInstance(); |
方法二:SimpleDateFormat类
1 | String[] strNow1 = new SimpleDateFormat("yyyy-MM-dd").format(new Date()).toString().split("-"); |
时间转换案例
1 | // 2017-01-01 19:01:01转化为19:01:01 |
第三方库Joda
https://www.ibm.com/developerworks/cn/java/j-jodatime.html
excel
- poi支持.xls和.xlsx
- jxl只支持.xls
POI:是对所有office资源进行读写的一套工具包、属于apache开源组织。
组成
- [.xls]excel 2003 HSSFWorkbook workbook = new HSSFWorkbook();
- [.xlsx]excel 2007 XSSFWorkbook workBook = new XSSFWorkbook();
元素 | .xls excel2003 | .xlsx excel 2007 |
---|---|---|
工作簿 | HSSFWorkbook | XSSFWorkbook |
工作表 | HSSFSheet | XSSFSheet |
行 | HSSFRow | XSSFRow |
单元格 | HSSFCell | XSSFCell |
HSSFCellStyle | XSSFCellStyle |
引入依赖
1 | <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> |
多个sheet导出
1 | // 创建Excel文件 |
合并单元格
合并单元格之后单元格内容会保留第一个单元格的内容
1 | //合并单元格 |
样式属性
1 | // 行高,行高计算公式:x*20 (x为需要设置的行高) |
输出流
1 | ServletOutputStream out = null; |
反射
Reflection
正常方式:
graph LR A(包类名称) --> B(new实例化) --> C(得到实例化对象)
反射方式:
graph LR A(实例化对象) --> B(getClass方法) --> C(得到包类名称)
类的加载过程与ClassLoader
Class对象是在运行时、在内存中产生,是动态的。
加载load:
- 将javac编译后的.class文件内容加载到内存中,即,将静态数据转换成方法区的运行时数据结构
- 加载类之后,在堆内存的方法区中,产生一个Class类型的对象(java.lang.Class)。该对象包含了完整的类的结构信息,可以通过这个对象看到类的结构。一个类只有唯一一个Class对象。就像镜子,称之为反射。
链接link:
目的是将Java类的二进制代码合并到JRE(java runtime environment)中。
验证:加载的java类信息符合JRE规范,没有安全问题。报错机制。
准备:
为类变量(static)分配内存
为类变量(static)设置默认值
解析:将常量名(虚拟机常量池内的符号引用)替换为直接引用地址
- 常量:final static int = 324;
初始化:
- JVM执行类构造器
()方法的过程(构造器初始化) - 当初始化一个类时,如果父类还没有初始化,会先父类初始化
- 虚拟机保证一个类的
()方法在多线程环境中被正确加锁和同步
什么时候发生类的初始化?
一、类的主动引用,一定会发生类的初始化:
- new 一个对象
- 反射
- 类的静态成员和静态方法(final常量除外)
- 首先初始化main方法所在类
- 首先初始化父类
二、类的被动引用,不会发生类的初始化:
- 当子类引用父类的静态变量,子类不会被初始化。【只有真正声明静态域的类才会被初始化】
- 通过【数组】定义类引用,类不会被初始化。
- 使用类的【final常量】,类不会被初始化。(链接link阶段已经放入常量池了)
graph TB A(程序调用类) --> B{类是否在内存中} B --否--> C subgraph 类的初始化 C(类的加载Load) --> C2(类的链接Link) --> C3(类的初始化Initialize) end C -.- D1>类加载器,将类的.class读入内存并为之创建一个java.lang.Class对象] C2 -.- D2>将类的二进制数据合并到JRE中] C3 -.- D3>JVM负责对类初始化]
栈
堆
方法区(特殊的堆)
哪些元素类型拥有Class对象
只要元素类型相同,则拥有同一个Class对象
- class,外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
- interface
- 数组
- 枚举
- 注解
- 基本数据类型
- void
1 | // 类 |
创建Class对象的方式
- 通过类的
class
获取。最安全可靠、性能最高
1 | Class clazz = User.class; |
- 通过类的实例的
getClass()
方法获取。
1 | User user = new User(); |
- 通过
Class.forName("类的全类名")
获取。可能存在ClassNotFoundException
异常。
1 | Class clazz = Class.forName("demo.User"); |
- 内置基本类型的包装类可直接使用
类名.Type
1 | Class clazz = Integer.TYPE; |
- 利用
ClassLoader
Class对象的用途
动态的创建一个新的实例newInstance
- 默认调用类的无参构造器
- 类构造器必须有足够的访问权限
1 | // 无参数构造器,构造对象 newInstance |
调用方法
- getDeclaredMethod 根据方法名获取方法
- invoke 调用方法
- 反射操作方法,比直接调用更灵活,因为方法名,可以作为字符串参数传进去
1 | Class userClazz = Class.forName("User"); |
调用属性
- getDeclaredField 根据属性名获取属性
- set
- 默认情况下,由于类的属性是私有属性private,所以不能直接操作。通过setAccessible(true)来关闭程序的安全监测,从而可以操作私有属性。默认是setAccessible(false)。
1 | Class userClazz = Class.forName("User"); |
setAccessible
用于启动(默认fasle)或关闭(true)访问安全检查的开关,如此可以直接处理类中的私有属性、私有方法等。以下都有setAccessible方法:
- Method 方法
- Field 属性
- Constructor 构造器
关闭安全检查,可以提高性能。
操作泛型
1 | public class DbReflectAnnotation { |
操作注解
1 | public class DbReflectAnnotation { |
性能
正常效率最高 > 反射(关闭检测) > 反射(启动检测)效率最低