Java语法笔记
Since 2018/07/12
作用域
- 与C++不同,Java在新建变量时,不允许其名称与其上一级作用域的变量名相同.
- 若某一时刻某一作用域中,某个名字的变量被销毁,则该名字可以再次使用.
数据类型
- 整数默认为int, 小数默认为double(8字节), 字面值不能大于类型最大值.
- 数字可以加后缀指定类型, long为
L
, double为d
, float为f
. - 缩窄转换会报错,除非强制类型转换(前置括号). 类型提升不会报错(如int->double)
- short是16位有符号类型, char是16位无符号类型.
- 非基础的数据类型只有引用数据类型,像阉割的指针,使用点号时自动解引用.
数组
int[] array = new int[n]; // array.length 为数组长度, 越界会报错
int[] array = new int[] {2, 0, 4, 1}; //array长度为4, 仅分配内存可初始化
T[][] array = { {new T(), new T()}, {new T()} } //低维长度不定
int[][] array = new int[n1][]; array[1] = new int[n2]; //低维长度不定
- 凡是new生成的东西都在堆内存中, 只有array作为一个引用存在于栈内存中
- 与C++不同, 已有数组名(引用)可以赋值给另一个已有数组名(引用), 允许变动.
switch
1 | switch(value) { //value范围在int内,且不为boolean |
构造代码块
- 类中用
{}
包裹的代码块,将在每次构造函数调用时执行 - 构造对象触发的动作:初始化(静态代码块)->super()->构造代码块->构造函数剩余部分
构造函数
- 构造函数的第一行可以用
this(...)
调用其它构造函数. 编译器会检测递归构造器调用并报错 - 编译器保证若有父类,构造方法一定会调用父类构造方法,故
this(...)
意味着会调用super(....)
继承
- 只允许一个父类
class Son extends Father {...}
- 当前对象的父类指针为
ThisClass.super
?, - 子类的构造函数的第一行都有隐式的
super()
调用,可以替换为各种显式调用 - 重写 针对成员方法
- 继承中当函数名, 参数列表(即特征标)相同时发生重写
- 访问限制级别必须相同或放宽
- 若父类函数返回类型为基础类型,则子类重写返回类型必须相同
- 若父类返回引用类型, 则子类返回相同或其子类类型
- 重写方法不能抛出新异常, 只可以抛出相同/更少异常
- 抽象方法必须在具体类中被重写
- 父类引用指向子类对象时,会动态绑定子类重写函数
- 隐藏 针对所有成员变量和静态成员方法
- 成员变量类型可以改变
- 父类引用指向子类对象时,静态绑定父类被隐藏成员.(由对象调用的静态方法将被翻译为由类调用的静态方法。因此是隐藏而不是重写)
- 为什么是隐藏?因为子类的构造函数总会调用父类的构造函数。若一个变量被两次修改,可能产生隐患。
- 向上转型
- 成员方法
编译时**检查声明类型类**中是否含有被调用的成员方法,而不检查子类对象
运行时**根据对象**调用最后重写的成员方法,而不依赖与声明类型类
被重写的方法没有丢失,但仅能通过类方法中super访问.
- 成员变量
编译时**检查声明类型类**中是否含有被访问的成员变量, 而不检查子类对象
运行时**访问声明类型类**中的成员变量, 而不访问子类对象所重写的
- 成员方法
instanceof
- 判断一个对象是否为某个类的实例或是否实现了某个接口.
- 若判断是否类的实例, 则编译器要求引用类型和类有关联(至少有父子关系)
- 常用于强制类型转换前.
静态代码块
- 静态代码块在程序生命周期中最多执行一次
- 执行静态代码块的行为叫做初始化
- 能触发初始化的动作是主动引用
- 创建类的实例
- 访问类的静态变量(常量除外, 因为常量在代码中被直接替换, 不会新开内存)
- 访问类的静态方法
- 反射
- 当子类被初始化时, 父类还没初始化, 那么先执行父类初始化
- 虚拟机启动时, 先初始化含main()定义的类
- 接口(禁止了static代码块)不要求父类初始化,直到真正引用父接口
- 不会触发初始化的动作是被动引用
- 子类调用父类静态变量或父类静态方法, 只初始化父类
- 访问类的常量
- 声明对象数组(因为声明的是数组头引用和引用数组, 实际不含任何访问)
- 访问静态内部类的任何组份
final
- final修饰变量: 声明常量, 其内容不可修改
- 对于基本数据类型, 其值不可修改
- 对于引用数据类型, 指向不能更换, 但所指向的内容仍可修改
- 常量和普通变量一样可以重写/隐藏.
- 每个对象都包含各自的final变量, 在构造其中初始化
- final修饰类: 定义不可被继承类
- 一般出于安全性原因才会考虑final修饰类
- 因为不可被继承, 所以类不可能为abstract, 方法不含abstract
- final修饰方法: 定义不可被重写方法
abstract
- abstract修饰类: 指明类是抽象类, 不能实例化. 含抽象方法的类必须用abstract修饰.
- 抽象类不可能含final方法, 但无其他限制, 可像普通类一样编写.
- abstract修饰方法: 指明方法是抽象方法, 原型后加分号, 而不能写方法体.
interface
- 对应关键字
implements
实现 - 接口是对行为的抽象, 方便描述类的共同行为.
- 接口的变量默认且仅限于
public static final
(意味着在接口外能访问) - 接口的方法默认且仅限于
public abstract
- 新接口可以继承(extends)多个旧接口.
- 类实现(implements)接口后必须重写接口方法, 否则必须定义为abstract类.
- 类可以实现多个方法, 即使这些方法有同名常量或同一函数.
- 若实现多个方法后有同名常量, 则尝试访问它们时会产生编译时二义性错误.
- 接口作为一种数据类型, 可以引用, 可以向上转型以实现多态.
包
- 访问不同包中的类需要加上
包名.
, 或者使用import包名.类名
或包名.*
- 包是开放的(可以跨单元). 一个包可拥有多个public类, 但一个单元最多拥有一个public类, 且必须与单元名相同(大小写敏感).
- 同一包中的类可以互相访问非private成员.
- 继承另一个包的类后, 继承所得成员所属包不变.
数据权限
- 类中数据权限修饰符
private
: 数据能在本类中访问.(空, 即默认修饰符)
: 数据能在同包中访问.protected
: 当类为public时有意义, 数据能在包外继承类中访问.public
: 当类为public时有意义, 数据能在包外访问.
- 同类对象可以互相访问本类的private成员.
- 重写方法时, 权限不能降低, 否则会影响多态.
- 类权限修饰符
(空, 即默认修饰符)
: 本类能在同包中访问.public
: 本类能在包外访问. 一个单元最多拥有一个public类, 且必须与单元名相同(大小写敏感).
内部类
- 成员内部类
- 在类中以成员形式定义的另一个类, 称为成员内部类.
- 内部类是外部类的成员, 依赖于外部对象的存在,因此不能含有静态方法或静态变量(常量除外).
- 其他类中声明示例
1
2OuterClass p1 = new OuterClass();
OuterClass.InnerClass p2 = p1.new InnerClass(); - 因为是成员之一, 可以访问任何外部类成员, 存在引用
OuterClass.this
- 静态内部类
- 在类中以静态成员形式定义的另一个类, 称为静态内部类.
- 静态内部类的外部类一定全是静态的.==?_?==
- 静态内部类可以访问外部类的静态成员.
- 静态内部类可以定义静态成员变量,静态成员方法和静态内部类.
- 初始化某个静态内部类不会触发外部类的初始化.
- 局部类
- 定义在方法中的, 有类名的类, 称为局部类.
- 局部类依赖于方法的运行, 因此本身不是静态的, 不能含有静态成员(常量除外).
- 局部类可以访问方法中的局部变量(jr8之前只能访问final).
- 若方法是成员方法, 则能访问外部类的所有成员, 存在引用
OuterClass.this
- 若方法是静态方法, 则只能访问外部类的静态成员.
- 匿名类
- 匿名类是没有类名的子类, 使用格式:
new FatherClassOrInterface() {...} ;
- 匿名类通常意味着向上转型, 并即时生成一个实例, 因此本身不是静态的.
- 匿名类可以出现在成员变量中/方法中.
- 匿名类不能定义新的构造方法/实现新的接口/派生出子类.
- 匿名类若出现在成员变量中, 则类似于成员内部类; 若出现在方法中, 则类似于局部类.
- 匿名类是没有类名的子类, 使用格式:
回调(思想)
- 某个对象A引发另一对象B的行为,同时使B持有A的引用。B在行为过程中再引发A的行为,此谓回调。
- A的引用,可能是直接引用,也可能是接口引用等
- 令B持有A的引用,可能通过方法参数传递,也可能通过set成员变量引用
- 在多线程中,回调尤为常用
异常
- Throwable的直接子类有Error(JVM错误用),Exception(异常类)。Exception的直接子类有RuntimeException(算术异常,丢失资源,找不到类,空指针,非法参数,数组越界,未知异常),IOException(EOF异常,找不到文件)
- 运行时异常无需手动管理,所有过程隐式进行。IOException需要显式处理。
- 当程序发生异常时,需要手写
throw new XXException(..)
,则方法会抛出一个异常。在异常被抛出的地方,必须被处理。 - 处理异常:
- 用
try{}
包括可能会抛出异常的代码块,后接catch (XXExcepetion e){} catch (BiggerException e){}... finally{}
代码块。或在方法声明中注明throws XXException
(则调用此方法的方法必须处理此异常) - 若
try{}
代码块中确实抛出异常,则程序跳至catch代码块,并用e接收异常实例以供分析。 - 无论在
try{}
,catch(){}
中有无遇到异常,程序必定执行finally{}
,一般在其中回收资源。在finally{}
中引发的异常会中止余下代码的执行。 - 需要同一时间分别处理多个异常时(比如关闭多个流),常用try嵌套。注意在finally中判断引用是否为空。
- 用
输入输出流
字节流
- 抽象父类:InputStream,OutputStream(抽象方法是read(), write())
- 文件字节流:FileInputStream,FileOutputStream
- 构造方法(常用的)有(String name), (File file), OutputStream还有(File file, boolean append), 若append,则文件写入在末尾
int read()
用int返回下一字节byte(无输入则返回-1),对文件单个字节操作.int read(byte b[])
将最多b.length的字节读入到b[],返回实际读入的字节数。只遇到EOF则返回-1int read(byte b[], int off, int len)
将最多len的字节读入到b[off]或以后,返回实际读入的字节数。只遇到EOF则返回-1void write(int b)
写一个字节b(抛弃高位)void write(byte b[], int off, int len)
从b[off]
开始写出len个字节void write(byte b[])
写出b.length个字节
BufferedInputStream(InputStream)
利用内置的缓冲数组加速读取BufferedOutputStream(OutputStream)
加速写出
字符流
- 抽象父类:Reader, Writer
- 文件字符流:FileReader, FileWriter(使用默认字符集)
- 若要指定字符编码和字节缓冲区大小,应该构造InputStreamReader(FileInputStream in, String charsetName);
BufferedReader(Reader in)
,(Readerin int sz)
加速读入BufferedWriter(Writer out)
,(Writer out, int sz)
加速写出PrintWriter(File file)
(String fileName)
,(OutputStream out)
,(Writer out)
有格式的输出流
泛型
泛型类
- 可以定义泛型类
class<T> {}
- 不能调用泛型参数的构造方法
- 可以指定泛型类上界,以使用其成员
class<T extends K>
,编译器静态地禁止代码越过上界。泛型类在各处代码都能记住其上界。 - 声明一个泛型类对象时,省略尖括号表示
<Object>
- 在同一条声明语句中,后面的尖括号可以留空表示同上
<>
- 类型参数是运行时构造对象才能确定的,因此静态方法不能使用类型参数
- 泛型类是非协变的,
A<Person>
与A<Student>
没有关联 - 禁止声明类型为泛型类的数组(可以用arrayList代替)
将泛型类用作参数
- 使用通配符
<?>
, 此时可以指定泛型参数的下界(super)或更严格的上界(无视变得宽松的上界)
泛型方法
- 可以定义泛型方法
public static <T> T func(){ return null; }
- 不能调用泛型参数的构造方法
- 可以指定泛型参数上界,以使用其成员
public static <T extends K> T func() { return null; }
,编译器静态地禁止代码越过上界 - 类型参数视为方法接受的实数,因此可以用于定义静态方法
- 编译实现将把泛型改写成Object,并在适当的时候向下转型。因此,
Collection
- 接受泛型参数
boolean add(E e)
boolean addAll(Collention<? extends E> c)
boolean contains(Object o), containsAll(Collect<?> c)
boolean equals(Object o)
boolean isEmpty()
Iterator<E> iterator()
boolean remove(Object o)
删除成功返回tureboolean removeAll(Collenton<?> c)
int size()
Object[] toArray()
<T> T[] toArray(T[])
Collections 由静态方法构成的类
void sort(Collection<?> c)
list 允许重复的列表
ArrayList
void add(int index, E element)
void add(int index, Collection<? extends E> c)
- 常用
void ensureCapacity(int minCapacity)
可以优化新开内存的耗时 int indexOf(Object o)
返回第一次出现的位置,无则-1int lastIndexOf(Object o)
E remove(int index)
删除指定位置的元素E set(int index, E element)
替换指定位置的元素void sort(Comparator<? super E> c)
排序
LinkedList
- 同ArrayList
void addFirst(E e)
void addLast(E e)
E getFirst()
E getLast
Iterator<E> descendingIterator()
逆序迭代器E pop()
void push(E e) == addFirst(E e)
set 不允许重复的集合
boolean(如果集合发生改变) remainAll(Collection<?> c), removeAll(Collection<?> c)
void clear()
清空
HashSet
- 依赖于
HashCode()
判断元素是否相同 - 基于Object的
HashCode()
会将地址纳入计算,可以覆写HashCode()
以忽略地址差异 - 若
HashCode()
相同,则调用equals()
判断。基于Object的equals()
仅比较地址(String类已覆写好)。
TreeSet
- 依赖于接口Comparable的
compareTo()
或者比较类的compare(,)
比较大小。优先使用比较类。小在前,大在后。 - 比较类需要实现接口Comparator,并
@Override compare(,)
Iterator<E> descendingIterator()
逆序迭代器Comparator <? super E> comparator()
返回比较器,或nullE ceiling(E e)
返回最小的大于等于e的元素,或nullE floor(E e)
返回最大的小于等于e的元素,或nullE higher(E e)
返回最小的大于e的元素,或nullE lower(E e)
返回最大的小于e的元素,或null
Map 键值绑定
static interface Map.Entry<K, V>
int size()
HashMap
- 允许键值为null
HashMap()
默认容量为16,负载因子为0.75HashMap(int intialCapacity)
HashMap(int intialCapacity, float loadFactor)
HashMap(Map<? extends K, ? extends V> m)
boolean containsKey(Object key)
boolean containsValue(Object value)
Set<Map.Entry<K, V>> entrySet()
V get(Object key)
Set<K> keySet()
V put(K key, V value)
返回上一个值或nullvoid putAll(Map<? extends K, ? extends V> m)
复制映射V remove(Object key)
boolean remove(Object key, Object value)
V replace(K key, V value)
如果有键则替换boolean replace(K key, V oldValue, V newValue)
如果键key映射到oldValue则替换Collection<V> values()
返回值的Collection