1. 反射概念
反射就是将一个类的class文件,封装成一个对象
从class中获取(解剖)类中的成员,并且运行起来
反射有关系的类
java.langClass 封装class文件的
java.lang.reflect.Constructor 封装构造方法的
java.lang.reflect.Field 封装成员变量的
java.lang.reflect.Method 封装成员方法的
//以下所有代码的演示都会使用此类
/*
*
* 用于反射演示的Person类
*
*/
public class Person {
private String name;
private int age;
public String email;
public Person(){System.out.println("空参赛构造");}
public Person(String name,int age){
this.age = age;
this.name = name;
System.out.println("两个参数构造");
}
public Person(String name)
{
this.name = name;
System.out.println("私有构造");
}
//定义多个普通方法
public void speak()
{
System.out.println("say");
}
public void show(int x)
{
System.out.println("一个人的x"+x);
}
public String toString()
{
return "Person " +name+"......"+age+"..."+email;
}
// {
// System.out.println("构造代码要建对象,才运行");
// }
//
// static{
// System.out.println("静态代码块,加载类的时候运行");
// }
}
//==================================================
2.获取反射的三种方式
编译后的class文件,对象的方式
描述类是Class,三种方式的返回值类型也是Class类型
A. 对象.getClass()
B. 类名.class
C. Class.forName()获取
推荐使用:Class.forName方式获取一个类的字节码文件对象
灵活方便,你的类名可以通过字符串参数传递的
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
//第一种,通过对象获取 Object类的方法 class<?> getClass()
Person p = new Person();
Class c1 = p.getClass();
System.out.println(c1);
//第二种,通过类,直接获取,多线程中,任何一个数据类型,都有一个静态成员变量class
//静态成员变量,返回这个累的class的文件对象
Class c2 = Person.class;
System.out.println(c2);
System.out.println(c1==c2);//t
System.out.println(c1.equals(c2));//t
//以上结果都是T,因为你的Person.class 对象只有一份
//第三种,通过forName(String className)
Class c3 = Class.forName("cn.itcast.reflects.Person");
System.out.println(c3);
// method("cn.itcast.reflects.Person") //推荐这种方式
}
private static void method(String className) throws ClassNotFoundException
{
Class c = Class.forName(className);
System.out.println(c);
}
}
//==================================================
3. 通过class文件对象,获取构造方法并运行构造方法
Class类的方法Constructor<?>[] getConstructors() 公共权限的
获取构造方法,返回数组
Constructor返回值类型,是描述构造方法的类
Class类的方法获取一个构造方法
Constructor getConstructor(Class...c)传递参数,传递和构造方法一致的参数,就可以获取到构造方法了
获取到了构造方法,如何运行呢
Constructor类方法 Object newInstance(Object... initargs) 创建类的对象,构造方法就运行了
//反射获取构造方法并运行
import java.lang.reflect.*;
public class ReflectDemo1 {
public static void main(String[] args) throws Exception {
//获取Person字节码文件对象
Class clazz = Class.forName("cn.itcast.reflects.Person");
//通过字节码文件对象获取构造方法getConstructors方法,返回构造方法数组
Constructor[] cons = clazz.getConstructors();
for(Constructor c : cons){
System.out.println(c);
}
//获取一个构造方法,并运行
Constructor con = clazz.getConstructor();
System.out.println(con);
Object obj = con.newInstance();
System.out.println(obj);
//获取一个有参数的构造方法,并运行‘
Constructor con2 = clazz.getConstructor(String.class,int.class); //
System.out.println(con2);
obj = con2.newInstance("张三",23);
System.out.println(obj);
}
}
//===================
获取私有构造方法,并运行,单例模式无效了
Class类的getDeclaredConstructor()获取私有的构造方法
void setAccessible(boolean flag) 方法是Constructor父类AccessibleObject类的方法
运行时期,取消Java检查(权限) ,
暴力访问
//获取私有构造方法运行
import java.lang.reflect.*;
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("cn.itcast.reflects.Person");
//获取私有构造
/* Constructor[] cons = clazz.getDeclaredConstructors();
for(Constructor c : cons){
System.out.println(c);
}*/
Constructor con = clazz.getDeclaredConstructor(String.class);
con.setAccessible(true);
Object obj = con.newInstance("haha");
System.out.println(obj);
}
}
//=====
/*
* 反射打破单例模式
*/
import java.lang.reflect.Constructor;
class Single{
private Single (){}
private static final Single s = new Single();
public static Single getInstance(){
return s;
}
}
public class ReflectDemo4 {
public static void main(String[] args) throws Exception{
Class clazz = Class.forName("cn.itcast.reflects.Single");
Constructor con = clazz.getDeclaredConstructor();
con.setAccessible(true);
Object obj = con.newInstance();
System.out.println(obj);
obj = con.newInstance();
System.out.println(obj);
}
}
//==================================================
4. 通过class文件对象,获取成员变量,并修改值
Class类的方法Field[] getFields()类中的成员变量,公共的
Class类的方法 Field getField(String name) 获取指定的成员变量,公共的
传递一个变量名
Field类的方法set(obj,修改后的新值)修改值
/*
* 获取成员变量,并运行
*/
import java.lang.reflect.*;
public class ReflectDemo5 {
public static void main(String[] args)throws Exception {
Class clazz = Class.forName("cn.itcast.reflects.Person");
//利用Class类的方法getFields()获取成员变量
/*Field[] fields = clazz.getFields();
for(Field f : fields){
System.out.println(f);
}*/
Object obj = clazz.newInstance();
//获取一个成员变量email
Field field = clazz.getField("email");
field.set(obj, "123456@qq.com");
System.out.println(obj);
//获取私有成员变量age修改值
Object obj2 = clazz.newInstance();
Field field2 = clazz.getDeclaredField("age");
field2.setAccessible(true); //暴力访问
field2.set(obj2, 333);
System.out.println(obj2);
}
}
//==================================================
5. 通过class文件对象,获取成员方法,并运行
Class类的方法 Method[] getMethods()获取类中,所有的公共的成员方法,包括继承的
Class类的方法,Method getMethod(字符串的方法名,要获取的方法的参数列表)获取一个方法
Method类中有一个方法,可以运行获取到的方法,名字invoke(对象,运行方法时传递的实际参数列表...)
运行方法的方法
Class类的方法Method[] getDeclaredMethods() 公共的,私有的,受保护,但是不包括继承的
//反射获取成员方法,并运行
import java.lang.reflect.*;
public class ReflectDemo6 {
public static void main(String[] args) throws Exception{
Class clazz = Class.forName("cn.itcast.reflects.Person");
//通过Class类的方法getMethods()
/* Method[] method = clazz.getMethods();
for(Method m : method)
{
System.out.println(m);
}*/
Object obj = clazz.newInstance();
//获取一个成员方法
Method method1 = clazz.getMethod("speak");
//
//使用Method类的invoke方法,运行获取到的方法
method1.invoke(obj);
//获取一个参数的 int show方法运行
Method method2 = clazz.getMethod("show", int.class);
method2.invoke(obj, 123);
}
}
//================
/*
* 获取私有的成员方法运行
*/
import java.lang.reflect.*;
public class ReflectDemo7 {
public static void main(String[] args)throws Exception {
Class clazz = Class.forName("cn.itcast.reflects.Person");
Method[] methods = clazz.getDeclaredMethods();
for(Method m : methods){
System.out.println(m);
}
Object obj = clazz.newInstance();
//获取私有的run方法
Method method = clazz.getDeclaredMethod("run");
method.setAccessible(true);
method.invoke(obj);
}
}
//=====================================
反射绕过编译器检查,将不同的数据类型,存储到带有泛型的集合(泛型的擦除)
import java.lang.reflect.*;
import java.util.*;
public class GenericReflect {
public static void main(String[] args)throws Exception {
ArrayList<String> array = new ArrayList<String>();
array.add("123");
//Class clazz =Class.forName("cn.itcast.reflects.GenericReflect");
Class clazz = array.getClass();
//Class clazz = GenericReflect.class;
Method method = clazz.getMethod("add", Object.class);//改成了Object类型的
method.invoke(array, 123);
method.invoke(array,false);
System.out.println(array);
Iterator it = array.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}