概述
- 反射是指对于任何一个Class类,在"运行的时候"都可以直接得到这个类全部成分。
- 在运行时,可以直接得到这个类的构造器对象:Constructor
- 在运行时,可以直接得到这个类的成员变量:Field
- 在运行时,可以直接得到这个类的成员方法对象:Methon
- 这种运行时动态获取类信息的以及动态调用类中成分的能力称为Java语言的反射机制
反射的基本作用和关键
- 作用: 反射是在运行时获取类的字节码文件对象:然后可以解析类中的全部成分
- 关键: 反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分
反射第一步:获取Class类的对象(三种)
- 1.通过 Class类中的一个静态方法:
forName(全限名:报名 + 类名)
- 2.通过
类名.class
- 3.通过
对象.getClass();
获取对象对应类的Class对象
/**
- 目标:反射第一步,获取Class对象
*/
public class Test {
public static void main(String[] args) throws Exception {
/**
* 获取Class对象的第一种方法 forName(全限名:报名 + 类名)
*/
//1.Class类中的一个静态方法:forName(全限名:报名 + 类名)
Class c = Class.forName("com.Reflect.Study.Student");
System.out.println(c);//c:Student.class 文件
/**
* 获取Class对象的第二种方法 类名.class
*/
//2.类名.class
Class c1 = Student.class;
System.out.println(c1);
/**
* 获取Class对象的第三种方法 对象.getClass() 获取对象对应类的Class对象
*/
//2.对象.getClass() 获取对象对应类的Class对象
Student s = new Student();
Class c2 = s.getClass();
System.out.println(c2);
}
}
使用反射技术获取构造器对象并使用
想要获取构造器首先要获取类对象
四种方法获取不同的的构造器
- 1.
getConstructors();
拿公共的权限的构造器(由public修饰) - 2.
getDeclaredConstructors();
获取全部构造器的方法 无所谓什么权限 - 3.
getConstructor(Class ... parameterTypes);
获取投个构造器 只能拿public修饰的构造器 - 4.
getDeclaredConstructor();
通过参数定位有参构造器
import org.junit.Test;
import java.lang.reflect.Constructor;
public class TestStudent {
/**
* 1.getConstructors() 拿公共的全限的构造器
*/
@Test
public void getConstructors() {
//1.获取类Class对象
Student s = new Student();
Class c = s.getClass();
//2.提取类中全部的构造器对象 这里只能拿Public的构造器
Constructor[] constructors = c.getConstructors();
//3.遍历构造器数组
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "==" + constructor.getParameterCount());
}
}
/**
* 2.getDeclaredConstructors() 获取全部构造器的方法 无所谓什么权限
*/
@Test
public void getDeclaredConstructors() {
//1.获取类Class对象
Student s = new Student();
Class c = s.getClass();
//2.提取类中全部的构造器对象 这里只能拿全部的构造器
Constructor[] constructors = c.getDeclaredConstructors();
//3.遍历构造器数组
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "==" + constructor.getParameterCount());
}
}
/**
* 3.getConstructor(Class ... parameterTypes) 获取投个构造器 只能拿public修饰的构造器
*/
@Test
public void getConstructor() throws Exception {
//1.获取类Class对象
Student s = new Student();
Class c = s.getClass();
//2.提取类中全部的构造器对象 这里只能拿Public的构造器
//定位单个构造器对象 定位无参数构造器
Constructor cons = c.getConstructor();
//3.
System.out.println(cons.getName() + "==" + cons.getParameterCount());
}
/**
* 4.getDeclaredConstructor() 通过参数定位有参构造器
*/
@Test
public void getDeclaredConstructor() throws Exception {
//1.获取类Class对象
Student s = new Student();
Class c = s.getClass();
//2.提取类中全部的构造器对象 这里只能拿Public的构造器
//定位单个构造器对象 定位有参数构造器
Constructor cons = c.getDeclaredConstructor(int.class,String.class);
//3.
System.out.println(cons.getName() + "==" + cons.getParameterCount());
}
}
使用获取来的构造器(创建对象)
- 获取构造器的作用依旧是初始化一个对象返回
newInstance();
构造器的创建对象的方法
cons1.setAccessible(true) ;
暴力打开权限,如果遇到了私有的构造器,可以暴力反射
注意:反射可以破坏封装性,私有的也可以执行了
import org.junit.Test;
import java.lang.reflect.Constructor;
public class TestStudentDemo2 {
/**
* 1.调用无参构造器得到一个类的对象返回
* @throws Exception
*/
@Test
public void getDeclaredConstructor() throws Exception {
//a.获取类Class对象
Student s = new Student();
Class c = s.getClass();
//b.定位单个构造器对象(按照参数定位无参数构造器对象)
Constructor cons1 = c.getDeclaredConstructor();
System.out.println(cons1.getName() + "==" + cons1.getParameterCount());
Student stu = (Student)cons1.newInstance();
System.out.println(stu);
//如果遇到了私有的构造器,可以暴力反射
cons1.setAccessible(true);
//c.定位单个构造器对象 (定位有参数构造器)
Constructor cons2 = c.getDeclaredConstructor(int.class,String.class);
System.out.println(cons2.getName() + "==" + cons2.getParameterCount());
}
}
反射获取成员变量并使用
两种方法获取不同的成员方法
- 1.获取全部的成员变量
Field[] getDeclaredFields();
获得所有的成员变量对应的Field对象,只要申明了就可以得到 - 2.根据名字获取某个成员变量
Filed getDeclaredField(String name);
import org.junit.Test;
import java.lang.reflect.Field;
public class TestStudent {
/**
* 1.获取全部的成员变量
* Field[] getDeclaredFields();
* 获得所有的成员变量对应的Field对象,只要申明了就可以得到
*/
@Test
public void getDeclaredFields(){
//a.获取Class对象
Class c = Student.class;
//b.定位全部成员变量
Field[] fields = c.getDeclaredFields();
//c.遍历一下
for (Field field : fields) {
System.out.println(field.getName() + "==>" + field.getType());
}
}
/**
* 2.获取某个成员变量
* Filed getDeclaredField(String name);
*/
@Test
public void getDeclaredField() throws NoSuchFieldException {
//a.获取Class对象
Class c = Student.class;
//b.根据名称定位某个成员变量
Field age = c.getDeclaredField("age");
//c.打印变量
System.out.println(age.getName() + "===>" + age.getType());
}
}
使用获取来的成员变量
set(Object obj,Object value) ;
对获取得变量进行赋值。参数一:要负值的对象,参数二:要赋得值- **
get(Object obj) ;
** 对获取得变量进行取值。参数:要取值得对象
import org.junit.Test;
import java.lang.reflect.Field;
public class TestStudentDemo2 {
@Test
public void getDeclaredField() throws NoSuchFieldException, IllegalAccessException {
//a.获取Class对象
Class c = Student.class;
//b.根据名称定位某个成员变量
Field age = c.getDeclaredField("age");
//c.打印变量
System.out.println(age.getName() + "===>" + age.getType());
//暴力设置权限
age.setAccessible(true);
//对获取来的age变量进行赋值
Student student = new Student();
age.set(student,18);
System.out.println(student);
}
}
反射获取方法Method
四种获取Method方法对象的方式
Method getMethod(String name,Class... args);
根据方法名和参数类型获得对应的方法对象,只能获得public修饰的Method getDeclaredMethod(String name,Class... args);
根据方法名和参数类型获得对应的方法对象,包括private修饰的Method[] getMethods();
获得类中的所有成员方法对象,返回数组,只获得public修饰的且包含父类的方法Method[] getDeclaredMethods();
获得类中的所有成员方法对象,返回数组,只获得本类申明的方法
使用通过反射技术获取的方法对象
- 获取成员方法的作用依然是再某个对象中执行此方法
Method类中用于出发执行的方法:
Object incoke(Object obj,Object... args);
- 参数一:用obj对象调用该方法
- 参数二:调用方法的传递参数,如果没有就不写
- 返回值:方法的返回值,如果没有就不写
通过invoke方法启动Student类中的求和方法:
import org.junit.Test;
import java.lang.reflect.Method;
public class TestStudent {
@Test
public void getMethod() throws Exception {
//1.获取class对象
Class c = Student.class;
//2.获取方法
Method getSum = c.getMethod("getSum", int.class, int.class);
//3.使用方法
Student s = new Student();
//这里用的强转为int类型
int sum = (int)getSum.invoke(s, 2, 3);
System.out.println(sum);
}
}
反射的作用(了解)
- 可以在运行时得到一个类的全部成分然后操作
- 可以破坏封装性(很突出)
- 也可以破坏泛型的约束性(很突出)
- 更重要的用途是适合:做Java高级框架
绕过编译阶段为集合添加数据
- 反射是作用再运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素的。
- 泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList了,反向相当于被擦除了。