java反射基础

本文涉及的产品
Serverless 应用引擎 SAE,800核*时 1600GiB*时
注册配置 MSE Nacos/ZooKeeper,118元/月
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 本文主要针对java中的反射基础知识进行讲解

1 - 反射概念

Java反射机制就是在运行状态中,通过任意一个类的class文件,都能够获取这个类的所有属性和方法,这种动态获取信息的方法,称为Java的反射机制。通过反射机制可以操作代码片段。(class文件)

2 -关于反射类的包

       java.lang.Class:代表整个字节码,代表一个类型,代表整个类。

       java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法。

       java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法

       java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。

3 -获取Class的三种方式

       第一种:Class c = Class.forName("完整类名带包名");


       第二种:Class c = 对象.getClass();


       第三种:Class c = 任何类型.class;


如果你只是希望一个类的静态代码块执行,其它代码一律不执行, 你可以使用:

Class.forName("完整类名");

这个方法的执行会导致类加载,类加载时,静态代码块执行。

import java.util.Date;

 

/**

* @author Mr.乐

* @Description 获取Class的三种方式

*/

public class Demo01 {

   public static void main(String[] args) throws ClassNotFoundException {

         /*

       Class.forName()

           1、静态方法

           2、方法的参数是一个字符串。

           3、字符串需要的是一个完整类名。

           4、完整类名必须带有包名。java.lang包也不能省略。

        */

       Class c1 = null;

       Class c2 = null;

       try {

           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类型

       } catch (ClassNotFoundException e) {

           e.printStackTrace();

       }

 

       // java中任何一个对象都有一个方法:getClass()  引用对象

       String s = "abc";

       Class x = s.getClass(); // x代表String.class字节码文件,x代表String类型。

       System.out.println(c1 == x); // true(==判断的是对象的内存地址。)

 

       Date time = new Date();

       Class y = time.getClass();  

       System.out.println(c2 == y); // true (c2和y两个变量中保存的内存地址都是一样的,都指向方法区中的字节码文件。)

 

       // 第三种方式,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类型

 

       System.out.println(x == z); // true

 

   }

}

image.png

通过反射实例化对象

注意:newInstance()方法内部实际上调用了无参数构造方法,必须保证无参构造存在才可以。

5 -获取文件路径或内容

FileReader reader = new FileReader("chapter25/classinfo2.properties");

这种方式的路径缺点是:移植性差,在IDEA中默认的当前路径是project的根。

这个代码假设离开了IDEA,换到了其它位置,可能当前路径就不是project的根了,这时这个路径就无效了。

以下代码可以获取文件类路径下文件的绝对路径。

/**

* @author Mr.乐

* @Description  获取文件的绝对路径

*/

public class Path {

   public static void main(String[] args) {

       //Thread.currentThread() 当前线程对象

       //getContextClassLoader() 是线程对象的方法,可以获取到当前线程的类加载器对象。

       //getResource() 【获取资源】这是类加载器对象的方法,当前线程的类加载器默认从类(必须为类路径)的根路径下加载资源。

       // 采用以下的代码可以拿到一个文件的绝对路径。

       String path = Thread.currentThread().getContextClassLoader().getResource("my.properties").getPath();

// 这种方式获取文件绝对路径是通用的。

       System.out.println(path);

       ///E:/ideaproject/myjavase/out/production/myjavase/my.properties

   }

}

--------------------------------------------------------------------------

/**

* @author Mr.乐

* @Description

*/

public class Path02 {

   public static void main(String[] args) throws Exception {

       // 获取一个文件的绝对路径了!!!!!

       /*String path = Thread.currentThread().getContextClassLoader()

               .getResource("my.properties").getPath();

       FileReader reader = new FileReader(path);*/

 

       // 直接以流的形式返回。

       InputStream reader = Thread.currentThread().getContextClassLoader()

               .getResourceAsStream("my.properties");

 

       Properties pro = new Properties();

       pro.load(reader);

       reader.close();

       // 通过key获取value

       String className = pro.getProperty("name");

       System.out.println(className);

   }

}

--------------------------------------------------------------------------

/*

java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容。

使用以下这种方式的时候,属性配置文件xxx.properties必须放到类路径下。

*/

public class ResourceBundleTest {

   public static void main(String[] args) {

 

       // 资源绑定器,只能绑定xxx.properties文件。并且这个文件必须在类路径下。文件扩展名也必须是properties

       // 并且在写路径的时候,路径后面的扩展名不能写。

       //ResourceBundle bundle = ResourceBundle.getBundle("my");

 

       ResourceBundle bundle = ResourceBundle.getBundle("my");

 

       String name = bundle.getString("name");

       System.out.println(name);

 

   }

}

6- 获取成员变量

/**

* @author Mr.乐

* @Description

*/

public class Student {

   //四个不同权限的属性

   public int no;

   private String name;

   protected Integer age;

   boolean sex;

   public static final long PHONE=1888888888;

}

--------------------------------------------------------

import java.lang.reflect.Field;

import java.lang.reflect.Modifier;

 

