一、 反射的介绍
1.反射的定义
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
Java反射机制,可以实现以下功能:
①在运行时判断任意一个对象所属的类;
②在运行时构造任意一个类的对象;
③在运行时判断任意一个类所具有的成员变量和方法;
④在运行时调用任意一个对象的方法;
⑤生成动态代理;
二、获取源头Class(重点)
所有类的对象其实都是Class的实例。这个 Class 实例可以理解为类的模子,就是包含了类的结构信息,类似于图纸。我们日常生活中,需要创造一个产品,如想山寨一个iphone手机,怎么办?
有三种方式可以实现:
⑴买个iphone手机,拆的七零八落的,开始山寨;
⑵到iphone工厂参观,拿到iphone磨具,开始山寨;
⑶跑到美国盗取iphone的图纸,开始山寨,最后一种最暴力,最爽。
同理,获取类的Class对象也有三种方式
⑴Class.forName(”包名.类名”) //一般尽量采用该形式
(2)类.class
(3)对象.getClass()
思考:目前我们创建对象的方式有哪写?
[1]获取Class对象
Class是一切的源头,所有伟大的事业都有一个不起眼的开头。而反射有三种出场方式
第一种方式: 对象.class
Person person = new Person();
//对象.getClass()
Class<? extends Person> aClass = person.getClass();
System.out.println(aClass.getName());
第二种方式: 类.class
//类名.class
Class<Person> aClass = Person.class;
第三种方式(推荐方式): Class.forName()
// Class.forName("全限定路径") 全限定路径:包名+类名
Class<?> aClass = Class.forName("com.shsxt.reflect.Person");
有了class对象,我们就有了一切,这就是反射的源头,接下来就是“庖丁解牛”。
[2] 获取修饰符
获取修饰符,使用 getModifiers() 即可, Modifier 类提供了 static 方法和
常量来解码类和成员访问修饰符
Class<Person> aClass = (Class<Person>) Class.forName("com.shsxt.reflect.Person");
int modifiers = aClass.getModifiers();
//使用Modifier转换为相应的字符串
System.out.println(Modifier.toString(modifiers));
三、创建对象
1. 构造器
根据Class对象,我们可以获得构造器,为实例化对象做准备。调用以下api即可。
Constructor | getDeclaredConstructor([参数列表.class]) 返回一个Constructor对象,这个构造器是父类或子类的共有的构造器 |
---|---|
Constructor<?>[] | getDeclaredConstructors()返回包含一个数组Constructor对象反射,这个构造器对象是自己的公有和私有的构造器 |
私有的属性、构造器、方法均可通过调研setAccessible(true)来打开权限。
//获取Person的class
Class<Person> personClass = Person.class;
//不能获取私有的构造器,只能获取公开的构造器
Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor);
Person person = constructor.newInstance("张三", 18);
System.out.println(person);
//可以获取私有的构造器,也可以获取公开的构造器
Constructor<Person> declaredConstructor = personClass.getDeclaredConstructor();
System.out.println(declaredConstructor);
//如果是私有的,则打开权限再使用
declaredConstructor.setAccessible(true);
System.out.println(declaredConstructor.newInstance());
//获取所有的公有的构造器
Constructor<?>[] constructors = personClass.getConstructors();
System.out.println(constructors.length);
//获取所有的构造器 公有+私有
Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
System.out.println(declaredConstructors.length);
2.实例化对象
创建对象的方式,有new 、克隆、反序列化,再加一种,根据Class对象,使用newInstance() 或者构造器实例化对象。调用以下api即可
// 通过反射
// clz newInstance()
// 通过获取构造器, 利用构造器去创建对象
public class NewInstance {
public static void main(String[] args) throws Exception {
//1、获取Class
Class<Person> aClass = (Class<Person>)Class.forName("com.shsxt.reflect.Person");
//2、创建对象,必须保证空构造存在.而且只能是调用空构造,属性是没有数据的
//(一)创建对象的方式一:
Person person = aClass.newInstance();
System.out.println(person);
// (二)创建对象方式二:无参
// 获取构造器对象(无参构造)
Constructor<Person> constructor = aClass.getConstructor();
//执行构造器,获取Bean对象
Person person1 = constructor.newInstance();
System.out.println(person1);
// (二)创建对象方式三:有参 获取指定构造器 获取带参构造 String类型, int类型
Constructor<Person> constructor1 = aClass.getConstructor(String.class, int.class);
Person person2 = constructor1.newInstance("张三", 18);
System.out.println(person2);
//(三)创建对象的方式四:通过私有构造器创建
// 获取私有的构造器
Constructor<Person> declaredConstructor = aClass.getDeclaredConstructor();
//打开权限
declaredConstructor.setAccessible(true);
Person person3 = declaredConstructor.newInstance();
System.out.println(person3);
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
}
}
注意:newInstance()是调用空构造,如果空构造不存在,会出现异常。由此可知,使用其他构造器创建对象比较麻烦,使用空构造非常简单。确保空构造存在
3. 父类与接口
定义Person类,Student类继承Person类
//获取Student的Class
Class<Student> studentClass = Student.class;
//student的父类
Class<? super Student> superclass = studentClass.getSuperclass();
System.out.println(superclass);
四、属性和方法
1. 属性(获得属性及设置属性值)
获取所有属性(包括父类或接口) ,使用 Field 即可操作, Field 作为描述属性的对象
/**
Class
属性的操作: Field对象
*/
public class ReflectField {
public static void main(String[] args) throws Exception {
//获取Class对象
Class<Student> aClass = Student.class;
Student student = aClass.newInstance();
Field id = aClass.getField("id");
// 属性的权限, 类型, 名称
// 通过id对象获取 studnet对象的 id属性值
int idValue = (int)id.get(student); // 获取某个对象的这个属性的值
System.out.println(idValue);//10
//要获取一个对象的属性值
Field money = aClass.getDeclaredField("money");
// 如果是私有属性则打开权限
money.setAccessible(true);
//获取指定对象的属性
System.out.println(money.get(student));//100
//修改一个对象的属性值
money.set(student,2999);
System.out.println(student.getMoney());//2999
//获取money属性的类型
System.out.println(money.getType());//int
System.out.println(Modifier.toString(money.getModifiers()));//private
//获取属性名称
System.out.println(money.getName());//money
//获取静态属性scoolName
Field scoolName = aClass.getField("scoolName");
// 静态的内容 尽量不要和对象关联 对象参数设为null
scoolName.set(null,"sxt");
System.out.println(Student.scoolName);//sxt
}
}
2.方法(通过反射执行方法)
获取所有方法(包括父类或接口),使用 Method 即可。 Method 即作为描述方法的对象。
实体类Person,Student的父类
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
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 testFatherPublict(){
System.out.println("Person.testFatherPublict");
}
private void testFatherPrivate(){
System.out.println("Person.testFatherPrivate");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
实体类Student
public class Student extends Person{
public int id;
private int money;
public static String scoolName;
public Student() {
this.id = 10;
this.money = 100;
}
public Student(int id, int money) {
this.id = id;
this.money = money;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getMoney() {
return money;
}
public void test(String str){
System.out.println(str);
}
public void setMoney(int money) {
this.money = money;
}
public void testSelefPublic(){
System.out.println("Student.testSelefPublic");
}
private void testSelefPrivate(){
System.out.println("Student.testSelefPrivate");
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", money=" + money +
'}';
}
}
//获取Class对象
Class<Student> studentClass = Student.class;
Student student = studentClass.newInstance();
//获取方法 方法的对象
//方法名 、参数类型.class
Method method = studentClass.getMethod("test", String.class);
System.out.println(method);
//执行方法
// 通过student执行它的 m1对象中的方法, 将 "helloworld" 作为实参,执行这个方法得到的结果, invoke的返回值
Object o = method.invoke(student, "helloworld");
//System.out.println(o);
//获取返回值
Class<?> type = method.getReturnType();
System.out.println(type);
Method method1 = studentClass.getDeclaredMethod("testSelefPrivate");
//打开方法的权限
method1.setAccessible(true);
method1.invoke(student);
通过反射获取方法
//获取Class对象
Class<Student> studentClass = Student.class;
Student student = studentClass.newInstance();
//获取方法 方法的对象
//方法名 、参数类型.class
Method method = studentClass.getMethod("test", String.class);
System.out.println(method);
//执行方法
// 通过student执行它的 m1对象中的方法, 将 "helloworld" 作为实参,执行这个方法得到的结果, invoke的返回值
Object o = method.invoke(student, "helloworld");
//System.out.println(o);
//获取返回值
Class<?> type = method.getReturnType();
System.out.println(type);
Method method1 = studentClass.getDeclaredMethod("testSelefPrivate");
//打开方法的权限
method1.setAccessible(true);
method1.invoke(student);
五、数组(仅了解)
操作数组需要借助Array类
//1、创建数组
Object obj = Array.newInstance(int.class, 5);
//2、获取大小
if(obj.getClass().isArray()){
//3、判断是否为数组
System.out.println(Array.getLength(obj));
//4、设置值
Array.set(obj,0, 100);
//5、获取值
System.out.println(Array.get(obj,0));
}