JAVA之反射知识点整理
Posted 大忽悠爱忽悠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA之反射知识点整理相关的知识,希望对你有一定的参考价值。
JAVA之反射知识点整理
概念
将类的各个组成部分封装成其他对象,这就是反射机制
好处
- 在程序运行过程中操作这些对象
- 可以解耦,提高程序的可扩展性
反射机制的含义及其功能
含义:
反射是被视为动态语言的关键,反射机制能够让程序在执行期间借助Reflection API获取任何类的内部信息,并能直接操作任意对象的内部属性和方法
功能:
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用一个对象的成员变量和方法
生成动态代理
处理流程图
反射相关API
java.lang.Class : 代表一个类
java.lang.reflect.Method: 代表类的方法
java.lang.reflect.Field: 代表类的成员变量
java.lang.reflect.Constuctor: 代表类的构造方法
Class类
反射可以得到的信息: 某个类的属性,方法和构造器,某个类到底实现了哪些接口.
对于每个类而言,JRE都为其保留一个不变的Class对象,
一个Class对象包含了特定某个类的相关信息
Class本身也是一个类
Class对象只能由系统建立对象
一个类在JVM中只会有一个实例
一个Class对象对应的是一个加载到JVM中的一个.class文件(每个类在编译后会生成一个.class文件)
每个类的实例都会记得自己是由哪个Class实例生成的
通过Class可以完整得到一个类中的完整结构
获取class对象的方式
1.class.forName(“全类名”): 将字节码文件加载进内存,返回class对象
多用于配置文件,将类名定义在配置文件中。 读取文件,加载类
全类名: 包名.类名
会抛出ClassNotFoundException的异常
2.类名.class: 通过类名的属性class获取
多用于参数传递
3.对象.getClass(): getClass()方法在Object类中定义
多用于对象的获取字节码的方式
注意
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪种方式获取的class对象都是同一个
演示
package test;
public class main1 {
public static void main(String[] args) throws Exception {
//1.类全名
Class cls1= Class.forName("test.main1");
System.out.println(cls1);
//类名.class
Class cls2=main1.class;
System.out.println(cls2);
//对象.getClass()
main1 m=new main1();
Class cls3=m.getClass();
System.out.println(cls3);
//比较这三个对象
System.out.println(cls1==cls2);
System.out.println(cls1==cls3);
System.out.println(cls2==cls2);
}
}
获取一个类的父类和接口
package reflect;
public class main {
public static void main(String[] args) throws Exception {
Class cl1=Class.forName("reflect.stu");//获取指定类的Class实例
System.out.println(cl1.getName());
Class cl2=cl1.getSuperclass();//获取父类
System.out.println(cl2.getName());
//获取当前类的所有接口
Class[] interfaces=cl1.getInterfaces();
for(Class c:interfaces)
System.out.println(c.getName());
}
}
获取一个类的构造方法
//获取当前类的共有构造方法
Constructor[] con=cl1.getConstructors();
for(Constructor c:con)
{
//getModifiers(): 获取构造方法修饰符 返回1代表public 返回2代表private
//getName(): 获取方法名称
System.out.println("修饰符:"+c.getModifiers()+" 构造方法:"+c.getName());
//获取构造函数的参数,参数有几个数组里面元素就有几个
Class[] paramClass=c.getParameterTypes();
for(Class c1:paramClass)
{
System.out.println("构造方法: "+c.getName()+ " 参数类型: "+c1.getName());
}
}
System.out.println("--------------------------------------------------------");
//获取当前类的所有构造方法,包括共有和私有构造方法
Constructor[] con1=cl1.getDeclaredConstructors();
for(Constructor c:con1)
{
//getModifiers(): 获取构造方法修饰符 返回1代表public 返回2代表private
System.out.println("修饰符: "+c.getModifiers()+" 构造方法:"+c.getName());
Class[] paramClass=c.getParameterTypes();
for(Class c1:paramClass)
{
System.out.println("构造方法: "+c.getName()+ " 参数类型: "+c1.getName());
}
}
通过反射创建一个对象
Class cl1=Class.forName("reflect.stu");
//相当于调用Stu类的无参构造方法
Object obj=cl1.newInstance();
stu s=(stu)obj;
System.out.println(s.name+" "+s.age);
System.out.println("-----------------------------");
//指定一个有两个参数,一个为String,一个为int的共有构造函数
Constructor c=cl1.getConstructor(String.class,int.class);
stu s2=(stu)c.newInstance("小朋友",19);//实例化对象,相当于调用对应的有参构造函数
System.out.println(s2.name+" "+s2.age);
System.out.println("-----------------------------");
//通过反射机制,强制调用私有的构造方法
Constructor c3=cl1.getDeclaredConstructor(int.class);
//解除私有的封装,下面就可以对这个私有的方法进行强制调用
c3.setAccessible(true);
stu s5=(stu)c3.newInstance(100);
System.out.println(s5.name+" "+s5.age);
获取一个类的方法
获取到类的所有共有方法
Class cl1=stu.class;
//获取到类的所有共有方法
Method[] mt=cl1.getMethods();
for(Method m:mt)
{
System.out.println("方法名: "+m.getName());
System.out.println("返回值类型: "+m.getReturnType());
System.out.println("修饰符: "+m.getModifiers());
//获取方法的参数类型,是一个数组,方法有几个参数,数据就有几个
Class[] pcs=m.getParameterTypes();
if(pcs!=null&&pcs.length>0)
{
for(Class pc:pcs)
{
System.out.println("参数类型: "+pc.getName());
}
}
}
获取到类的所有方法,包括共有和私有方法,不包括继承方法
Class cl1=stu.class;
//获取到类的所有共有方法
Method[] mt=cl1.getDeclaredMethods();
for(Method m:mt)
{
System.out.println("方法名: "+m.getName());
System.out.println("返回值类型: "+m.getReturnType());
System.out.println("修饰符: "+m.getModifiers());
//获取方法的参数类型,是一个数组,方法有几个参数,数据就有几个
Class[] pcs=m.getParameterTypes();
if(pcs!=null&&pcs.length>0)
{
for(Class pc:pcs)
{
System.out.println("参数类型: "+pc.getName());
}
}
}
获取一个类的属性和包
获取类的所有公有属性,包含父类的公有属性
stu s = new stu();
Class c = s.getClass();
//获取类的所有公有属性,包含父类的公有属性
Field[] fs = c.getFields();
for (Field f : fs)
{
System.out.println("修饰符: "+f.getModifiers());
System.out.println("属性的类型: "+f.getType());
System.out.println("属性的名称: "+f.getName());
}
获取类的所有属性,包括私有,但不包括继承至父类的属性
stu s = new stu();
Class c = s.getClass();
//获取类的所有属性
Field[] fs = c.getDeclaredFields();
for (Field f : fs)
{
System.out.println("修饰符: "+f.getModifiers());
System.out.println("属性的类型: "+f.getType());
System.out.println("属性的名称: "+f.getName());
}
获取包名
stu s = new stu();
Class c = s.getClass();
//获取类所在包的包名
Package p=c.getPackage();
System.out.println(p.getName());
反射机制调用指定方法
//注意:下面不论是反射调用show还是display方法,都调用obj对象的方法,obj对象实际上就是stu对象
Class c=Class.forName("reflect.stu");
Constructor con=c.getConstructor();//获取无参构造
Object obj=con.newInstance();
//调用display公有的无参方法,无返回值
Method m=c.getMethod("display");
m.invoke(obj);
System.out.println("--------------------");
//调用公有的有参有返回值的重载dispaly
Method m1=c.getMethod("display",String.class);
String ret=(String) m1.invoke(obj,"大忽悠");
System.out.println("返回值打印:"+ret);
System.out.println("--------------------");
//调用私有无参无返回值的方法
m=c.getDeclaredMethod("show");
//解除私有的封装,下面可以强制调用私有的方法
m.setAccessible(true);
m.invoke(obj);
System.out.println("--------------------");
//调用私有有参有返回值的重载show方法
m1=c.getDeclaredMethod("show",String.class);
//解除私有的封装,下面可以强制调用私有的方法
m1.setAccessible(true);
ret=(String) m1.invoke(obj,"小朋友");
System.out.println("返回值打印:"+ret);
反射机制调用指定属性
Class c=Class.forName("reflect.stu");
//反射创建一个对象
stu s=(stu)c.newInstance();//默认调用无参构造
//获取名称为name的属性
Field f=c.getField("name");
//将对象s的name属性设置为大忽悠
f.set(s,"大忽悠");
//获取对象s的name属性值
String name=(String) f.get(s);
System.out.println("name属性值: "+name);
System.out.println("-----------------");
//获取私有属性
f=c.getDeclaredField("age");
//解除私有的封装,下面就可以强制的调用这个属性
f.setAccessible(true);
//设置私有属性
f.set(s,18);
System.out.println("私有属性age值: "+f.get(s));
JAVA动态代理
其实动态代理很好理解,就是有些情况下我们不能直接对目标类进行一个访问,这个时候就需要中间商,也就是代理对象,我们通过Proxy里的newProxyInstance,指定目标对象的父类接口,它就会根据这个接口里的抽象方法,隐含的在底层实现一个代理类,这个时候肯定有人会问,那实现了代理类,里面重写的方法咋办?,,其实代理类并没有重写接口里的那些方法,是直接通过反射对目标对象里的方法进行的调用,在此基础之上,还可以添加一些额外的非业务逻辑代码,例如日志信息、验证啊啥的,下面是我话的一张草图,希望有助于大家理解。
举例:
一个java项目,有100个类,每个类有10个方法,一共1000个方法
现在要求在每个方法执行前后加上两句话
testDemo接口 :
package reflect;
public interface testDemo {
void test1();
void test2();
}
test实现testDemo接口:
package reflect;
public class test implements testDemo{
@Override
public void test1()
{
System.out.println("test1方法执行中...");
}
@Override
public void test2() {
System.out.println("test2方法执行中....");
}
}
proxyDemo实现代理类接口:
package reflect;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class proxyDemo implements InvocationHandler {
//被代理的对象
Object obj;
proxyDemo( Object obj)
{
this.obj=obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName()+"开始执行");
//执行指定代理对象的指定方法
Object ret=method.invoke(obj,args);//不管代理对象的方法有无返回值都接收一下,然后返回
System.out.println(method.getName()+"执行完毕");
return ret;
}
}
主函数:
package reflect;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class main 关于JAVA 反射 基础知识/编码经验的一些总结