天天看点

反射创建对象_反射

反射创建对象_反射

在Java中一切皆对象,其实所有的类底层都有一个字节码对象,可以使用反射来描述着一个个类底层的字节码对象。

在运行时期,动态地去获取类中的信息(类的信息,方法的信息,构造方法的信息,字段等信息)。一个类中,包括构造方法,字段,方法。

Class:描述类

Method:描述方法

Constructor:描述构造方法

Field:描述字段

获取类的Class实例三种方式

1.类名.class

2.类的对象.getClass()

3.Class.forName("类的全限定名") 【全限定名=包名+类名】

获取9大内置类的字节码实例

对于对象来说,可以直接使用对象.getClass()或者Class.forName(className); 类名.class都可以获取Class实例.

但是我们的基本数据类型,就没有类的权限定名,也没有getClass方法.

问题: 那么如何使用Class类来表示基本数据类型的Class实例?

八大基本数据类型和 void关键字都是有 字节码实例的

byte,short,int,long,char,float,double,boolean ,void关键字

答 : 数据类型/void.class 即可

每个基本数据类型都是包装类型 如 :int ----Integer包装类型

注意: 基本数据类型和包装数据类型底层的字节码实例是不相同,即int和Integer的字节码是不相等的。

数组的Class实例:

String[] sArr1 = {"A","C"};

Class clz = String[].class;//此时clz表示就是一个String类型的一位数组类型

所有具有

相同元素类型和维数

的数组才共享同一份字节码(Class对象);

注意:和数组中的元素没有一点关系.

构造函数-Constructor

类的函数有有参构造和无参构造,公共构造函数,非公共构造函数,根据不同的构造函数Class提供了几种获取不同构造函数的方法。

反射创建对象_反射
public void testName() throws Exception {
  
  //1.获取Student的字节码实例
  Class<?>  stuClz = Student.class;
  
  //2.获取所有的公共构造函数
  Constructor<?>[] cts1 = stuClz.getConstructors();
  for (Constructor<?> ct : cts1) {
   System.out.println(ct);
  }
  System.out.println("----------------------");
  //3.获取所有的构造函数包括私有的
  Constructor<?>[] cts2 = stuClz.getDeclaredConstructors();
  for (Constructor<?> ct : cts2) {
   System.out.println(ct);
  }
  System.out.println("----------------------");
  
  //4.获取指定的构造函数(clz.getConstructor(...))只能获取公共的构造函数
  Constructor<?> ct1 = stuClz.getConstructor();
  System.out.println(ct1);
  
  Constructor<?> ct2 =stuClz.getConstructor(String.class);
  System.out.println(ct2);
  //4.获取指定的构造函数(clz.getDeclaredConstructor(...))获取的构造函数和权限没有关系
  Constructor<?> ct3=stuClz.getDeclaredConstructor(String.class,int.class);
  System.out.println(ct3);
 }
}
           
调用构造函数创建对象
反射创建对象_反射

如果使用Class直接创建对象,必须保证类中有一个无参数公共构造函数

反射创建对象_反射

虽然可以获得私有的构造方法,但是反射默认是无法直接执行的,要找到父类中accessibleobject的方法,设置为true,才可以忽略访问权限。

反射创建对象_反射
反射创建对象_反射
//1.获取Student的字节码实例
  Class<?> clz = Class.forName("cn.sxt.reflect.Student");
  
  //1.1如果类有无参数公共构造函数,直接可以使用类的字节码实例就创建对象
  Student stu0 = (Student) clz.newInstance();
  
  
  //2.获取一个参数的构造函数
  Constructor<Student> ct1 = (Constructor<Student>) clz.getConstructor(String.class);
  //2.1.创建对象
  Student stu1 = ct1.newInstance("东方不败");
  
  //3.获取私有构造函数并创建对象
  Constructor<Student> ct2 =  (Constructor<Student>) clz.getDeclaredConstructor(String.class,int.class);
  //3.1设置权限可以创建对象
  ct2.setAccessible(true);
  //3.2创建对象
  Student stu2 = ct2.newInstance("西门吹雪",50);
 }
           

