反射 不念不忘少年蓝@ 2021-09-23 00:44 309阅读 0赞 ## RTTI ## -------------------- 运行时类型识别(RTTI, Run-Time Type Identification)是Java中的机制,在Java运行时,RTTI维护类的相关信息。 多态是基于RTTI实现的。RTTI的功能主要是由Class类实现的。 Java中每个对象都有相应的Class对象,因此,我们随时能通过Class对象知道某个对象“真正”所属的类。无论我们对引用进行怎样的类型转换,对象本身所对应的Class对象都是同一个。当我们通过某个对象引用调用方法时,Java总能找到正确的Class类中所定义的方法,并执行该Class类中的代码。由于Class对象的存在,Java不会因为类型的向上转换而迷失。这就是(运行时)多态的原理。 ## java.lang.Class ## -------------------- Class类,保存着对象的运行时类型信息。类和接口都有。 ###### 源码 ###### //包含与类有关的信息 public final class Class<T> implements java.io.Serializable, GenericDeclaration,Type, AnnotatedElement {} ###### 获取一个类的Class对象 ###### 法1:public static Class<?> **forName**(String className)\{\} // java.lang.Class //要放在try...catch语句块中 Class c1 = Class.forName("类的全限定名"); Class<?> c1=Class.forName("类的全限定名"); 法2:public final native Class<?> **getClass**(); // java.lang.Object //返回 用来表示 该对象的实际类型的 Class引用 Class c2 = 类的对象.getClass(); Class<?> c2 = 类的某对象.getClass(); Class<? extends 该类> = 类的某对象.getClass(); 法3:类字面常量 //编译期就会受到检查,无需try块 //类不存在也就没有.class项 Class c3 = 类名.class; Class<?> c3 = 类名.class; Class<类名> c3 = 类名.class; 法1与法3的区别:用法3创建对Class对象的引用时还没有进行类加载过程中的初始化阶段;而调用Class.forName,Class对象已经自动完成了加载过程的初始化阶段。而只有触发类初始化条件时,法3中的Class对象才会开始进行初始化阶段的初始化操作。 而法2需要导入类的包。 ## 反射 ## -------------------- 在Java中的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。 1. 以下方法的输出中:参数,域,方法名,都为全限定名。 2. 使用private的成员:先获取private成员,再设置访问标志,最后调用。 ## 创建实例 ## -------------------- ###### 法1:一般不用 ###### 利用Class类型的方法: public T newInstance()(@Deprecated(since=“9”)) 该方法只能利用默认构造函数创建对象。 Class<?> c1= COM.class; Object obj = c1.newInstance(); ###### 法2 ###### 利用Constructor类型。 ## 判断某对象是否为某个类的实例 ## -------------------- public native boolean isInstance(Object obj); public class COM { public static void main(String[] args) throws Exception { Class<?> c1 = String.class; String s1 = new String("hello"); String s2 = new String("world"); String s3 = new String("helloworld"); boolean b1 = c1.isInstance(s1); boolean b2 = c1.isInstance(s2); boolean b3 = c1.isInstance(s3); System.out.println(""+b1+b2+b3); } } Output: truetruetrue ## java.lang.reflect.Constructor ## -------------------- 用于描述类的构造器。默认构造器也会被获取到。 相关方法介绍: public Constructor<?>\[\] getConstructors():获取所有public构造方法 public Constructor<?>\[\] getDeclaredConstructors():获取所有的构造方法(包括私有、默认、受保护、公有) public Constructor< T> getConstructor(Class<?>… parameterTypes):获取单个的public构造方法: public Constructor< T> getDeclaredConstructor(Class<?>… parameterTypes):获取某个构造方法(包括私有、默认、受保护、公有) public T newInstance(Object … initargs):调用构造方法,创建一个该类的对象,并用指定的参数进行初始化 Class<?> c1 = Class.forName("test.Student"); Constructor[] conArray = c1.getConstructors(); conArray = c1.getDeclaredConstructors(); Constructor con = c1.getConstructor(cahr.class); //获取参数为char的public构造方法 Constructor con = c1.getConstructor(null); //获取无参的public构造方法,null可以不写 Object obj = con.newInstance(); //调用构造方法 Student stu = (Student)obj; //转型 con = c1.getDeclaredConstructor(int.class); //获取参数为int的私有构造方法 con.setAccessible(true);//暴力访问(忽略掉访问修饰符) //在创建对象前,必须设置的一项 obj = con.newInstance(56); Output: public test.Student(java.lang.String,int) ## java.lang.reflect.Field ## -------------------- 用于描述类的成员变量。 相关方法介绍: public Field\[\] getFields():获取所有的public字段 public Field\[\] getDeclaredFields():获取所有字段,(包括私有、默认、受保护、公有) public Field getField(String name):获取某个public字段 public Field getDeclaredField(String name):获取某个字段(包括私有、默认、受保护、公有) public void set(Object obj, Object value):设置字段的值。要设置的字段所在的对象,要为字段设置的值) (obj=null时是在设置类的静态域) public String name; private String phoneNum; Class<?> c1 = Class.forName("test.Student"); Field[] fieldArray = c1.getFields(); fieldArray = c1.getDeclaredFields(); Field f = c1.getField("name"); Object obj = c1.getConstructor().newInstance();//产生Student对象,Student stu = new Student() f.set(obj, "hi");//为Student对象中的name属性赋值,stu.name = "hi" Student stu = (Student)obj; f = c1.getDeclaredField("phoneNum"); f.setAccessible(true);//暴力反射,解除私有限定 f.set(obj, "110"); Output: public java.lang.String test.Student.name ## java.lang.reflect.Method ## -------------------- 用于描述类的方法。 相关方法介绍: public Method\[\] getMethods():获取所有public方法,(包含了所有父类的public方法也包含Object类) public Method\[\] getDeclaredMethods():仅获取本类或本接口的成员方法(包括私有、默认、受保护、公有) public Method getMethod(String name, Class<?>… parameterTypes):获取单个public方法,包括父类的。(方法名,形参的Class类型对象) public Method getDeclaredMethod(String name, Class<?>… parameterTypes):仅获取本类或本接口的单个方法。(包括私有、默认、受保护、公有) public Object invoke(Object obj, Object… args):调用某方法。(要调用方法的对象,调用方式时所传递的实参) (obj=null是在调用静态方法) Class c1 = Class.forName("test.Student"); Method[] methodArray = c1.getMethods(); methodArray = c1.getDeclaredMethods(); Method m = c1.getMethod("show1", String.class); Object obj = c1.getConstructor().newInstance(); m.invoke(obj, "hi"); m = c1.getDeclaredMethod("show4", int.class); m.setAccessible(true);//解除私有限定 Object result = m.invoke(obj, 20); Output: private java.lang.String test.Student.show4(int) ## main方法的反射 ## -------------------- Class c1 = Class.forName("test.Student"); Method m1 = c1.getMethod("main", String[].class); m1.invoke(null, (Object)new String[]{"d","d","x"}); //这里相当于传了个new String[1]给invoke m1.invoke(null, new Object[] {new String[] {"d","d","x"}}); ## 通过反射越过泛型检查 ## -------------------- 泛型用在编译期,编译过后泛型擦除(消失掉)。所以是可以通过反射越过泛型检查的。 import java.lang.reflect.Method; import java.util.ArrayList; public class COM { public static void main(String[] args) throws Exception { ArrayList<String> strList = new ArrayList<>(); strList.add("aaa"); strList.add("bbb"); Class c1 = strList.getClass(); Method m = c1.getMethod("add", Object.class); //由于泛型擦除,方法的参数类型变成了Object m.invoke(strList, 100); for(Object obj : strList){ System.out.println(obj); } } } Output: aaa bbb 100 ## 利用反射创建数组–java.lang.reflect.Array ## -------------------- 数组可以赋值给一个Object Reference。 相关方法介绍: public static Object newInstance(Class<?> componentType, int length); public static native void set(Object array, int index, Object value); public static native Object get(Object array, int index); import java.lang.reflect.Array; public class COM { public static void main(String[] args) throws Exception { Class<?> c1= Class.forName("java.lang.String"); Object array = Array.newInstance(c1,25); //往数组里添加内容 Array.set(array,0,"1"); Array.set(array,1,"2"); Array.set(array,2,"3"); Array.set(array,3,"4"); Array.set(array,4,"5"); //获取某一项的内容 System.out.println(Array.get(array,3)); } } Output: 4 ## 反射缺点 ## -------------------- 反射会额外消耗一定的系统资源,所以如果不需要动态地创建一个对象,那么就不需要用反射。 反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。
相关 Java反射-反射 API 转自:https://www.jianshu.com/p/e55770dd48d3 涉及这些类 ![watermark_type_ZmFuZ3poZW5naGVpdGk_s 深碍√TFBOYSˉ_/ 2023年01月17日 07:40/ 0 赞/ 196 阅读
相关 反射_反射概述 反射 JAVA反射机制是在运行状态中,对于任意一个 类,都能够知道这个类的所有属性和方法;对 于任意一个对象,都能够调用它的任意一个方 清疚/ 2022年06月17日 02:22/ 0 赞/ 247 阅读
相关 反射 知识点: 1. 类对象概念 2. Class类的使用:创建类对象 3. 动态加载类 4. 获取方法信息 5. 获取成员变量、构造函数信息 6. 方法反射的基本操作 比眉伴天荒/ 2022年04月14日 04:14/ 0 赞/ 202 阅读
相关 反射 // 1.定义一个标准的JavaBean,名叫Person,包含属性name、age。 // 使用反射的方式创建一个实例、调用构造函数初始化name、age,使用反射方式调 Dear 丶/ 2022年04月03日 08:16/ 0 赞/ 207 阅读
相关 反射 > JAVA反射机制是在运行状态中 > > 对于任意一个类,都能够知道这个类的所有属性和方法; > > 对于任意一个对象,都能够调用它的任意一个方法和属性; > > 这种 柔光的暖阳◎/ 2022年02月16日 13:24/ 0 赞/ 155 阅读
相关 反射 反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态 喜欢ヅ旅行/ 2022年01月25日 19:23/ 0 赞/ 108 阅读
相关 反射 反射 类加载器的概述 当程序要使用某个类时,如果该类还未被加载到内存中, 则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。 加载 就是指将c 怼烎@/ 2022年01月17日 12:13/ 0 赞/ 232 阅读
相关 【反射】 JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法 比眉伴天荒/ 2021年11月09日 20:40/ 0 赞/ 492 阅读
相关 反射 反射机制简述 静态编译:在编译时确定类型,绑定对象,即通过。 动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的 小咪咪/ 2021年09月27日 14:00/ 0 赞/ 376 阅读
相关 反射 RTTI -------------------- 运行时类型识别(RTTI, Run-Time Type Identification)是Java中的机制,在Jav 不念不忘少年蓝@/ 2021年09月23日 00:44/ 0 赞/ 310 阅读
还没有评论,来说两句吧...