反射
通过.class来得到对象,属性,方法的一种手段
1. 类对象和他的三种获取方式
- 通过对象
- Class cls = obj.getClass();
- 通过类名(常用)
- Class cls = Test.class;
- 通过Class的静态方法
- Class cls = Class.forName(“类全名”);
/**
* 字节码对象的三种获取方式
* 1: 通过对象.getClass()方法; 直接能够得到这个类的对象,就可以直接通过对象获取 Class cls1 = p.getClass();
* 2: 通过类名.class 来获取这个字节码对象 ; 和Person类在一起,就可以使用这个
* 3: 通过静态方法来获取这个对象; 只知道这个类的类全名; 可以使用这个手段;
*/
public class DemoGetClass {
public static void main(String[] args) {
//正常获取Person对象
Person person = new Person();
//反射获取Person对象,Class cls; 这个就代表一个.class文件
//1: 通过对象.getClass()方法
Class class1 = person.getClass();
//2: 通过类名.class 来获取这个字节码对象
Class class2 = Person.class;
//3: 通过静态方法来获取这个对象
try {
Class class3 = Class.forName("com.qianfeng.xqc.day0319.fanshe.Person");
System.out.println(class3 == class2);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println(class1);
System.out.println(class2);
}
}
2. 通过反射获取构造器
/**
* 通过反射获取我们.class对象的所有构造器
* 作用: 能够实例一个对象
*/
public static void test1() {
Class cls = Person.class;// 获取了person的字节码对象
try {
//获取构造器对象
Constructor constructor = cls.getConstructor();
// 获取public的构造器
Constructor[] constructors = cls.getConstructors();
for(Constructor c : constructors) {
c.getParameterTypes();//获取参数类型Class
System.out.println(c.getName());
}
System.out.println("===============================");
// 获取所有的构造器
Constructor[] declaredConstructors = cls.getDeclaredConstructors();
for(Constructor c : declaredConstructors) {
System.out.println(c.getName());
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
3. 通过反射获取对象实例
/**
* 获取不同的构造器,来实例化对象
*/
public static void test2() {
Class cls = Person.class;
try {
//获取公共的构造器,没有参数
Person p1 = (Person) cls.newInstance();//获取默认的无参的构造器,创建对象
//无参的构造器
Constructor constructor = cls.getConstructor();
Person p2 = (Person) cls.newInstance();
//获取带参数的构造器,使用带参的构造器实例,指定参数,实例化一个对象
Constructor constructor3 = cls.getDeclaredConstructor(char.class);//public
Person p3 = (Person) constructor3.newInstance('a');
Constructor constructor4 = cls.getDeclaredConstructor(int.class);//default
Person p4 = (Person) constructor4.newInstance(5);
//传值的时候,一定要和你获取构造器的时候的数据类型匹配
Constructor constructor5 = cls.getDeclaredConstructor(int.class,String.class);
Person p5 = (Person) constructor5.newInstance(5,"sda");
//获取私有的构造器,并且能够实例化对象
Constructor constructor6 = cls.getDeclaredConstructor(String.class);
//如果通过反射去破解我们私有属性、构造器、方法,必须破解他的权限;
constructor6.setAccessible(true);
Person p6 = (Person) constructor6.newInstance("ss");
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
4. 通过反射获取属性,并且修改对象的属性值
案例:修改一个类的私有属性的值;
import java.lang.reflect.Field;
/**
* 通过反射,来获取我们的所有的属性
*
*/
public class DemoGetShuxing {
public static void main(String[] args) {
modifysx();
}
/**
* 修改对象的私有属性值
*/
public static void modifysx() {
//得到这个属性
Class cls = Person.class;
try {
//获取私有属性age对象
Field declaredField = cls.getDeclaredField("age");
//需要通过setAccessible()方法破解私有属性的开关,设置为true,就代表可以访问这个私有属性
declaredField.setAccessible(true);
//通过对象,才能访问这个对象的 某个属性或者修改 某个属性的值
Person p = (Person) cls.newInstance();
//使用属性去得到属性的值; 得到p1对象的这个属性的值
int age = declaredField.getInt(p);//得到p对象的 age属性的值;
System.out.println("age:" + age);
//对这个属性的值,进行修改
declaredField.setInt(p, 100);//修改p对象age属性的值,修改成100
Object object = declaredField.get(p);
System.out.println("修改后age:" + object);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* 通过反射获取属性
*/
public static void getsx() {
Class cls = Person.class;
// 根据属性名称,来获取这个属性对象
try {
Field field = cls.getField("id");// 只能得到public修饰的属性
Field field2 = cls.getDeclaredField("age");// 获取名字为id的属性;(所有的属性都能获取)
System.out.println(field.getName());
System.out.println(field2.getName());
System.out.println("---------------------");
// 获取public修饰过的属性
Field[] fields = cls.getFields();
for (Field f : fields) {
System.out.println(f.getName());
}
System.out.println("---------------------");
// 获取所有属性
Field[] declaredFields = cls.getDeclaredFields();
for (Field f : declaredFields) {
System.out.println(f.getName());
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
5. 通过反射获取方法,并且调用对象的方法
案例:调用一个类的私有方法
/**
* 调用一个类的私有方法
*/
public static void getprivatemethod() {
Class cls = Person.class;
try {
Method declaredMethod = cls.getDeclaredMethod("test4");
//获取一个对象
Object obj = cls.newInstance();
//私有方法使用需要破解权限
declaredMethod.setAccessible(true);
//调用方法
declaredMethod.invoke(obj);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* 获取一个类的方法
*/
public static void getmethod() {
Class cls = Person.class;
try {
//获取public的方法(根据方法名称)
Method method = cls.getMethod("test1");
//获取所有public的方法
Method[] methods = cls.getMethods();
for(Method m : methods) {
System.out.println(m.getName());
}
System.out.println("--------------");
//获取所有的修饰符修饰的方法(根据方法名称)
Method declaredMethod = cls.getDeclaredMethod("test4");
//获取本类所有的方法
Method[] declaredMethods = cls.getDeclaredMethods();
for(Method m : declaredMethods) {
System.out.println(m.getName());
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
带参数的方法调用
/**
* 调用一个类的带参数返回值的私有方法
*/
public static void getprivatemethodcs() {
Class cls = Person.class;
try {
//获取这个方法
Method declaredMethod = cls.getDeclaredMethod("plus",int.class,int.class);
//获取一个对象
Object obj = cls.newInstance();
//私有方法使用需要破解权限
declaredMethod.setAccessible(true);
//调用这个方法; 需要传递2个参数;参数的类型是 int 和 int
//如果方法有返回值,一定要使用一个参数去接收这个返回值;
//调用方法
Object result = declaredMethod.invoke(obj,10,12);
System.out.println(result);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}