- java.lang.Class:是反射的源头
- 如何获取Class的实例(3种)必会的
- 创建运行时类对象
- 通过反射获取类的完整结构
- 调用运行时类指定的属性
- ClassLoader
java.lang.Class:是反射的源头
我们创建一个类,通过编译,生成对应的.calss文件,之后使用java.exe加载(jvm的类加载器)此.class文件,此.class文件加载到内存以后,就是一个运行时类,存在缓存区,那么这个运行时类的本身就是一个class的实例
- 每一个运行时类只加载一次
- 有了Class实例以后,我们才可以进行如下的操作:
- 创建对应的运行时类的对象(重点)
- 可以获取对象的运行时类的完整结构(属性、方法、构造器、内部类、、、)(理解)
- 调用对应的运行时类的指定的结构(属性、方法)(重点)
- 在反射以前,如何创建一个类的对象,并调用其中的方法属性
public void test1() {
Person p = new Person();
p.setAge(10);
p.setName("AA");
p.show();
System.out.println(p);
}
- 有了反射,可以通过反射创建一个类的对象,并调用其中的方法
public void test2() throws Exception {
Class clazz = Person.class;
//1.创建clazz对应的运行时类Person类的对象
Person p = (Person)clazz.newInstance();
System.out.println(p);
//2.通过反射调用运行时类的指定属性,public name的修改方式
Field f1 = clazz.getField("name");
f1.set(p, "LiuDaHua");
System.out.println(p);
//private age的方式
Field f2 = clazz.getDeclaredField("age");
// 私有的属性是设置这个
f2.setAccessible(true);
f2.set(p, 20);
System.out.println(p);
//3.通过反射调用运行时类的指定方法
Method m1 = clazz.getMethod("show");
m1.invoke(p);
Method m2 = clazz.getMethod("display", String.class);
m2.invoke(p, "cn");
}
如何获取Class的实例(3种)必会的
- 调用运行时类本身的.class属性
Class clazz = Person.class;
System.out.println(clazz.getName());
Class clazz1 = String.class;
System.out.println(clazz1.getName());
//com.md.a.Person
//java.lang.String
2.通过运行时类的对象获取
Person p = new Person();
Class clazz2 = p.getClass();
System.out.println(clazz2.getName());
//com.md.a.Person
- 通过Class的静态方法获取,通过此方式,体会反射的动态性
String className = "com.atguigu.java.Person";
Class clazz4 = Class.forName(className);
System.out.println(clazz4);
- 通过类的加载器
ClassLoader classLoader = this.getClass().getClassLoader();
Class clazz5 = classLoader.loadClass(className);
System.out.println(clazz5.getName());
- 整个代码
public void test4() throws Exception {
//1.调用运行时类本身的.class属性
Class clazz = Person.class;
System.out.println(clazz.getName());
Class clazz1 = String.class;
System.out.println(clazz1.getName());
//2.通过运行时类的对象获取
Person p = new Person();
Class clazz2 = p.getClass();
System.out.println(clazz2.getName());
//3.通过Class的静态方法获取,通过此方式,体会反射的动态性
String className = "com.atguigu.java.Person";
Class clazz4 = Class.forName(className);
System.out.println(clazz4);
//4.通过类的加载器
ClassLoader classLoader = this.getClass().getClassLoader();
Class clazz5 = classLoader.loadClass(className);
System.out.println(clazz5.getName());
}
创建运行时类对象
- 获取Class的实例(三种方式)
String className = "com.atguigu.java.Person";
Class clazz = Class.forName(className);
创建运行时类对象
创建对应的运行时类的对象,使用的是newInstance()实际上就是运用了运行时类的空参数的构造器-
要想能够创建成功
- 要求对应的运行时类要有空参数的构造器
- 构造器的权限修饰符的权限要足够
Object obj = clazz.newInstance();//调用的是空参构造器
Person p = (Person)obj;
System.out.println(p);
- 全部代码
public void test1() throws Exception {
//获取Class的实例
String className = "com.atguigu.java.Person";
Class clazz = Class.forName(className);
//创建对应的运行时类的对象,使用的是newInstance(),实际上就是运用了运行时类的空参数的构造器
//要想能够创建成功,①要求对应的运行时类要有空参数的构造器,②构造器的权限修饰符的权限要足够
Object obj = clazz.newInstance();//调用的是空参构造器
Person p = (Person)obj;
System.out.println(p);
}
通过反射获取类的完整结构
- 获取运行时类的属性
- getFields() 返回 :表示公共字段的 Field 对象的数组,只能获取运行时类中以及父类中声明的为public的属性
Field[] fiels = clazz.getFields();
for(int i=0;i
- getDeclaredFields() :获取运行时类本身声明的所有的属性
Field[] fiels1 = clazz.getDeclaredFields();
for(int i=0;i
- 获取属性的各个部分的内容
权限修饰符 变量类型 变量名- 获取每个属性的权限修饰符
Field[] field = clazz.getDeclaredFields();
for(Field i:field) {
//1.获取每个属性的权限修饰符
int a = i.getModifiers();
String str1 = Modifier.toString(a);
System.out.print(str1+" ");
}
- 获取属性的变量类型
Field[] field = clazz.getDeclaredFields();
for(Field i:field) {
//2.获取属性的变量类型
Class type = i.getType();
System.out.print(type+" ");
}
- 获取属性名
Class clazz = Person.class;
Field[] field = clazz.getDeclaredFields();
for(Field i:field) {
//3.获取属性名
System.out.print(i.getName());
System.out.println();
}
- 获取运行时类的方法
- getMethods() 获取运行时类及其父类中所有声明为public的方法
Class clazz = Person.class;
Method[] m1 = clazz.getMethods();
for(Method m:m1) {
System.out.println(m);
}
- getDeclaredMethods() 获取运行时类本身声明的所有的方法
Method[] methods = clazz.getDeclaredMethods();
for(int i=0;i
- 获取方法的各个部分的内容
注解 权限修饰符 返回值类型 方法名 形参列表 异常
- 注解
Class clazz = Person.class;
Method[] m1 = clazz.getMethods();
for(Method m:m1) {
Annotation[] an = m.getAnnotations();
for(Annotation a:an) {
System.out.println(a);
}
}
- 权限修饰符
int a = m.getModifiers();
String str1 = Modifier.toString(a);
System.out.print(str1+" ");
- 返回值类型
Class return1 = m.getReturnType();
System.out.print(return1+" ");
- 方法名
System.out.print(m.getName()+" ");
- 形参列表
System.out.print("(");
Class[] params = m.getParameterTypes();
for(Class p : params) {
System.out.print(p.getName());
}
System.out.println(")"+" ");
- 抛的异常
Class[] ex = m.getExceptionTypes();
for(Class e:ex) {
System.out.print(e.getName());
}
// for(int i=0;i
- 获取构造器
@Test
public void test5() throws Exception {
Class clazz = Class.forName("com.atguigu.java.Person");
Constructor[] cons = clazz.getDeclaredConstructors();
for(Constructor c : cons) {
System.out.println(c);
}
}
- 获取运行时类的父类
@Test
public void test6() {
Class clazz = Person.class;
Class super1 = clazz.getSuperclass();
System.out.println(super1);
}
- 获取带泛型的父类
@Test
public void test7() {
Class clazz = Person.class;
Type type1 = clazz.getGenericSuperclass();
System.out.println(type1);
}
- 获取父类的泛型
@Test
public void test8() {
Class clazz = Person.class;
Type type1 = clazz.getGenericSuperclass();
ParameterizedType param= (ParameterizedType)type1;
Type[] ars = param.getActualTypeArguments();
System.out.println((Class)ars[0]);
}
- 获取实现的接口
@Test
public void test9() {
Class clazz = Person.class;
Class[] i = clazz.getInterfaces();
for(Class a:i) {
System.out.println(a);
}
}
- 获取所在的包
@Test
public void test10() {
Class clazz = Person.class;
Package p = clazz.getPackage();
System.out.println(p);
}
- 全部代码如下:
package com.atguigu.java;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import org.junit.Test;
/**
* 通过反射获取类的完整结构
*
* @author MD
*
*/
public class TestField {
/**
* 1.获取运行时类的属性
*/
@Test
public void test1() {
Class clazz = Person.class;
//1.getFields() 返回 :表示公共字段的 Field 对象的数组
// 只能获取运行时类中以及父类中声明的为public的属性
// Field[] fiels = clazz.getFields();
// for(int i=0;i
调用运行时类指定的属性#
- 获取指定的属性
getField(String fieldName):获取运行时类中声明为public的指定的属性名为fieldName的属性
Field name = clazz.getField("name");
- 创建运行时类的对象
Person p = (Person) clazz.newInstance();
System.out.println(p);
- 将运行时类的指定属性赋值
name.set(p, "Jerry");
System.out.println(p);
- 给age赋值,private需要注意
getDeclareField(String fieldName):获取运行时类中指明为filedName的属性
Field age = clazz.getDeclaredField("age");
//由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作
age.setAccessible(true);//私有的设置成可以访问的
age.set(p,1);
System.out.println(p);
- 给id赋值,默认的修饰符
Field id = clazz.getDeclaredField("id");
id.set(p,10);
System.out.println(p);
- 调用运行时类中指定的方法
- getMethod(String methodName,Class...params)获取指定的public方法,方法名,参数列表
Class clazz = Person.class;
Method m1 = clazz.getMethod("show");
- 创建运行时类的对象
Person p =(Person)clazz.newInstance();
- 和属性相似,这里是invoke关键字里面是对象和参数列表,或许还有返回值,用Object接收
Object returnVal = m1.invoke(p);
System.out.println(returnVal);//没返回值的打印为null
- 获取toString()有返回值的
Method m2 = clazz.getMethod("toString");
Object returnVal1 = m2.invoke(p);
System.out.println(returnVal1);
- 获取display()带参数的
Method m3 = clazz.getMethod("display",String.class);
m3.invoke(p, "china");
- 获取info()静态的方法
Method m4 = clazz.getMethod("info");
m4.invoke(Person.class);
- 获取Test() 私有的带参数的有返回值的
Method m5 = clazz.getDeclaredMethod("Test",String.class,Integer.class);
m5.setAccessible(true);
Object o = m5.invoke(p,"测试",5);
System.out.println(o);
- 调用指定的构造器,创建类对象
public void test3() throws InstantiationException, Exception {
Class clazz = Person.class;
Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
cons.setAccessible(true);
Person p = (Person)cons.newInstance("迪丽热巴",20);
System.out.println(p);
}
- 全部代码
package com.atguigu.java;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.junit.Test;
/**
* ******调用对应的运行时类的指定的结构(属性、方法)
* @author MD
*
*/
public class TestField1 {
/**
* 调用运行时类指定的属性
* @throws Exception
* @throws NoSuchFieldException
*/
@Test
public void test1() throws Exception {
Class clazz = Person.class;
//1.获取指定的属性
//getField(String fieldName):获取运行时类中声明为public的指定的属性名为fieldName的属性
Field name = clazz.getField("name");
//2.创建运行时类的对象
Person p = (Person) clazz.newInstance();
System.out.println(p);
//3.将运行时类的指定属性赋值
name.set(p, "Jerry");
System.out.println(p);
//给age赋值,private需要注意
//getDeclareField(String fieldName):获取运行时类中指明为filedName的属性
Field age = clazz.getDeclaredField("age");
//由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作
age.setAccessible(true);//私有的设置成可以访问的
age.set(p,1);
System.out.println(p);
//给id赋值,默认的修饰符
Field id = clazz.getDeclaredField("id");
id.set(p,10);
System.out.println(p);
}
/**
* 调用运行时类中指定的方法
* @throws Exception
* @throws NoSuchMethodException
*/
@Test
public void test2() throws NoSuchMethodException, Exception {
Class clazz = Person.class;
//getMethod(String methodName,Class...params)获取指定的public方法,方法名,参数列表
Method m1 = clazz.getMethod("show");
//创建运行时类的对象
Person p =(Person)clazz.newInstance();
//和属性相似,这里是invoke关键字里面是对象和参数列表,或许还有返回值,用Object接收
Object returnVal = m1.invoke(p);
System.out.println(returnVal);
//获取toString()有返回值的
Method m2 = clazz.getMethod("toString");
Object returnVal1 = m2.invoke(p);
System.out.println(returnVal1);
//获取display()带参数的
Method m3 = clazz.getMethod("display",String.class);
m3.invoke(p, "china");
//获取info()静态的方法
Method m4 = clazz.getMethod("info");
m4.invoke(Person.class);
//获取Test() 私有的带参数的有返回值的
Method m5 = clazz.getDeclaredMethod("Test",String.class,Integer.class);
m5.setAccessible(true);
Object o = m5.invoke(p,"测试",5);
System.out.println(o);
}
/**
* 调用指定的构造器,创建类对象
* @throws Exception
* @throws InstantiationException
*/
@Test
public void test3() throws InstantiationException, Exception {
Class clazz = Person.class;
Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
cons.setAccessible(true);
Person p = (Person)cons.newInstance("迪丽热巴",20);
System.out.println(p);
}
}
ClassLoader
类加载器是用来把类(class)装载进内存的
- 获取一个系统类加载器
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);
- 测试当前类由哪个类加载器进行加载
Class clazz1 = Person.class;
ClassLoader loader4 = clazz1.getClassLoader();
System.out.println(loader4);//系统类加载器
-
面试题
描述一下JVM加载class文件的原理机制?- JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。
总代码如下
public void test5() {
//1.获取一个系统类加载器
ClassLoader loader1 = ClassLoader.getSystemClassLoader();
System.out.println(loader1);
//2.获取系统类加载器的父类加载器,即扩展类加载器
ClassLoader loader2 = loader1.getParent();
System.out.println(loader2);
//3.获取扩展类加载器的父类加载器,即引导类加载器,加载的是核心库,打印为null
ClassLoader loader3 = loader2.getParent();
System.out.println(loader3);
//4.测试当前类由哪个类加载器进行加载
Class clazz1 = Person.class;
ClassLoader loader4 = clazz1.getClassLoader();
System.out.println(loader4);//系统类加载器
}
学习视频链接