如果有错误欢迎指出 ,大家不要客气哈,本人也在学习中哈哈
一、什么是反射机制
首先我们来看看百度百科的定义:反射机制就是在运行状态中,对于任意一个实体类都能知道这个类的所有属性和方法,将这种动态获取信息以及动态调用对象的方法的功能称为java语言的反射机制。 通常在编程的时候我们都是在运行之前就得将我们需要使用到的类通过new进行实例化,然后再使用其对应的方法和部分属性,这是静态加载,而java的反射机制可以使得程序运行的过程中根据需求来动态的创建对象并且调用对应的方法和属性(就像我们调用java中方法一样,当我们程序运行过程中传入不同的值就会有不同的返回值)。
二、反射机制的优点和缺点
优点:
由于我们可以在程序运行的时候动态的创建对象和使用对应的方法,这提高了程序的灵活性、降低了类之间的耦合,同时可以让我们在任何地方使用任何类的任何方法和属性,不必如同静态方法中需要在编程过程中将类与类联系在一起然后使用。
缺点:
缺点同样很明显,我们通过使用反射机制打破了java的封装特性,可以在任何地方使用一个类的所有方法和属性,这让类的封装失去了意义,让类的构建者不希望被其他类所知道的属性完全暴露出来了。因此通常情况下并不适合使用java的反射机制。
三、如何在java中反射的使用
要想了解java反射机制的使用我们首先需要了解java的四个类:
(1)Class类:可以动态根据用户的需求获取对于的Class对象。(这里就可以这样理解:类是对象的抽象,我们可以通过对类进行实例化来获取对应的对象,而Class则是类的某种意义上的抽象,我们可以通过类名来获取对应的Class对象——就是类)
例如:
在获取对象时候 具体类名 name=new 具体类名(); //通过构造方法获取对象
在获取的类时 Class name=Class.forName("类的全称"); //通过类的名称来获取对于的类(不是类对象)
(2)Constructor类:该类封装了类的构造函数的属性信息。在上面我们根据类名获取对于的类之后,然后可以通过对应的方法将该类的构造函数存储在我们定义的Constructor对象中,就像把一个变量的值保存起来一样。然后我们通过调用Constructor对象的对应方法来创建一个对象的实例。(总结起来就是:在根据类名获取对于的类之后,我们将该类的构造函数存储在Constructor对象中,然后使用Constructor对象来为获取的类创建一个对象实例)
(3)Method类:提供了保存一个类的方法和调用该方法的功能。内容大致与Constructor类一致,同样,根据类名获取对应的类之后,通过对应的方法将该类中方法存储在我们定义的Method类对象中,然后我们通过调用Method类对象的对应方法来调用该类的方法(这里有一点需要注意,一个没有实例化的类本身不能使用其方法成员,只能通过该类的一个实例化对象调用方法成员,这一点在后面就可以知道)
(4)Field类:提供了保存一个类中成员变量属性信息的功能。根据类名获取类之后,可以将该类中的成员变量信息保存在Field对象中,然后通过使用该对象来使用对应的成员变量。
然后我们来介绍四个类的常用方法以及其作用
(1)Class类对象方法
1. Class.forName("类名"); //返回一个类的对象,根据类名获取对应的类
2. Class类对象.getConstrucor("参数"); //根据传入的参数获取类中使用public修饰的对应构造函数,并将获取的结果给Constructor对象。(获取失败则返回异常)
3. Class类对象.getDeclaredConstructor("参数"); //根据传入的参数获取类中对应的构造函数(没有修饰符限制),并将结果给Constructor对象。(获取失败返回异常)
4. Class类对象.getConstructors(); //获取类中所有使用public修饰的构造函数,并将结果保存在Constructor对象数组中。
5. Class类对象.getDeclaredConstructor()); //获取类中所有的构造函数,并将结果保存在Constructor对象数组中。
6. Class类对象.getMethod(name,param); //根据方法的名称和方法中参数的类型来获取类中用public修饰的方法,并将结果保存在Method类对象中,param可以为空
7. Class类对象.getDeclaredMethod(name,parm); //根据方法的名称和方法中参数的类型来获取类中的方法(没有修饰符限制),并将结果保存在Method类对象中,param可以为空
8. Class类对象.getMethods(); //获取类中所有使用public修饰的方法(包括从父类中继承的public方法),并将结果保存在Method数组中
9. Class类对象.getDeclaredMethods(); //获取类中所有的方法(不包括从父类中继承的方法),并将结果保存在Method数组中
10. Class类对象.getField(name); //通过属性的名称获取类中使用public修饰的对应属性,并将其保存在Field类对象中。
11. Class类对象.getDeclaredField(name); //通过属性的名称获取类中对应的属性(没有修饰符限制),并将其保存在Field类对象中。
12. Class类对象.getFields(); //获取类中使用public修饰的所有属性,并将其保存在Field数组中。
13. Class类对象.getDeclaredFields(); //获取类中对应的属性(没有修饰符限制),并将其保存在Field数组中。
这么多是不是看累了,下面我来总结一下:1 是根据类名获取对应类(获取Class对象),只有在获取到Class对象之后,后面的方法才可以用;2-5 是通过获取的类来获取其构造方法的过程,前两种是根据参数获取一个构造函数,后面两种是获取多个构造函数;6-9 是通过获取的类来获取其对应成员方法的过程,前两种是通过参数获取一个对于的成员方法,后面的两种是获取多个成员方法(注意有的能够获取父类中方法);10-13 是获取类中属性的方法,前两种是通过属性的名称来获取一个属性变量,后两种是获取多个属性变量。
例子:
Example类的代码
package reflection;
public class Example {
//属性变量
private String name="wang";
public String sex="nan";
//构造方法
private Example() {
System.out.println("private方法");
}
public Example(String namee) {
System.out.println("public方法,参数为"+namee);
}
//所有的方法
public void getName() {
System.out.println(this.name);
}
public void setName(String namm) {
this.name=namm;
}
}
使用上面方法中的代码:
package reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @Introduction 通过Class来获取对于的类,并且获取类的构造方法、方法成员和属性
*/
public class Demo {
public static void main(String[] args) throws Exception{
//获取Class对象
Class example=Class.forName("reflection.Example"); //根据类名获取对应的类(类名的书写要注意写全称包括包名)
//获取构造方法
Constructor constructor1=example.getConstructor(String.class); //获取的是public Example(String namee){}构造方法
Constructor constructor2=example.getDeclaredConstructor(); //获取的是public Example(){}构造方法
Constructor[] constructor3=example.getConstructors(); //获取所有public的构造方法
Constructor[] constructor4=example.getDeclaredConstructors(); //获取所有的构造方法
//获取类对应的方法
Method method1=example.getMethod("getName"); //获取的是public void getName() {}方法
Method method2=example.getDeclaredMethod("setName", String.class); //获取的是public void setName(String namm) {}方法
Method[] method3=example.getMethods(); //获取类中所有public修饰的方法
Method[] method4=example.getDeclaredMethods(); //获取类中所有方法
//获取类中对应的属性
Field field1=example.getField("sex"); //获取类中public String sex="nan";属性
Field field2=example.getDeclaredField("name"); //获取类中private String name="wang";属性
Field[] field3=example.getFields(); //获取类中所有public修饰的属性变量
Field[] field4=example.getDeclaredFields(); //获取类中所有属性变量
}
}
(2)Constructor类的对应方法
Constructor类对象.newInstance("参数值"); //调用类中的构造方法(根据先前赋给Constructor对象的构造方法),并将参数值传递给构造方法中的参数,然后返回一个类的实例化对象
Constructor类对象.getName(); //获取构造方法的名称
例子:(仍然使用上面的Example)
package reflection;
import java.lang.reflect.Constructor;
public class Reflect{
public static void main(String[] args) throws Exception{
Class example=Class.forName("reflection.Example");
Constructor constructor=example.getConstructor(String.class);
Example my=(Example)constructor.newInstance("hahaha"); //这里使用强转,获取Example类的一个实例对象,一个对象就这样被奇妙的造出来了
System.out.println(constructor.getName()); //获取构造方法的名字
}
}
运行结果如下:
(3)Method类对应的方法
Method对象.invoke("类的实例化对象","被调用方法的参数值"); //相当于调用类的实例化对象中Method对象所代表的方法,并将参数值作为实参传入该方法中。
Method对象.getName(); //获取Method对象所代表方法的名称
例子如下:
package reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Reflect{
public static void main(String[] args) throws Exception{
Class example=Class.forName("reflection.Example");
Constructor constructor=example.getConstructor(String.class);
Method method=example.getMethod("getName"); //获取public void getName() {}方法
Example my=(Example)constructor.newInstance("hahaha");
method.invoke(my,null); //调用对应的方法,这里需要将对应类的实例化对象作为参数,因为一个没有实例化的类不能直接调用其方法
System.out.println("调用的方法是:"+method.getName());
}
}
结果如下:
(4)Field类对应的方法
Field对象.setAccessible(boolean类型的值); //当Field对象对应的属性是private修饰的时候,需要使用该方法使得该属性可以被访问
Field对象.get("类的实例化对象"); //在实例化对象中返回Field对象所代表的属性值
Field对象.set("类的实例化对象","属性的值"); //设置Field对象对应属性的值
例子:
package reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class Reflect{
public static void main(String[] args) throws Exception{
Class example=Class.forName("reflection.Example");
Constructor constructor=example.getConstructor(String.class);
Example my=(Example)constructor.newInstance("hahaha");
Field name=example.getDeclaredField("name"); //获取private name
name.setAccessible(true); //设置该private修饰的属性可访问和设置
System.out.println("获取Field属性的具体值:"+name.get(my)); //获取该属性在my实例化对象中的值
name.set(my, "光"); //设置在my实例化对象中该属性的值
System.out.println("获取Field属性的具体值:"+name.get(my));
}
}
结果为:
总结如下
java的反射机制的使用步骤大致为:
首先根据类名(注意类名要写全,而且这类名是一个字符串,这代表了我们可以在这里设置一个字符串变量,程序在运行的时候可以根据变量的值来获取对应的Class对象);然后我们获取类对应构造方法,通过类构造方法我们可以创建出类的实例化对象;最后就是获取类的属性和方法了,我们通过构造方法获得的实例化对象来使用对应的方法和属性。(其实这里将的都是比较基础的,关于java反射机制还有好多没有提到:比如java反射的原理、在什么场合下如何使用反射机制以及如何通过配置文件来动态的使用反射机制等等,大家有兴趣的话可以自己搜一下嘻嘻)