反射📦
定义🍨
Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任 意一个对象,都能够调用它的任意方法和属性,既然能拿到,那么我们就可以修改部分类型信息;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射(reflection)机制。
用途😋
- 在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法 。
- 用于各种通用框架(了解)
反射的基本信息🌵
如平时写一句向上转型的代码,父类引用在编译结束后可以看到父类引用的类型是父类,而运行结果却是子类.那我们通过反射就能判断一个对象到底是属于哪个类.
反射相关的类🤐
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的java应用程序中表示类和接口 |
Field类 | 代表类的成员变量或者属性 |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造方法 |
Note:一个类编译结束都会生成一个.class文件,而一个.class文件在加载到JVM中时都会被解析为一个class对象,所以说每个类对象都可以视作Class类的一个实例化对象,通过对获取到的Class类对象的读写,就可以做到对这个Class对象所对应的类对象进行添加改变属性和动作的目的!使得这个类变成一个动态的类
反射中常见的使用🍰
获取指定类的class对象👶
进行反射必不可少的一步,也是第一步.可以有三种方式进行获取
- Class.forName(“想获取的类全路径名称”);//forName()是一个静态方法,直接可以用Class类进行调用,该方法适用于明确指定类的全路径名称
- 类名.class;仅适用于编译之前就明确想操作的类是哪个类的情况
- 使用已有类对象的引用来调用getClass(),进而获取这个类的class对象
代码:
-
class Student{ private String name; public Student(){ System.out.println("我是公有构造方法"); } private Student(String str){ System.out.println("我是带一个参数的私有构造方法"); } } public class TestDemo { public static void main(String[] args) { try { //第一种 Class<?> c1=Class.forName("Student"); //第二种 Class<?> c2=student.class; //第三种 Student student=new Student(); Class<?> c3=student.getClass(); }catch(ClassNotFoundException e){ e.printStackTrace(); } } }
-
上述三种获取class对象的方法,获取到的对象只有一个
class Student{ private String name; public Student(){ System.out.println("我是公有构造方法"); } private Student(String str){ System.out.println("我是带一个参数的私有构造方法"); } } public class TestDemo { public static void main(String[] args) { try { //第一种 Class<?> c1=Class.forName("Student"); //第二种 Class<?> c2=student.class; //第三种 Student student=new Student(); Class<?> c3=student.getClass(); }catch(ClassNotFoundException e){ e.printStackTrace(); } System.out.println(c1==c2);//true System.out.println(c1==c2);//true System.out.println(c2==c3);//true } }
基于class对象构造一个什么都能获取的对象🦅
-
利用class对象中公有构造方法来构造对象
class Student{ private String name; public Student(){ System.out.println("我是公有构造方法"); } private Student(String str){ System.out.println("我是带一个参数的私有构造方法"); } } public class TestDemo { public static void main(String[] args){ //共有构造方法的调用 try { Class<?> c=Class.forName("Student"); Student student=(Student) c.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } }
-
利用class对象中私有构造方法来构造对象
public class TestDemo { public static void main(String[] args) { //调用私有构造方法 try { Class<?> c=Class.forName("Student"); //利用参数情况来获取指定的构造方法(因为构造方法构成了重载) Constructor<?> constructor=c.getDeclaredConstructor(String.class); constructor.setAccessible(true);//对获取到的构造方法设置权限为可访问 //利用上述的构造方法来构造对象 Student student=(Student) constructor.newInstance("xixi"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
步骤总结:
- 获取class对象
- 如果是公有构造方法,就可以拿着这个Class类对象的引用去调用newInstance()去构造对象了,构造出来是Object,可强转为想要的那个类
- 如果是私有构造方法,还得多做两件事,先获取到Class对象中指定的构造方法(利用的是重载),私有公有都随便拿,然后将这个构造方法的权限设置为true,最后拿着这个"开放权限"的Constructor类对象的引用去调用newInstance(形参列表)来构造对象即可,返回的也是Object,强不强转随便你
基于什么都能获取的对象去反射属性🚶
直接上代码:
class Student{ private String name; public Student(){ System.out.println("我是公有构造方法"); } private Student(String str){ System.out.println("我是带一个参数的私有构造方法"); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + '}'; } } public class TestDemo { public static void main(String[] args){ //共有构造方法的调用 try { //获取class对象 Class<?> c=Class.forName("Student"); //获取字段 Field name=c.getDeclaredField("name"); //开放权限 name.setAccessible(true); //通过公有构造方法实例化一个name字段被开放的student对象 Student student=(Student) c.newInstance(); //对已经开放的name字段进行修改 name.set(student,"大哥"); System.out.println(student); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } } } //打印: //我是私有构造方法 //Student{name='大哥'}
基于什么都能获取的对象去反射方法😡
class Student{ private String name; public Student(){ System.out.println("我是公有构造方法"); } private Student(String str){ System.out.println("我是带一个参数的私有构造方法"); } private void display(String str){ System.out.println("恭喜你获取到了我这私有方法"+str); } @Override public String toString() { return "Student{" + "name='" + name + '\'' + '}'; } } public class TestDemo { public static void main(String[] args) { try { //获取class对象 Class<?> c=Class.forName("Student"); //指定方法的获取 Method method=c.getDeclaredMethod("display", String.class); //对选取的方法开放权限 method.setAccessible(true); //实例化一个刚才指定方法已经开放权限的对象 Student student=(Student) c.newInstance(); //对那个方法进行访问,注意手段invoke method.invoke(student,"haha"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
反射的优缺点⚙️
优点:
- 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法
- 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力
- 反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等。
缺点:.
- 使用反射会有效率问题。会导致程序效率降低。
- 反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂 。