反射机制

  • 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进阶之反射机制相关推荐

  1. 浅说Java中的反射机制(一)

    在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...

  2. JAVA基础--JAVA中的反射机制详解

    JAVA反射机制     JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的信息以及动态调用对象的方法的功能 ...

  3. java 有哪些反射机制_Java 的反射机制你了解多少?

    不知道多少次听说过了Java反射机制的使用,比如:Spring 框架如何实例化IoC容器中的Bean,编码过程中如何动态的清理对象中的字段信息等等.工作中只是听说.看同事们编码实践,但是自己却只是概念 ...

  4. java代码安全检测机制_全面解析:java中的反射机制,内含代码验证解析

    什么是反射? 在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功 ...

  5. 根据实例详解Java中的反射机制

    概念: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java ...

  6. JAVA Reflection(反射机制)续

    接上一篇文章  JAVA Reflection(反射机制) 动态数组 java.lang.reflect.Array static Object set(Object array, int index ...

  7. JAVA Reflection(反射机制)

    Java 反射机制 反射机制简介 反射机制应用示例 简单的Ioc实现 代理模式 Java动态代理 简单的Aop实现 "程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言" ...

  8. Java语言基础-反射机制、正则表达式

    反射机制 反射机制是在运行状态中,对于任意一个类,都能知道这个类(class文件)的所有属性和方法. 对于任意一个对象,都能调用它的任意一个方法和属性. 这种动态获取信息以及动态调用对象的方法的功能称 ...

  9. formdata 接受参数中带有class 对象_浅析JAVA中的反射机制及对Servlet的优化

    今天来聊聊java中的反射机制,工作以后发现很多东西动不动就要使用反射或者动态代理,如果不能很好的理解反射,那么对于动态代理等一些重要的设计模式就会有种不够通透的感觉. 所谓的反射,就是在运行状态中, ...

  10. java中的反射机制是什么

    给大家介绍一下java中的反射机制,java中反射机制更体现出了java的灵活性.多态.和类之间的耦合性. 1:反射是一种间接操作目标对象的机制,只要给定类的名字,就可以通过反设机制获取所有的类信息. ...

最新文章

  1. “跟风离职后,找不到工作了!”:好多同事离职,这家公司还值不值得待?...
  2. 选本还是从缓存设计理念选择更好
  3. CSDN博客代码块代码没有高亮颜色解决办法
  4. SAP CRM Fiori应用My Note的OData调用设计
  5. python打包成exe文件、提示缺少pgzrun模块_命令行运行python项目文件,报错:ModuleNotFoundError: No module named 'xxxx' 解决办法...
  6. Linux文件编程(2)
  7. 其他一些单元测试技巧
  8. 【博弈论】【SG函数】bzoj1777 [Usaco2010 Hol]rocks 石头木头
  9. 【hive】hive常见的几种文件存储格式与压缩方式的结合-------Parquet格式+snappy压缩 以及ORC格式+snappy压缩文件的方式
  10. 富士施乐3065扫描教程_富士施乐怎么设置扫描到PC
  11. 《The Pragmatic Programer》 reading notes
  12. 郭盛华为什么不去阿里巴巴?原因竟是这个
  13. 使用VMware启动centos6.6并使用Qume+kvm虚拟化linux和windows虚机
  14. 浪潮英信服务器如何用u盘装系统,浪潮英信服务器操作系统安装指引V20-Inspur.PDF...
  15. 为perf4j提供集中式监控项目perf4j-dashboard
  16. C语言——测试电脑大小端
  17. 陈文俊 计算机科学,2019年丘成桐中学科学奖总决赛获奖结果揭晓!
  18. 用计算机弹红莲华教程,原神红莲华琴谱 原神琴谱红莲华怎么弹
  19. 语音朗读带进度高亮显示
  20. PMP考试流程是怎么样的?

热门文章

  1. 美股,期货和国债随着大选进行中持续大幅度波动,华尔街如何看待这次结局?
  2. 提高github下载速度的方法
  3. Anaconda 的Jupyter Notebook更换默认浏览器
  4. 三种碎片化方法:RECAP, BRICS与eMolFrag
  5. Android碎片化问题
  6. 逻辑架构和物理架构在架构设计中的应用
  7. python字典题_Python字典练习题
  8. 蒙特卡罗方法(Monte Carlo)
  9. Day-3 文字排版
  10. MIPI DSI的linux kernel驱动原理 | 基于RK3399