目录
什么是反射?
(1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到类对象之后,再通过类对象进行反编译,从而获取对象的各种信息。
(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁
反射:能够分析类信息的能力叫做反射
类的生命周期
Java代码在计算机中经历的三个阶段
一、三种获取类信息的方式
- 类名.class
- 对象.getClass();
- Class.forName(“这里面是类的全限定名 包名+类名”)
public class TestClass {
// private Map<String,String> map;
public static void main(String[] args) {
}
public void test() throws ClassNotFoundException {
//获取Cat对象
Class<Cat> catClass = Cat.class;
//通过对象方式获取
Cat cat = new Cat();
Class<? extends Cat> aClass = cat.getClass();
//通过类名字获取类对象
Class<? extends Object> aClass1 = Class.forName("com.fanshe.Cat");
System.out.println(catClass == aClass);
}
}
结论:
同一个类加载器加载的文件(*.class)在一次程序运行过程中,只会被加载一次,不论你通过那种方式获取的class对象都是同一个
二、获取类的相关信息
@Test
public void testClass() {
//获取 猫类的类对象
Class<Cat> catClass = Cat.class;
//获取该类的加载器
System.out.println("该类的加载器"+catClass.getClassLoader());
//获取 类的 类名
System.out.println(catClass.getName());
System.out.println(catClass.getSimpleName());
System.out.println(catClass.getTypeName());
//获取该类的 父类 (继承是单继承)
Class<? super Cat> superclass = catClass.getSuperclass();
System.out.println(superclass.getName());
//获取 该类 实现的所有接口(Java采用的是多实现)
Class<?>[] interfaces = catClass.getInterfaces();
System.out.println(Arrays.toString(interfaces));
//获取类上的注解
Annotation[] annotations = catClass.getAnnotations();
System.out.println(Arrays.toString(annotations));
}
三、通过反射获取构造方法并使用
Student测试类
public class Student {
//---------------构造方法-------------------
//(默认的构造方法)
Student(String str){
System.out.println("(默认)的构造方法 s = " + str);
}
//无参构造方法
public Student(){
System.out.println("调用了公有、无参构造方法执行了。。。");
}
//有一个参数的构造方法
public Student(char name){
System.out.println("姓名:" + name);
}
//有多个参数的构造方法
public Student(String name ,int age){
System.out.println("姓名:"+name+"年龄:"+ age);//这的执行效率有问题,以后解决。
}
//受保护的构造方法
protected Student(boolean n){
System.out.println("受保护的构造方法 n = " + n);
}
//私有构造方法
private Student(int age){
System.out.println("私有的构造方法 年龄:"+ age);
}
}
共有6个构造方法
测试类
public class StudentConstructors {
/*
* 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
*
* 1.获取构造方法:
* 1).批量的方法:
* public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
* 2).获取单个的方法,并调用:
* public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
* public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
*
* 调用构造方法:
* Constructor-->newInstance(Object... initargs)
*/
public static void main(String[] args) throws Exception {
//1.加载Class对象
Class clazz = Class.forName("com.fanshe.Student");
//2.获取所有公有构造方法
System.out.println("**********************所有公有构造方法*********************************");
Constructor[] conArray = clazz.getConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
conArray = clazz.getDeclaredConstructors();
for(Constructor c : conArray){
System.out.println(c);
}
System.out.println("*****************获取公有、无参的构造方法*******************************");
Constructor con = clazz.getConstructor(null);
//1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
//2>、返回的是描述这个无参构造函数的类对象。
System.out.println("con = " + con);
//调用构造方法
Object obj = con.newInstance();
// System.out.println("obj = " + obj);
// Student stu = (Student)obj;
System.out.println("******************获取私有构造方法,并调用*******************************");
con = clazz.getDeclaredConstructor(char.class);
System.out.println(con);
//调用构造方法
con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
obj = con.newInstance('男');
}
}
输出
**********************所有公有构造方法*********************************
public com.fanshe.Student(java.lang.String,int)
public com.fanshe.Student(char)
public com.fanshe.Student()
************所有的构造方法(包括:私有、受保护、默认、公有)***************
private com.fanshe.Student(int)
protected com.fanshe.Student(boolean)
public com.fanshe.Student(java.lang.String,int)
public com.fanshe.Student(char)
public com.fanshe.Student()
com.fanshe.Student(java.lang.String)
*****************获取公有、无参的构造方法*******************************
con = public com.fanshe.Student()
调用了公有、无参构造方法执行了。。。
******************获取私有构造方法,并调用*******************************
public com.fanshe.Student(char)
姓名:男
调用方法:
1.获取构造方法:
- 批量的方法:
public Constructor[] getConstructors():所有”公有的”构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保 护、默认、公有)
- 获取单个的方法,并调用:
public Constructor getConstructor(Class… parameterTypes):获取单个的”公有的”构造方法:
public Constructor getDeclaredConstructor(Class… parameterTypes):获取”某个构造方法”可以是私有的,或受保护、默认、公有;
调用构造方法:
Constructor–>newInstance(Object… initargs)
2、 newInstance是 Constructor类的方法(管理构造函数的类)
newInstance(Object… initargs)
使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象。并为之调用
四、获取成员变量并调用
Student类:
public class Student {
public Student(){
}
//**********字段*************//
public String name;
protected int age;
char sex;
private String phoneNum;
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", sex=" + sex
+ ", phoneNum=" + phoneNum + "]";
}
}
测试类:
public class Fields {
public static void main(String[] args) throws Exception {
//1.获取Class对象
Class stuClass = Class.forName("com.fanshe.student.Student");
//2.获取字段
System.out.println("************获取所有公有的字段********************");
Field[] fieldArray = stuClass.getFields();
for(Field f : fieldArray){
System.out.println(f);
}
System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************");
fieldArray = stuClass.getDeclaredFields();
for(Field f : fieldArray){
System.out.println(f);
}
System.out.println("*************获取公有字段**并调用***********************************");
Field f = stuClass.getField("name");
System.out.println(f);
//获取一个对象
Object obj = stuClass.getConstructor().newInstance();//产生Student对象--》Student stu = new Student();
//为字段设置值
f.set(obj, "刘德华");//为Student对象中的name属性赋值--》stu.name = "刘德华"
//验证
Student stu = (Student)obj;
System.out.println("验证姓名:" + stu.name);
System.out.println("**************获取私有字段****并调用********************************");
f = stuClass.getDeclaredField("phoneNum");
System.out.println(f);
f.setAccessible(true);//暴力反射,解除私有限定
f.set(obj, "18888889999");
System.out.println("验证电话:" + stu);
}
}
结果:
************获取所有公有的字段********************
public java.lang.String com.fanshe.student.Student.name
************获取所有的字段(包括私有、受保护、默认的)********************
public java.lang.String com.fanshe.student.Student.name
protected int com.fanshe.student.Student.age
char com.fanshe.student.Student.sex
private java.lang.String com.fanshe.student.Student.phoneNum
*************获取公有字段**并调用***********************************
public java.lang.String com.fanshe.student.Student.name
验证姓名:刘德华
**************获取私有字段****并调用********************************
private java.lang.String com.fanshe.student.Student.phoneNum
验证电话:Student [name=刘德华, age=0, sex= , phoneNum=18888889999]
由此可见:
调用字段时:需要传递两个参数:
Object obj = stuClass.getConstructor().newInstance();//产生Student对象–》Student stu = new Student();
//为字段设置值f.set(obj, “刘德华”);//为Student对象中的name属性赋值–》stu.name = “刘德华”
第一个参数:要传入设置的对象,第二个参数:要传入实参
五: 获取成员方法并调用
Student
public void show1(String s){
System.out.println("调用了:公有的,String参数的show1(): s = " + s);
}
protected void show2(){
System.out.println("调用了:受保护的,无参的show2()");
}
void show3(){
System.out.println("调用了:默认的,无参的show3()");
}
private String show4(int age){
System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);
return "abcd";
}
测试类:
public class MethodClass {
public static void main(String[] args) throws Exception {
//1.获取Class对象
Class stuClass = Class.forName("com.fanshe.student.Student");
//2.获取所有公有方法
System.out.println("***************获取所有的”公有“方法*******************");
stuClass.getMethods();
Method[] methodArray = stuClass.getMethods();
for(Method m : methodArray){
System.out.println(m);
}
System.out.println("***************获取所有的方法,包括私有的*******************");
methodArray = stuClass.getDeclaredMethods();
for(Method m : methodArray){
System.out.println(m);
}
System.out.println("***************获取公有的show1()方法*******************");
Method m = stuClass.getMethod("show1", String.class);
System.out.println(m);
//实例化一个Student对象
Object obj = stuClass.getConstructor().newInstance();
m.invoke(obj, "刘德华");
System.out.println("***************获取私有的show4()方法******************");
m = stuClass.getDeclaredMethod("show4", int.class);
System.out.println(m);
m.setAccessible(true);//解除私有限定
Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
System.out.println("返回值:" + result);
}
}
m = stuClass.getDeclaredMethod(“show4”, int.class);//调用制定方法(所有包括私有的),需要传入两个参数,第一个是调用的方法名称,第二个是方法的形参类型,切记是类型。
System.out.println(m);
m.setAccessible(true);//解除私有限定
Object result = m.invoke(obj, 20);//需要两个参数,一个是要调用的对象(获取有反射),一个是实参
System.out.println(“返回值:” + result);
六、 将map转成对象
Cat
public class Cat extends Animal {
public String name;
private int age;
@Override
public void call() {
System.out.println("猫在叫~~~~");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
", type='" + type + '\'' +
'}';
}
}
测试
@Test
public void testMapToCat() throws Exception{
Map<String, Object> map = new HashMap<>();
map.put("name", "小白胖");
map.put("age", 2);
map.put("type","加菲猫");
//将上述的Map 通过 反射转换成一个 猫对象
//Class<Cat> clz = Cat.class;
Class<?> clz = Class.forName("com.fanshe.Cat");
//获取猫类的所有属性
Field[] fields = clz.getDeclaredFields();
//获取父类定义的所有属性
Field[] parents = clz.getSuperclass().getDeclaredFields();
//合并2个类的所有属性
List<Field> collect = Arrays.stream(fields).collect(Collectors.toList());
List<Field> collect2 = Arrays.stream(parents).collect(Collectors.toList());
collect.addAll(collect2);
// Cat cat = new Cat();
//反射去new Cat 调用他的无参构造
Object obj = clz.getDeclaredConstructor().newInstance();
//遍历所有的Field
for(Field f : collect){
//破坏封装
f.setAccessible(true);
//属性名,是否在Map中
if(map.containsKey(f.getName())){
//将map 中对应的key值,写入到f中
f.set(obj, map.get(f.getName()));
}
}
System.out.println(obj);
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/80104.html