java
[toc]
java
1. 基础
1.1 面向对象三大特征
- 封装: 对象属性私有话,只提供外界访问方法
- 继承: 在已存在类基础上建立新类,增加新的数据,功能; 但是不能选择性基础父类
- 多态: 程序定义的引用变量指向的具体类型,方法在运行期间确定
1.2. 多态类型
- 编译时多态: 主要是指方法的重载. 根据参数列表不同, 通过编辑变为两个不同的函数
- 运行时多态: 动态绑定, 运行时才能确定具体调用的哪个类中实现方法
1.3 面向对象基本原则
- 单一职责SPR(Single Responsibility Principal): 类功能要单一
- 开放封闭原则OCP(Open Close Principal): 类对于拓展是开放的, 对于修改是封闭的
- 里氏替换原则LSP(Liskov Substitution Principal): 子类可以替换所有父类的功能
- 依赖倒置原则DIP(Dependency Inversion Principle): 高层次模块不能依赖低层次模块, 他们都应该依赖抽象.抽象应该依赖抽象.
- 接口分离原则ISP(Interface Segregation Principal): 设计采用多个接口比一个通用接口要好.
1.4 内部类
- 静态内部类: 以
static class
修饰的内部类, 只能访问外部类的静态变量, 使用new 外部类.静态内部类()
初始化 - 成员内部类: 以
class
修饰的内部类. 能访问外部的的所有变量和方法. 包括静态, 非静态;私有,公有.使用以下方式初始化Outer outer = new Outer(); Outer.Inner inner = outer.new Inner();
- 局部内部类: 定义在方法中的内部类.定义在实例方法中的内部类能访问外部类的所有变量,方法. 定义在静态方法中的内部类只能访问外部类的静态变量,方法.使用时, 在对于方法中直接
new
初始化 - 匿名内部类: 继承抽象类或者实现一个接口. 不能定义任何静态成员,静态方法. 当前方法形参被内部类使用时, 必须声明为
final
.内部类不能抽象,必须实现所有抽象方法
为何局部内部类, 匿名内部类访问局部变量,变量必须加final
生命周期不一致. 局部变量存在栈中.当方法执行完. 非final局部变量就被销毁了.
1.5 重写与重载
重写(override): 放生在父子类中, 方法名, 参数列表必须相同, 返回值小于等于父类, 抛出异常小于等于父类, 访问修饰符大于等于父类.如果父类中方法为private. 则不是重写
重载(overload): 同一类中,参数列表不同(参数类型,个数,顺序不同). 与方法返回值,修饰符无关
1.6 == 与 equals区别
==: 判断对象地址是否相等. 基本类型比较值, 引用类型比较地址
equals: 判断对象是否相等.分为两种情况:
1: 未重写equals()方法. 判断比较该类两个对象, 等价与判断对象是否相等
2: 重写equals()方法.使用该方法判断对象内容是否相等.
1.7 hashcode与equals
当对象放入HashSet时, 先计算对象的hashcode. 判断有没有相等的hashcode. 如果存在相同的hashcode.则用equals()判断是否相等.相等则不会加入成功. 减少了equals()判断的次数.提高了执行速度.
1: 两对象相等. 则hashcode一定相等
2: 两对象相等. 则调用equals()返回true
3: 两对象hashcode相等. 对象不一定相等
1.8 IO
IO操作方式分类
@startmindmap
* Java IO
** Reader: 字符读取
*** 字节流
**** FileReader
**** PipedReader
**** CharArrayReader
*** 字符流
**** BufferdReader
**** InputStreamReader
** Writer: 字符输出
*** 字节流
**** FileWriter
**** PipedWriter
**** CharArrayWriter
*** 字符流
**** BufferdWriter
**** InputStreamWriter
**** PrintWriter
** InputStream: 字节读取
*** 字节流
**** FileInputStream
**** PipedInputStream
**** ByteArrayInputStream
*** 处理流
**** BufferdInputStream
**** DataInputStream
**** ObjectInputStream
**** SequenceInputStream
** OutputStream: 字节输出
*** 字节流
**** FileOutputStream
**** PipedOutputStream
**** ByteArrayOutputStream
*** 处理流
**** BufferdOutputStream
**** DataOutputStream
**** ObjectOutputStream
**** PrintStream
@endmindmap
操作对象分类:
@startmindmap
* Java IO
** 文件操作
*** FileReader
*** FileWriter
*** FileInputStream
*** FileOutputStream
** 管道操作
*** PipedReader
*** PipedWriter
*** PipedInputStream
*** PipedOutputStream
** 数组操作
*** ByteArrayInputStream
*** ByteArrayOutputStream
*** CharArrayReader
*** CharArrayWriter
** 缓冲操作
*** BufferdReader
*** BufferdWriter
*** BufferdInputStream
*** BufferdOutputStream
** 基本类型操作
*** DataInputStream
*** DataOutputStream
** 对象序列化操作
*** ObjectInputStream
*** ObjectOutputStream
** 转换操作
*** InputStreamReader
*** InputStreamWriter
** 打印操作
*** PrintStream
*** PrintWriter
@endmindmap
BIO: Block IO 同步阻塞I/O模式. 读取写入必须在一个阻塞在一个线程等待其完成
NIO: Non-blocking IO 同步非阻塞的I/O模型, 客户端,服务端通过Channel
通信. 实现多路复用
IO复用: 线程发起select调用, 查询内核数据是否准备就绪, 再发起read调用, read调用(内核空间->用户空间)还是阻塞的,
目前支持多路复用的系统调用有select, epoll等等, 基本所有操作系统都支持select调用
select调用: 内核提供的系统调用, 支持一次查询多个系统调用可用状态
epoll: linux2.6内核以上支持, 属于select调用增强
NIO通过Selector
管理多个连接, 有数据才为连接提供服务
AIO: Asynchronous IO 异步非堵塞 IO模型, 基于事件和回调机制. 应用操作之后直接返回, 当后台完成后, 操作系统通知对应线程进行后续操作.
1.9 基础类型大小
基本类型 | 大小 | 字节 | 最小值 | 最大值 | 默认值 | 常量池 | 包装类 |
---|---|---|---|---|---|---|---|
boolean[1] | - | 未定义 | - | - | false | true, false | Boolean |
char | 16 bit | 2 | Unicode 0 | Unicode 216 -1 | 'u0000' | [0, 127] | Character |
byte | 8 bit | 1 | -128 | 127 | 0 | [-128, 127] | Byte |
short | 16 bit | 2 | -215 | 215 -1 | 0 | [-128, 127] | Short |
int | 32 bit | 4 | -231 | 231 -1 | 0 | [-128, 127] | Integer |
long | 64 bit | 8 | -263 | 263 -1 | 0L | [-128, 127] | Long |
float | 32bit | 4 | IEEE754 | IEEE754 | 0f | - | Float |
double | 64bit | 8 | IEEE754 | IEEE754 | 0d | - | Double |
void | - | - | - | - | - | - | Void |
自动拆装箱:
Integer i = 10;
int n = i;
// 实际等效与
Integer i = Integer.valueOf(10);
int n = i.intValue();
1.10 Object常见方法
public final native Class<?> getClass()//native方法,用于返回当前运行时对象的Class对象,使用了final关键字修饰,故不允许子类重写.
public native int hashCode() //native方法,用于返回对象的哈希码,主要使用在哈希表中,比如JDK中的HashMap.允许重写.
public boolean equals(Object obj)//用于比较2个对象的内存地址是否相等,String类对该方法进行了重写用户比较字符串的值是否相等. 允许子类重写.
protected native Object clone() throws CloneNotSupportedException //naitive方法,用于创建并返回当前对象的一份拷贝.一般情况下,对于任何对象 x,表达式 x.clone() != x 为true,x.clone().getClass() == x.getClass() 为true.Object本身没有实现Cloneable接口,所以不重写clone方法并且进行调用的话会发生CloneNotSupportedException异常. 允许子类重写.
public String toString()//返回类的名字@实例的哈希码的16进制的字符串.建议Object所有的子类都重写这个方法.允许子类重写.
public final native void notify()//native方法,并且不能重写.唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念).如果有多个线程在等待只会任意唤醒一个. 不允许子类重写.
public final native void notifyAll()//native方法,并且不能重写.跟notify一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程.不允许子类重写.
public final native void wait(long timeout) throws InterruptedException//native方法,并且不能重写.暂停线程的执行.注意:sleep方法没有释放锁,而wait方法释放了锁.timeout是等待时间.不允许子类重写.
public final void wait(long timeout, int nanos) throws InterruptedException//多了nanos参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999).所以超时的时间还需要加上nanos毫秒.不允许子类重写.
public final void wait() throws InterruptedException//跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念.不允许子类重写.
protected void finalize() throws Throwable //实例被垃圾回收器回收的时候触发的操作, 允许子类重写. 一般很少重写
1.11 static{}静态代码块与{}非静态代码块
相同: 都在JVM加载类时且在构造方法之前执行, 定义多个时, 按照定义顺序执行, 一般对static进行赋值
不同: 静态代码块在非静态之前执行, 且只在第一次new()时或者Class.forNmae("com.mysql.cj.jdbc.Driver")
时执行静态代码块, 之后不在执行. 而非静态代码块在每次new()时都会执行, 且非静态代码块可在普通方法中定义
执行顺序: 静态代码块 -> 非静态代码块 -> 默认构造方法 -> 方法 -> 方法中代码块
2. 集合类
2.1 Collection类
digraph javaCollection {
"Iterable" -> "Collection"
"Collection" -> "Set"
"Collection" -> "List"
"Collection" -> "Queue"
"Set" -> "HashSet"
"HashSet" -> "LinkedHashSet"
"Set" -> "SortedSet"
"SortedSet" -> "NavigableSet"
"NavigableSet" -> "TreeSet"
"List" -> "LinkedList"
"List" -> "ArrayList"
"List" -> "Vector"
"Vector" -> "Stack"
"Queue" -> "Deque"
"Deque" -> "LinkedList"
"Deque" -> "ArrayDeque"
"Queue" -> "PriorityQueue"
"Queue" -> "BlockingQueue"
}
Collection:
- List:
- ArrayList: Object[]数组, 扩容时增加50%
- Vector: Object[]数组, 线程安全, 扩容时增加一倍, 不推荐使用
- LinkedList: 双向链表(JDK1.6之前为循环链表, JDK1.7之后取消循环)
- Stack: 栈, 线程安全, 先进后出, 不推荐使用
- Set:
- HashSet: 唯一, 无序, 基于HashMap实现, 底层采用HashMap(Key为存储对象, Value为内部定义全局private static final Object PRESENT对象)
- LinkedHashMap: 唯一, 按照存储顺序有序. 继承自HashSet, 内部使用LinkedHashMap
- TreeSet: 唯一, 有序,需实现排序方法. 红黑树(自平衡排序二叉树)
- Queue:
- PriorityQueue: Object[]数组实现二叉堆
- ArrayDeque: Object[]数组 + 双指针
Collection提供一个RandomAccess接口, 实现该接口,则读取元素平均复杂度为O(1), 当调用binarySearch()
时, 继承了RandomAccess的容器就会使用Collections.indexedBinarySearch(list, key)
,直接使用索引查询
ArrayList
扩容逻辑
- 初始化容量大于0, 则数组大小设置为容量大小
- 初始化容量为0, 则设置为默认final静态空数组
EMPTY_ELEMENTDATA
- 如果不传初始化容量. 则设置为默认静态空数组
DEFAULTCAPACITY_EMPTY_ELEMENTDATA
- 方法
ensureCapacity(n)
:
4.1 ArrayLis内部未使用, 外部需要保存大量数据时, 为了减少扩容次数插入之前调用.
4.2 先判断数组是否为DEFAULTCAPACITY_EMPTY_ELEMENTDATA
(还未存数据), 则判断大小n是否大于默认容量(DEFAULT_CAPACITY
)10, 大于10则扩容
4.3 如果数组不等于, 且最小容量大于0则直接扩容 - 新增时, 调用
ensureCapacityInternal(size + 1)
, 判断是否需要扩容
5.1 先判断数组是否为DEFAULTCAPACITY_EMPTY_ELEMENTDATA
(还未存数据), 判断插入的数量是否超过DEFAULT_CAPACITY
, 也就是初始化扩容时默认就是10个
5.2 不等时, 就直接判断数组长度最小必须为size + 1
个 - 再判断最小长度是否小于数组长度, 小于. 则调用
grow()
执行扩容 - grow()开始扩容
7.1 先获取原始的长度为数组产犊oldCapacity = elementData.length, 计算新的长度为newCapacity = oldCapacity + (oldCapacity >> 1)
; 可以看到, 是新容量=老容量+老容量/2; 即长度增长1.5倍
7.2 如果新长度还是小于最小长度, 那新长度就等于最小长度
7.3 如果新最小长度超过了最大长度(MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8, 部分JVM有头限制, 所以留8个格子),newCapacity - MAX_ARRAY_SIZE > 0
[2]
7.4 执行Arrays.copyOf()扩容.
BlockingQueue
进行检索或者移出一个元素时,会等待队列变为非空, 添加一个元素时, 等待队列中可用空间. 主要用于生产者-消费者模式.
poll(): 返回第一个元素并从队列中移出该元素. 当队列
为空, 则返回null;
remove(): 返回第一个元素并移出该元素. 当队列为空, 则抛异常.
2.2 Map类
digraph javaCollection {
"Map" -> "HashTable"
"Map" -> "HashMap"
"HashMap" -> "LinkedHashMap"
"Map" -> "IdentityMap"
"Map" -> "SortedMap"
"SortedMap" -> "NavigableMap"
"Map" -> "WeakHashMap"
}
Map:
- HashMap: JDK1.8之前采用数组+链表组成, 链表为了解决hash冲突而存在的. JDK1.8之后,当链表长度大于阈值(默认值8)后, 链表会转变为红黑树, 检查hash冲突后的搜索时间
- LinkedHashMap: 继承自HashMap. 并在其基础上加上了一条双向链表,记录键值对的插入顺序
- HashTable: 数组+链表. 线程安全, 不推荐使用
- TreeMap: 红黑树(自平衡排序二叉树)
2.3 HashMap
存储逻辑:
- put时, 利用key的hashcode计算当前元素在数组中的下标
- 如果hash相同的key
a) key equals比较相同. 则覆盖该数据
b) 如果key equals不同. 则key-value放入链表 - 获取时, 根据key获取值对应下标
a) key hashcode在数组中不存在. 则map中不存在数据
b) key hashcode在数组中存在. 则在链表中根据key进行equals判断
JDK1.7 VS JDK1.8:
不同 | JDK1.7 | JDK1.8 |
---|---|---|
存储结构 | 数组+链表 | 数组+链表+红黑树 |
初始化方式 | 单独函数: inflateTable() | 直接集成到扩展函数resize() 中 |
hash值计算方式 | 扰动处理 = 9次扰动 = 4次位运算 + 5次异或运算 | 扰动处理 = 2次扰动 = 1次位运算 + 1次异或运算 |
存放数据的规则 | 无冲突时,存放数组;冲突时,存放链表 | 无冲突时,存放数组;冲突 & 链表长度 < 8:存放单链表;冲突 & 链表长度 > 8:树化并存放红黑树 |
插入数据方式 | 头插法(先讲原位置的数据移到后1位,再插入数据到该位置) | 尾插法(直接插入到链表尾部/红黑树) |
扩容后存储位置的计算方式 | 全部按照原来方法进行计算(即hashCode ->> 扰动函数 ->> (h&length-1)) | 按照扩容后的规律计算(即扩容后的位置=原位置 or 原位置 + 旧容量) |
put()
逻辑
- 计算hash: key.hashcode ^ key.hashcode >>> 16; key的hashcode高位与低位亦或
- 判断table是否为空. 为空则
resize()
- 判断key所属
Node<K, V>[] table
数组位置:tab[(n-1)&hash]
. 其中n为数组长度
3.1 n为数组长度. 与hash 按位与.如n为16. 则(0xAAAAAAAA)与(0x0000000F). 与计算之后, 最后保留到最后一位了
3.2 这也就是为什么map的数组长度需要固定为2的倍数 - 找到所在位置的数据
4.1 如果为空. 则直接写入数据
4.2 如果不为空.
4.2.1 比较第一个值是否相等(调用hashcode与equals()). 相等则设置值, 跳出循环
4.2.2 如果第一个值不等, 判断是否为二叉树类型, 为二叉树则调用二叉树put
4.2.3 如果不为二叉树, 便遍历链表
4.2.3.1 如果都不相等且遍历到最后一个节点. 则插入到链表, 并判断联创长度是否超过TREEIFY_THRESHOLD
, 超过则转为红黑树
4.2.3.2 如果相等. 则替换值, 执行回调后,返回
4.2.4 判断计算hashmap总的元素数. 判断是否超过最大容量,超过则执行resize()
扩容 - 执行插入后回调
resize()
逻辑
- 判断tab是否为null或者
tab.length()==0
, 直接设置新的最大容量,阈值 - 判断tab长度不为空
2.1 判断是否超过MAXIMUM_CAPACITY
. 则不处理
2.2 如果扩容后不超过MAXIMUM_CAPACITY
. 则新的容量newThr = oldThr << 1
双倍扩容
2.3 如果tab长度为0, 但是容量大于0.则已扩容过了. 直接不管 - 开始迁移所有桶中数据, 遍历桶, 过滤桶中数据不为空的数据
3.1 先将原有桶中的数据设置null(为了方便GC回收)
3.2 如果Node<K, V> node
的node.next()
为空. 则存的单个数据. 直接计算最新位置tab[node.hash & (newcap -1)]
并赋值
3.3 如果node
为树. 则拆分树
3.4 如果node
为链表, 计算最新位置 node.hash & oldcap 最新的位置
3.4.1 如果结果为1. 代表要换到最新的点位. 由于现在为链表, 所以新位置肯定不会超过MAXIMUM_CAPACITY
转为红黑树, 所以直接在新位置挂载, 如果多个相同则挂载成链表
3.4.2 如果为0, 直接链表保存
注: - cap为tab的长度
- 原node所在位置为 node.hash & (oldcap - 1)
- 新位置为 node.hash & oldcap. 所以必定原位置的链表中的数据必定为当前位置或者当前位置*2的位置.
2.4 ConcurrentHashMap原理
JDK1.7中. 默认所有tab分为16个segment分段. 每个分段一个锁. 访问一个分段时, 不会影响其他分段访问, 使用可重入锁ReentrantLock
JDK1.8中, 通过Node + CAS + Synchronized来实现并发. 默认只锁数组中元素(也就是链表或者红黑树中的第一个元素).
3. 异常
@startwbs
* Throwable
** Error
*** VirtualMachineError
**** StackOverFlowError
**** OutOfMemoryError
*** AWTError
** Exception
*** IOException
**** FileNotFoundException
**** NetWorkException
*** ClassCastExcetion
*** RuntimeExcetion
**** NullPointException
**** IndexOutOfBoundsException
@endwbs
3.1 Throwable
所有错误和异常的超类. 包含了创建线程执行堆栈的快照, 提供了printStackTrace()
等获取堆栈跟踪数据的方法
3.2 Error
运行程序出现的严重错误. 一般为JVM问题. 发生此类问题. 不应处理该类问题, 也不应实现新的Error子类
3.3 Exception
可捕获可处理的异常
- 运行时异常: java编译器不会检查它, 此类异常属于不受检异常, 由虚拟机自动抛出异常并自动捕获, 一般代码本身由问题应从逻辑上解决改进代码
- 编译时异常: java编译器会检查它,要么通过try-catch捕获异常,否则不能编译通过. 一般不会自定义异常,而是使用提供的异常类
3.4 try-catch-finally
- catch中返回了值, finally也会执行
- 如果finally中修改了返回值,那么返回值会被修改. (catch到异常后, 返回值放入暂存区, 执行finally, 这时修改返回值, 返回值会被修改)
4. 反射
4.1 优缺点
优点: 代码灵活, 有了运行时分析操作类的能力
缺点: 安全问题, 性能也稍差
4.2 类加载过程
@startuml
:加载;
partition 链接 {
:验证;
:准备;
:解析;
}
:初始化;
:使用;
:卸载;
@enduml
加载: 通过类名获取二进制字节流, 将字节流转换java.lang.Class对象
链接: 执行验证,准备,解析步骤; 解析步骤是可选的
验证: 检查类或者接口二进制数据正确性(文件格式,元数据校验,字节码校验,符合引用验证)
准备: 类静态变量分派存储空间
解析: 常量池中的符号引用转直接引用
初始化: 初始化静态变量, 静态代码块
4.3 获取Class对象
- 知道具体类:
Class objClass = Object.class;
- 通过Class.forName()通过路径获取
Class driver = Class.forNmae("com.mysql.cj.jdbc.Driver");
类的.class文件加载到jvm, 同时还会对类进行解释,执行static{}块. 也可以通过 Class<?> forName(String name, boolean initialize, ClassLoader loader)
, 通过initialize
控制是否执行static方法
- 通过实例获取
Object o = new Object();
Class objClass = o.getClass();
- 通过Classloader.loadClass()获取
Class driver = Classloader.loadClass("com.test.Test");
类的.class文件加载到jvm, 不会执行static{}块. 只有再newInstance才执行静态代码块
注意: Class.newInstance()可以创建实例, 但是只能调用public的无参数构造方法
4.4 动态代理
4.4.1 JDK动态代理
生成动态代理对象:
public static Object newProxyInstance(ClassLoader loader, // 类加载器
Class<?>[] interfaces, //被代理的接口
InvocationHandler h) //代理执行方法
throws IllegalArgumentException
{
......
}
自定义处理逻辑
public interface InvocationHandler {
/**
* 当你使用代理对象调用方法的时候实际会调用到这个方法
*/
public Object invoke(Object proxy, // 代理类
Method method, // 调用的方法
Object[] args) // 调用参数
throws Throwable;
}
注意: JDK代理实现接口的类
4.4.2 CGLIB动态代理
cglib基于ASM
字节码生成库, 运行运行时对字节码进行修改和动态生成, 通过继承的方式实现代理
public interface MethodInterceptor
extends Callback{
// 拦截被代理类中的方法
public Object intercept(Object obj, // 被代理对象
Method method, // 被代理对象中的方法
Object[] args, // 方法参数
MethodProxy proxy // 代理后方法
) throws Throwable;
}
生成代理对象
public static Object getProxy(Class<?> clazz) {
// 创建动态代理增强类
Enhancer enhancer = new Enhancer();
// 设置类加载器
enhancer.setClassLoader(clazz.getClassLoader());
// 设置被代理类
enhancer.setSuperclass(clazz);
// 设置方法拦截器
enhancer.setCallback(new DebugMethodInterceptor());
// 创建代理类
return enhancer.create();
}
4.4.3 对比
JDK Proxy: 代理实现了接口的类或者直接代理接口; 效率上比CGLIB更高.后期Graalvm静态编译只支持JDK Proxy.
CGLIB:代理任何类, 通过继承方法来拦截调用, 因此不能代理声明未final的类型的类和方法
4.5 访问字段, 方法, 构造方法, 获取继承关系
4.5.1 访问字段
字段:
- Field getField(name):根据字段名获取某个public的field(包括父类)
- Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)
- Field[] getFields():获取所有public的field(包括父类)
- Field[] getDeclaredFields():获取当前类的field(不包括父类)
Field包括字段所有信息 - getName(): 返回字段名称
- getType(): 返回字段类型, Class实例
- getModifiers(): 字段修饰符, int, 不同bit位代表不同含义
int m = f.getModifiers();
Modifier.isFinal(m); // true
Modifier.isPublic(m); // false
Modifier.isProtected(m); // false
Modifier.isPrivate(m); // true
Modifier.isStatic(m); // false
设置,获取值
Class c = p.getClass();
Field f = c.getDeclaredField("name");
f.setAccessible(true);
Object value = f.get(p);
f.set(p, "Xiao Hong");
4.5.1 访问方法
方法:
- Method getMethod(name, Class...):获取某个public的Method(包括父类)
- Method getDeclaredMethod(name, Class...): 获取当前类的某个Method(不包括父类)
- Method[] getMethods():获取所有public的Method(包括父类)
- Method[] getDeclaredMethods():获取当前类的Method(不包括父类)
Method包括字段所有信息 - getName(): 返回方法名称
- getReturnType(): 返回方法返回值类型, Class实例
- getParameterTypes(): 返回方法的参数类型,是一个Class数组
- getModifiers(): 方法的修饰符, int, 不同bit位代表不同含义
调用方法
Method m = String.class.getMethod("substring", int.class);
// 当非public方法使, 需要调用setAccessible
m.setAccessible(true);
// 在s对象上调用该方法并获取结果:
String r = (String) m.invoke(s, 6);
调用静态方法
Method m = Integer.class.getMethod("parseInt", String.class);
// 调用该静态方法并获取结果:
Integer n = (Integer) m.invoke(null, "12345");
多态下: 总是调用实际类型的覆写方法(如果存在)
4.5.1 构造方法
构造方法:
- getConstructor(Class...):获取某个public的Constructor
- getDeclaredConstructor(Class...): 获取某个Constructor
- getConstructors():获取所有public的Constructor
- getDeclaredConstructors():获取所有Constructor
调用构造方法
// 访问非public构造器
constructor.setAccessible(true);
// 创建对象
constructor.newInstance(Object... parameters);
4.5.2 继承关系
Class n = i.getSuperclass(); // 当前类父类型, 只有Object父类型为null
Class[] is = s.getInterfaces(); // 只返回当前类的实现接口
Object.class.isAssignableFrom(Integer.class); //true, 是否可以向上转型
5. 其他
5.1 注解
注解大多用于标记和检查.
5.1.2 元注解
除了基本注解外, 还有常用的元注解(修饰注解的注解)
@Retention: 标记注解的生命周期
@Target: 注解可以修饰那些地方(方法,成员变量, 类等等)