目录
获得类的Class对象后,如何获取类信息并操作对象中的成员?
为什么需要java反射?
在编写代码的时候,当你仅仅知道一个类名,并且想要动态得到类的定义消息,包含的方法和属性等的时候,我们就需要通过java反射来获得这些.由于像框架,tomcat,或者一些其他的组件(jackson 对象-->json),事先不知道是哪个类,只能根据配置文件中配置的类的地址决定要创建并且操作哪一个类.
回顾之前java中如何使用类和对象
1.定义类
public class Car{
String name;
.....
public void run(){}
}
2.创建已知类的对象,明确知道要创建哪个类的对象
Car car = new Car();
一切都是已知的,这对于我们自己写的程序时没有任何问题(业务代码)
但是像框架,tomcat,或者一些其他的组件(Jackson 对象-->json),事先是不知道具体处理哪些类的,只能根据配置文件中配置的类的地址决定要创建并操作哪一个类
框架要做到可以处理任何类,只要写一套处理程序即可
框架要做到以不变应万变
问题:如果我们只知道类的地址,如何使用类
框架可以做到给他什么类名,就可以创建给定类的对象,并调用该对象的方法和属性
(1)创建对象
(2)将查询到的结果,封装到创建的对象中(调用setxxx(),调用xxx属性)
如何做到写一套程序可以处理任何类
答案是:反射机制
反射机制,可以看做是一种反向使用类
反射:
概念:
在程序运行状态中,可以动态获取类的信息,可以动态创建类的对象,可以调用类的成员(变量,方法,构造方法)的机制称为java反射机制
提出问题:
如何获得类的信息?
可以通过获取到类的Class对象,然后通过Class独享就可以获得类中想要的信息
如何获得类的Class对象?
1.方式1 框架中常用的,只知道类的字符串地址
Class c = Class.forName("com.ffyc.javareflect.demo2.User")
2.方式2 类名.class 获得类的Class对象
Admin.class
3.方式3 适用的场景 是已知对象,需要对任何对象进行操作
User user=new User();
Car car=new Car();
Class c1=user.getClass();
Class c2=car.getClass();
package com.ffyc.javareflect.demo2;
import com.ffyc.javareflect.demo1.Car;
public class Test2 {
public static void main(String[] args) throws ClassNotFoundException {
//方式1
String s="com.ffyc.javareflect.demo2.User";
Class c1 = Class.forName(s);//把给定的地址类进行了加载,为其创建Class对象
Class c2 = Class.forName(s);//把给定的地址类进行了加载,为其创建Class对象
System.out.println(c1);
System.out.println(c1==c2);
//通过类的Class对象,就可以任意获取类中的信息
c1.getFields();
c1.getMethods();
c1.getConstructors();
//方式2
Class c3=User.class;
System.out.println(c2==c3);
//方式3
User user=new User();
Car car=new Car();
Class c4=user.getClass();//通过已知的对象中的getClass 获得该对象的Class对象
}
}
获得类的Class对象后,如何获取类信息并操作对象中的成员?
1.获取类中的构造方法信息
获得指定(参数个数,类型)的公共构造方法,返回Constructor来表示获得到的构造方法
Constructor getConstructor(类<?>... parameterTypes) 获得指定(参数个数,类型)的公共构造方法
newInstance() 创建类的对象
Constructor[] getConstructors() 返回所有公共的构造方法
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) 获得指定的构造方法(包含私有,受保护,默认,公共)
Constructor<?>[] getDeclaredConstructors() 获得所有的构造方法
getConstructor()和getDeclaredConstructor()方法:
两个方法如果不传参数的话,就会自动调用无参构造方法,而在框架中,框架在通过反射获得类的对象的时候,就是默认调用无参构造方法,所以当我们定义了有参构造方法后,必须定义一个无参构造方法来满足后面框架的需求.如果想要获得有参的构造方法,我们需要在调用方法的时候在参数里写入所需的参数类型的class类.
两个方法在功能上是一致的,都是为了获得类的构造方法,但是区别是getConstructor只能获得该类中的公共方法,而getDeclaredConstructor看可以获得该类中的所有方法,包含私有方法.
package com.ffyc.javareflect.demo2;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test3 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
String s="com.ffyc.javareflect.demo2.User";
//创建对象方式
//new
//流 反序列化
//反射
//加载类,并获得类的Class对象
Class c=Class.forName(s);
/*
1.通过Class类的对象创建对象
Object userobject=c.newInstance();
2.获取类中的构造方法信息,通过构造方法中的newInstance()创建对象
Constructor constructor = c.getConstructor();
Object userobject = constructor.newInstance();
* */
//通过Class类的对象创建User对象
//Object userobject=c.newInstance();
//System.out.println(userobject);
//获取类中的构造方法信息
Constructor constructor = c.getConstructor();//获得类中指定的公共构造方法,将获得到的无参构造方法封装到一个Constructor中
Object userobject = constructor.newInstance();//通过构造方法中的newInstance()创建对象
System.out.println(userobject);
Constructor constructor1 = c.getDeclaredConstructor();//获得类中指定的构造方法(包含私有)
Constructor constructor2=c.getConstructor(String.class,String.class);//获得公共的有参构造方法
Object userobject1 = constructor2.newInstance("111","222");//创建对象,并为对象属性赋值
//向下转型
User user=(User) userobject1;
System.out.println(user);
Constructor[] constructors = c.getConstructors();//获得所有的公共的构造方法
Constructor[] constructors1 = c.getDeclaredConstructors();//获得所有的构造方法(包括私有)
System.out.println(constructors.length);
System.out.println(constructors1.length);
}
}
2.获得成员变量
Field field = getField(String name); 获得指定名字的公共属性,返回Field对象 表示获得属性
Field[] fields = getFields(); 获得所有的公共的属性
Field field = getDeclaredField(String name); 获得指定名字的属性(包含私有)
Field[] fields = getDeclaredFields(); 获得所有属性(包含私有)
getFields()和getDeclaredFields()方法
两个方法都是用于获取类的属性,但是getFields()只能获得该类的所有公共属性,但是getDeclaredFields()可以获得该类中的所有属性(包括私有属性).
package com.ffyc.javareflect.demo2;
import java.lang.reflect.Field;
public class Test4 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
String s="com.ffyc.javareflect.demo2.User";
Class c=Class.forName(s);//获得类的Class对象
Object userobject = c.newInstance();//创建User类的对象
//获得类中的成员变量
//获得类中指定的公共的属性,把属性封装到一个Field对象中
//Field field = c.getField("userName");
//获得类中指定的的属性(包含私有,受保护,默认,公共),把属性封装到一个Field对象中
Field userfield = c.getDeclaredField("userName");
//Field[] fields = c.getFields();
//System.out.println(fields.length);
//获得到所有的属性(包含私有的)
Field[] fields = c.getDeclaredFields();
System.out.println(fields.length);
//循环所有的属性,为属性赋值
for (Field f:fields){
f.setAccessible(true);//设置私有属性可以操作
f.set(userobject, "111");
}
System.out.println(userobject);
}
}
3.获得方法
getMethods(); 获得本类和父类中所有公共的成员方法
getDeclaredMethods(); 获得本类中所有的成员方法
package com.ffyc.javareflect.demo2;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test5 {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException {
String s="com.ffyc.javareflect.demo2.User";
Class c=Class.forName(s);//获得类的Class对象
Object userobject = c.newInstance();//创建User类的对象
Method eat = c.getMethod("eat");
//执行userobject对象中的 无参的eat方法
eat.invoke(userobject );
Method eat1=c.getMethod("eat", String.class);
eat1.invoke(userobject, "烤肉");
Method[] methods = c.getMethods();//获得本类和父类中所有公共的成员方法
Method[] methods1 = c.getDeclaredMethods();//获得本类中所有的成员方法
System.out.println(methods.length);//15
System.out.println(methods1.length);//7
}
}
实例验证:
自定义的对象转json方法
package com.ffyc.javareflect.util;
import com.ffyc.javareflect.demo1.Car;
import com.ffyc.javareflect.demo2.User;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class JsonUtil {
/*
自定义的对象转json方法
* */
public String objectToJson(Object object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
String json = "{";
Class c=object.getClass();//获得对象类的Class对象
//获得对象中所有私有属性
Field[] declaredFields=c.getDeclaredFields();
for(Field f:declaredFields){
//生成属性的get方法名字
//String get="get"+(String.valueOf(f.getName().charAt(0))).toUpperCase()+f.getName().substring(1);
String get="get"+(char)(f.getName().charAt(0)-32)+f.getName().substring(1);
System.out.println(get);
Method getMethod = c.getMethod(get);//通过get方法名,获得方法
json+=f.getName()+":"+getMethod.invoke(object)+",";
}
json=json.substring(0,json.length()-1);
json+="}";
return json;
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
User user=new User();
user.setUserName("admin");
user.setPassword("111");
Car car=new Car();
car.setName("奔驰");
car.setColor("黑色");
System.out.println(new JsonUtil().objectToJson(user));
System.out.println(new JsonUtil().objectToJson(car));
}
}