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
2
3
4
5
6
7
8
9
switch(value) {  //value范围在int内,且不为boolean
case value1:
do sth;
break;
...
default: //default可以放在前面,程序保证入口挑选正确且唯一.
do sth;
break;
}

构造代码块

  • 类中用{}包裹的代码块,将在每次构造函数调用时执行
  • 构造对象触发的动作:初始化(静态代码块)->super()->构造代码块->构造函数剩余部分

构造函数

  • 构造函数的第一行可以用this(...)调用其它构造函数. 编译器会检测递归构造器调用并报错
  • 编译器保证若有父类,构造方法一定会调用父类构造方法,故this(...)意味着会调用super(....)

继承

  • 只允许一个父类class Son extends Father {...}
  • 当前对象的父类指针为ThisClass.super ?,
  • 子类的构造函数的第一行都有隐式的super()调用,可以替换为各种显式调用
  • 重写 针对成员方法
    • 继承中当函数名, 参数列表(即特征标)相同时发生重写
    • 访问限制级别必须相同或放宽
    • 若父类函数返回类型为基础类型,则子类重写返回类型必须相同
    • 若父类返回引用类型, 则子类返回相同或其子类类型
    • 重写方法不能抛出新异常, 只可以抛出相同/更少异常
    • 抽象方法必须在具体类中被重写
    • 父类引用指向子类对象时,会动态绑定子类重写函数
  • 隐藏 针对所有成员变量和静态成员方法
    • 成员变量类型可以改变
    • 父类引用指向子类对象时,静态绑定父类被隐藏成员.(由对象调用的静态方法将被翻译为由类调用的静态方法。因此是隐藏而不是重写)
    • 为什么是隐藏?因为子类的构造函数总会调用父类的构造函数。若一个变量被两次修改,可能产生隐患。
  • 向上转型
    • 成员方法
      1. 编译时**检查声明类型类**中是否含有被调用的成员方法,而不检查子类对象
        
        1. 运行时**根据对象**调用最后重写的成员方法,而不依赖与声明类型类
          
          1. 被重写的方法没有丢失,但仅能通过类方法中super访问.
            
    • 成员变量
      1. 编译时**检查声明类型类**中是否含有被访问的成员变量, 而不检查子类对象
        
        1. 运行时**访问声明类型类**中的成员变量, 而不访问子类对象所重写的
          
  • instanceof
    • 判断一个对象是否为某个类的实例或是否实现了某个接口.
    • 若判断是否类的实例, 则编译器要求引用类型和类有关联(至少有父子关系)
    • 常用于强制类型转换前.

静态代码块

  • 静态代码块在程序生命周期中最多执行一次
  • 执行静态代码块的行为叫做初始化
  • 能触发初始化的动作是主动引用
    1. 创建类的实例
    2. 访问类的静态变量(常量除外, 因为常量在代码中被直接替换, 不会新开内存)
    3. 访问类的静态方法
    4. 反射
    5. 当子类被初始化时, 父类还没初始化, 那么先执行父类初始化
    6. 虚拟机启动时, 先初始化含main()定义的类
    7. 接口(禁止了static代码块)不要求父类初始化,直到真正引用父接口
  • 不会触发初始化的动作是被动引用
    1. 子类调用父类静态变量或父类静态方法, 只初始化父类
    2. 访问类的常量
    3. 声明对象数组(因为声明的是数组头引用和引用数组, 实际不含任何访问)
    4. 访问静态内部类的任何组份

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成员.
  • 继承另一个包的类后, 继承所得成员所属包不变.

数据权限

  • 类中数据权限修饰符
    1. private : 数据能在本类中访问.
    2. (空, 即默认修饰符) : 数据能在同包中访问.
    3. protected : 当类为public时有意义, 数据能在包外继承类中访问.
    4. public : 当类为public时有意义, 数据能在包外访问.
    • 同类对象可以互相访问本类的private成员.
    • 重写方法时, 权限不能降低, 否则会影响多态.
  • 类权限修饰符
    1. (空, 即默认修饰符) : 本类能在同包中访问.
    2. public : 本类能在包外访问. 一个单元最多拥有一个public类, 且必须与单元名相同(大小写敏感).

内部类

  • 成员内部类
    • 在类中以成员形式定义的另一个类, 称为成员内部类.
    • 内部类是外部类的成员, 依赖于外部对象的存在,因此不能含有静态方法或静态变量(常量除外).
    • 其他类中声明示例
      1
      2
      OuterClass 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则返回-1
    • int read(byte b[], int off, int len) 将最多len的字节读入到b[off]或以后,返回实际读入的字节数。只遇到EOF则返回-1
    • void 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) 删除成功返回ture
  • boolean 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) 返回第一次出现的位置,无则-1
  • int 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() 返回比较器,或null
  • E ceiling(E e) 返回最小的大于等于e的元素,或null
  • E floor(E e) 返回最大的小于等于e的元素,或null
  • E higher(E e) 返回最小的大于e的元素,或null
  • E lower(E e) 返回最大的小于e的元素,或null

Map 键值绑定

  • static interface Map.Entry<K, V>
  • int size()

HashMap

  • 允许键值为null
  • HashMap() 默认容量为16,负载因子为0.75
  • HashMap(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) 返回上一个值或null
  • void 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