发布于2021-05-29 22:30 阅读(1065) 评论(0) 点赞(5) 收藏(3)
String classpath = "com.xxx.Person";
// 获取Person类对应的Class对象
Class<?> clazz = Class.forName(classpath);
// 获取运行类型 直接输出clazz则表示为哪个类的Class对象
clazz.getClass();
// 获取包名
clazz.getPackage().getName();
// 获取全类名
clazz.getName();
// 通过clazz创建对象实例
Person p = (Person)clazz.newInstance();
// 获取(非私有属性)属性 例如pName
Field pName = clazz.getField("pName");
// 给属性设置值
pName.set(p, "设置了新值");
// 获取所有属性
Field[] fields = clazz.getFields();
for(Field field : fields) {
// do something...
}
前提:已知一个类的全类名,且该类在类路径下,可以通过Class类的静态方法**forName()**获取。
例如:Class clazz = Class.forName(“java.lang.Person”);
可能出现的异常:ClassNotFoundException
应用场景:多用于配置文件读取类全路径,加载类
前提:已知具体的类,通过类的class获取,该方式最为可靠程序性能最高。
例如:Class clazz = Person.class; System.out.println(String.class);
应用场景:多用于参数传递,比如通过反射得到对应构造方法对象
前提:已知某个类的实例,调用该实例的**getClass()**方法获取Class对象。
实例:Class clazz = 对象.getClass(); //运行类型
应用场景:通过创建好的对象,获取Class对象。
其它方式:通过类加载器获取类的Class对象
ClassLoader cl = 对象.getClass().getClassLoader();
Class clazz = cl.loadClass(“全类名”);
注:上面4个clazz 其实是同一对象(符合上述 Class类分析 第三条)
八种基本数据类型 按照如下方式得到Class类对象
Class<Integer> intClazz = int.class; //int
Class<Character> charClazz = char.class;
Class<Boolean> boolClazz = boolean.class;
......
八种基本数据类型对应的包装器类,可以通过.TYPE 得到Class类对象
Class<Integer> intType = Integer.TYPE; //int
......
注 intClazz和intType也是同一对象 它们的hashCode是相等的
图片截图于B站 韩顺平 的视频
JVM虚拟机在该阶段的主要目的是将字节码从不同的数据源(可能是class文件、jar包、网络等)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象
JVM虚拟机会在该阶段对静态变量分配内存并默认初始化(对应数据类型的默认初始化值如0、0L、null、false等)。这些变量所使用的内存都将在方法区中进行分配。
举例
// n1是实例属性,不是静态变量,在准备阶段,不会分配内存
public int n1 = 10;
// n2是静态变量,分配内存且在准备阶段默认初始化为0,不是20 注意:20是在初始化阶段分配的值
public static int n2 = 20;
// n3是静态变量且final修饰的常量,与一般的静态变量不同,final修饰的一旦赋值就不变了。因此n3此阶段直接为30
public static final int n3 = 30;
// 正是因为这个机制,才能保证某个类在内存中,只有一份Class对象
// 验证了 【Class类分析】 中的第3条
synchronized(getClassLoadingLock(name)) {......}
/*
执行结果:
static代码块执行
-1
num在连接阶段会被初始化为0,在初始化阶段clinit对两个赋值(num=1和num=-1合并)所以num=-1,参照初始化阶段第2条描述。
*/
class Test {
static {
System.out.println("static代码块执行");
num = 1;
}
static int num = -1;
public static void main(String[] args) {
System.out.println(Test.num);
}
}
// 1.获取xxx类的Class对象
Class<?> clazz = Class.forName("类全路径名") // 例com.abc.User
// 2.通过public的无参构造方法创建实例
Object o = newInstance();
// 3.通过public的有参构造方法创建实例
// getConstructor()参数应该传入构造器对应的参数类型 例如String.class,可以多个参数。
// newInstance()传入getConstructor()参数对应的类型 例如String.class对应String类型,可以多个参数。
Constructor<?> constructor = clazz.getConstructor(xxx.class);
Object obj = constructor.newInstance(参数);
// 4.非public的有参构造方法创建实例
// getDeclaredConstructor()参数应该传入构造器对应的参数类型 例如int.class,可以多个参数。
// newInstance()传入getConstructor()参数对应的类型 例如int.class对应int类型,可以多个参数。
Constructor<?> constructor1 = clazz.getDeclaredConstructor(xxx.class);
// setAccessible爆破,使用反射可以访问非public构造方法
// 如果不设置setAccessible(true) Object obj1 = constructor1.newInstance(参数)将会报IllegalAccessException
constructor1.setAccessible(true);
Object obj1 = constructor1.newInstance(参数);
// 1.获取xxx类的Class对象
Class<?> clazz = Class.forName("类全路径名") // 例com.abc.User
// 2.创建对象
Object obj = clazz.newInstance(); // obj运行类型是User
// 3.通过反射得到public的 属性对象
Field field = clazz.getField("属性名") // 例 age (public int age)
field.set(obj,99); //通过反射操作属性 此时将age赋值为99 如果输出obj的话,age=99 如有其他属性则其他属性为null
System.out.println(obj); // User[age=99, name=null]
System.out.println(field.get(obj)); // 99
// 4.通过反射操作 非public的static的 属性对象
Field field1 = clazz.getField("属性名") // 例 name (private static String name)
// setAccessible爆破,使用反射可以访问非public属性
// 如果不设置setAccessible(true) field1.set(obj,"你的名字")将会报IllegalAccessException
field1.setAccessible(true);
field1.set(obj,"你的名字");
// 因为name是static的,obj也可以写成null
//field1.set(null,"你的新名字");
System.out.println(obj); // User[age=null, name="你的名字"]
System.out.println(field1.get(obj)); // 你的名字
// static还可以这样写
//System.out.println(field1.get(null));
// 1.获取xxx类的Class对象
Class<?> clazz = Class.forName("类全路径名") // 例com.abc.User
// 2.创建对象
Object obj = clazz.newInstance(); // obj运行类型是User
// 3.调用public的方法
// 得到func方法对象
// 对于public方法,下面两种都可正常拿到
Method method = clazz.getMethod("方法名"); //例func 如果有参还需要在方法名后指定 例 getMethod("func",String.class);
Method method1 = clazz.getDeclareMethod("方法名"); //例func
// 调用
method.invoke(obj, "func方法调用了...");
// 4.调用非public的方法 private static String func1(int age, String msg);
Method method2 = clazz.getDeclareMethod("方法名", int.class, String.class); //例func1
// 爆破,原理同前面的
method2.setAccessible(true);
method2.invoke(obj, 123, "func1方法调用了");
// 由于func1方法是静态的,也可以这样调用
method2.invoke(null, 123, "func1方法又调用了");
// 5.反射中的方法返回值无论该方法原来的返回值是什么都统一返回Object,但是它的运行类型和方法的返回类型一致
System.out.println(method2.invoke(null, 123, "func1方法又调用了").getClass()); // String
作者:听说你很拽
链接:http://www.javaheidong.com/blog/article/207627/44199e4f80e2682533ab/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!