- 反射(Reflection)
- //getFields():获取当前运行时类及其父类中声明为public访问权限的属性
- //getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
- //获取属性的修饰符,数据类型,变量名
- //获取方法的注解,权限修饰符,返回值,方法名,参数列表,抛出的异常
- //getConstructors():获取当前运行时类中声明为public的构造器
- //getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
- // 获取运行时类的父类
- // 获取运行时类的带泛型的父类
- //获取运行时类的带泛型的父类的泛型
- // 获取运行时类实现的接口
- //获取运行时类所在的包
- //获取运行时类声明的注解
- //创建运行时类的对象
- //操作运行时类中的指定的属性
- //操作运行时类中的指定的方法
- //获取指定的构造器:getDeclaredConstructor():参数:指明构造器的参数列表
- //读取配置文件
- //了解类的加载器
- 反射的应用:动态代理
反射(Reflection)
- 动态语言的关键,反射机制允许程序在执行期借助Reflection API取得任何类的内部信息,并直接操作任意对象的内部属性及方法,
- 加载完类之后,在堆内存的方法区就产生了一个完整的Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类结构信息,我们可以通过这个对象看到类的结构,这个对象就像一面镜子,透过这个镜子看到类部的结构,所以我们形象的称其为:反射
- 动态语言:运行时可以改变其结构的语言
- 静态语言:运行时结构不可变的语言就是静态语言,Java
- Java不是动态语言但是可以称之为”准动态语言”,即java有一定的动态性,我们可以利用反射机制,字节码的操作来获得类时动态语言得特性
- java.long.Class类:反射的源头
- 类的加载过程:程序经过javac.exe命令以后,会生成一个或者多个字节码文件(.class结尾),接着我们使用java.exe命令对某一字节码文件进行解释运行.相当于将某个字节码文件加载到内存中,此过程就称为类的加载,加载到内存中的类,我们称为运行时类,这个运行时类就作为Class的一个实例.
- 类的加载过程:程序经过javac.exe命令以后,会生成一个或者多个字节码文件(.class结尾),接着我们使用java.exe命令对某一字节码文件进行解释运行.相当于将某个字节码文件加载到内存中,此过程就称为类的加载,加载到内存中的类,我们称为运行时类,这个运行时类就作为Class的一个实例.
- Class实例就对应者一个运行时类
- 加载到内存中的运行时类,会缓冲一定时间,我们可以通过不同的方式来获取运行时类
- 获取Class实例
- 调用运行类的class属性:例如 Class clazz = Person.class
- 通过运行时类的对象: Person p= new Person; class clazz = p.getClass();
- 调用Class的静态方法 : Class.forName(“com.adong.java.person”);
- 使用类的加载器: CassLoader cl = 当前类.class.getClassLoader(); Class claszz = Cl.loadClass(“com.adong.java.Rerson”)
- 调用运行类的class属性:例如 Class clazz = Person.class
- Class方法
- newInstance() : 创建对应的运行时类的对象:调用空参构造器,空参构造器不能为private
- Field getField(string name) : 获取运行时类的指定属性,要求属性为public
- Feild对象: set(Object obj,object obj) : 参数一,为要设置对象,属性二属性值设置为多少.
- get(object obj):获取属性的值
- Feild对象: set(Object obj,object obj) : 参数一,为要设置对象,属性二属性值设置为多少.
- Field getDeclaredField(String name):获取运行时类指定的属性
- setAccessible(true) :保证当前属性是 可以访问的
- setAccessible(true) :保证当前属性是 可以访问的
- Field[] getFields(): 获取当前运行时类及其父类中声明为public访问权限的属性
- Field[] getDeclaredFields():获取当前运行时类中声明的所有属性(不包含父类声明的属性)
- 可以通过field[] 数组元素知道权限修饰符,数据类型,变量名
- Field中方法
- int getModifiers(): 返回权限修饰符,可以Modifier.toString(int modifier);获取具体<br />
- Class getType() : 获取数据类型, 获取的class对象.getName()获取具体类型<br />
- String getName(); : 获取变量名<br />
- 可以通过field[] 数组元素知道权限修饰符,数据类型,变量名
- Method getDeclareMethod(String name,形参.class) : 参数一获取方法的名称,参数二获取方法的形参列表
- Object invoke(object obj,String name);参数一为方法的调用者,参数二给方法赋值的实参
- 静态的化要是使用运行类.class
- 静态的化要是使用运行类.class
- Object invoke(object obj,String name);参数一为方法的调用者,参数二给方法赋值的实参
- Method[] getMethods() : 获取当前运行时类及其所有父类声明为public权限的方法
- Method[] getDeclareMethods();:获取当前运动时类中声明的所有方法(不包含父类中声明的方法)
- Method中方法
- Annotation[] getAnnotations():获取方法声明 的注解
- int getModifiers(): 返回权限修饰符,可以Modifier.toString(int modifier);获取具体
- Class getReturnType() : 返回值类型 .getName() 获取类型字符串
- String getName() : 方法名
- Class[] getParameterType() :参数列表
- class[] getExceptionTypes() : 获取异常类型
- Annotation[] getAnnotations():获取方法声明 的注解
- Method中方法
- Constructor getDEclaredConstructor(参数.class):获取指定为构造器,参数为构造器的参数列表
- Constructor[] getConstructors() : 获取当前运行时类为public权限的构造器
- Constructor[] getDeclaredConstructors() ; 获取当前运行时类的全部构造器
- Class getSuperclass():获取运行类的父类
- Type getGenericSuperclass() : 获取运行时带泛型的父类
- Class[] getInterface() :获取运行时类实现的接口
- Package getPackage() : 获取运行时类所在的包
- Annotation[] getAnnotations():获取运行时类声明的注解
- newInstance() : 创建对应的运行时类的对象:调用空参构造器,空参构造器不能为private
- 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
- 哪些类型可以有Class 对象?
- (1)class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
- (2)interface:接口
- (3)[]:数组
- (4)enum:枚举
- (5)annotation:注解@interface
- (6)primitive type:基本数据类型
- (7)void
- (1)class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
- 获取Class实例
//getFields():获取当前运行时类及其父类中声明为public访问权限的属性
Field[] fields = clazz.getFields();
//getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
Field[] declaredFields = clazz.getDeclaredFields();
//获取属性的修饰符,数据类型,变量名
Field[] declaredFields = clazz.getDeclaredFields();
for(Field f : declaredFields){
//1.权限修饰符
int modifier = f.getModifiers();
System.out.print(Modifier.toString(modifier) + “\t”);
//2.数据类型<br /> Class type = f.getType();<br /> System.out.print(type.getName() + "\t");
//3.变量名<br /> String fName = f.getName();<br /> System.out.print(fName);<br /> }<br />//getMethods():获取当前运行时类及其所有父类中声明为public权限的方法<br /> Method[] methods = clazz.getMethods();<br />//getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)<br /> Method[] declaredMethods = clazz.getDeclaredMethods();
//获取方法的注解,权限修饰符,返回值,方法名,参数列表,抛出的异常
Class clazz = Person.class;<br /> Method[] declaredMethods = clazz.getDeclaredMethods();
for(Method m : declaredMethods){<br /> //1.获取方法声明的注解<br /> Annotation[] annos = m.getAnnotations();<br />
//2.权限修饰符<br /> System.out.print(Modifier.toString(m.getModifiers()) + "\t");
//3.返回值类型<br /> System.out.print(m.getReturnType().getName() + "\t");
//4.方法名<br /> System.out.print(m.getName());<br /> //5.形参列表<br /> Class[] parameterTypes = m.getParameterTypes();<br /> if(!(parameterTypes == null && parameterTypes.length == 0)){<br /> for(int i = 0;i < parameterTypes.length;i++){
if(i == parameterTypes.length - 1){<br /> System.out.print(parameterTypes[i].getName() + " args_" + i);<br /> break;<br /> }
System.out.print(parameterTypes[i].getName() + " args_" + i + ",");<br /> }<br /> }
System.out.print(")");
//6.抛出的异常<br /> Class[] exceptionTypes = m.getExceptionTypes();
if(exceptionTypes.length > 0){<br /> System.out.print("throws ");<br /> for(int i = 0;i < exceptionTypes.length;i++){<br /> if(i == exceptionTypes.length - 1){<br /> System.out.print(exceptionTypes[i].getName());<br /> break;<br /> }
System.out.print(exceptionTypes[i].getName() + ",");<br /> }<br /> }
//getConstructors():获取当前运行时类中声明为public的构造器
Constructor[] constructors = clazz.getConstructors();
//getDeclaredConstructors():获取当前运行时类中声明的所有的构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
// 获取运行时类的父类
Class superclass = clazz.getSuperclass();
// 获取运行时类的带泛型的父类
Type genericSuperclass = clazz.getGenericSuperclass();
//获取运行时类的带泛型的父类的泛型
Type genericSuperclass = clazz.getGenericSuperclass();<br /> ParameterizedType paramType = (ParameterizedType) genericSuperclass;<br /> //获取泛型类型<br /> Type[] actualTypeArguments = paramType.getActualTypeArguments();<br /> //二者选一<br /> System.out.println(actualTypeArguments[0].getTypeName());<br /> System.out.println(((Class)actualTypeArguments[0]).getName());
// 获取运行时类实现的接口
Class[] interfaces = clazz.getInterfaces();
//获取运行时类所在的包
Package pack = clazz.getPackage();
//获取运行时类声明的注解
Annotation[] annotations = clazz.getAnnotations();
//创建运行时类的对象
Class clazz = Person.class;<br /> Person p = (Person) clazz.newInstance();
//操作运行时类中的指定的属性
Class clazz = Person.class;<br /> //创建运行时类的对象<br /> Person p = (Person) clazz.newInstance();
//1. getDeclaredField(String fieldName):获取运行时类中指定变量名的属性<br /> Field name = clazz.getDeclaredField("name");
//2.保证当前属性是可访问的<br /> name.setAccessible(true);<br /> //3.获取、设置指定对象的此属性值<br /> name.set(p,"Tom"); //参数一为要操作属性的对象,参数二修改属性的值,静态的成员变量 :name.set(Person.class,"Tom");修改<br /> //获取变量的值<br /> System.out.println(name.get(p));
//操作运行时类中的指定的方法
Class clazz = Person.class;<br /> //创建运行时类的对象<br /> Person p = (Person) clazz.newInstance();<br /> <br /> //1.获取指定的某个方法 : getDeclaredMethod():参数1 :指明获取的方法的名称 参数2:指明获取的方法的形参列表<br /> Method show = clazz.getDeclaredMethod("show", String.class);
//2.保证当前方法是可访问的<br /> show.setAccessible(true);
//3. 调用方法的invoke():参数1:方法的调用者 参数2:给方法形参赋值的实参,invoke()的返回值即为对应类中调用的方法的返回值。<br /> Object returnValue = show.invoke(p,"CHN"); //String nation = p.show("CHN");<br /> System.out.println(returnValue);
System.out.println("*************如何调用静态方法*****************");
// private static void showDesc()
Method showDesc = clazz.getDeclaredMethod("showDesc");<br /> showDesc.setAccessible(true);<br /> //如果调用的运行时类中的方法没有返回值,则此invoke()返回null<br /> // Object returnVal = showDesc.invoke(null);<br /> Object returnVal = showDesc.invoke(Person.class);<br /> System.out.println(returnVal);//null
//获取指定的构造器:getDeclaredConstructor():参数:指明构造器的参数列表
Constructor constructor = clazz.getDeclaredConstructor(String.class);<br /> //保证此构造器是可访问的<br /> constructor.setAccessible(true);<br /> //调用此构造器创建运行时类的对象<br /> Person per = (Person) constructor.newInstance("Tom");
//读取配置文件
Properties pros = new Properties();
//此时的文件默认在当前的module下。
//读取配置文件的方式一:
//FileInputStream fis = new FileInputStream(“jdbc.properties”);
//FileInputStream fis = new FileInputStream(“src\jdbc1.properties”);
//pros.load(fis);
//读取配置文件的方式二:使用ClassLoader<br /> //配置文件默认识别为:当前module的src下<br /> ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();<br /> InputStream is = classLoader.getResourceAsStream("jdbc1.properties");<br /> pros.load(is);
String user = pros.getProperty("user");<br /> String password = pros.getProperty("password");<br /> System.out.println("user = " + user + ",password = " + password);
//了解类的加载器
• //1.获取一个系统类加载器
• ClassLoader classloader = ClassLoader.getSystemClassLoader();
• System.out.println(classloader);
• //2.获取系统类加载器的父类加载器,即扩展类加载器
• classloader = classloader.getParent();
• System.out.println(classloader);
• //3.获取扩展类加载器的父类加载器,即引导类加载器
• classloader = classloader.getParent();
• System.out.println(classloader);
• //4.测试当前类由哪个类加载器进行加载
• classloader = Class.forName(“exer2.ClassloaderDemo”).getClassLoader();
• System.out.println(classloader);
• //5.测试JDK提供的Object类由哪个类加载器加载
• classloader = Class.forName(“java.lang.Object”).getClassLoader();
• System.out.println(classloader);
• //*6.关于类加载器的一个主要方法:getResourceAsStream(String str):获取类路径下的指定文件的输入流
• InputStream in = null;
• in = this.getClass().getClassLoader().getResourceAsStream(“exer2\test.properties”);
• System.out.println(in);
反射的应用:动态代理
- 静态代理:代理类和被代理类在编译期间就去确定下来了,不利于程序的扩展
- 每一个代理类只能为一个接口服务,程序开发中必然产生过多的代理类
- 实现动态代理类解决的问题
- 实现动态代理类解决的问题
- 根据加载到内存中的被代理类,动态创建一个代理类及其对象
- 代理类的对象调方法时,调用被代理类中同名的方法
package com.adong.java;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
*
* 动态代理的举例
*
* @author shkstart
* @create 2019 上午 10:18
*/
interface Human{
String getBelief();
void eat(String food);
}
//被代理类
class SuperMan implements Human{
@Override<br /> public String getBelief() {<br /> return "I believe I can fly!";<br /> }
@Override<br /> public void eat(String food) {<br /> System._out_.println("我喜欢吃" + food);<br /> }<br />}
class ProxyFactory{
//调用此方法,返回一个代理类的对象。解决问题一
public static Object getProxyInstance(Object obj){//obj:被代理类的对象
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);<br /> //被代理类的类加载器,其实现的方法, 第一个类加载器,第二个这个类实现的接口,<br /> return Proxy._newProxyInstance_(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);<br /> }
}
class MyInvocationHandler implements InvocationHandler{
private Object obj;//需要使用被代理类的对象进行赋值<br /> <br /> public void bind(Object obj){<br /> this.obj = obj;<br /> }
//当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()<br /> //将被代理类要执行的方法a的功能就声明在invoke()中<br /> @Override<br /> public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {<br /> //method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法<br /> //obj:被代理类的对象<br /> //args:方法的参数<br /> Object returnValue = method.invoke(obj,args);<br /> //上述方法的返回值就作为当前类中的invoke()的返回值。<br /> return returnValue;
}<br />}
public class ProxyTest {
public static void main(String[] args) {<br /> //代理类的对象<br /> SuperMan superMan = new SuperMan();<br /> //proxyInstance:代理类的对象<br /> Human proxyInstance = (Human) ProxyFactory._getProxyInstance_(superMan);<br /> //当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法<br /> String belief = proxyInstance.getBelief();<br /> System._out_.println(belief);<br /> proxyInstance.eat("四川麻辣烫");
System._out_.println("*****************************");
NikeClothFactory nikeClothFactory = new NikeClothFactory();
ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory._getProxyInstance_(nikeClothFactory);
proxyClothFactory.produceCloth();
}<br />}