JavaSE
java语法
System.out.println(var)当参数为引用类型时, 自动转换为System.out.println(var.toString()). 其中System在java.lang中, 而System.out为System类的一个静态成员.
java中没有函数默认值机制
java成员函数的实现必须直接写在类体中
java.lang目录下的"顶级"类无需import可以直接使用
const与goto也是java关键字, 但目前没有具体含义(保留关键字). 注意, java中用final表示常量
java源代码位置
java代码规范
违反如下规范不会报语法错误
命名规范
变量名, 方法名采用小写字母开头的驼峰式命名方法
常量名全部大写中间加下划线
类名, 接口名使用大写字母开头的驼峰式命名方法
源代码(.java)文件名与类名一致, 且一个文件里只放一个外部类, 可以是public或没有修饰符
包名(目录名)全部小写使用倒序的网址名加上项目名, 例如com.baidu.project1
注释规范
其他
IDEA中提示一个文件里只能有一个外部类(备注: matlab里强制一个文件里只能有一个方法, 否则直接报语法错误, 有异曲同工之处)
java程序的执行顺序与内存结构
在JVM的存储空间主要包含三个重要区域: 方法区, 栈, 堆. java程序被运行时, 首先将代码片段存储至方法区中, 调用方法时将方法栈帧压入栈区, 使用new运算符时在堆上为对象分配内存. 静态变量在类加载时初始化, 所以存放在方法区. 每个对象内部除了自己的成员外, 还存储这一个特殊的引用型成员变量this(存储在堆区).
变量与常量
基本数据类型: long/int/short/byte/boolean/char/double/float
引用数据类型: 其余
循环与条件判断
方法
java中函数的参数传递只有值传递
类(class)
静态代码块与实例代码块
语法例子:
静态代码块与实例代码块都用的不多, 静态代码块的执行时机为类加载时机, 实例代码块在每次调用构造方法前执行.
构造方法(new)
当一个类没有编写构造方法时, java编译器会自动未知添加一个无参数构造方法, 此构造方法会将所有基本类型的变量赋值为0, 为引用类型的变量赋值为null. 当一个类编写了构造方法后, java将不会自动提供隐含的无参构造方法. 一个好的习惯是让每个类都写上默认的无参数构造方法
由于java中有垃圾回收机制, 所以没有析构函数这种东西
java构造方法没有C++那样的冒号赋初值的语法
this
每个对象都会隐含的带着一个实例变量this, 它是一个引用数据类型
this只能出现在实例方法, 构造方法中. 当它出现在构造方法中时, 必须出现在第1行, 此时的使用方式为this(...)的形式.
封装
一个好的编程习惯是将所有实例变量都设置为private变量, 并同时提供setAttr与getAttr方法
继承(extends)
继承实际上是将父类的东西除了构造方法/private方法/private变量/静态方法/静态变量以外的所有东西都复制过来一份
注意事项
java中只有单继承
没有写继承关系的类默认继承Object类
子类可以定义与父类同名的变量, 不会发生覆盖. 但是同名方法在满足返回类型与参数类型完全相同时会形成覆盖
子类无法直接访问父类的私有成员
父类的构造函数不会被继承
this与super对比
this与super都只能出现在成员函数, 构造函数中
super在构造方法中只能出现在第一行, 因此this与super在构造方法中有且仅有一个. 若一个构造方法既没有this(...)也没有super(...), 则自动补上super().
super的主要用于访问父类被覆盖的方法或与子类同名的变量.
super不是引用, 必须使用super(...)或super.xxx两种形式之一.
方法覆盖与多态
向上转型: 子类对象转换为父类对象. 可自动进行. 一般用这种方式实现多态
向下转型: 父类对象转换为子类对象. 必须使用强制类型转换符
向上转型与向下转型的说法仅适用于引用数据类型, 基本数据类型应该使用术语: 自动类型转换与强制类型转换.
向下转型有风险, 一般需要使用类似于如下的代码段
方法覆盖也被称为方法重载写 方法覆盖的注意事项为
子类方法的访问权限应高于或等于父类的访问权限, 例如父类为protected, 则子类可以时protected或public
子类方法不能抛出更多的异常
静态方法没有覆盖的概念(不会被覆盖)
父类的私有方法无法被覆盖
多态的含义是编译与运行时有着不一样的状态
覆盖后的返回值类型可以是父类方法的返回值类型的子类
访问权限修饰符(private/protected/public)
参考链接(还未完全阅读完)
属性或方法的访问权限
Note: 网上大部分关于无修饰符和protected的访问权限都是错误的, 代码可以参考src/java/access
外部类的访问权限
public: public修饰的类在其他包中可见, public修饰的类名必须与文件名一致
默认: 默认类在本包内可见, 在其他包不可见
无private与protected
内部类的访问权限
内部类本身的访问权限可以是private/protected/默认/public四种, 但是IDEA工具会不建议使用protected修饰, 另外, 从设计上看, 内部类应该仅供外部类访问. 因此修饰符应该设为private.
内部类和外部类的访问是相互透明的, 不受内部/外部类成员的控制访问修饰符影响, 都可以相互直接访问, 见下例.
外部接口/内部接口的访问权限
只能是public的, 所以会省略不写
final关键字
修饰普通数据类型: 相当于C++的const
修饰方法: 该方法不能被重写
修饰类: 该类不能被继承
修饰引用数据类型: 可以修改引用内部的值
修饰成员变量
final修饰成员变量时一般会与static连用, 表示常量. 命名规范: 全部大写, 单词之间用下划线连接. 常量一般用public修饰.
package与import机制
语法
package用于声明本文件所在的包
注意: java.lang
这个package会被自动import, 例如java.lang.String
, java.lang.System
.
package命名规范
公司域名倒置+项目名+模块名,例如:
com.baidu.projectname.module1
接口(interface)
接口可以看作是特殊的抽象类, 接口中的方法必须都是抽象的(抽象方法可以带有非抽象方法), 语法如下
备注: 接口使用的比较多, 抽象类使用的相对较少
default关键字
见Iterator与Iterable源代码
常用的一些接口
Iterable接口与Iterator接口
注意, 由于java历史原因, Iterable在java.lang包内, 因此无需import, 而Iterator在java.util包内, 因此必须import.
Iterator的源代码如下
Iterable的源代码如下
抽象类(abstract)
抽象类的子类可以是抽象类或者是普通类
抽象类中可以没有抽象方法, 但是抽象方法必须出现在抽象类中.
抽象方法必须被重写.
抽象类中有构造方法
abstract与final不能一起用
注意: java中有些方法没有方法体, 但它们不是抽象方法(native关键字修饰的方法调用底层C++实现)
内部类(inner class)
内部类可以定义在方法中, 也可以定义在类中(与成员变量同级), 内部类的访问权限修饰符可以是public/private
内部类分为:
静态内部类,类似静态变量
实例内部类,类似实例变量
局部内部类,类似局部变量,匿名内部类属于局部内部类
使用内部类可读性差,尽量不用
泛型机制
基本语法
高级用法
异常
多线程(待完善)
线程
概念
java 中有两类线程:
用户线程:例如主线程(以及下面所写各种线程)
守护线程(后台线程):例如垃圾回收线程,所有用户线程结束后,守护线程将自动结束。守护线程一般都是些死循环
语法:定义
语法:使用
线程生命周期:
新建状态:new 执行后进入此状态
就绪状态:start 执行完后进入此状态
运行状态:抢到CPU时间片后由就绪状态进入运行状态,时间片结束后回到就绪状态
阻塞状态:遇到阻塞状态例如调用 Thread.sleep(1000)
时进入此状态,阻塞结束后回到就绪状态
死亡状态:整个 run 函数执行完毕
线程同步(synchronized)
语法
java 中的三种变量类型:
死锁
上述代码必然发生死锁现象
规避死锁的 rule of thumber:不要嵌套使用 synchronized。
例子:定时器
实现定时器可以手动使用 Thread.sleep
来实现,或使用内置的 java.util.Timer
,或 Spring 框架中的 SpringTask 等等。下面简述 java.util.Timer
的使用方法
内置数据结构
String、StringBuffer、StringBuilder
八种基本数据类型的包装类
JDK 1.5 之后,自动装箱拆箱:
int, byte, short, long, float, double, boolean, char
Integer, Byte, Short, Long, Float, Double, Boolean, Character
杂录
java中似乎不会区分声明与定义, 更仔细地说, 只有"声明", 也可以理解成声明时包含了定义. 这体现在编写类的时候函数的代码需写在类内部
java中只允许单继承, 多继承通过interface实现
只引入java.util.Iterator则可以使用Iterable标识符
has a关系 => 类组合
is a关系 => 类继承
like a关系 => 类实现接口
java关键字列表
基本类型相关: byte, short, int, long, float,double, boolean, char, strictfp, void
控制结构相关: if, for, else, while, do, continue, break, switch, case, default, return
访问权限相关: public, protected, private
异常相关: throw, throws, try, catch, finally
常量: final
包相关: package, import
调用构造函数: new
类相关: class, interface, static, enum, abstract, extends, implements, this, super, instanceof
小东西: assert
声明该函数底层用计算机相关语言实现: native
transient: 声明不用序列化的成员
synchronized: 声明一段代码同步执行
volatile: 声明多个变量同步发生变化
保留关键字, 没有实际含义: goto, constant
Object源码分析
重写finalize方法可以在垃圾回收时机做些事情, 垃圾回收器会自动调用这个方法. 但垃圾回收器的执行时机是不可控的. 它可能会垃圾太多了垃圾回收器才会启动
自动类型推断
JDK 8引入, 如下写法可以正常编译通过.
java内存分析
参考algorithm 4 page201-204分析.
在64位机器上,
每个对象一般有16字节的额外开销(overhead)
引用数据类型占用空间为8字节
每个对象所占字节数为8的整数倍(字节对齐)
实例内部类需要8字节的额外开销
String对象需要40字节, 其内部的字符数组另外计算
例子1:
Date类的对象所占空间为32字节: 其中overhead为16字节, 3个整型数据各占4个字节, 再加4字节补齐至8的整数倍.
例子2
Counter类的对象所占空间为32字节: 16(overhead)+8(String是引用类型)+4(int类型)+4(overhead)
例子3:
占用内存为$32+64N$个字节
其中Stack类本身带有16字节的overhead, 8字节的Node引用, 4字节的整数, 加上4字节的padding. 因此在堆上每个Stack需要分配32个字节.
每个Node对象需要16字节的overhead, 由于是Node是内部类, 还需要8个字节的overhead, 再加上两个引用16个字节, 所以一个Node需要40个字节. 而每个Node所指向Integer类型需要24字节(16字节的overhead+4字节的整型+4字节的padding). 所以每次增加一个节点, 总共需要64字节的开销.
例子4:
a占用$24+4N+padding$的内存, 因为数组也是对象, 所以有16字节overhead, 加上记录长度的整数为4字节, 加上4字节padding为24字节. 存储每个整数需要4字节, 共$4N+padding$字节.
例子5:
数组本身分析同上, 需要24字节, 每个Date对象占32字节, 每个Date对象还需要一个额外的引用8字节. 因此一共为$24+40N$字节.
例子6:
占用内存为$24+32M+8MN$, 首先数组需要24字节, 数组的每个元素都是一个数组, 每个需要8字节的引用, 所以需要$8M$字节, 而每个内层数组double [N]需要$24+8N$的大小, 所以总共需要$24+8M+M(24+8N)=24+32M+8MN$字节
例子7:
String类型, 本身作为对象有16字节开销, 内部数据为一个字符数组及3个整数, 需要8+12=20字节, 最后padding为4个字节. 因此总共为16+8+12+4一共40个字节. java内部实现时很多字符串可以共用一个内部的字符数组, 因此字符数组的开销不能简单记为$24+2N+padding$.
备注:
实例内部类才会有8 byte的额外开销, 静态内部类没有8 byte的额外开销
JAVA虚拟机存在一个小整数池, 用以节约内存, 因此一个全为1的整数数组的开销可能会比较小, 参考algs4-question
Iterator实现细节
当一个Iterator被创建后, 原始对象被修改了, 工程实现上应该抛出异常: java.util.ConcurrentModificationException
Notes:
在C++标准库中, 类似的情况也有, 尚不清楚STL是怎么处理这个问题的.
Springboot
Last updated