Java进阶之反射机制
反射机制
- 1>反射机制基础
- 1.1、反射机制的作用
- 1.2、反射机制的相关类
- 1.3、反射机制重要的类
- 2>Java中获取Class的三种方式
- 3>关于类加载器(了解,无需掌握)
- 3.1、什么是类加载器?
- 3.2、JDK自带的三个类加载器
- 3.3、类加载器的例子
- 3.4、利用类加载机制调用静态代码块
- 4>利用反射机制创建对象
- 5>反射机制创建对象与普通实例化的区别
- 5.1、简单例子
- 5.2、路径问题
- 5.3、资源配置文件
- 5.4、根据路径问题得出更优代码
- 6>反射方法的重要类以及重要方法
- 6.1、Class类
- 6.2、Field类
- 6.2.1、访问类的属性并进行修改
- 6.3、Method类
- 6.3.1、通过反射机制调用方法
- 6.3.2、可变长度参数
1>反射机制基础
1.1、反射机制的作用
通过java语言中的反射机制可以操作字节码文件。优点类似于黑客。(可以读和修改字节码文件。)通过反射机制可以操作代码片段。(class文件。)
1.2、反射机制的相关类
java.lang.reflect.*;
1.3、反射机制重要的类
- java.lang.Class:代表整个字节码,代表一个类型,代表整个类。
- java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法。
- java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法
- java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。
java.lang.Class:public class User{// Fieldint no;// Constructorpublic User(){}public User(int no){this.no = no;}// Methodpublic void setNo(int no){this.no = no;}public int getNo(){return no;}}
2>Java中获取Class的三种方式
第一种: Class c = Class.forName("完整类名");//包名.类名第二种:Class c = 对象.getClass();第三种:Class c = int.class;Class c = String.class;
//第一种方式
c1 = Class.forName("java.lang.String");// c1代表String.class文件,或者说c1代表String类型。
c2 = Class.forName("java.util.Date");
// c2代表Date类型
Class c3 = Class.forName("java.lang.Integer");
// c3代表Integer类型
Class c4 = Class.forName("java.lang.System");
// c4代表System类型
//第二种方式String s = "abc";Class x = s.getClass();
// x代表String.class字节码文件,x代表String类型。
// 第三种方式,java语言中任何一种类型,包括基本数据类型,它都有.class属性。
Class z = String.class; // z代表String类型
Class k = Date.class; // k代表Date类型
Class f = int.class; // f代表int类型
Class e = double.class; // e代表double类型
3>关于类加载器(了解,无需掌握)
3.1、什么是类加载器?
专门负责加载类的命令/工具。
ClassLoader
3.2、JDK自带的三个类加载器
- 启动类加载器:rt.jar
- 扩展类加载器:ext/*.jar
- 应用类加载器:classpath
3.3、类加载器的例子
假设有这样一段代码:String s = "abc";代码在开始执行之前,会将所需要类全部加载到JVM当中。通过类加载器加载,看到以上代码类加载器会找String.class文件,找到就加载,那么是怎么进行加载的呢?首先通过“启动类加载器”加载。注意:启动类加载器专门加载:C:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jarrt.jar中都是JDK最核心的类库。如果通过“启动类加载器”加载不到的时候,会通过"扩展类加载器"加载。注意:扩展类加载器专门加载:C:\Program Files\Java\jdk1.8.0_101\jre\lib\ext\*.jar如果“扩展类加载器”没有加载到,那么会通过“应用类加载器”加载。注意:应用类加载器专门加载:classpath中的类。java中为了保证类加载的安全,使用了双亲委派机制。优先从启动类加载器中加载,这个称为“父”“父”无法加载到,再从扩展类加载器中加载,这个称为“母”。双亲委派。如果都加载不到,才会考虑从应用类加载器中加载。直到加载到为止。
3.4、利用类加载机制调用静态代码块
package com.bjpowernode.java.reflect;
/*
研究一下:Class.forName()发生了什么?记住,重点:如果你只是希望一个类的静态代码块执行,其它代码一律不执行,你可以使用:Class.forName("完整类名");这个方法的执行会导致类加载,类加载时,静态代码块执行。提示:后面JDBC技术的时候我们还需要。*/
public class ReflectTest04 {public static void main(String[] args) {try {// Class.forName()这个方法的执行会导致:类加载。Class.forName("com.bjpowernode.java.reflect.MyClass");} catch (ClassNotFoundException e) {e.printStackTrace();}}
}
public class MyClass {// 静态代码块在类加载时执行,并且只执行一次。static {System.out.println("MyClass类的静态代码块执行了!");}
}
4>利用反射机制创建对象
package com.bjpowernode.java.reflect;
import com.bjpowernode.java.bean.User;/*
获取到Class,能干什么?通过Class的newInstance()方法来实例化对象。注意:newInstance()方法内部实际上调用了无参数构造方法,必须保证无参构造存在才可以。*/
public class ReflectTest02 {public static void main(String[] args) {// 这是不使用反射机制,创建对象User user = new User();System.out.println(user);// 下面这段代码是以反射机制的方式创建对象。try {// 通过反射机制,获取Class,通过Class来实例化对象Class c = Class.forName("com.bjpowernode.java.bean.User"); // c代表User类型。// newInstance() 这个方法会调用User这个类的无参数构造方法,完成对象的创建。// 重点是:newInstance()调用的是无参构造,必须保证无参构造是存在的!Object obj = c.newInstance();System.out.println(obj); // com.bjpowernode.java.bean.User@10f87f48} catch (ClassNotFoundException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();}}
}
5>反射机制创建对象与普通实例化的区别
5.1、简单例子
- 利用IO流在Properties通过key得到value
- 并根据value的值实例化value对应的类
package com03;import java.io.FileReader;
import java.util.Properties;/*
验证反射机制的灵活性。java代码写一遍,再不改变java源代码的基础之上,可以做到不同对象的实例化。非常之灵活。(符合OCP开闭原则:对扩展开放,对修改关闭。)后期我们要学习的是高级框架,而工作过程中,也都是使用高级框架,
包括: ssh ssmSpring SpringMVC MyBatisSpring Struts Hibernate...这些高级框架底层实现原理:都采用了反射机制。所以反射机制还是重要的。学会了反射机制有利于你理解剖析框架底层的源代码。*/class Test {public static void main(String[] args) throws Exception{// 这种方式代码就写死了。只能创建一个User类型的对象//User user = new User();// 以下代码是灵活的,代码不需要改动,可以修改配置文件,配置文件修改之后,可以创建出不同的实例对象。// 通过IO流读取classinfo.properties文件FileReader reader = new FileReader("classinfo2.properties");// 创建属性类对象MapProperties pro = new Properties(); // key value都是String// 加载pro.load(reader);// 关闭流reader.close();// 通过key获取valueString className = pro.getProperty("className");//System.out.println(className);// 通过反射机制实例化对象Class c = Class.forName(className);Object obj = c.newInstance();//这个地方也可以用泛型//Class<User> c = (Class<User>)Class.forName(className);User obj = c.newInstance(); System.out.println(obj);}
}
package com03;public class User {public User(){System.out.println("无参数构造方法!");}// 定义了有参数的构造方法,无参数构造方法就没了。public User(String s){}
}
//classinfo2.properties
className = com03.User
5.2、路径问题
package com.bjpowernode.java.reflect;import java.io.FileReader;/*
研究一下文件路径的问题。
怎么获取一个文件的绝对路径。以下讲解的这种方式是通用的。但前提是:文件需要在类路径下。才能用这种方式。*/
public class AboutPath {public static void main(String[] args) throws Exception{// 这种方式的路径缺点是:移植性差,在IDEA中默认的当前路径是project的根。// 这个代码假设离开了IDEA,换到了其它位置,可能当前路径就不是project的根了,这时这个路径就无效了。//FileReader reader = new FileReader("chapter25/classinfo2.properties");// 接下来说一种比较通用的一种路径。即使代码换位置了,这样编写仍然是通用的。// 注意:使用以下通用方式的前提是:这个文件必须在类路径下。// 什么类路径下?方式在src下的都是类路径下。【记住它】// src是类的根路径。/*解释:Thread.currentThread() 当前线程对象getContextClassLoader() 是线程对象的方法,可以获取到当前线程的类加载器对象。getResource() 【获取资源】这是类加载器对象的方法,当前线程的类加载器默认从类的根路径下加载资源。*/String path = Thread.currentThread().getContextClassLoader().getResource("classinfo2.properties").getPath(); // 这种方式获取文件绝对路径是通用的。// 采用以上的代码可以拿到一个文件的绝对路径。// /C:/Users/Administrator/IdeaProjects/javase/out/production/chapter25/classinfo2.propertiesSystem.out.println(path);// 获取db.properties文件的绝对路径(从类的根路径下作为起点开始)String path2 = Thread.currentThread().getContextClassLoader().getResource("com/bjpowernode/java/bean/db.properties").getPath();System.out.println(path2);}
}
5.3、资源配置文件
package com.bjpowernode.java.reflect;import java.util.ResourceBundle;/*
java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容。
使用以下这种方式的时候,属性配置文件xxx.properties必须放到类路径下。*/
public class ResourceBundleTest {public static void main(String[] args) {// 资源绑定器,只能绑定xxx.properties文件。并且这个文件必须在类路径下。文件扩展名也必须是properties//类路径起始就在module下//并且在写路径的时候,路径后面的扩展名不能写。//ResourceBundle bundle = ResourceBundle.getBundle("classinfo2");//classinfo2文件与src同级ResourceBundle bundle = ResourceBundle.getBundle("com/bjpowernode/java/bean/db");//src下是类的根路径,省略srcString className = bundle.getString("className");System.out.println(className);}
}
5.4、根据路径问题得出更优代码
package com.bjpowernode.java.reflect;import java.io.FileReader;
import java.io.InputStream;
import java.util.Properties;public class IoPropertiesTest {public static void main(String[] args) throws Exception{// 获取一个文件的绝对路径了!!!!!/*String path = Thread.currentThread().getContextClassLoader().getResource("classinfo2.properties").getPath();FileReader reader = new FileReader(path);*/// 直接以流的形式返回。InputStream reader = Thread.currentThread().getContextClassLoader().getResourceAsStream("classinfo2.properties");Properties pro = new Properties();pro.load(reader);reader.close();// 通过key获取valueString className = pro.getProperty("className");System.out.println(className);}
}
6>反射方法的重要类以及重要方法
- java.lang.Class:代表整个字节码,代表一个类型,代表整个类。
- java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法。
- java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法
- java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。
6.1、Class类
- public String getName() 获取类完整名字(包.类)
- public String getSimpleName() 获取类名(类)
- public Field[] getFields() 获取所有用public修饰的Field(属性)
- public Field[] getDeclaredFields() 获取所有Field(无论修饰符)
- public Field getDeclaredField(String s) 根据属性名获得Field
- public Method[] getDeclaredMethods() 获得所有Method
- public Method getDeclaredMethod(String name, Class<?>… parameterTypes) 根据方法名,参数类型获得方法
// 获取整个类Class studentClass = Class.forName("com.bjpowernode.java.bean.Student");//com.bjpowernode.java.bean.StudentString className = studentClass.getName();System.out.println("完整类名:" + className);String simpleName = studentClass.getSimpleName();System.out.println("简类名:" + simpleName);
6.2、Field类
- public String getName() 获得成员的名字
- public int getModifiers() 获取修饰符数字()
- public Class<?> getType() 获取Field的类型
- public int getModifiers() 获取Field修饰符代号
- Modifier中静态方法public static void toString(int i) 将修饰符代号转换String类型
// 获取类中所有的public修饰的FieldField[] fields = studentClass.getFields();System.out.println(fields.length); // 测试数组中只有1个元素// 取出这个FieldField f = fields[0];// 取出这个Field它的名字String fieldName = f.getName();System.out.println(fieldName);// 获取所有的FieldField[] fs = studentClass.getDeclaredFields();System.out.println(fs.length); // 4System.out.println("==================================");// 遍历for(Field field : fs){// 获取属性的修饰符列表int i = field.getModifiers(); // 返回的修饰符是一个数字,每个数字是修饰符的代号!!!System.out.println(i);// 可以将这个“代号”数字转换成“字符串”吗?String modifierString = Modifier.toString(i);System.out.println(modifierString);// 获取属性的类型Class fieldType = field.getType();//String fName = fieldType.getName();String fName = fieldType.getSimpleName();System.out.println(fName);// 获取属性的名字System.out.println(field.getName());
6.2.1、访问类的属性并进行修改
- 访问一个类的属性并进行修改
- public void set(Object obj, Object value) 给obj对象的Field赋值value
- public Object get(Object obj) 获得Field的属性值
- public void setAccessible(boolean flag) 打破封装,可以给private修饰的属性赋值
public static void main(String[] args) throws Exception{// 我们不使用反射机制,怎么去访问一个对象的属性呢?Student s = new Student();// 给属性赋值s.no = 1111; //三要素:给s对象的no属性赋值1111//要素1:对象s//要素2:no属性//要素3:1111// 读属性值// 两个要素:获取s对象的no属性的值。System.out.println(s.no);// 使用反射机制,怎么去访问一个对象的属性。(set get)Class studentClass = Class.forName("com.bjpowernode.java.bean.Student");Object obj = studentClass.newInstance(); // obj就是Student对象。(底层调用无参数构造方法)// 获取no属性(根据属性的名称来获取Field)Field noFiled = studentClass.getDeclaredField("no");// 给obj对象(Student对象)的no属性赋值/*虽然使用了反射机制,但是三要素还是缺一不可:要素1:obj对象要素2:no属性要素3:2222值注意:反射机制让代码复杂了,但是为了一个“灵活”,这也是值得的。*/noFiled.set(obj, 22222); // 给obj对象的no属性赋值2222// 读取属性的值// 两个要素:获取obj对象的no属性的值。System.out.println(noFiled.get(obj));// 可以访问私有的属性吗?Field nameField = studentClass.getDeclaredField("name");// 打破封装(反射机制的缺点:打破封装,可能会给不法分子留下机会!!!)// 这样设置完之后,在外部也是可以访问private的。nameField.setAccessible(true);// 给name属性赋值nameField.set(obj, "jackson");// 获取name属性的值System.out.println(nameField.get(obj));}
6.3、Method类
- public int getModifiers() 获得修饰符代号
- public String getName() 获得方法名
- public Class<?>[] getParameterTypes() 获得所有 参数类型
- public Class<?> getReturnType() 获得method返回值的类型
- Modifier中静态方法public static void toString(int i) 将Field修饰符代号转换String类型
public static void main(String[] args) throws Exception{// 获取类了Class userServiceClass = Class.forName("com.bjpowernode.java.service.UserService");// 获取所有的Method(包括私有的!)Method[] methods = userServiceClass.getDeclaredMethods();//System.out.println(methods.length); // 2// 遍历Methodfor(Method method : methods){// 获取修饰符列表System.out.println(Modifier.toString(method.getModifiers()));// 获取方法的返回值类型System.out.println(method.getReturnType().getSimpleName());// 获取方法名System.out.println(method.getName());// 方法的修饰符列表(一个方法的参数可能会有多个。)Class[] parameterTypes = method.getParameterTypes();for(Class parameterType : parameterTypes){System.out.println(parameterType.getSimpleName());}}}
6.3.1、通过反射机制调用方法
- public Object invoke(Object obj, Object… args) 对obj对象的该method方法传参
package com.bjpowernode.java.reflect;import com.bjpowernode.java.service.UserService;import java.lang.reflect.Method;/*
重点:必须掌握,通过反射机制怎么调用一个对象的方法?五颗星*****反射机制,让代码很具有通用性,可变化的内容都是写到配置文件当中,将来修改配置文件之后,创建的对象不一样了,调用的方法也不同了,但是java代码不需要做任何改动。这就是反射机制的魅力。*/
public class ReflectTest10 {public static void main(String[] args) throws Exception{// 不使用反射机制,怎么调用方法// 创建对象UserService userService = new UserService();// 调用方法/*要素分析:要素1:对象userService要素2:login方法名要素3:实参列表要素4:返回值*/boolean loginSuccess = userService.login("admin","123");//System.out.println(loginSuccess);System.out.println(loginSuccess ? "登录成功" : "登录失败");// 使用反射机制来调用一个对象的方法该怎么做?Class userServiceClass = Class.forName("com.bjpowernode.java.service.UserService");// 创建对象Object obj = userServiceClass.newInstance();// 获取MethodMethod loginMethod = userServiceClass.getDeclaredMethod("login", String.class, String.class);//Method loginMethod = userServiceClass.getDeclaredMethod("login", int.class);// 调用方法// 调用方法有几个要素? 也需要4要素。// 反射机制中最最最最最重要的一个方法,必须记住。/*四要素:loginMethod方法obj对象"admin","123" 实参retValue 返回值*/Object retValue = loginMethod.invoke(obj, "admin","123123");System.out.println(retValue);}
}
package com.bjpowernode.java.service;/*** 用户业务类*/
public class UserService {/*** 登录方法* @param name 用户名* @param password 密码* @return true表示登录成功,false表示登录失败!*/public boolean login(String name,String password){if("admin".equals(name) && "123".equals(password)){return true;}return false;}// 可能还有一个同名login方法// java中怎么区分一个方法,依靠方法名和参数列表。public void login(int i){}/*** 退出系统的方法*/public void logout(){System.out.println("系统已经安全退出!");}
}
6.3.2、可变长度参数
可变长度参数
int... args 这就是可变长度参数
语法是:类型... (注意:一定是3个点。)1、可变长度参数要求的参数个数是:0~N个。
2、可变长度参数在参数列表中必须在最后一个位置上,而且可变长度参数只能有1个。
3、可变长度参数可以当做一个数组来看待,也就是说可以传入数组
Java进阶之反射机制相关推荐
- 浅说Java中的反射机制(一)
在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...
- JAVA基础--JAVA中的反射机制详解
JAVA反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能 ...
- java 有哪些反射机制_Java 的反射机制你了解多少?
不知道多少次听说过了Java反射机制的使用,比如:Spring 框架如何实例化IoC容器中的Bean,编码过程中如何动态的清理对象中的字段信息等等.工作中只是听说.看同事们编码实践,但是自己却只是概念 ...
- java代码安全检测机制_全面解析:java中的反射机制,内含代码验证解析
什么是反射? 在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功 ...
- 根据实例详解Java中的反射机制
概念: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java ...
- JAVA Reflection(反射机制)续
接上一篇文章 JAVA Reflection(反射机制) 动态数组 java.lang.reflect.Array static Object set(Object array, int index ...
- JAVA Reflection(反射机制)
Java 反射机制 反射机制简介 反射机制应用示例 简单的Ioc实现 代理模式 Java动态代理 简单的Aop实现 "程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言" ...
- Java语言基础-反射机制、正则表达式
反射机制 反射机制是在运行状态中,对于任意一个类,都能知道这个类(class文件)的所有属性和方法. 对于任意一个对象,都能调用它的任意一个方法和属性. 这种动态获取信息以及动态调用对象的方法的功能称 ...
- formdata 接受参数中带有class 对象_浅析JAVA中的反射机制及对Servlet的优化
今天来聊聊java中的反射机制,工作以后发现很多东西动不动就要使用反射或者动态代理,如果不能很好的理解反射,那么对于动态代理等一些重要的设计模式就会有种不够通透的感觉. 所谓的反射,就是在运行状态中, ...
- java中的反射机制是什么
给大家介绍一下java中的反射机制,java中反射机制更体现出了java的灵活性.多态.和类之间的耦合性. 1:反射是一种间接操作目标对象的机制,只要给定类的名字,就可以通过反设机制获取所有的类信息. ...
最新文章
- “跟风离职后,找不到工作了!”:好多同事离职,这家公司还值不值得待?...
- 选本还是从缓存设计理念选择更好
- CSDN博客代码块代码没有高亮颜色解决办法
- SAP CRM Fiori应用My Note的OData调用设计
- python打包成exe文件、提示缺少pgzrun模块_命令行运行python项目文件,报错:ModuleNotFoundError: No module named 'xxxx' 解决办法...
- Linux文件编程(2)
- 其他一些单元测试技巧
- 【博弈论】【SG函数】bzoj1777 [Usaco2010 Hol]rocks 石头木头
- 【hive】hive常见的几种文件存储格式与压缩方式的结合-------Parquet格式+snappy压缩 以及ORC格式+snappy压缩文件的方式
- 富士施乐3065扫描教程_富士施乐怎么设置扫描到PC
- 《The Pragmatic Programer》 reading notes
- 郭盛华为什么不去阿里巴巴?原因竟是这个
- 使用VMware启动centos6.6并使用Qume+kvm虚拟化linux和windows虚机
- 浪潮英信服务器如何用u盘装系统,浪潮英信服务器操作系统安装指引V20-Inspur.PDF...
- 为perf4j提供集中式监控项目perf4j-dashboard
- C语言——测试电脑大小端
- 陈文俊 计算机科学,2019年丘成桐中学科学奖总决赛获奖结果揭晓!
- 用计算机弹红莲华教程,原神红莲华琴谱 原神琴谱红莲华怎么弹
- 语音朗读带进度高亮显示
- PMP考试流程是怎么样的?