Java 反射
Java 反射表示重要反射机制问题这种方法贼牛 X,也就是通过外部文件配置,在不修改源码的情况下,来控制程序,也符合设计模式的 ocp 原则(开闭原则:不修改源码,扩容功能)
可以通过修改 properties 配置文件的 method 的配置,实现修改程序的表现方式。
举例子:
src\re.properties 文件
classfullpath = opp3.Catmethod=cry // 如果 cry 改为 hi 则会改变 Cat.class
package opp3;
public class Cat {private String name = "招财";public void hi(){System.out.println("hi,招财");}public void cry(){System.out.println("hi,喵喵叫");}}ReflectionQuestion.class
package opp3;
import javax.swing.plaf.synth.SynthOptionPaneUI;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Properties;
/**
反射问题的引入*/public class ReflectionQuestion {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {//根据配置文件 re.properties 指定信息,创建 Cat 对象并调用 hi 方法
// Cat cat = new Cat();// cat.hi();
}反射原理图 java.reflection
Java 反射插图
反射相关的主要类 java.lang.Class:代表一个类,Class 对象表示某个类加载后在堆中的对象 java.lang.reflect.Method:代表类的方法,Method 对象表示某个类的方法 java.lang.reflect.Field:代表类的成员变量,Field 对象表示某个类的成员变量 java.lang.reflect.Constructor:代表类的构造方法,Constructor 表示构造器这些类在 java.lang 包
package opp3;
public class Cat {private String name = "招财";public int age = 10;public Cat(){} //无参构造器 public Cat(String name){ this.name = name; }public void hi(){System.out.println("hi,招财");}public void cry(){System.out.println("hi,喵喵叫");}
}classfullpath = opp3.Catmethod=crypackage opp3;
import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Properties;
public class demo01 {public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
// Field field = cls.getField("name"); //getField 不能得到 private 私有的属性 private String name = "招财";Field field = cls.getField("age");// 传统写法: 对象.成员变量 , 反射:成员变量对象.get(对象)System.out.println(field.get(cat)); // public int age = 10;
}反射调用优化反射的
优点:可以动态的创建和使用对象(也可以是框架底层核心),使用灵活,没有反射机制,框架即时就是去底层支撑
缺点:使用反射基本就是解释执行,对执行速度有影响
package opp3;
import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;
public class demo02 {public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {m1();m2();
}稍微优化一下 setAccessible(true);
setAccessible:启动和禁用访问安全检查的开关。参数值为 true 则指反射的对象在使用时应该取消 java 语言访问检查。
提高反射效率。如果代码中必须使用反射,而该句代码需要频发的被调用,那么请设置为 true 使得原本无法访问的私有成员也可以访问 package opp3;
import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;
public class demo02 {public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchMethodException {m1();m2();m3();
}Method 的 setAccessible 优化
Method hi = cls.getMethod("hi");hi.setAccessible(true);Field 的 setAccessible 优化
Field name = cls.getField("name");name.setAccessible(true);
//因为原来的的属性是 private,不能直接访问,所以需要关闭安全检测 private String name = "招财";Class 类 Class 也是类,因此也继承 Object 类 Class 类对象不是 new 出来的,而是系统生成的对于某个类的 Class 类对象,在内存中只有一份,因此类只加载一次每个类的实例都会记得自己是哪个 Class 实例所生成通过 Class 可以完整地得到一个类的完整结构,通过一些列 APIClass 对象是存放在堆中类的字节码二进制数据,是放在方法区,有的地方称为类的元数据(包括 方法代码,变量名,方法名,访问权限等等)Java 注解与反射 基础插图
获取 Class 对象的六种方法 package opp3;
/**
演示 getClass()*/public class GetClass {public static void main(String[] args) throws ClassNotFoundException {
}}哪些类型有 Class 对象 class:外部类、成员(内部成员、外部成员),局部内部类,匿名内部类
interface:接口
[] :数组
enum:枚举
annotation:注解 @interface
primitive type:基本数据类型
void
package opp3;
import java.io.Serializable;
public class TypeClass {public static void main(String[] args) {Class stringClass = String.class; //外部类 Class serializableClass = Serializable.class; //接口 Class aClass = Integer[].class; //数组 Class aClass1 = float[][].class; //二维数组 Class deprecatedClass = Deprecated.class; //注解//枚举 Class stateClass = Thread.State.class;Class longClass = long.class; //基本数据类型 Class voidClass = void.class; //void 数据类型 Class classClass = Class.class;
}}类加载静态和动态加载静态加载:编译时加载相关类,如果没有则报错,依赖性太强动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,降低依赖性类加载时机:
当创建对象时(new) //静态加载当子类被加载时,父类也加载 //静态加载调用类种的静态成员时 //静态加载通过反射 package opp3;
import java.lang.reflect.Method;
public class ClassLoad_ {public static void main(String[] args) throws Exception {// //静态加载,依赖性很强// //编译前必须有 Cat 类,否则会报错// Cat cat = new Cat();// cat.hi();
}类加载流程图 Java 反射插图 2
Java 反射插图 3
类加载的五个阶段一、加载
二、验证阶段:
目的是为了去额宝 Class 文件的字节流种包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全包括:文件格式验证(是否以魔数 oxcafebabe 开头)、元数据验证、字节码验证和符号引用验证可以考虑使用 -Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机加载时间(只要你项目足够大,小项目就不考虑)三、准备阶段:
//1. n1 是实例属性,不是静态变量,因此在准备阶段不会分配内存//2. n2 是静态变量,分配内存 n2 是默认初始化 0 ,而不是 20//3. n3 是 static final 常量,它和静态变量不一样,因为一旦赋值就不边 n3 = 30
// class 内部//属性-成员变量-字段
public int n1 = 10;public static int n2 = 20;public static final int n3 = 30 四、解析 阶段
虚拟机将常量池内的符号引用替换为直接引用的过程
五、初始化
到初始化阶段,才正在执行类中定义的 java 程序代码,此阶段是执行()方法的过程()方法是按语句在源文件中出现的顺序,依次自动收集类中所有的静态变量的赋值动作和静态代码块中的语句,并进行合并虚拟机会保证一个类()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,知道活动线程执行()方法完毕。反射获取类的结构信息第一组:
getName(); 获取全类名 getSimpleName(); 获取简单类名 getFields(); 获取所有 public 修饰的属性,包括父类的 getDeclaredFields(); 获取本类中所有属性 getMethods(); 获取多有的 public 修饰的方法,包括父类的 getDeclaredMethods(); 获取本类所有的方法 getConstructors(); 获取本类所有 public 修饰的构造器 getDeclaredConstructors(); 获取本类中所有的构造器 getPackage(); 以 package 形式返回父类信息 getSuperclass(); 以 class 形式返回父类信息 getInterfaces(); 以 Class[]形式返回接口信息 getAnnotations(); 以 Annotations[]形式返回注解信息 package opp3;
import org.testng.annotations.Test;
import java.lang.annotation.Annotation;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;
/**
如何获取类的结构信息*/
public class Demo05 {public static void main(String[] args) throws Exception{api_01();}
}
class A {public String hobby;public A(){}}
interface IA{
}interface IB{
}@Deprecatedclass Person extends A implements IA,IB{public String name;protected int age;String job;private double sal;
}第二组:java.lang.reflect.Field 类
getModifiers :以 int 形式返回修饰符
(说明:默认修饰符是 0 , public 是 1 , private 是 2, protected 是 4 ,static 是 8, final 是 16)
其他的举例说明:修饰符 public static:1+8 = 9
getType:以 Class 形式返回类型
getName : 返回属性名
public void api_02() throws Exception{Class cls = Class.forName("opp3.Person");Field[] declaredFields = cls.getDeclaredFields();for (Field declaredField : declaredFields) {System.out.println("本类的所有属性 " + declaredField.getName()+" 该属性的修饰符值 " + declaredField.getModifiers()+ " 该属性的类型 " + declaredField.getType());}}第三组:java.lang.reflect.Method 类
getModifiers :以 int 形式返回修饰符
(说明:默认修饰符是 0 , public 是 1 , private 是 2, protected 是 4 ,static 是 8, final 是 16)
getReturnType: 以 Class 形式获取 返回类型
getName:返回方法名
getParameterTypes:以 Class[]返回参数类型数组
package opp3;
import org.testng.annotations.Test;
import java.lang.annotation.Annotation;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Type;
/**
如何获取类的结构信息*/
public class Demo05 {public static void main(String[] args) throws Exception{api_01();}
}
class A {public String hobby;public A(){}}
interface IA{
}interface IB{
}@Deprecatedclass Person extends A implements IA,IB{public String name;protected int age;protected static int id; //修饰符值 : 4 + 8 = 12String job;private double sal;
}第四组:java.lang.reflect.Constructor 类
getModifiers :以 int 形式返回修饰符
(说明:默认修饰符是 0 , public 是 1 , private 是 2, protected 是 4 ,static 是 8, final 是 16)
getName:返回构造器名(全类名)
getParameterTypes:以 Class[]返回参数类型数组
package opp3;
import org.testng.annotations.Test;
import java.lang.annotation.Annotation;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Type;
/**
如何获取类的结构信息*/
public class Demo05 {public static void main(String[] args) throws Exception{api_01();}
}
class A {public String hobby;public A(){}}
interface IA{
}interface IB{
}@Deprecatedclass Person extends A implements IA,IB{public String name;protected int age;protected static int id; //修饰符值 : 4 + 8 = 12String job;private double sal;
}反射爆破创建实例方式一:调用类中的 public 修饰的无参构造器方式二:调用类中的指定构造器 Class 类相关方法 newInstance:调用类中的无参构造器,获取对应类的对象 getConstructor(Class...clazz):根据参数列表,获取对应的构造器对象 getDecalaredConstructor(Class...clazz):根据参数列表,获取对应的构造器对象 Constructor 类相关说法 setAccessible:爆破 newInstance(Object...obj):调用构造器 package opp3;
import java.lang.reflect.Constructor;
/**
通过反射机制创建实例*/public class Demo06 {public static void main(String[] args) throws Exception {
}}
class User{private int age = 500;private String name = "Nahida";
}操作属性如何通过反射访问类中的成员
根据属性名获取 Field 对象
Field f = clazz 对象.getDeclaredField(属性名)
爆破:f.setAccessible(true) //f 是 Field
访问
f.set(o,值); //o 表示对象
syso(f.get(o)); // o 表示对象
如果是静态属性,则 set 和 get 中的参数 o,可以写成 null
package opp3;
import java.lang.reflect.Field;
/**
反射操作属性*/public class Demo07 {public static void main(String[] args) throws Exception {//1.得到 Student 对应的 Class 对象 Class<?> aClass = Class.forName("opp3.Student");
// name.set(o,"巴巴托斯"); 也可以如下一句:name.set(null,"巴巴托斯"); //因为 name 是静态 static 的,所以 o 也可以是 null, 【注意】不是静态的的这么写会报错 System.out.println(o);System.out.println(name.get(o)); //获取属性值
}
class Student{public int age; //公共 agepublic static String name;
}操作方法如何通过反射访问类中的成员
访问方法:
根据方法名获取 Method 方法对象
Method f = clazz 对象.getDeclaredMethod(方法名, XX.class) //得到本类所有方法
获取对象:Object o = clazz.newInstance();
爆破:m.setAccessible(true); //m 是 Method
访问
Object returnValue = m.invoke(o,实参列表);
如果是静态属性,则 invoke 中的参数 o,可以写成 null
package opp3;
import java.lang.reflect.Method;
/**
演示反射调用发发*/public class Demo08 {public static void main(String[] args) throws Exception {
// Method hi = aClass.getMethod("hi", String.class); //getMethod() 获取公共方法,这里可行,但是私有方法不行不能用//得到 hi 方法 Method hi1 = aClass.getDeclaredMethod("hi", String.class); //getDeclaredMethod() 获得类的所有方法,这里也可行 hi1.invoke(o,"香菱");
}
class Boss{public int age;private static String name;
}作业 Java 反射插图 4
package opp3.opp32;
import java.lang.reflect.Field;import java.lang.reflect.Method;
public class HomeWork {public static void main(String[] args) throws Exception {//1. 得到 PrivateTest 类对应的 Class 对象 Class<?> cls = Class.forName("opp3.opp32.PrivateTest");
}
class PrivateTest{private String name = "HelloKitty";public String getName(){return name;}}Java 反射插图 5
package opp3.opp32;
import java.lang.reflect.Constructor;import java.lang.reflect.Method;
public class HomeWork02 {public static void main(String[] args) throws Exception {//1. 利用 Class 类的 forName 得到 File 类的 class 对象 Class<?> cls = Class.forName("java.io.File");//2. 获得所有的构造器 Constructor<?>[] declaredConstructors = cls.getDeclaredConstructors();//遍历输出所有的的构造器 for (Constructor<?> declaredConstructor : declaredConstructors) {System.out.println("File 的构造器:" + declaredConstructor);}//3. 单独的得到 public java.io.File(java.lang.String)Constructor<?> declaredConstructor = cls.getDeclaredConstructor(String.class);String filePath = "e://mynew.txt";Object file = declaredConstructor.newInstance(filePath); //创建文件 File 对象//4. 调用 createNewFile()方法,创建文件 Method createNewFile = cls.getDeclaredMethod("createNewFile");createNewFile.invoke(file);//file 的运行类型就是 FileSystem.out.println(file.getClass());System.out.println("文件创建成功");
}
版权声明: 本文为 InfoQ 作者【卢衍飞】的原创文章。
原文链接:【http://xie.infoq.cn/article/4692ef49358b7e36dad6d9b36】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论