Java反射机制学习笔记
一 概述
反射机制的概述
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java反射机制的作用
主要用于编写一些通用性较高的代码或者框架的时候使用。
Java中反射常用的API有
- Class类
- Constructor类
- Field类
- Method类
二 实践
下面用一些实际的代码例子来详细研究学习
首先我准备了一个猫咪对象Cat.java, 其中创建了一些公共属性和私有属性,方便测试学习。
package com.lucasmai.reflect.test;
/**
* @Author Lucas_mai
* @Date 2021/1/30
*/
public class Cat {
public String catOwner;
private String name = "";
private int age;
public Cat() {}
public Cat(String catOwner, String name, int age) {
this.catOwner = catOwner;
this.name = name;
this.age = age;
}
public String getCatOwner() {
return catOwner;
}
public void setCatOwner(String catOwner) {
this.catOwner = catOwner;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void run(){
System.out.println("猫咪"+ name +"跑起来了!");
}
public void run(int distance){
System.out.println("猫咪"+ name +"开心的跑了"+distance+"米!");
}
private void eat(){
System.out.println("猫咪"+ name +"正在享用美味!");
}
private void sleep(int hour){
System.out.println("让猫咪"+ name +"去睡"+ hour +"个小时^_^");
}
@Override
public String toString() {
return "Cat{" +
"catOwner='" + catOwner + '\'' +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
1.使用Class类获取对象
Class 类用于表示一个字节码文件(xxx.class)
此处我们演示如何从某个class文件中得到对应的Class对象
-
已知类和对象
类名.class
对象.getClass()
-
未知类和对象的情况下
Class.forName(“包名.类名”)
上述方法中Class.forName(“包名.类名”) 在实际中比较常用,比如我们学的JDBC中的加载MySQL数据库驱动时就会使用到Class.forName("com.mysql.jdbc.Driver")
。
CatClassTest.java
package com.lucasmai.reflect.test;
import org.junit.Test;
public class CatClassTest {
/**
* 这个测试中,我将通过Java的反射机制获取到Cat这个对象
*/
@Test
public void getCatClassDemo(){
//1.通过类名.class 获取
Class class1 = Cat.class;
System.out.println(class1);
//2.通过对象.getClass()获取
Cat cat = new Cat();
Class class2 = cat.getClass();
System.out.println(class2);
//3.Class.forName("包名.类名")获得,非常常用。
try {
Class class3 = Class.forName("com.lucasmai.reflect.test.Cat");
System.out.println(class3);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
2.通过Field类获取成员变量
Field对象的使用
- 得到全部成员变量
Field[] fields = cat.getFields();
// 获得某个类的所有的公共(public)的字段,包括父类中的字段。Field[] fields = cat.getDeclaredFields();
// 获得某个类的所有声明的字段,即包括public、private和protected,但是不包括父类的声明字段。
- 得到指定成员变量
Field[] fields = cat.getFields("name");
Field[] fields = cat.getDeclareFields("name");
- 私有属性需要设置访问权限
- setAccessible(true)
package com.lucasmai.reflect.test;
import org.junit.Test;
import java.lang.reflect.Field;
import static org.junit.Assert.*;
public class CatFieldTest {
@Test
// 测试公有的属性
public void demo1() throws Exception{
// 获得Class
Class class1 = Class.forName("com.lucasmai.reflect.test.Cat");
// 获得属性:
Field field = class1.getField("catOwner");
Cat cat = (Cat) class1.newInstance();
field.set(cat, "Lucas_Mai");// 相当于cat.catOwner = "Lucas_Mai";
Object obj = field.get(cat);
System.out.println(obj);
System.out.println(cat);
}
@Test
// 测试私有的属性
public void demo2() throws Exception{
// 获得Class
Class class1 = Class.forName("com.lucasmai.reflect.test.Cat");
// 获得私有的属性
Field field = class1.getDeclaredField("name");
Cat cat = (Cat) class1.newInstance();
// 私有属性,需要设置一个可访问的权限:
field.setAccessible(true);
field.set(cat, "泡芙");
// 获取值:
Object obj = field.get(cat);
System.out.println(obj);
System.out.println(cat);
}
}
~ demo1运行结果 ~
Lucas_Mai
Cat{catOwner='Lucas_Mai', name='', age=0}
~ demo2运行结果 ~
泡芙
Cat{catOwner='null', name='泡芙', age=0}
3.通过Method类来获得方法
主要用到的方法
-
获得全部方法
-
getMothods() // 返回一个包含某些
Method
对象的数组,这些对象反映此Class
对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。 -
getDeclaredMethods() // 返回
Method
对象的一个数组,这些对象反映此Class
对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
-
-
获得指定方法
-
getMethod( String name, Class<?>… parameterTypes )
-
getDeclaredMethod( String name, Class<?>… parameterTypes )
-
-
执行方法
- 使用invoke()方法
package com.lucasmai.reflect.test;
import org.junit.Test;
import java.lang.reflect.Method;
import static org.junit.Assert.*;
public class CatMethodTest {
@Test
//测试获取public的方法
public void demo1() throws Exception {
//先获取到这个类
Class class1 = Class.forName("com.lucasmai.reflect.test.Cat");
//实例化Cat类
Cat cat = (Cat)class1.newInstance();
//获得Cat类中的公共方法
Method method1 = class1.getMethod("run");//无参数的方法
Method method2 = class1.getMethod("run", int.class);//有参数的方法,需要在后面加入类似String.class,int.class声明
//使用invoke()执行方法
method1.invoke(cat);
method2.invoke(cat,10);
}
@Test
//获取private的方法
public void demo2() throws Exception{
//先获取到这个类
Class class1 = Class.forName("com.lucasmai.reflect.test.Cat");
//实例化Cat类
Cat cat = (Cat)class1.newInstance();
// 获得方法:
Method method = class1.getDeclaredMethod("eat");
Method method1 = class1.getDeclaredMethod("sleep", int.class);
// 设置私有的属性的访问权限:
method.setAccessible(true);
method1.setAccessible(true);
// 执行方法:
method.invoke(cat);
method1.invoke(cat,8);
}
}
~ demo1运行结果 ~
猫咪跑起来了!
猫咪开心的跑了10米!
~ demo2运行结果 ~
猫咪正在享用美味!
让猫咪去睡8个小时^_^
4.通过Constructor类获得构造方法
跟上面的几个类很类似,主要用到的方法有获得无参数的构造方法getConstructor()
和 获得有参数的构造方法getConstructor( Class<?>... parameterTypes)
package com.lucasmai.reflect.test;
import org.junit.Test;
import java.lang.reflect.Constructor;
import static org.junit.Assert.*;
public class CatConstructorTest {
@Test
/**
* 获得无参数的构造方法
*/
public void demo1() throws Exception{
Class class1 = Class.forName("com.lucasmai.reflect.test.Cat");
Constructor c = class1.getConstructor();
Cat cat = (Cat) c.newInstance();// 相当于Cat cat = new Cat();
System.out.println(cat);
cat.run(10);
}
@Test
/**
* 获得有参数的构造方法
*/
public void demo2() throws Exception{
Class class1 = Class.forName("com.lucasmai.reflect.test.Cat");
Constructor c = class1.getConstructor(String.class,String.class,int.class);
Cat cat = (Cat) c.newInstance("LucasMai","泡芙",5);
System.out.println(cat);
}
}
~ demo1运行结果 ~
Cat{catOwner='null', name='', age=0}
猫咪开心的跑了10米!
~ demo2运行结果 ~
Cat{catOwner='LucasMai', name='泡芙', age=5}
5