反射
1.那什么是反射:
反射java语言中的一种机制,通过这种机制可以动态的实例化对象、读写属性、调用方法,并且能改变它的属性。而这也是Java被视为动态(或准动态,为啥要说是准动态,因为一般而言的动态语言定义是程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言,从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。)语言的一个关键性质。
2.反射能做什么?
我们知道反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,包括包括其modifiers(修饰符),fields(属性),methods(方法)等,并可于运行时改变fields内容或调用methods。那么我们便可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等等;但是需要注意的是反射使用不当会造成很高的资源消耗;
3.反射的具体实现
下面是一个实体类student
package com.bowen.reflect;
public class Student {
private String sid;
private String sname;
public Integer age;
static{
System.out.println("加载进jvm中!");
}
public Student() {
super();
System.out.println("调用无参构造方法创建了一个学生对象");
}
public Student(String sid) {
super();
this.sid = sid;
System.out.println("调用带一个参数的构造方法创建了一个学生对象");
}
public Student(String sid, String sname) {
super();
this.sid = sid;
this.sname = sname;
System.out.println("调用带二个参数的构造方法创建了一个学生对象");
}
@SuppressWarnings("unused")
private Student(Integer age) {
System.out.println("调用Student类私有的构造方法创建一个学生对象");
this.age = age;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public void hello() {
System.out.println("你好!我是" + this.sname);
}
public void hello(String name) {
System.out.println(name + "你好!我是" + this.sname);
}
@SuppressWarnings("unused")
private Integer add(Integer a, Integer b) {
return new Integer(a.intValue() + b.intValue());
}
}
得到Class有三种方法:
//1、通过对象调用 getClass() 方法来获取,通常应用在:比如你传过来一个 Object
// 类型的对象,而我不知道你具体是什么类,用这种方法
Student stu=new Student();
Class forName=stu.getClass();
//2、直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高
// 这说明任何一个类都有一个隐含的静态成员变量 class
Student stu=Student .class;
//3、通过 Class 对象的 forName() 静态方法来获取,用的最多,
// 但可能抛出 ClassNotFoundException 异常
Class forName=Class.forName("com.bowen.reflect.Student");
查阅 API 可以看到 Class 有很多方法:
getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。包括private 声明的和继承类
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
实例化对象 newInstance()----- Constructor
( Constructor.getConstructor/Constructor.getDeclaredConstructor
注:一定要提供无参构造器
)
package com.bowen.reflect;
import java.lang.reflect.Constructor;
/**
* 利用反射进行对象的实例化
* 之前:通过关键字进行实例化
* 现在:
* 通过Java.lang
*
* @author 125x
*
*/
public class Demo2 {
public static void main(String[] args) throws Exception, Exception {
/*Student stu=new Student();
Class stuClz=stu.getClass();*/
//newInstance这个方法默认使用无惨构造器去实例化对象
// Student stu2=(Student) stuClz.newInstance();
// System.out.println(stu2);
//调用有参构造去实例化对象(一个参数)
// Class stuClz=Student.class;
// Constructor<Student> constructor= stuClz.getConstructor(String.class);
// Student stu2=(Student)constructor.newInstance("zs");
//调用有参构造去实例化对象(两个参数)
// Class stuClz=Student.class;
// Constructor<Student> constructor= stuClz.getConstructor(String.class,String.class);
// Student stu2=(Student)constructor.newInstance("s001","zs");
//调用有参构造去实例化对象(两个参数)
Class stuClz=Student.class;
Constructor<Student> constructor= stuClz.getConstructor(String.class,String.class);
Student stu2=(Student)constructor.newInstance("s001","zs");
运行如下:
下面你是用这个方法的话会报错(java.lang.NoSuchMethodException:没有找到匹配的方法)
//调用私有构造去实例化对象(两个参数)
//java.lang.NoSuchMethodException
Class stuClz=Student.class;
Constructor<Student> constructor= stuClz.getConstructor(Integer.class);
Student stu2=(Student)constructor.newInstance(18);//会报错
如下:
如果把.getConstructor改成getDeclaredConstructor;(又报以下错误)
不能访问private修饰的( java.lang.IllegalAccessException: Class com.bowen.reflect.Demo2 can not access a member of class com.bowen.reflect.Student with modifiers “private”)
要是不想报错:
加一个(constructor.setAccessible(true);)
Class stuClz=Student.class;
Constructor<Student> constructor= stuClz.getDeclaredConstructor(Integer.class);
constructor.setAccessible(true);
Student stu2=(Student)constructor.newInstance(18);
** 动态调用方法**(实列)
调用一个无参的
package com.bowen.reflect;
import java.lang.reflect.Method;
/**
* 动态方法调用
* @author 125x
*
*/
public class Demo3 {
public static void main(String[] args) throws Exception, Exception {
Student stu=new Student();
Class<? extends Student> stuClz=stu.getClass();
//调用一个无参的
Method m= stuClz.getDeclaredMethod("hello");
m.invoke(stu);
}
}
运行如下:
调用一个有参的
package com.bowen.reflect;
import java.lang.reflect.Method;
/**
* 动态方法调用
* @author 125x
*
*/
public class Demo3 {
public static void main(String[] args) throws Exception, Exception {
Student stu=new Student();
Class<? extends Student> stuClz=stu.getClass();
//调用一个有参的
Method m=stuClz.getDeclaredMethod("hello", String.class);
m.invoke(stu,"zs");
}
}
运行结果:
调用add方法
package com.bowen.reflect;
import java.lang.reflect.Method;
/**
* 动态方法调用
* @author 125x
*
*/
public class Demo3 {
public static void main(String[] args) throws Exception, Exception {
Student stu=new Student();
Class<? extends Student> stuClz=stu.getClass();
//调用add方法
Method m=stuClz.getDeclaredMethod("add", Integer.class,Integer.class);
// Method.invoke的返回值是被动态调用的方法的返回值
m.setAccessible(true);
Object invoke=m.invoke(stu,25,2);
System.out.println(invoke);
}
}
运行结果:
读写属性
package com.bowen.reflect;
import java.lang.reflect.Field;
/**
* 反射读属性
* 自定义标签库。通用分页。自定义MVC要用
*
* 访问修饰符
* getModifiers()
* java:private 1
* protected public 2
* static 4
* final 8
* abstract...
* 判断属性或方法被那些修饰符所修饰
* @author 125x
*
*/
public class Demo4 {
public static void main(String[] args) throws Exception{
Student stu=new Student("s001","zs");
stu.age=22;
System.out.println(stu.getSid());
System.out.println(stu.getSname());
Class<? extends Student> stuClz=stu.getClass();
/*Field f= stuClz.getDeclaredField("sname");
f.setAccessible(true);
System.out.println(f.get(stu));*/
//获取当前Student实例中的stu所有属性以及属性值
Field[] f=stuClz.getDeclaredFields();
for (Field field : f) {
field.setAccessible(true);
System.out.println(field.getName()+":"+field.get(stu));
}
}
}
运行结果: