反射机制就是:这运行状态中,可以获取任意一个类的的所有属性和方法,调用任意对象的属性和方法。
其原理就是:在编译过程中,我们并不能确定哪个类被加载了,在运行过程中,当Java虚拟机加载某个类的时候需要类装载器定位相应的class文件,然后读到虚拟机中,然后虚拟机提取class中的类信息,并将这些信息储存到虚拟机的方法区。而反射就是利用这里去拿类的信息。
反射的作用:既然可以拿到类的所有信息然后就是判断方法、属性以及对象是否属于某个类,还有就是构造一个类的对象、调用类中的方法。
关于反射的好处,一般是都是说灵活性、多态、降低耦合之类的。个人觉得就是一个给程序员留的bug,给程序员玩的。给一个常见反射的例子:Class.forName("com.mysql.jdbc.Driver")。这就是连接数据库,加载jdbc驱动的代码。
下面用代码来了解反射机制。先给出两个类
package reflect;
public abstract class Father {
public String name;
public int age;
private double salary;
abstract void putmoney();
public Father(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
System.out.println("有参构造函数");
}
public Father() {
System.out.println("无参构造函数");
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
private void print(String type){
System.out.println(type+"的父亲");
}
}
package reflect;
public class Son extends Father implements Comparable{
public String sonname;
public int sonage;
private double spend;
public Son() {
System.out.println("子类无参构造函数");
}
public Son( String sonname, int sonage, double spend) {
name = sonname;
age = sonage;
this.spend = spend;
System.out.println("子类有参构造函数");
}
public double getSpend() {
return spend;
}
public void setSpend(double spend) {
this.spend = spend;
}
private void printson(String type){
System.out.println(type+"的儿子");
}
@Override
void putmoney() {
System.out.println("收到钱了");
}
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
}
}
接下来是具体操作的类
package reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Scanner;
public class Main {
public static void main(String[] args){
System.out.println("获取类对象");
Son s1=new Son("小儿子",12,20.0);
Class c=s1.getClass();
Class c1=Son.class;
Class c2=null;
try {
c2=Class.forName("reflect.Son");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(c);
System.out.println(c1);
System.out.println(c2);
try {
System.out.println("获取类的单个属性");
Field field=c.getField("sonage");
System.out.println(field);
System.out.println("修改、获取属性值");
field.setInt(s1, 10);
System.out.println(field.getInt(s1)+"");
System.out.println("获取类的所有公有属性");
//所有属性用getDeclaredFields()
Field[] fields=c.getFields();
for(Field f:fields){
System.out.println(f);
}
System.out.println("获取类中的所有接口");
Class[] ss=c.getInterfaces();
for(Class sc: ss){
System.out.println(c);
}
System.out.println("获取类中的所有方法(不包括父类、接口)");
Method[] methods=c.getDeclaredMethods();
for(Method m:methods)
System.out.println(m);
System.out.println("获取类中的所有公有方法(包括父类、接口)");
Method[] methods2=c.getMethods();
for(Method m:methods2)
System.out.println(m);
System.out.println("获取公共构造器");
//所有构造器用getDeclaredConstructors()
Constructor[] cons=c.getConstructors();
for(Constructor con:cons)
System.out.println(con);
System.out.println("实例化一个对象");
Class newclass=Class.forName("reflect.Son");
Object o=newclass.newInstance();
System.out.println(o);
System.out.println("调用对象方法");
Method m=newclass.getDeclaredMethod("printson", String.class);
m.setAccessible(true);
m.invoke(o,"聪明的");
System.out.println("获取父类方法实例");
Class supe=o.getClass().getSuperclass();
System.out.println(supe);
//之后就可以像对子类一样对父类进行各种操作
//如涉及的非公有方法或者属性。使用Field、Method之前
//必须调用Field(Method)setAccessible(true)
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出:
获取类对象
无参构造函数
子类有参构造函数
class reflect.Son
class reflect.Son
class reflect.Son
获取类的单个属性
public int reflect.Son.sonage
修改、获取属性值
10
获取类的所有公有属性
public java.lang.String reflect.Son.sonname
public int reflect.Son.sonage
public java.lang.String reflect.Father.name
public int reflect.Father.age
获取类中的所有接口
class reflect.Son
获取类中的所有方法(不包括父类、接口)
public int reflect.Son.compareTo(java.lang.Object)
private void reflect.Son.printson(java.lang.String)
public double reflect.Son.getSpend()
public void reflect.Son.setSpend(double)
void reflect.Son.putmoney()
获取类中的所有公有方法(包括父类、接口)
public int reflect.Son.compareTo(java.lang.Object)
public double reflect.Son.getSpend()
public void reflect.Son.setSpend(double)
public void reflect.Father.setSalary(double)
public double reflect.Father.getSalary()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
获取公共构造器
public reflect.Son()
public reflect.Son(java.lang.String,int,double)
实例化一个对象
无参构造函数
子类无参构造函数
reflect.Son@70dea4e
调用对象方法
聪明的的儿子
获取父类方法实例
class reflect.Father
再来说说利用发射实现的动态代理。那么静态代理和动态代理有什么不同呢?静态代理也就是一般的代理(不懂代理模式,自行百度),我们需要手动敲完每一个代理类,代理较多时,浪费时间,而且有很多重复代码。这个时候就得用到我们的动态代理了。动态代理利用了反射机制,那么自然就是在程序运行期间起作用了,它是在程序运行期间,动态地创建代理类及其实例。给出一段代码,慢慢体会。
package reflect2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class M {
public static void main(String[] args){
Real real=new Real();
Inter inter=(Inter) Proxy.newProxyInstance(Inter.class.getClassLoader(),
real.getClass().getInterfaces(),
new Pro(real));
System.out.println(inter);//输出的是real
inter.print();
}
}
interface Inter{
public void print();
}
//被代理类
class Real implements Inter{
@Override
public void print() {
System.out.println("我是被代理类");
}
}
class Pro implements InvocationHandler{
Object p;
public Pro(Object p) {
this.p=p;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(p, args);
}
}
如果还想了解更多关于反射的就去看看文档中java.lang.reflect这个软件包