/**

* @author Mr.乐

* @Description  获取成员变量属性

*/

public class Demo03 {

   public static void main(String[] args) throws ClassNotFoundException {

 

       // 获取整个类

       Class studentClass = Class.forName("reflect.Student");

       //Student

       String className = studentClass.getName();

       System.out.println("完整类名:" + className);

       String simpleName = studentClass.getSimpleName();

       System.out.println("简类名:" + simpleName);

       //简类名:Student

 

       // 获取类中所有的public修饰的Field

       Field[] fields = studentClass.getFields();

       System.out.println(fields.length); // 测试数组中只有1个元素 1

       // 取出这个Field

       Field f = fields[0];

       // 取出这个Field它的名字

       String fieldName = f.getName();

       System.out.println(fieldName); //no

 

       // 获取所有的Field

       Field[] fs = studentClass.getDeclaredFields();

       System.out.println(fs.length); // 4

 

       System.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());

       }

   }

}

---------------------------------------------------------------------

import java.lang.reflect.Field;

import java.lang.reflect.Modifier;

 

/**

* @author Mr.乐

* @Description  反编译类的属性

*/

public class Demo04 {

   public static void main(String[] args) throws ClassNotFoundException {

// 创建这个是为了拼接字符串。

       StringBuilder s = new StringBuilder();

 

       //Class studentClass = Class.forName("reflect.Student");

       Class studentClass = Class.forName("java.lang.Thread");

 

       s.append(Modifier.toString(studentClass.getModifiers()) + " class " + studentClass.getSimpleName() + " {\n");

 

       Field[] fields = studentClass.getDeclaredFields();

       for(Field field : fields){

           s.append("\t");

           s.append(Modifier.toString(field.getModifiers()));

           s.append(" ");

           s.append(field.getType().getSimpleName());

           s.append(" ");

           s.append(field.getName());

           s.append(";\n");

       }

       s.append("}");

       System.out.println(s);

   }

}

6.1 -反射的优点

import java.lang.reflect.Field;

 

/**

* @author Mr.乐

* @Description 反射的灵活性

*/

public class Demo05 {

   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("reflect.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));

   }

}

7 -通过反射获取成员方法

import java.lang.reflect.Method;

import java.lang.reflect.Modifier;

 

/**

* @author Mr.乐

* @Description 反射Method

*/

public class Demo06 {

   public static void main(String[] args) throws ClassNotFoundException {

       // 获取类了

       Class userServiceClass = Class.forName("reflect.UserService");

 

       // 获取所有的Method(包括私有的!)

       Method[] methods = userServiceClass.getDeclaredMethods();

       //System.out.println(methods.length); // 2

 

       // 遍历Method

       for(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());

           }

       }

   }

}

7.1 -反编译一个方法

import java.lang.reflect.Method;

import java.lang.reflect.Modifier;

 

/**

* @author Mr.乐

* @Description 反编译一个方法

*/

public class Demo07 {

   public static void main(String[] args) throws ClassNotFoundException {

       StringBuilder s = new StringBuilder();

       Class userServiceClass = Class.forName("reflect.UserService");

       s.append(Modifier.toString(userServiceClass.getModifiers()) + " class "+userServiceClass.getSimpleName()+" {\n");

 

       Method[] methods = userServiceClass.getDeclaredMethods();

       for(Method method : methods){

           //public boolean login(String name,String password){}

           s.append("\t");

           s.append(Modifier.toString(method.getModifiers()));

           s.append(" ");

           s.append(method.getReturnType().getSimpleName());

           s.append(" ");

           s.append(method.getName());

           s.append("(");

           // 参数列表

           Class[] parameterTypes = method.getParameterTypes();

           for(Class parameterType : parameterTypes){

               s.append(parameterType.getSimpleName());

               s.append(",");

           }

           // 删除指定下标位置上的字符

           s.deleteCharAt(s.length() - 1);

           s.append("){}\n");

       }

 

       s.append("}");

       System.out.println(s);

   }

}

7.2 -通过反射机制调用方法

import java.lang.reflect.Method;

 

/**

* @author Mr.乐

* @Description 反射机制调用方法

*/

public class Demo10 {

   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("reflect.UserService");

       // 创建对象

       Object obj = userServiceClass.newInstance();

       // 获取Method

       Method 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);

   }

}

7.3 -反编译构造方法

import java.lang.reflect.Constructor;

import java.lang.reflect.Modifier;

 

/**

* @author Mr.乐

* @Description 反编译构造方法

*/

public class Demo09 {

