前言
我们在编码学习或者面试过程中经常会提到反射这个概念。今天我们就简单聊一下反射。
概念
反射是什么呢?或者说,反射机制是什么呢?Java的反射机制,就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和访问它的任意属性;这种动态获取信息,以及任意动态调用对象方法的功能称之为Java的反射机制。
类加载器
概念
ClassLoader在Java中有着非常重要的作用,它主要工作在Class装载的阶段,其重要作用是从系统外部获得Class的二进制数据流。它是Java的核心组件,所有的Class都是由ClassLoader加载的,ClassLoader负责将Class文件的二进制数据流装载进系统,然后交给Java虚拟机进行连接初始化等操作。
分类
- BootstrapClassLoader:C++编写,加载核心库java.*。
- ExtClassLoader:Java编写,加载扩展库javax.*。
- AppClassLoader:Java编写,加载程序所在目录。
- 自定义ClassLoader:Java编写,定制化加载。
自定义ClassLoader
重点关注findClass
和defineClass
两个方法:
package com.rubin;
import java.io.*;
/**
* Created by rubin on 2019/5/4.
*/
public class MyClassLoader extends ClassLoader {
private String path;
public MyClassLoader(String path) {
this.path = path;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] cByte = this.loadClassData(name);
return defineClass(name, cByte, 0, cByte.length);
}
private byte[] loadClassData(String s) {
FileInputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(new File(path + s + ".class"));
out = new ByteArrayOutputStream();
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return out.toByteArray();
}
}
调用示例:
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
MyClassLoader m = new MyClassLoader("/Users/rubin/Desktop/");
Class c = m.findClass("Test");
c.newInstance();
}
双亲委派机制
概念
双亲委派机制,简单来说就是在ClassLoader加载类的时候,首先查找父ClassLoader加载的类中有没有该类,有的话,就不重复加载,而是直接使用已经加载的类。如下图所示:
作用
避免重复加载相同的字节码
loadClass和forName的区别
如下图所示:
图中我们可以看到,类的加载过程分为三步:加载、链接和初始化。Class.forName
方法,会执行类加载的全部步骤,而ClassLoader.loadClass
只会执行类的加载过程,并不会执行链接和初始化。
常用方法
getName()
解释
获取类的类类型对象在Java虚拟机中的名称
示例
- String.class.getName() -> "java.lang.String"
- byte.class.getName() -> "byte"
- (new Object[3]).getClass().getName() -> "[Ljava.lang.Object;"
- (new int[3][4][5][6][7][8][9]).getClass().getName() -> "[[[[[[[I"
getClassLoader()
解释
获取类的类加载器
getTypeParameters()
解释
获取类的泛型数组
示例
- Map.class.getTypeParameters() -> [K, V]
- List.class.getTypeParameters() -> [E]
getSuperclass()
解释
获取类的父类(注意:如果类没有父类,将返回Object的Class,如果是接口话,调用该方法将返回null)
示例
- Map.class.getSuperclass() -> null
- HashMap.class.getSuperclass -> java.util.AbstractMap
- Object.class.getSuperclass() -> null
- HashMap[].class.getSuperclass() -> java.lang.Object
getGenericSuperclass()
解释
获取类的父类(如果有泛型也会返回父类的泛型)(注意:如果类没有父类,将返回Object的Class,如果是接口话,调用该方法将返回null)
示例
- Map.class.getGenericSuperclass() -> null
- HashMap.class.getGenericSuperclass-> java.util.AbstractMap<K, V>
- Object.class.getGenericSuperclass() -> null
- HashMap[].class.getGenericSuperclass()-> java.lang.Object
getPackage()
解释
获取类所在的包(如果没有包,将返回null,比如数组)
示例
- HashMap.class.getPackage().getName() -> java.util
- HashMap[].class.getPackage().getName() -> null
isPrimitive()
解释
判断该类是不是原始类型(八种基本类型)
getInterfaces()
解释
获取该类所实现的接口类列表(注意:只包含自己的,不包含父类实现的接口)
getGenericInterfaces()
解释
获取该类所实现的接口类型(Type)列表(如果有泛型也会返回父类的泛型)(注意:只包含自己的,不包含父类实现的接口)
getComponentType()
解释
获取数组类的元素的类类型,如果是基本类型,则返回null(提示:可以通过Array.newInstance()来反射生成数组对象)
示例:
- char.class.getComponentType() -> null
- char[].class.getComponentType() -> char
- char[] charArr = (char[])Array.newInstance(char[].class.getComponentType(), 10)
getModifiers()
解释
获取类的访问修饰符,该方法返回一个int类型的数字,通过Modifier.toString(i)来获取修饰符的文案。
示例
- Modifier.toString(Integer.class.getModifiers()) -> public final
getDeclaringClass()
解释
获取类的声明类。源码中的解释是如果此类是另外一个类中声明的属性或者方法,则返回声明类的类类型。数组或者泛型或者void等等基础类均返回null。如果该类不是另一个类中声明的变量或者方法,则返回null。
示例
- HashMap.class.getDeclaringClass() -> null
getSimpleName()
解释
获取类在源码中的名称(不包含包的名称),如果是数组,将返回类的名称并拼接上[],如果是匿名内部类,则返回空串。
示例
- HashMap.class.getSimpleName() -> HashMap
- HashMap[].class.getSimpleName() -> HashMap[]
getTypeName()
解释
获取类的类型的名称,如果是数组,将返回名称的基础上拼接上[]。匿名内部类将返回引用类的类名称。
示例
- Map.class.getTypeName() -> java.util.Map
public class Test { public static void main(String[] args) throws Exception { new Thread(new Runnable() { @Override public void run() { // 这个输出将打印 com.rubin.aspect.Test$1 System.out.println(this.getClass().getTypeName()); } }).start(); } }
getCanonicalName()
解释
将按照java语言规范来反回类的名称。匿名内部类将返回null。
示例
- Map.class.getCanonicalName() -> java.util.Map
- Map[].class.getCanonicalName() -> java.util.Map[]
isAnonymousClass()
解释
判断是不是匿名类。
示例
- Map.class.isAnonymousClass() -> false
- Map[].class.isAnonymousClass() -> false
isMemberClass()
解释
判断是不是内部类。
示例
- Map.class.isMemberClass() -> false
- Map.Entry.class.isMemberClass() -> true
getClasses()
解释
返回该类声明为public的成员内部类或者接口类的集合(包括自己声明的以及继承父类的所有的public的成员内部类的类型)。基本类型或者数组将返回空集合。
示例
- Arrays.toString(HashMap.class.getClasses()) -> [class java.util.AbstractMap$SimpleEntry, class java.util.AbstractMap$SimpleImmutableEntry]
- Arrays.toString(HashMap[].class.getClasses()) -> []
getFields()
解释
返回该类声明的所有public的、继承父类(包括父类的父类,一直到最顶级)的public的以及实现所有接口(包括接口的父接口,一直到最顶级)的属性集合。集合类和基本类返回空数组。
示例
- Arrays.toString(Connection.class.getFields()) -> [public static final int java.sql.Connection.TRANSACTION_NONE,...]
- Arrays.toString(Connection[].class.getFields()) -> []
getMethods()
解释
返回该类声明的所有public的(这里面包括了所有实现接口的方法)、继承父类(包括父类的父类,一直到最顶级)的public的方法集合。集合类返回Object类定义的public的方法。基本类返回空数组。
示例
- Arrays.toString(Connection.class.getMethods()) -> [public abstract void java.sql.Connection.setReadOnly(boolean) throws java.sql.SQLException,...]
- Arrays.toString(Connection[].class.getMethods()) -> [public final void java.lang.Object.wait() throws java.lang.InterruptedException,...]
getConstructors()
解释
返回该类所声明的所有public的构造器列表。数组、接口或者基本类型返回空数组。
示例
- Arrays.toString(HashMap.class.getConstructors()) -> [public java.util.HashMap(int), public java.util.HashMap(), public java.util.HashMap(java.util.Map), public java.util.HashMap(int,float)]
- Arrays.toString(HashMap[].class.getConstructors()) -> []
getField(String name)
解释
通过属性名称来获取该类中或者父类中(包含弗雷德父类,一直到顶级父类)或者实现的接口中(包括接口的父接口,一直到顶级接口)声明的public的属性。查找顺序为先查找本类中,本类查不到的话会去查找实现的所有接口(包括父类实现的接口),接口查不到会再去查找所有父类。如果均查不到,会抛出异常。数组或者基本类型会抛出异常。
getMethod(String name, Class<?>... parameterTypes)
解释
通过方法名称和参数列表(按照声明顺序传值,为了准确查找重载的方法)来获取该类中或者父类中(包含弗雷德父类,一直到顶级父类)或者实现的接口中(包括接口的父接口,一直到顶级接口)声明的public的方法。查找顺序为先查找本类中,本类查不到的话会去查找实现的所有接口(包括父类实现的接口),接口查不到会再去查找所有父类。如果均查不到,会抛出异常。
getConstructor(Class<?>... parameterTypes)
解释
获取本类中参数列表相符合(顺序也要一致)的public的构造器对象。找不到会抛出异常。
getDeclaredClasses()
解释
返回该类声明的所有成员内部类或者接口类的集合(但是不包括继承的)。基本类型或者数组将返回空集合。
getDeclaredFields()
解释
返回该类所声明的所有属性集合(不包括继承的)。数组将返回空集合。
getDeclaredMethods()
解释
返回该类所声明的所有方法集合(不包括继承的)。数组将返回空集合。
getDeclaredConstructors()
解释
返回该类所声明的所有构造器集合(不包括继承的)。数组、基本类型、接口将返回空集合。
getDeclaredField(String name)
解释
获取该类中声明的(不包括父类)名为name的属性。找不到则抛出异常。数组、基本类型无任何声明属性。
getDeclaredMethod(String name, Class<?>... parameterTypes)
解释
返回该类所声明的参数列表匹配(类型和顺序)的方法对象(不包含父类),找不到会抛出异常。数组、基本类型无任何声明方法。
getDeclaredConstructor(Class<?>... parameterTypes)
解释
获取本类中参数列表相符合(顺序也要一致)的构造器对象(不区分访问标识符)。找不到会抛出异常。
getResourceAsStream(String name)
解释
将classpath下的文件加载为输入流,name为当前类的相对路径。如果从classpath根目录下加载,在路径上面加/。例如/com/rubin/demo/Demo.class。也可以通过相对路径加载,比如当前文件同目录下的文件:Test.class。
getAnnotation(Class<A> annotationClass)
解释
获取某个类下(如果次注解被@Inherited元注解标注,则会向上查找父类标注的注解有无此注解)指定类型的注解实体。
isAnnotationPresent(Class<? extends Annotation> annotationClass)
解释
判断当前类的实体上(如果次注解被@Inherited元注解标注,则会向上查找父类标注的注解有无此注解)是否标有某个注解。
getAnnotations()
解释
获取当前类(以及父类上面的被@Inherited元注解标注的注解)上面标注的所有的注解集合。没有注解返回空数组。
getAnnotationsByType(Class<T> annotationClass)
解释
源码当中的解释是查找相关联的注解列表。也就是说,如果要查找的注解类型是可继承的(注解被@Inherited元注解标注),则会首先查找本类上面是否有该注解,没有的话,会查找他的父类,看是否有该注解,并返回注解集合(通常找到了就只有目标注解一个元素,没找到则返回空集合)。
getDeclaredAnnotation(Class<T> annotationClass)
解释
获取当前类(会忽略父类上的任意注解)上的某个直接标注的注解。
getDeclaredAnnotationsByType(Class<T> annotationClass)
解释
通过类型获取当前类上直接标注的注解中的关联注解集合列表。通常有的话,会返回含有该注解一个元素的集合,没有返回空集合。
getDeclaredAnnotations()
解释
获取该类上直接标注(忽略所有父类的任意注解)的注解的集合。
文章评论