反射:把Java中的各种数据(方法、属性、构造器、类名)映射成一个个Java对象。
可以通过Class类创建一个类,获取类的信息,操作类的属性。
准备一个Uer类,在 package lurenjia.leaning; 包下,有int id、int age、String name三个私有属性,及其对应的set/get方法(其中 setId 为 private 私有方法),一个无参构造器和一个有参构造器。
package lurenjia.leaning;
public class User {
private int id;
private int age;
private String name;
public int getId() {
return id;
}
private void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User() {
}
public User(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
}
查看User 类
一、获取Class对象
方式一:有此类的对象,直接通过getClass()方法获取。
public static void main(String[] args) {
User t= new User();
Class cl =t.getClass();
}
方式二:能够直接使用类的时候,通过类名.class获取。
public static void main(String[] args) {
Class cls = User.class;
}
方式三:通过静态方法Class.forName("包名.类名")。
public static void main(String[] args) throws ClassNotFoundException {
Class cls = Class.forName("lurenjia.leaning.User");
}
方式四:通过子类的类对象获取
//获取子类的类对象
Class son = Son.class;
//获取自身的类对象
Class father = son.getSuperclass();
二、通过Class对象获取类信息
1、获取类的实例(Instance)
public static void main(String[] args) throws Exception{
Class cls = Class.forName("java.lang.String");
//jdk9以前,使用Class对象创建一个String对象
String str0 = (String)cls.newInstance();
//jdk9推荐方式:使用构造器创建对象,所以它推荐所有类加入无参构造器。
String str1 = (String) cls.getConstructor().newInstance("iloveyou");
}
2、获取类名(Name)
getName 包括包名
getSimpleName 不包括包名
public static void main(String[] args) throws Exception{
Class clszz = Class.forName("lurenjia.leaning.User");
//获取类名,包括包名
System.out.println(clszz.getName());
//获取类名,不包括包名
System.out.println(clszz.getSimpleName());
}
运行结果:
3、 获取属性(Filed)、方法(Method)、构造器(Constructor):
public static void main(String[] args) throws Exception{
Class clszz = Class.forName("lurenjia.leaning.User");
//获取指定public属性,不存在会抛出异常
//Field field=clszz.getField("id");
//获取指定属性
Field field2=clszz.getDeclaredField("id");
//获取所有的public属性,包括它的父类的public属性
Field[] fields=clszz.getFields();
//获取所有的属性
Field[] fields2=clszz.getDeclaredFields();
//获取指定public方法
Method method = clszz.getMethod("setId", int.class);
//获取指定方法,带参数则输入参数类型.class,无参则null
Method method2 = clszz.getDeclaredMethod("setId", int.class);
//获取所有的public方法
Method[] methods = clszz.getMethods();
//获取所有的方法
Method[] methods2 = clszz.getDeclaredMethods();
//获取public无参构造器
Constructor constructor = clszz.getConstructor();
//获取指定public带参数的构造器
Constructor constructor2 = clszz.getConstructor(int.class,int.class,String.class);
//获取所有public构造器
Constructor[] constructors = clszz.getConstructors();
//获取所有的构造器
Constructor[] constructors2 = clszz.getDeclaredConstructors();
}
总结:
Class对象获取信息:
获取public:使用:get 属性(Filed)、方法(Method)、构造器(Constructor)。
获取非public:使用:getDeclared 属性(Filed)、方法(Method)、构造器(Constructor)。
获取全部:+s,返回数组。获取public会获取到父类的,Declared则会获取自身的。
三、通过Class对象操作实际对象
1、使用对象的方法:
public static void main(String[] args) throws Exception{
//创建一个User对象
User u1 = new User(1,18,"二狗子");
//获取User类的Class对象
Class c = u1.getClass();
//获取User类的setId方法
Method method = c.getDeclaredMethod("setName", String.class);
//操作u1中的setName方法
method.invoke(u1,"老苗子");
}
2、操作对象的属性:
public static void main(String[] args) throws Exception{
//创建一个User对象
User u1 = new User(1,18,"二狗子");
//获取User类的Class对象
Class c = u1.getClass();
//获取User类的name属性
Field field = c.getDeclaredField("name");
//将此反射对象的accessible标志设置为指示的布尔值,值为true表示反射对象应该在使用Java语言访问控制时抑制检查。
field.setAccessible(true);
//操作u1的属性
field.set(u1,"老苗子");
//获取u1的属性
System.out.println(field.get(u1));
}
注意:如果属性为私有属性,我们可以通过设置accessible标识来抑制检查,达到访问效果:
setAccessible(true); (设置是否禁用 访问的安全检查。)它可以提供反射运行的速度。