1.关于反射的理解
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何 类的内部信息,并能直接操作任意对象的内部属性及方法。
框架 = 反射 + 注解 + 设计模式。
2.相关API
3.关于java.long.Class类的理解
1)类的加载过程:
程序经过javac.exe命令后,会生成一个或多个字节码文件(.class结尾的文件)。然后通过java.exe命令对某个字节码文件进行解释运行进行解释运行。就相当于将某个字节码文件加载到内存中,此过程就称之为类的加载。加载到内存中的类就叫做运行时类,此运行时类,就作为Class的一个实例。
2)Class实例就对应着一个运行时类。
3)加载在内存中的运行时类,会缓存一段时间。在此时间内,我们可以用不同的方式来获取此运行时类。
//获取Class实例的方法 @Test public void test3() throws ClassNotFoundException { //方式一:调用运行时类的属性:.class Class clazz1 = Person.class; System.out.println(clazz1); //方式二:通过运行时类的对象,调用getClass() Person person = new Person("张三",19); Class clazz2 = person.getClass(); System.out.println(clazz2); //(常用)方式三:调用Class类的静态方法:forName(String className) Class clazz3 = Class.forName("com.slxy.reflex.Person"); System.out.println(clazz3); //(了解)方式四:使用类的加载器:ClassLoader ClassLoader classLoader = PersonTest.class.getClassLoader(); Class clazz4 = classLoader.loadClass("com.slxy.reflex.Person"); System.out.println(clazz4); System.out.println(clazz1 == clazz4); }
4.Class实例可以是那些结构的说明:
@Test public void test4(){ Class c1 = Object.class; Class c2 = Comparable.class;//接口 Class c3 = String[].class; Class c4 = int[][].class; Class c5 = ElementType.class;//枚举类 Class c6 = Override.class;//注解 Class c7 = int.class; Class c8 = void.class; Class c9 = Class.class; int[] a = new int[2]; int[] b = new int[3]; System.out.println(a.getClass()==b.getClass());//结果为true //结论:只要数组元素的类型和维度相同,就是同一个Class }
5.使用Classloader加载src目录下的配置文件
public class PersonTest{ @Test public void test5() throws Exception { Properties properties = new Properties(); //读取配置文件的方式一: FileInputStream fis = new FileInputStream("src\\jdbc.properties"); properties.load(fis); //读取配置文件的方式二: ClassLoader classLoader = PersonTest.class.getClassLoader(); InputStream is = classLoader.getResourceAsStream("jdbc.properties"); properties.load(is); String user = properties.getProperty("user"); String password = properties.getProperty("password"); System.out.println("user="+user+";password="+password); } }
防止properties文件乱码的解决方法:File-->Settings-->Editor-->File Encodings
6.反射的应用一:通过反射创建运行时类的对象
@Test public void test6() throws IllegalAccessException, InstantiationException { Class clazz6 = Person.class; /*调用newInstance()方法,创建运行时类的对象。内部调用了运行时类的空参构造器。 想用此方法正常创建运行时类对象要求: 1.运行时类必须提供空参构造器。 2.空参构造器的访问权限得够。通常设置为public 在javabean中要求提供一个public的空参构造器。原因: 1.便于通过反射,创建运行时类的对象 2.便于子类继承此运行时类,默认调用super()时,保证父类有此构造器 */ Object obj = clazz6.newInstance(); Person p = (Person)obj; System.out.println(p); }
总结:创建类对象的方式:
方式一:new+构造器
方式二:要创建Xxx类的对象,可以考虑:Xxx、Xxxs、XxxFactory、XxxBuilder类中可能构造器被私有化了,可以查看是否有静态方法的存在。可以调用其静态方法,创建Xxx对象。
方式三:通过反射
7.反射应用二:获取运行时类的完整结构(框架中会经常用到的两种):
1)获取运行时类的父类实现的接口
2)获取运行时类的带泛型的父类的泛型
/* 获取运行时类的带泛型的父类的泛型 */ Class clazz = Person.class; Type genericSuperclass = clazz.getGenericSuperclass(); ParameterizedType paramType = (ParameterizedType) genericSuperclass; //获取泛型类型 Type[] actualTypeArguments = paramType.getActualTypeArguments(); System.out.println(actualTypeArguments[0].getTypeName()); /* 获取运行时类的父类实现的接口 */ Class[] interfaces1 = clazz.getSuperclass().getInterfaces(); for(Class c : interfaces1){ System.out.println(c); }
8.反射应用三:调用运行时类的指定结构
1)如何操作运行时类中指定的属性
方式一: 不推荐 @Test public void Test1() throws Exception { Class clazz1 = Person.class; Person p = (Person) clazz1.newInstance(); Field age = clazz1.getField("age"); age.set(p,18); System.out.println(age.get(p)); } 方式二: @Test public void Test2() throws Exception { Class clazz2 = Person.class; //创建运行时类的对象 Person p = (Person) clazz2.newInstance(); //getDeclaredField(String name):获取运行时类中指定变量名的属性 Field name = clazz2.getDeclaredField("name"); //保证当前属性是可访问的 name.setAccessible(true); //获取或设置指定对象的此属性值 //set():参数1:指明设置哪个对象的属性 参数2:将此属性值设置为多少 name.set(p,"Tom"); //get():参数1:获取哪个对象的当前属性值 System.out.println(name.get(p)); }
2)如何操作运行时类中指定的方法
方式一:不推荐 @Test public void Test1() throws Exception { Class clazz1 = Person.class; Person p = (Person)clazz1.newInstance(); Method show = clazz1.getMethod("show",String.class); show.invoke(p,"Tom"); } 方式二: @Test public void Test2() throws Exception { Class clazz1 = Person.class; //创建运行时类的对象 Person p = (Person)clazz1.newInstance(); /* 1.获取指定的某个方法 getDeclaredMethod():参数1 :指明获取的方法的名称 参数2:指明获取的方法的形参列表*/ Method nationshow = clazz1.getDeclaredMethod("nationShow", String.class); //2.保证当前方法是可访问的 nationshow.setAccessible(true); /* 3. 调用方法的invoke():参数1:方法的调用者 参数2:给方法形参赋值的实参 invoke()的返回值即为对应类中调用的方法的返回值。 */ nationshow.invoke(p,"中国"); }
3)如何操作运行时类的构造器
@Test public void Test3() throws Exception { Class clazz = Person.class; //获取指定的构造器 Constructor con = clazz.getDeclaredConstructor(String.class); //设置此构造器可以访问 con.setAccessible(true); //调用此构造器创建运行时类的对象 Person p = (Person)con.newInstance("李四"); System.out.println(p); }
9.反射应用四:动态代理
静态代理举例:
package com.slxy.reflex; /*静态代理 * 特点:代理类和被代理类在编译期间就已经确定了 * */ public class ProxyTest { public static void main(String[] args) { Star star = new Star(); Proxy proxy = new Proxy(star); proxy.otherWork(); proxy.sing(); } } interface Show{ void otherWork(); void sing(); } //被代理类 class Star implements Show{ @Override public void otherWork() { } @Override public void sing() { System.out.println("表演唱歌"); } } //代理类 class Proxy implements Show{ Show star; public Proxy(Star star){ this.star = star; } @Override public void otherWork() { System.out.println("做一些准备工作"); } @Override public void sing() { star.sing(); } }
动态代理
package com.slxy.reflex; import sun.java2d.Surface; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //动态代理 /* 要想实现动态代理,需要解决的问题? 问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。 问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。 */ public class ProxyTest1 { public static void main(String[] args) { SuperMan superMan = new SuperMan(); Human proxy =(Human)PorxyFactory.getProxyInstance(superMan); proxy.faith(); proxy.eat("饺子"); System.out.println("*************"); Star star = new Star(); Show proxy1 =(Show) PorxyFactory.getProxyInstance(star); proxy1.otherWork(); proxy1.sing(); } } interface Human{ void faith(); void eat(String str); } //被代理类 class SuperMan implements Human{ @Override public void faith() { System.out.println("I believe i can fly!"); } @Override public void eat(String str) { System.out.println("我喜欢吃" + str); } } //动态代理类 class PorxyFactory{ //调用此方法,返回一个代理类的对象。解决问题一 public static Object getProxyInstance(Object obj){//obj:被代理类的对象 MyInvocationHandler handler = new MyInvocationHandler(obj); return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler); } } class MyInvocationHandler implements InvocationHandler{ private Object obj; public MyInvocationHandler(Object obj){ this.obj = obj; } //当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke() //将被代理类要执行的方法a的功能就声明在invoke()中 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法 //obj:被代理类的对象 Object value = method.invoke(obj,args); //上述方法的返回值就作为当前类中的invoke()的返回值。 return value; } }
原文:https://www.cnblogs.com/miao-wu/p/14715757.html