一反射概念
java反射机制就是在运行状态中,对任意一个类,都能知道其所有属性和方法。
对于任意一个对象,都能调用它的任意方法和属性。
这种动态获取信息以及动态调用对象的方法的功能就是java的反射机制。
反射就是可以在动态运行的时候,对任意一个类,获得它所有方法,所有的变量(包括私有的)
二反射的作用
-
获取某些类的一些变量,调用某些类的私有方法(案例:再Android开发中可以开启wifi热点,调用 WifiManager中的setWifiApEnabled|()方法)
-
增加代码的灵活性(像ssm框架都是采用xml做配置文件+反射技术 这两种技术)
三反射的常用对象
- Class
Class类的实例表示正在运行的java应用程序中的类和接口 - Constructor
关于类的单个构造方法的信息以及对它的访问权限 - Field
Field提供有关类或接口的单个字段的信息,以及对它的动态访问权限 - Method
Method 提供关于类或接口上单独某个方法的信息
对象在内存中的关系对照图
Animal.java被执行,会被编译成Animal.class文件,而Animal.class想要执行,就会被类加载器(ClassLoader)加载到JVM中执行,JVM就会将它加载到内存。
而加载后,Animal.class字节码文件在内存中会有一个对象的表示。在java中"万物皆对象",而.class文件在内存中的对象就是Class对象,所以只有获取Class,才能获取它的构造方法,属性以及方法。
相应的构造方法在内存中对应的是Constructor对象,
属性对应的就是Field对象
方法对应的就是Method对象
不管是想要构造方法,属性,还是方法,前提都是要先获取Class对象
四反射对象类详解
1.Class类
- Java中java.lang.Class类用于表示一个类的字节码(.class)文件
- 如何获得某个class文件对应的Class文件
已知类和对象的情况下
1类名.class
2对象.getClass() //Object类提供
未知类和对象的情况下
Class.forName(“包名.类名”) //通过全限定类名获取未知类的Class
Class类代表某个类的字节码,并提供了加载字节码的方法:forName(“全限定类名”),forName方法用于加载类字节码到内存中,并封装成一个Class对象代码演示
package JavaReflectTest;
public class Animal {
public String name;
private int id;
public Animal(){
System.out.println("我是无参构造方法");
}
public Animal(int id,String name){
this.setId(id);
this.setName(name);
System.out.println("我是有参构造方法");
}
public void eat(){
System.out.println("我是公有方法");
}
private void drink(){
System.out.println("我是私有方法");
}
private void play(String name,String sex){
System.out.println("我是私有带参方法");
}
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
public class ClassTest {
/**
* 获得Class对象
* 1.通过类名.class
* 2.对象.getClass()
* 3.Class.forName();
*/
public void demo1() throws ClassNotFoundException {
//1.通过类名.class的方式
Class class1 = Animal.class;
//2.通过对象.getClass()的方式
Animal animal = new Animal();
Class class2 = animal.getClass();
//3.Class类forName();获得(推荐)
Class class3 = Class.forName("JavaReflectTest.Animal");
}
public static void main(String[] args){
}
}
三种获取Class对象的方法,推荐使用第三种,因为通常做反射都是不知道类的实例时进行操作的。
使用Class.forName();获取对象时需要注意,若路径找不到类会抛出ClassNotFoundException 没有发现类的异常,可以用try …catch处理
2.Constructor类
- Constructor类的实例对象代表类的一个构造方法
- 获得某个类的所有构造方法
Constructor [] constructors=Class.forName("java.lang.String").getConstructors();
- 获得指定构造方法并调用
Constructor constructor = Class.forName("java.lang.String").getConstrutors(String.class);
String str = (String)constructor.getInstance("abc");
- Class类的newInstance()方法用来调用类的默认构造方法
String obj = (String)Class.forName("java.lang.String").newInstance();
代码演示
package JavaReflectTest;
import java.lang.reflect.Constructor;
public class ConstructorTest {
/**
*获得无参构造方法
*/
public void demo1() throws Exception {
//获得类的字节码文件对应的对象:
Class class1 = Class.forName("JavaReflectTest.Animal");
Constructor c = class1.getConstructor();
Animal animal = (Animal)c.newInstance();//相当于 Animal animal = new Animal();
}
/**
*获得有参构造方法
*/
public void demo2() throws Exception{
Class class1 = Class.forName("JavaReflectTest.Animal");
Constructor c = class1.getConstructor(int.class,String.class);
Animal animal = (Animal)c.newInstance(2,"猴子");//相当于 Animal animal = new Animal(2,"猴子");
System.out.println(animal.toString());
}
public static void main(String[] args) throws Exception {
ConstructorTest c = new ConstructorTest();
c.demo1();
System.out.println("------------");
c.demo2();
}
}
3.Field类
- Field类代表某个类中的一个成员变量,并提供动态的访问权限
- Field对象的获取
Field[] fields = class1.getFields(); //获取所有public属性(包括父类继承)
Field[] fields = class1.getDeclaredFields();//获取所有声明的属性
- 获得指定的成员变量
Field name = class.getField("name");
Field name = class.getDeclaredField("name");
- 设置Field变量是否可以访问(设置 private 私有变量时需要先设置可访问)
field.setAccessible(boolean);
- Field变量值的读取,set
field.get(obj);
field.set(obj,value);
代码演示
package JavaReflectTest;
import java.lang.reflect.Field;
public class FieldTest {
//测试共有属性
public void demo1() throws Exception{
//获得Class
Class class1 = Class.forName("JavaReflectTest.Animal");
//获得属性:
Field field = class1.getField("name");
//操作属性:
Animal animal = (Animal)class1.getConstructor().newInstance();
field.set(animal,"老虎");// animal.name = "老虎";
//获取值
Object obj = field.get(animal);
System.out.println(obj);
System.out.println(animal);//这样会自动调用toString()方法
}
//测试私有方法
public void demo2() throws Exception{
//获得Class
Class class1 = Class.forName("JavaReflectTest.Animal");
//获得私有属性:
Field field = class1.getDeclaredField("id");
//操作属性:
Animal animal = (Animal)class1.getConstructor().newInstance();
//私有属性,需要设置一个可访问的权限
field.setAccessible(true);
field.set(animal,1);
//获取值:
Object obj = field.get(animal);
System.out.println(obj);
System.out.println(animal);
}
public static void main(String[] args) throws Exception {
FieldTest fieldTest = new FieldTest();
fieldTest.demo1();
System.out.println("----------------");
fieldTest.demo2();
}
}
4.Method类
- Method类代表某个类中的一个成员方法
- Method对象的获取
Method[] methods = class1.getMethods();//获取所有公共方法
Method[] methods = class1.getDeclaredMethods();//获取所有声明的方法
- 获取指定方法
Method method = class1.getMethod(String name,Class<?>...parameterTypes)
method method = class1.getDeclaredMethod(String name,Class<?>...parameterTypes)
- 设置Method变量方法是否可以访问 (调用 private 私有方法时需要先设置可访问)
Method method = class1.getMethod(String name,Class<?>...parameterTypes)
method.setAccessible(ture);
- 通过反射执行方法
method.invoke(Object obj,Object...args)
代码演示
package JavaReflectTest;
import java.lang.reflect.Method;
public class MethodTest {
//测试公有方法
public void demo1() throws Exception{
//获取Class对象
Class class1 = Class.forName("JavaReflectTest.Animal");
//实例化
Animal animal = (Animal)class1.getConstructor().newInstance();
//获得公有方法
Method method = class1.getMethod("eat");
//执行该方法
method.invoke(animal);// 相当于animal.eat();
}
//测试私有方法
public void demo2() throws Exception{
//获取Class对象
Class class1 = Class.forName("JavaReflectTest.Animal");
//实例化
Animal animal = (Animal)class1.getConstructor().newInstance();
//获得私有方法
Method method = class1.getDeclaredMethod("drink");
//设置私有的访问权限
method.setAccessible(true);
//执行该方法
method.invoke(animal);//相当于animal.drink();
}
public void demo3() throws Exception{
//获取Class对象
Class class1 = Class.forName("JavaReflectTest.Animal");
//实例化
Animal animal = (Animal)class1.getConstructor().newInstance();
//获得私有带参的方法
Method method = class1.getDeclaredMethod("play", int.class, String.class);
//设置私有的访问权限
method.setAccessible(true);
//执行该方法
Object obj = method.invoke(animal,2,"孔雀"); // 这是有返回值的情况 如果没有返回值可以直接写method.invoke(animal,2,"孔雀");
System.out.println(obj);//打印返回的东西,没有就是null
}
//测试私有带参数的方法
public static void main(String[] args) throws Exception{
MethodTest methodTest = new MethodTest();
methodTest.demo1();
System.out.println("--------------------");
methodTest.demo2();
System.out.println("--------------------");
methodTest.demo3();
}
}