目录
在运行时通过Class对象动态获取类信息,并且可以操作类或对象的内部属性。反射可以动态创建对象并调用其属性。而这种动态获取信息以及动态调用对象方法的功能就是JAVA的反射。
反射中常用到的有Class,Field,Method,Constructor这几个类,这些类也是将类信息封装成相应的类
Class类常用到的有方法有
Method对象最重要的方法就是invoke,Constructor最重要的方法是newInstance
下面是对反射中比较常用的一些方法的举例
class MondayStudyReflect{
private String getup;
private String wash;
public String review;
public String getWash() {
return wash;
}
public void setWash(String wash) {
this.wash = wash;
}
public String getReview() {
return review;
}
public void setReview(String review) {
this.review = review;
}
private String getGetup() {
return getup;
}
private void setGetup(String getup) {
this.getup = getup;
}
public MondayStudyReflect(){
System.out.println("无参构造方法");
}
public MondayStudyReflect(String wash,String review){
System.out.println("无参构造方法 wash:"+wash+";review:"+review);
this.wash = wash;
this.review = review;
}
public void study(String message){
System.out.println("公共有参方法调用:"+message);
}
private void summary() {
System.out.println("私有无参方法调用");
}
}
1.获取Class对象的三种方式
@Test
public void getClassThreeMethod() throws Exception{
Class classOne = MondayStudyReflect.class;
MondayStudyReflect mondayStudyReflect = new MondayStudyReflect();
Class classTwo = mondayStudyReflect.getClass();
Class classThree = Class.forName("com.example.findwork.reflect.MondayStudyReflect");
if(classOne == classTwo && classTwo == classThree){
System.out.println("三种方法获取的class对象是同一个");
//最后输出结果
//三种方法获取的class对象是同一个
}
}
一般都是通过调用Class的forName方法来获取类的Class对象,因为这个更加灵活,我们只需要获取到类的全限定名称就可以了
通过对象的getClass方法获取的话,我们已经有这个类的实例了,所以也不太需要class对象了。
2.获取类的相关属性
/**
* 测试反射属性的获取
* @throws Exception
*/
@Test
public void testReferectFields()throws Exception{
Class classField = Class.forName("com.example.findwork.reflect.MondayStudyReflect");
Field[] fieldArr = classField.getFields();
System.out.println("获取所有的公开的类属性");
for(Field field:fieldArr){
System.out.println("属性名:"+field.getName()+";属性类型:"+field.getType());
}
Field[] fieldArrTwo = classField.getDeclaredFields();
System.out.println("获取所有的类属性,包括私有属性");
for(Field field:fieldArrTwo){
System.out.println("属性名:"+field.getName()+";属性类型:"+field.getType());
}
Field filedReview = classField.getField("review");
System.out.println("通过属性名称获取公开属性");
System.out.println("属性名:"+filedReview.getName()+";属性类型:"+filedReview.getType());
Field filedWash = classField.getDeclaredField("wash");
System.out.println("通过属性名称获取私有属性");
System.out.println("属性名:"+filedWash.getName()+";属性类型:"+filedWash.getType());
}
输出结果
获取所有的公开的类属性
属性名:review;属性类型:class java.lang.String
获取所有的类属性,包括私有属性
属性名:getup;属性类型:class java.lang.String
属性名:wash;属性类型:class java.lang.String
属性名:review;属性类型:class java.lang.String
通过属性名称获取公开属性
属性名:review;属性类型:class java.lang.String
通过属性名称获取私有属性
属性名:wash;属性类型:class java.lang.String
3.获取类的公开方法和私有方法
/**
* 测试反射方法的运用
* @throws Exception
*/
@Test
public void testReflectMethod() throws Exception{
Class classMethod = Class.forName("com.example.findwork.reflect.MondayStudyReflect");
Method[] methodArr = classMethod.getMethods();
System.out.println("===========获取所有的公开的类方法=========");
for(Method method:methodArr){
System.out.print("方法名:"+method.getName()+" ");
}
Object object = classMethod.newInstance();//其实是得到了MondayStudyReflect的实例,等同于 new MondayStudyReflect
Method methodSetWash = classMethod.getMethod("setWash",String.class);
methodSetWash.invoke(object,"调用公开方法");
Method methodGetWash = classMethod.getMethod("getWash");
String wash = methodGetWash.invoke(object).toString();
System.out.println("通过反射调用方法获取到的参数 wash:"+wash);
//调用私有方法
Method methodSetGetup = classMethod.getDeclaredMethod("setGetup",String.class);
methodSetGetup.setAccessible(true);//表示可以调用,没有设置这一步调用私有方法是会出现问题的
methodSetGetup.invoke(object,"调用私有方法");
Method methodgetGetup = classMethod.getDeclaredMethod("getGetup");
methodgetGetup.setAccessible(true);//表示可以调用,没有设置这一步调用私有方法是会出现问题的
String getUp = methodgetGetup.invoke(object).toString().toString();
System.out.println("通过反射调用方法获取到的参数 getUp:"+getUp);
}
输出结果
===========获取所有的公开的类方法=========
方法名:setWash 方法名:getWash 方法名:getReview 方法名:setReview 方法名:study 方法名:wait 方法名:wait 方法名:wait 方法名:equals 方法名:toString 方法名:hashCode 方法名:getClass 方法名:notify 方法名:notifyAll 无参构造方法
通过反射调用方法获取到的参数 wash:调用公开方法
通过反射调用方法获取到的参数 getUp:调用私有方法
可以看到获取公开所有方法的时候还会获取父类Object公开的方法
4.获取构造方法
/**
* 测试构造方法的运用
*/
@Test
public void testReflectConsttruct() throws Exception{
Class classMethod = Class.forName("com.example.findwork.reflect.MondayStudyReflect");
Constructor constructor = classMethod.getDeclaredConstructor();
constructor.setAccessible(true);
MondayStudyReflect nondayStudyReflect = (MondayStudyReflect)constructor.newInstance();
Constructor constructorOne = classMethod.getConstructor(String.class,String.class);
MondayStudyReflect nondayStudyReflectTwo = (MondayStudyReflect)constructorOne.newInstance("aaa","bbb");
}
输出结果
无参构造方法
无参构造方法 wash:aaa;review:bbb
5.反射的好处和坏处
好处:
1.解耦类与类之间的关系,让类的调用更加灵活,向IOC的基本原理就是反射
坏处
1.调用性能没有直接调用好
2.破坏了类的封装性,可以调用私有方法和属性,最典型的就是破坏了单例模式