1、基本概念
java的动态处理技术,在运行时进行。
2、反射的例子
public class Student { public String name; public int age; public String gender; public Student() { } public Student(String name, int age, String gender) { this.name = name; this.age = age; this.gender = gender; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public String toString() { return "Student{" + "name='" + name + ''' + ", age=" + age + ", gender='" + gender + ''' + '}'; } } @Test public void test1(){ //软编码,灵活,把问题延迟到运行时解决 try { //干预类的加载,直接获取类模板对象 Class clazz = Class.forName("com.hike.javase.reflect.Student"); //通过类模板对象.newInstance创建实体对象 Object object = clazz.newInstance(); //调用无参构造器创建对象 System.out.println(object); } catch (ClassNotFoundException e) { // 在运行时动态加载类时, 发现没有找到类 e.printStackTrace(); } catch (IllegalAccessException e) { // 非法访问, 访问权限不够时出现 e.printStackTrace(); } catch (InstantiationException e) { // 在创建对象时出现异常, 可能是构造器不存在 e.printStackTrace(); } } @Test public void test(){ //编译时必须依赖类,硬编码 Student s1 = new Student(); //强烈依赖类 s1.name = "张三"; s1.age = 15; s1.gender = "男"; System.out.println(s1.getName()); System.out.println(s1.getAge()); System.out.println(s1.getGender()); Student s2 = new Student("小红", 16, "女"); System.out.println(s2); } }
3、反射中关于属性的访问
public void test2(){ try { Class clazz = Class.forName("com.hike.javase.reflect.Student"); Object object = clazz.newInstance(); System.out.println(object); //想要使用属性,先获取属性定义的对象 //Field ageField = clazz.getField("age"); //只能获取公共的属性,不可以获取私有属性 Field ageField = clazz.getDeclaredField("age"); //获取类中的任意属性 //暴力反射,不推荐使用 ageField.setAccessible(true); //设置此属性为可访问的 //根据属性名获取属性的定义对象 ageField.set(object,15); //相当于object.age = 15; System.out.println(ageField.get(object)); //相当于 System.out.println(object.age) //Field nameField = clazz.getField("name"); //nameField.set(object,"小李"); //System.out.println(nameField.get(object)); System.out.println(object); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (SecurityException e){ e.printStackTrace(); } }
4、一些方法
@Test public void test5() throws ClassNotFoundException { Class clazz = Class.forName("com.hike.javase.reflect.Student"); String name = clazz.getName(); System.out.println("类名 : " + name); System.out.println("简单类名 : " + clazz.getSimpleName()); Class superclass = clazz.getSuperclass(); System.out.println("父类 : " + superclass); Class[] interfaces = clazz.getInterfaces(); System.out.println("接口列表 "); for (Class class1 : interfaces) { System.out.println(class1); } }
@Test public void test6() throws ClassNotFoundException { // 获取类模板对象的方法 ,有4种 // 1) 直接通过类.class, 效率最高, 最安全. Class clazz1 = Student.class; // 2) 根据对象, 调用它的getClass()方法获取, 此方法也很常用. Student student = new Student("佟刚", 40, "男"); Class clazz2 = student.getClass(); System.out.println(clazz1 == clazz2); // 3) 反射中最常用的 Class.forName("全限定类名"); Class clazz3 = Class.forName("com.hike.javase.reflect.Student"); System.out.println(clazz2 == clazz3); // 4) 通过类加载器对象动态加载类 ClassLoader classLoader = this.getClass().getClassLoader(); Class clazz4 = classLoader.loadClass("com.hike.javase.reflect.Student"); System.out.println(clazz3 == clazz4); }
@Test public void test7() { Class strClazz = String.class; System.out.println(strClazz); // 基本数据类型的类模板只能用第一种方式获取. Class clazz1 = int.class; // 基本数据类型也有相应的类模板对象, 但是不能获取属性和方法, 只能作为一个标记来使用. Class clazz2 = Integer.class; // 这是一个普通类模板. System.out.println(clazz1 == clazz2); // 判断类模板类型 System.out.println("是否是基本型 : " + clazz1.isPrimitive()); System.out.println("是否是基本型 : " + clazz2.isPrimitive()); }
6、类加载器
@Test public void test8() { ClassLoader classLoader1 = ClassLoader.getSystemClassLoader(); // 获取系统类加载器 System.out.println(classLoader1); ClassLoader classLoader2 = this.getClass().getClassLoader(); // 使用最多的, 获取当前类的类加载器 System.out.println(classLoader2); ClassLoader classLoader3 = classLoader1.getParent(); // 获取父 "类加载器", 是 扩展 "类加载器" System.out.println(classLoader3); ClassLoader classLoader4 = classLoader3.getParent(); // 获取到的是引导类加载器(Bootstrap) System.out.println(classLoader4); // 这个类加载器无法获取, 无法使用 }
重要应用:使用类加载器读取资源文件
@Test public void test9() throws IOException { //FileInputStream fis = new FileInputStream("只能读当前目录下的文件"); ClassLoader classLoader = this.getClass().getClassLoader(); // 只能加载build-path和src下的文件 //InputStream inputStream = classLoader.getResourceAsStream("com/sun/corba/se/impl/logging/LogStrings.properties"); // 读取资源文件, 只要是Build-Path(classpath)中的文件都可以 InputStream inputStream = classLoader.getResourceAsStream("test.properties"); Properties properties = new Properties(); properties.load(inputStream); Set> entrySet = properties.entrySet(); for (Entry
使用全参构造器实例化对象
@Test public void test10() { try { Class clazz = Class.forName("com.hike.javase.reflect.Student"); //Object object = clazz.newInstance(); 没有无参构造器时出问题 //public Student(String name, int age, String gender) 要想定位这个构造器, 必须让参数列表一致. // 提供形式参数类型列表, 是类模板对象的列表 Constructor constructor = clazz.getConstructor(String.class, int.class, String.class); // 定位合适的构造器 // 调用时必须给定实参列表 Object object = constructor.newInstance("程程", 20, "女"); // new Teacher("程程", 20, "女"); System.out.println(object); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { // 参数列表出错, 或者方法名出错 e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { // 方法调用时实参和形参不匹配 e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } }
7、反射实现方法的调用
在Student类中添加方法
public void study(String content, int time){ System.out.println("学生在上[" + content + "]课, 共上了[" + time +"]小时"); //return true; //throw new RuntimeException("一个异常"); }
@Test public void test11() { try { Class clazz = Class.forName("com.hike.javase.reflect.Student"); Constructor constructor = clazz.getConstructor(String.class, int.class, String.class); Object object = constructor.newInstance("小明", 20, "女"); //object.study("JavaWEB", 5); //先获取方法 Method studyMethod = clazz.getMethod("study", String.class, int.class); // 后面是方法参数类型列表 Short n = 5; Object retValue = studyMethod.invoke(object, "JavaWEB", n); // 后面是实参列表, 如果方法没有返回值, 它的返回值是null System.out.println(retValue); } catch (ClassNotFoundException e) { // 类没有找到 e.printStackTrace(); } catch (NoSuchMethodException e) { // 方法没有找到, 方法名错误或参数列表错误 e.printStackTrace(); } catch (SecurityException e) { // 安全异常 e.printStackTrace(); } catch (InstantiationException e) { // 创建对象时出现异常 e.printStackTrace(); } catch (IllegalAccessException e) { // 非法访问异常 e.printStackTrace(); } catch (IllegalArgumentException e) { // 非法实参异常, 实参和形参不匹配, 类型和顺序和数量 e.printStackTrace(); } catch (InvocationTargetException e) { // 调用的目标方法内部出现异常了. e.printStackTrace(); } }
当调用的方法为private时,使用以下方法进行调用。
// getMethod只能获取公共的方法, 包括从父类继承的. //Method studyMethod = clazz.getMethod("study", String.class, int.class); // getDeclaredMethod可以获取本类中所有声明的方法 Method studyMethod = clazz.getDeclaredMethod("study", String.class, int.class); studyMethod.setAccessible(true);
通过反射访问静态方法
Object retValue = studyMethod.invoke(null, "JavaWEB", n); // 静态方法传null, 不需要传入对象
8、通过反射获取类模板的一些内容
@Test public void test14() throws Exception { Class clazz = Class.forName("com.hike.javase.reflect.Student"); System.out.println("父类 : " + clazz.getSuperclass()); Constructor[] constructors = clazz.getConstructors(); for (int i = 0; i < constructors.length; i++) { System.out.println("构造器 : " + constructors[i]); } System.out.println("************************************************"); Field[] fields = clazz.getFields(); // 所有公共属性 for (int i = 0; i < fields.length; i++) { System.out.println(fields[i]); } Field[] declaredFields = clazz.getDeclaredFields(); // 所有本类属性 for (Field field : declaredFields) { System.out.println(field); } System.out.println("************************************************"); Method[] methods = clazz.getMethods(); for (Method method : methods) { System.out.println(method); } System.out.println("************************************************"); Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method method : declaredMethods) { System.out.println(method); } }
熟悉运行机制,思路,在非高级编程中应用不多。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)