获取方法和方法的执行

一个类创建对象后,一般要执行对象的方法,使用反射对象首先要获取方法再执行。一个类中有很多方法,有参、无参、静态、可变参数的私有方法等等,针对不同的方法处理,提供不同的获取方案。

反射创建对象_反射

方法获取后,需要执行,Method对象中提供方法的执行功能。

反射创建对象_反射

和构造方法一样,如果是私有的,反射默认不能直接执行的,也要把AccessibleObject的方法设置为true即可忽略访问权限。

如果要执行静态方法,就是上图说的类方法,则传null进去,再传参数。

获取有字符串数组参数的方法,需要注意:如果反射传递参数是引用类型,底层有一个拆箱的功能,会将数组的元素拆成一个个参数传递过来。解决的方案:将数组外面再包装一层数组,如果拆箱一次,得到的还是一个数组。

Method method2 = clz.getMethod("method2", String[].class);
  method2.invoke(null,new Object[] {new String[] {"AA","BB","CC"}});
 

public class GetMethodTest {
 
 @Test
 public void testName() throws Exception {
  // 1.获取Person字节码实例
  Class<Person> clz = Person.class;
  // 2.创建对象
  Person p = clz.newInstance();
 
  // 3.获取方法(使用反射),获取所有公共方法,包含父类的公共方法
  Method[] methods1 = clz.getMethods();
  for (Method method : methods1) {
   System.out.println(method);
  }
  System.out.println("------------------------------");
  // 4.获取自己类中的所有方法(包括私有)
  Method[] methods2 = clz.getDeclaredMethods();
  for (Method method : methods2) {
   System.out.println(method);
  }
  System.out.println("------------------------------");
  // 4.获取单个指定名称的方法
  Method method = clz.getMethod("hello2", String.class);
  System.out.println(method);
 
  // 4.1执行方法
  Object res = method.invoke(p, "陆小凤");
  System.out.println(res);
 
  // 5.获取私有的方法
  Method hello3 = clz.getDeclaredMethod("hello3", String.class, int.class);
  System.out.println(hello3);
 
  // 5.1设置忽略访问权限
  hello3.setAccessible(true);
 
  Object res1 = hello3.invoke(p, "叶孤城", 30);
  System.out.println(res1);
 
  // 6.获取静态方法
  Method staticMethod = clz.getMethod("staticMethod", String.class);
 
  // 6.1执行静态方法
  staticMethod.invoke(null, "花满楼");
 
  // 7.获取有整数数组参数的方法
  Method method1 = clz.getMethod("method1", int[].class);
  method1.invoke(null, new Object[] {new int[] { 1, 2, 3, 4 }});
           

Class中获取字段方法和Field操作设置/获取值

反射创建对象_反射

操作设置值步骤:

1、找到被操作字段所在的类的字节码

2、获取到该操作的字段对象

3、设置值

反射创建对象_反射

如果要设置的字段为私有的,和构造方法或者其他方法一样,需要设置忽略访问权限,setAccessible(true)。

//3.获取指定的公共字段
  Field emialField = clz.getField("emial");
  System.out.println(emialField);
  
  //为字段设置值
  emialField.set(p, "[email protected]");
  System.out.println(p);
  //4.获取指定所有的字段,和访问权限无关
  Field nameFiled = clz.getDeclaredField("name");
  System.out.println(nameFiled);
  //设置忽略访问权限
  nameFiled.setAccessible(true);
  nameFiled.set(p, "张三");
  System.out.println(p);
  
  
  //5 获取age字段
  Field ageFile = clz.getDeclaredField("age");
  ageFile.setAccessible(true);
  //设置忽略访问权限
  ageFile.setInt(p, 18);
  System.out.println(p);