   public static void main(String[] args) throws ClassNotFoundException {

       StringBuilder s = new StringBuilder();

       Class vipClass = Class.forName("java.lang.String");

       s.append(Modifier.toString(vipClass.getModifiers()));

       s.append(" class ");

       s.append(vipClass.getSimpleName());

       s.append("{\n");

 

       // 拼接构造方法

       Constructor[] constructors = vipClass.getDeclaredConstructors();

       for(Constructor constructor : constructors){

           //public Vip(int no, String name, String birth, boolean sex) {

           s.append("\t");

           s.append(Modifier.toString(constructor.getModifiers()));

           s.append(" ");

           s.append(vipClass.getSimpleName());

           s.append("(");

           // 拼接参数

           Class[] parameterTypes = constructor.getParameterTypes();

           for(Class parameterType : parameterTypes){

               s.append(parameterType.getSimpleName());

               s.append(",");

           }

           // 删除最后下标位置上的字符

           if(parameterTypes.length > 0){

               s.deleteCharAt(s.length() - 1);

           }

           s.append("){}\n");

       }

 

       s.append("}");

       System.out.println(s);

   }

}

7.4 -反射调用构造方法

import java.lang.reflect.Constructor;

 

/**

* @author Mr.乐

* @Description 反射调用构造方法

*/

public class Demo11 {

   public static void main(String[] args) throws Exception {

       // 不使用反射机制怎么创建对象

       Student v1 = new Student();

       Student v2 = new Student(111,"张三",18,true);

 

 

       Class c = Class.forName("reflect.Student");

       // 调用无参数构造方法

       Object obj = c.newInstance();

       System.out.println(obj);

       //Student{no=0, name='null', age=null, sex=false}

 

       // 调用有参数的构造方法

       // 第一步:先获取到这个有参数的构造方法

       Constructor con = c.getDeclaredConstructor(int.class, String.class, Integer.class,boolean.class);

       // 第二步:调用构造方法new对象

       Object newObj = con.newInstance(110, "jackson", 18, true);

       System.out.println(newObj);

       //Student{no=110, name='jackson', age=18, sex=true}

 

       // 获取无参数构造方法

       Constructor con2 = c.getDeclaredConstructor();

       Object newObj2 = con2.newInstance();

       System.out.println(newObj2);

       //Student{no=0, name='null', age=null, sex=false}

   }

}

8 -获取父类及实现的接口

/**

* @author Mr.乐

* @Description 获取父类及实现的接口

*/

public class Demo12 {

   public static void main(String[] args) throws ClassNotFoundException {

       // String举例

       Class stringClass = Class.forName("java.lang.String");

 

       // 获取String的父类

       Class superClass = stringClass.getSuperclass();

       System.out.println(superClass.getName());

 

       // 获取String类实现的所有接口(一个类可以实现多个接口。)

       Class[] interfaces = stringClass.getInterfaces();

       for(Class in : interfaces){

           System.out.println(in.getName());

       }

   }

}

9 -总结

       反射在开发中并不常用,但学习反射有利于后期对框架底层知识的学习,能够让我们更好的理解代码。反射的重点在于通过反射调用属性、方法。希望大家可以通过本篇文章更好的了解反射


目录
相关文章
|
6天前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
12天前
|
Java 程序员 编译器
Java的反射技术reflect
Java的反射技术允许程序在运行时动态加载和操作类,基于字节码文件构建中间语言代码,进而生成机器码在JVM上执行,实现了“一次编译,到处运行”。此技术虽需更多运行时间,但广泛应用于Spring框架的持续集成、动态配置及三大特性(IOC、DI、AOP)中,支持企业级应用的迭代升级和灵活配置管理,适用于集群部署与数据同步场景。
|
2月前
|
安全 Java 测试技术
day26:Java零基础 - 反射
【7月更文挑战第26天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
29 5
|
1月前
|
缓存 安全 Java
【Java 第十篇章】反射
Java 反射技术让程序能在运行时动态获取类信息并操作对象,极大提升了灵活性与扩展性。本文将介绍反射的基本概念、原理及应用,包括如何使用 `Class`、`Field`、`Method` 和 `Constructor` 类进行动态操作。此外,还将探讨反射在动态加载、框架开发与代码测试中的应用场景,并提醒开发者注意性能与安全方面的问题,帮助你更合理地运用这一强大工具。
14 0
|
2月前
|
IDE Java 测试技术
Java进阶之反射
【7月更文挑战第14天】Java反射机制允许在运行时动态获取类信息、创建对象及调用其方法。它基于`Class`类,让我们能访问类的属性、方法、构造器。例如,通过`Class.forName()`加载类,`Class.newInstance()`创建对象,`Method.invoke()`执行方法。反射广泛应用于动态代理、单元测试、序列化及框架中,提供灵活性但牺牲了性能,且可破坏封装性。IDE的代码补全也是反射的应用之一。在使用时需谨慎,避免对私有成员的不当访问。
28 1
|
2月前
|
Java 程序员 测试技术
解析Java中的反射机制及其应用场景
解析Java中的反射机制及其应用场景
|
2月前
|
开发框架 Java Android开发
Java中的类反射与动态代理详解
Java中的类反射与动态代理详解
|
2月前
|
缓存 Java 测试技术
Java中的反射机制及其应用场景
Java中的反射机制及其应用场景
|
2月前
|
Java
Java中的反射与动态代理机制详解
Java中的反射与动态代理机制详解
|
2月前
|
存储 安全 Java
Java中的反射机制及其应用场景详解
Java中的反射机制及其应用场景详解