1.什么是反射?
反射是一门动态的创建对象的技术
反射可以在运行期期间 动态的 访问和操作对象的 属性 和 方法
2.为什么要有反射?
java 是一门静态的语言
因为有了反射 java被称为 半动态语言
java有一个致命的缺陷 : 所有的对象 都是预先定义好的
即 : 在编程期间定义好了 对象的创建 并不能根据实际运 行期需求来创建
3.反射的作用?
动态的创建对象 动态的 访问和操作对象的 属性 和 方法
4.类也是对象
Class类
1. 地址
2. 名字
3. 属性类对象4. 构造器类对象
5. 方法
该对象是 Class 类的对象 , 存储的东西 是 本类的信息
Class 类的对象 总是对应着 一个类信息 。
Class 类的对象 被称之 类对象
5.使用反射来操作
1. 使用反射来获取和操作 属性
2. 使用反射来获取和操作方法
3. 使用反射来获取和操作构造器
3种方法或得类对象:
*****************************************************
Student student = new Student();
// 1.根据类获得类对象
clazz = Student.class;
// 2.根据本类的对象获得 本类的 类对象
Class clazz2 = student.getClass();
// 3.根据类的地址 获得 本类的 类对象 最主要 用的最多的
Class clazz3 = Class.forName("com.hainiu.use.Person");
使用反射 获取和操作构造器
*****************************************************
/**
* 使用反射 获取和操作构造器
* @throws ClassNotFoundException
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws InstantiationException
*/
private static void useConstructor() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class clazz = Class.forName("com.hainiu.use.Student");
// 获取构造器
System.out.println("==========获取所有的公共的构造器==========");
// 获得本类所有的公共的构造器 没有父类的
Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("==========获取所有的声明的构造器==========");
// 获得本类声明的所有构造器
constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("==========获取唯一的公共的构造器==========");
Constructor constructor = clazz.getConstructor(String.class,int.class);
System.out.println(constructor);
System.out.println("==========获取唯一的声明的构造器==========");
constructor = clazz.getDeclaredConstructor(String.class);
System.out.println(constructor);
/**
* 基本操作
*/
System.out.println("*****"+constructor.getModifiers()); //获取修饰符
System.out.println(constructor.getName());
System.out.println(constructor.getParameterCount()); //获取形参数目
System.out.println(constructor.getParameterTypes()); //获取形参类型
System.out.println("===========操作构造器============");
// 操作构造器
// 它的操作最简单 也最重要
//使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
Object newInstance = constructor.newInstance("哈哈哈");
System.out.println(newInstance);
// 单例
Class mathClass = Math.class;
@SuppressWarnings("unchecked")
Constructor con = mathClass.getDeclaredConstructor();
con.setAccessible(true);
Object ooo = con.newInstance();
Math math = (Math)ooo;
System.out.println(math.hashCode());
System.out.println(math);
}
获取和操作方法
/**
* 使用反射获取和操作 方法
* @throws ClassNotFoundException
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws InstantiationException
*/
public static void useMethod() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{
Class clazz = Class.forName("com.hainiu.use.Student");
// 获取 方法对象 4种
// 1. 获取所有的公共的方法 包括父类的
Method[] methods = clazz.getMethods();
for (Method method : methods) {
// System.out.println(method);
}
System.out.println("============获取所有的 本类声明的方法========");
// 2. 获取所有的 本类声明的方法 不包括 想获得父类的 先获得父类的类对象
methods = clazz.getDeclaredMethods();
for (Method method : methods) {
// System.out.println(method);
}
System.out.println("============获取单个的 公共的方法========");
// 3. 获得单个的 公共的方法
Method method = clazz.getMethod("show",int.class);
// parameter->参数 types->类型 Class... parameterTypes
// Class [] c = {int.class,int.class};
// 有几个参数 就给几个 参数类型.class 没有就只给名字就可以
System.out.println(method);
System.out.println("============获取单个的声明的方法========");
// 4. 获得单个的 声明的方法
method = clazz.getDeclaredMethod("setSage", int.class);
System.out.println(method);
/**
* 以上是 获取方法对象的 4种方式
* 以下是 方法对象的简单操作
*/
System.out.println(method.getName());
System.out.println(method.getModifiers());
System.out.println(method.getReturnType());// 返回值类型
System.out.println(method.getParameterCount());// 参数个数
Class<?>[] parameterTypes = method.getParameterTypes();// 参数类型
for (Class<?> class1 : parameterTypes) {
System.out.println(class1);
}
// 操作 方法对象
/**
* 操作方法对象 方法有静态和非静态
* 静态从属类 非静态从属对象
*/
// 操作静态方法
method = clazz.getDeclaredMethod("show");
// 执行方法 必须给参数 不管方法有没有返回值 这里接收一个返回值 如果原方法没返回 那么返回null
Object obj = method.invoke(null);// 静态方法依附于类 所以参数1 给null
System.out.println(obj);
// 操作非静态方法 从属于对象
method = clazz.getDeclaredMethod("add",int.class,double.class);
Student stu = (Student) clazz.newInstance();
Student student = new Student();
Object invoke = method.invoke(stu,3,1.1);
method.invoke(student,3,1.1);
System.out.println(invoke);
System.out.println("============使用反射检测泛型运行期被擦除==============");
List<String> list = new ArrayList<>();
list.add("你不让我加stu");
list.add("我偏要加");
list.add("我要这天再也遮不住你的脸");
Class cl = list.getClass();
Method m = cl.getDeclaredMethod("add", Object.class);
m.invoke(list, stu);
for(Object o : list)
System.out.println(o);
System.out.println("---------");
for (String string : list) {
System.out.println(string);
}
}
操作属性
/**
* 使用反射 获取 和 操作 对象的属性
* @throws ClassNotFoundException
* @throws SecurityException
* @throws NoSuchFieldException
* @throws IllegalAccessException
* @throws IllegalArgumentException
* @throws InstantiationException
*/
public static void useField() throws ClassNotFoundException,
NoSuchFieldException, SecurityException, IllegalArgumentException,
IllegalAccessException, InstantiationException{
Class clazz = Class.forName("com.hainiu.use.Student");
// 获取属性 对应的对象 4种方式 各有千秋
// 获取所有的公共的属性 所对应的对象 包含父类的
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("===========获取本类声明的所有的属性对象==========");
// 获取所有本类声明的属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field);
}
// 如何获得父类声明的 属性对象呢 ? 先获得父类的类对象 然后用相同的方式
System.out.println("===========获取本类公共的单个的属性对象==========");
// 获得单个公共的属性对象
Field field = clazz.getField("name");
System.out.println(field);
System.out.println("===========获取本类公共的单个的属性对象==========");
// 获取单个本类声明的属性对象
field = clazz.getDeclaredField("sscore");
System.out.println(field);
/**
* 以上是获得 属性对象 四种方式
* 以下是 或得到属性对象的 基本操作
*/
System.out.println("===========基操==========");
System.out.println(field.getName());
System.out.println(field.getModifiers());
System.out.println(field.getType());
System.out.println("============获取操作静态属性=========");
/**
* 以下是操作属性
* 属性有静态 和 非静态 之分
* 静态的属性从属于类
* 非静态属性从属对象
*/
// 获取到属性 然后操作属性
// 操作静态属性
field = clazz.getDeclaredField("id");
// get方法是获取值得方法 因为静态属性从属于类 所以此时不需要给对象 直接给null
Object obj = field.get(null);
System.out.println(obj);
// set方法是修改值得方法 静态属性第一个参数给null 第二个参数给 值
field.set(null, 123);
obj = field.get(null);
System.out.println(obj);
// 操作非静态属性
// 操作非静态的属性 必须有对象才行 没有对象意味着 属性不存在
Student stu = (Student) clazz.newInstance();
Student student = new Student("张三",18,true,99);
System.out.println(stu);
field = clazz.getDeclaredField("sname");
// 此时必须指明对象
obj = field.get(student);
System.out.println(obj);
field.set(stu, "李四");
field.set(student, "不叫zhangsan");
System.out.println(stu);
System.out.println(student);
System.out.println("============暴力反射=================");
/**
* 暴力反射
*/
field = clazz.getDeclaredField("sscore");
System.out.println(field);
// 暴力反射 忽略权限的限制 方法来源父类
field.setAccessible(true);
System.out.println(field.get(student));
System.out.println(field.get(stu));
field.set(stu, 180);
field.set(student, 180);
System.out.println(field.get(student));
System.out.println(field.get(stu));
System.out.println(" ============ 再次 测试 暴力反射 ==============");
field = clazz.getDeclaredField("i");
field.setAccessible(true);
field.set(stu, 3333);
System.out.println(field.get(stu));// 反射获取属性值
System.out.println(stu);// 正常去输出 属性值
}