一 : Class解析
java.lang.Class:是反射的源头。
首先我们创建了一个类,通过编译(javac.exe),生成对应的.class文件。之后我们使用java.exe加载(JVM的类加载器完成的),此.class文件加载到内存以后,就是一个运行时类,存在在缓存区。那么这个运行时类本身就是一个Class的实例.
获取运行时类实例
Person p = new Person();
Class clazz = p.getClass();//通过运行时类的对象,调用其getClass(),返回其运行时类。
1.每一个运行时类只加载一次!
2.有了Class的实例以后,我们才可以进行如下的操作:
1)创建对应的运行时类的对象
2)获取对应的运行时类的完整结构(属性、方法、构造器、内部类、父类、所在的包、异常、注解、...)
3)调用对应的运行时类的指定的结构(属性、方法、构造器)
4)反射的应用:动态代理
二 : 获取Class的实例操作
- 调用运行时类本身的.class属性
Class clazz1 = Person.class;
System.out.println(clazz1.getName());
Class clazz2 = String.class;
System.out.println(clazz2.getName());
- 通过运行时类的对象获取
Person p = new Person();
Class clazz3 = p.getClass();
System.out.println(clazz3.getName());
- 通过Class的静态方法获取.通过此方式,体会一下,反射的动态性
String className = "com.atguigu.java.Person";
Class clazz4 = Class.forName(className);
System.out.println(clazz4.getName());
- 通过类的加载器
ClassLoader classLoader = this.getClass().getClassLoader();
Class clazz5 = classLoader.loadClass(className);
System.out.println(clazz5.getName());
证明每一个运行时类只加载一次
内存地址空间相同,证明为统一个运行时类
System.out.println(clazz1 == clazz3);//true
System.out.println(clazz1 == clazz4);//true
System.out.println(clazz1 == clazz5);//true
三 : 类的加载器
类加载的过程
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化.
类加载器
系统类加载器
ClassLoader loader1 = ClassLoader.getSystemClassLoader();
System.out.println(loader1);
扩展类加载器
ClassLoader loader2 = loader1.getParent();
System.out.println(loader2);
引导类加载器
打印结果(null) 自动加载,无法直接获取
ClassLoader loader3 = loader2.getParent();
System.out.println(loader3);
系统类加载器加载Person 类
Class clazz1 = Person.class;
ClassLoader loader4 = clazz1.getClassLoader();
System.out.println(loader4);
引导类加载器自动加载
打印结果null
String className = "java.lang.String";
Class clazz2 = Class.forName(className);
ClassLoader loader5 = clazz2.getClassLoader();
System.out.println(loader5);
四 : 通过反射获取Class对象和完整结构
-
获取对象
创建对应的运行时类的对象。使用newInstance(),实际上就是调用了运行时类的空参的构造器。
要想能够创建成功:
①要求对应的运行时类要有空参的构造器。
②构造器的权限修饰符的权限要足够。
person
空参构造器不能用private
修饰
public void test1() throws Exception{
String className = "com.atguigu.java.Person";
Class clazz = Class.forName(className);
Object obj = clazz.newInstance();
Person p = (Person)obj;
System.out.println(p);
}
-
获取设置运行时类的属性
① getFields()
获取到运行时类中及其父类中声明为public的属性
public void test1(){
Class clazz = Person.class;
Field[] fields = clazz.getFields();
for(int i = 0;i < fields.length;i++){
System.out.println(fields[i]);
}
System.out.println();
}
② getDeclaredFields()
获取运行时类本身声明的所有的属性
Field[] fields1 = clazz.getDeclaredFields();
for(Field f : fields1){
System.out.println(f.getName());
}
③获取 权限修饰符 变量类型 变量名
Class clazz = Person.class;
Field[] fields1 = clazz.getDeclaredFields();
for(Field f : fields1){
//1.获取每个属性的权限修饰符
int i = f.getModifiers();
String str1 = Modifier.toString(i);
System.out.print(str1 + " ");
//2.获取属性的类型
Class type = f.getType();
System.out.print(type.getName() + " ");
//3.获取属性名
System.out.print(f.getName());
System.out.println();
}
④获取运行时类中声明为public的指定属性名为fieldName的属性
getField(String fieldName)
获取运行时类中声明为public的指定属性名为fieldName的属性
Class clazz = Person.class;
Field name = clazz.getField("name");
⑤将运行时类的指定的属性赋值
Person p = (Person)clazz.newInstance();
name.set(p,"TZ");
System.out.println("%"+name.get(p));
⑥获取运行时类中指定的名为fieldName的属性
不惧权限修饰符
getDeclaredField(String fieldName)
Field age = clazz.getDeclaredField("age");
//由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作。
//声明为protected 不在一个包的情况下也要加`age.setAccessible(true)` 否则不用加
age.setAccessible(true);
age.set(p,10);
System.out.println(p);
-
获取运行时类的方法
①getMethods():
获取运行时类及其父类中所有的声明为public的方法
Method[] m1 = clazz.getMethods();
for(Method m : m1){
System.out.println(m);
}
System.out.println();
②getDeclaredMethods()
获取运行时类本身声明的所有的方法
Method[] m2 = clazz.getDeclaredMethods();
for(Method m : m2){
System.out.println(m);
}
③获取 注解 权限修饰符 返回值类型 方法名 形参列表 异常
Method[] m2 = clazz.getDeclaredMethods();
for(Method m : m2){
//1.注解
Annotation[] ann = m.getAnnotations();
for(Annotation a : ann){
System.out.println(a);
}
//2.权限修饰符
String str = Modifier.toString(m.getModifiers());
System.out.print(str + " ");
//3.返回值类型
Class returnType = m.getReturnType();
System.out.print(returnType.getName() + " ");
//4.方法名
System.out.print(m.getName() + " ");
//5.形参列表
System.out.print("(");
Class[] params = m.getParameterTypes();
for(int i = 0;i < params.length;i++){
System.out.print(params[i].getName() + " args-" + i + " ");
}
System.out.print(")");
//6.异常类型
Class[] exps = m.getExceptionTypes();
if(exps.length != 0){
System.out.print("throws ");
}
for(int i = 0;i < exps.length;i++){
System.out.print(exps[i].getName() + " ");
}
System.out.println();
}
④调用运行时类中指定的方法
Class clazz = Person.class;
//getMethod(String methodName,Class ... params):获取运行时类中声明为public的指定的方法
Method m1 = clazz.getMethod("show");
Person p = (Person)clazz.newInstance();
//调用指定的方法:Object invoke(Object obj,Object ... obj)
注 : 'returnVal' 为方法返回值
Object returnVal = m1.invoke(p);//我是一个人
//无返回值
System.out.println(returnVal);//null
Method m2 = clazz.getMethod("toString");
Object returnVal1 = m2.invoke(p);
//打印返回值
System.out.println(returnVal1);//Person [name=null, age=0]
//对于运行时类中静态方法的调用
Method m3 = clazz.getMethod("info");
m3.invoke(Person.class);
//getDeclaredMethod(String methodName,Class ... params):获取运行时类中声明了的指定的方法
注 : `其中 display 为private 修饰方法`
Method m4 = clazz.getDeclaredMethod("display",String.class,Integer.class);
m4.setAccessible(true);
Object value = m4.invoke(p,"CHN",10);//我的国籍是:CHN
System.out.println(value);//10
⑤获取所有构造器
public void test2() throws ClassNotFoundException{
String className = "com.atguigu.java.Person";
Class clazz = Class.forName(className);
Constructor[] cons = clazz.getDeclaredConstructors();
for(Constructor c : cons){
System.out.println(c);
}
}
⑥获取父类
@Test
public void test1(){
Class clazz = Person.class;
Class superClass = clazz.getSuperclass();
System.out.println(superClass);
}
⑦获取带着泛型的父类
public void test2(){
Class clazz = Person.class;
Type type1 = clazz.getGenericSuperclass();
System.out.println(type1);
}
⑧获取父类的泛型
public void test3(){
Class clazz = Person.class;
Type type1 = clazz.getGenericSuperclass();
ParameterizedType param = (ParameterizedType)type1;
Type[] ars = param.getActualTypeArguments();
System.out.println(((Class)ars[0]).getName());
}
⑨获取实现的接口
public void test4(){
Class clazz = Person.class;
Class[] interfaces = clazz.getInterfaces();
for(Class i : interfaces){
System.out.println(i);
}
}
⑩获取所在的包
public void test5(){
Class clazz = Person.class;
Package pack = clazz.getPackage();
System.out.println(pack);
}
11.获取注解
public void test6(){
Class clazz = Person.class;
Annotation[] anns = clazz.getAnnotations();
for(Annotation a : anns){
System.out.println(a);
}
}
12.调用指定的构造器
调用 private Person(String name,int age)
这个构造器
public void test3() throws Exception{
String className = "com.atguigu.java.Person";
Class clazz = Class.forName(className);
Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
cons.setAccessible(true);
Person p = (Person)cons.newInstance("TZ",20);
System.out.println(p);
}