反射基本操作

it2024-12-05  14

* 本文主要介绍反射相关: * 反射:(Reflection) 是java被视为动态语言的关键,反射机制允许程序在动态执行期间借助ReflectionAPI动态的获取类的任何 * 内部信息,并能直接操作对象的任何内部属性及方法。 * 通过类加载器,加载完类之后,在堆内存的方法区中就产生了Class类型的对象(对于相同的类只有一个Class对象),这个对象包含了 * 完整的类的结构信息,我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子,我们可以看到类的结构,所以,我们形象地称之为:反射. * 正常情况下,我们通过new关键字来实例化并获取实例对象 * 反射,通过实例化获取完整的类的内部结构 * 缺点: *      对性能影响极大,这类操作总是慢于直接执行相同的操作。 * java.lang.Class * java.lang.reflect.Method       类的方法 * java.lang.reflect.Field        类的成员变量 * java.lang.reflect.Constructor  类的构造器

 

public class OperationsOfReflection { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException { // 通过反射来获取类的class对象, 此处需要处理异常。 // 获取反射的Class对象方式1 Class.forName(全类名) // forName()里面是全类名 异常 ClassNotFoundException, Class c1 = Class.forName("cn.JAVandReflection.Reflection.Person"); // 获取方式2, 用某个类的对象的 对象.getClass()获取对应的Class对象 Person person = new Person(); Class c2 = person.getClass(); /** * 一个类一定只有一个class对象,验证:用反射获取的对象和这个类的对象的getClass()创建的对象比较其hashCode */ System.out.println(c2.hashCode() == c1.hashCode()); // true // 获取方式3 : 用类的class属性获取,该获取方式最快最可靠 Class c3 = Person.class; // 简介获取方式: 通过子类class对象获取父类的Class对象 /** * Man extend Person */ Class c4 = Man.class; Class c5 = c4.getSuperclass(); System.out.println(c5.hashCode() == c3.hashCode()); // true /** * Class对象反操作类的一些方法, 如下: */ // 获取类名 以Person的Class类为例 c3 或者 c5 // 获取到的是全类名 String allName = c3.getName(); System.out.println(allName); // 获取到的是仅仅类名 String simpleName = c3.getSimpleName(); System.out.println(simpleName); /** * 输出: * cn.JAVandReflection.Reflection.Person * Person */ // 根据Class对象获取类属性操作 // getFields() Field[] fields = c3.getFields(); Field[] fieldsAll = c3.getDeclaredFields(); // 打印查看区别 System.out.println(Arrays.toString(fields)); System.out.println(Arrays.toString(fieldsAll)); /** *[public java.lang.String cn.JAVandReflection.Reflection.Person.name, * public char cn.JAVandReflection.Reflection.Person.sex] * 第二个 * [public java.lang.String cn.JAVandReflection.Reflection.Person.name, * public char cn.JAVandReflection.Reflection.Person.sex, * private java.lang.String cn.JAVandReflection.Reflection.Person.id, * private int cn.JAVandReflection.Reflection.Person.age] * 可以看出,每一行第一个是修饰符,最后一个是字段名, * 第一个获取到的都是poublic修饰的 * 第二个获取到的是public 和 private 其实它可以获取所有修饰的属性,包括private 私有属性 */ // 以上是获取属性列表,那么如何获取单个属性呢? // 同样的 加上Declared就是获取所有属性的而没有这个的方法获取到的都是publc修饰的 // NoSuchFieldException // 像这样,获取的name属性必须是public修饰的,不然会抛出 NoSuchFieldException异常 Field name = c3.getField("name"); // 这样的可以获取任意修饰符修饰的属性 Field name1 = c3.getDeclaredField("name"); /** * 获取方法 */ // 获取所有public的方法和父类的public方法, 注意 c4是Man的class Method[] methods = c4.getMethods(); Method[] declaredMethods = c4.getDeclaredMethods(); System.out.println(Arrays.toString(methods)); System.out.println(Arrays.toString(declaredMethods)); /** *注意。因为Man继承了person类,而person类继承了Object类,所以它列出了所有的public方法,很多 * [public static void cn.JAVandReflection.Reflection.Man.main(java.lang.String[]), * public java.lang.String cn.JAVandReflection.Reflection.Person.toString(), * public java.lang.String cn.JAVandReflection.Reflection.Person.getName(), * public java.lang.String cn.JAVandReflection.Reflection.Person.getId(), * public void cn.JAVandReflection.Reflection.Person.setName(java.lang.String), * public void cn.JAVandReflection.Reflection.Person.setSex(char), * public char cn.JAVandReflection.Reflection.Person.getSex(), * public int cn.JAVandReflection.Reflection.Person.getAge(), * public final void java.lang.Object.wait() throws java.lang.InterruptedException, * public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, * public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, * public boolean java.lang.Object.equals(java.lang.Object), * public native int java.lang.Object.hashCode(), * public final native java.lang.Class java.lang.Object.getClass(), * public final native void java.lang.Object.notify(), * public final native void java.lang.Object.notifyAll()] * 第二个输出 应为man里面除了构造器,就创建了一个main方法用于测试 * [public static void cn.JAVandReflection.Reflection.Man.main(java.lang.String[])] */ // 获取单个方法 捕捉异常:NoSuchMethodException // 注意: 只能获取public修饰的方法 // 参数列表: 第一个:获取方法的名字, 后面的参数依次是该方法对应参数的Class对象,例如,setName(String str) // 那么第二个参数就是Strin.class Method setName = c3.getMethod("setName", String.class); // 获取构造器 Constructor[] constructors = c3.getConstructors(); Constructor[] constructors2 = c3.getDeclaredConstructors(); // 或者获取指定构造器 Constructor constructor = c3.getDeclaredConstructor(String.class, char.class, String.class, int.class); System.out.println(Arrays.toString(constructors)); System.out.println(Arrays.toString(constructors2)); System.out.println(constructor); /** * 输出: * [public cn.JAVandReflection.Reflection.Person(), * public cn.JAVandReflection.Reflection.Person(java.lang.String,char,java.lang.String,int)] * ----------------------------------------------------------------------------------------------- * [public cn.JAVandReflection.Reflection.Person(), * public cn.JAVandReflection.Reflection.Person(java.lang.String,char,java.lang.String,int)] * ----------------------------------------------------------------------------------------------- * public cn.JAVandReflection.Reflection.Person(java.lang.String,char,java.lang.String,int) * 经比对:完全一致: */ /* 上面是获取信息,下面利用反射来创建和使用对象 */ // 获取对象,注意:直接获取到的是Object的对象,需要向下转型 // 注意: 需要调用无参构造器,如果没有无参构造器就会抛异常,InstantiationException // 如果类构造器的权限是私有的,也不能通过这种方式获取对象 Object person2 = c3.newInstance(); // 通过获取到的构造器进行初始化 constructor 上面获取到的构造器 Person o = (Person)constructor.newInstance("李白", 'M', "002", 15); // 通过反射调用方法 // 调用方法前需要先创建对象,因为对象才能调用方法 // 通过反射获取方法 // 比如通过反射获取toString方法 Method toString = c3.getDeclaredMethod("toString"); // 使用invoke使用方法:invoke激活的意思 // 使用方法.invoke()参数的第一个是通过反射创建的对象,后面的参数是方法的参数列表,如果没有传入null System.out.println(toString.invoke(o, null)); /** * Person{name='李白', sex=M} 执行结果就和正常调用一样,说明处理正常 */ /** * !!!!!!!!!!! 注意:无论是获取私有方法还是私有属性,如果直接获取获取不到抛出异常 * 就用 .setAccessible(true)方法关闭安全检测,这不仅能加括执行速度,还可以获取private修饰的东西 */ // 操作属性 // 通过上面创建的对象 操作属性 // 属性通过反射获取 Field name2 = c3.getDeclaredField("name"); name2.setAccessible(true); // 通过set修改 name2.set(o, "张飞"); // 通过get查看 System.out.println(name2.get(o)); // 为了验证,我们再次使用toString方法查看 System.out.println(toString.invoke(o, null)); /** * Person{name='李白', sex=M} * 张飞 * Person{name='张飞', sex=M} * 可以看到,对象确实被修改了 */ /** * 反射操作泛型: * java采用泛型擦除机制来引入泛型,java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换的问题 * 但是一旦编译完成,所有和泛型相关的类型都会被擦除 * 为了通过反射操作泛型,java新增了ParameterizedType : 表示参数化类型 * 1、 getGenericParameterType * 2 遍历上面获取到Type 判断每一项 instanceof ParameterizedType * --- 此处理解先查看Type类型,然后是参数化类型 等 * */ } }

 Person 类

package cn.JAVandReflection.Reflection; public class Person { public String name; public char sex; private String id; private int age; public Person() { } public Person(String name, char sex, String id, int age) { this.name = name; this.sex = sex; this.id = id; this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", sex=" + sex + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public char getSex() { return sex; } public void setSex(char sex) { this.sex = sex; } public String getId() { return id; } private void setId(String id) { this.id = id; } public int getAge() { return age; } private void setAge(int age) { this.age = age; } protected void eat() { System.out.println("人要吃饭饭!!!"); } }

Man

package cn.JAVandReflection.Reflection; public class Man extends Person{ public Man() { super.sex = 'M'; } public Man(String name, String id, int age) { super(name, 'M', id, age); } public static void main(String[] args) { Man man = new Man("li", "001", 45); System.out.println(man); } }

 

 

最新回复(0)