反射简单应用
反射 Reflection
java属于静态语言,因为反射机制的存在,又可以成为“准动态语言”;
反射允许程序在运行时获取任何类的内部信息,并能直接操作任意对象的内部属性及方法;
正射与反射
正:引入包名 -> 通过new实例化 -> 取得实例化对象;
反:实例化对象 -> getClass() 方法 -> 得到完整的类信息;
反射机制提供的功能
运行时判断任意一个对象所属的类;
构造任何一个类的对象;
判断任何类所具有的成员变量和方法;
获取泛型信息;
调用任何对象的成员变量和方法
处理注解(注解配合反射、绝配);
生成动态代理;
。。。
反射的优缺点
优点:动态、灵活;
缺点:贼慢,比正常new的方式差了几十倍;
反射主要常用API
java.lang.Class : 代表一个类;
java.lang.reflect.Method : 代表类的方法;
java.lang.reflect.Field : 代表类的成员变量;
java.lang.reflect.Constructor : 代表类的构造器;
获取class实例
package com.yuxing.demo;
public class GetClass {
public static void main(String[] args) throws ClassNotFoundException {
// 通过getClass获得
Yuge y1 = new Yuge();
Class<?> c1 = y1.getClass();
// 通过forName获得,包名加载
Class<?> c2 = Class.forName("com.yuxing.demo.Yuge");
// 通过类直接获得
Class<Yuge> c3 = Yuge.class;
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
// 通过class获得父类的class
Class<?> superclass = c1.getSuperclass();
System.out.println(superclass.getName());
}
}
class Yuge{
}
// 一个类只有一个class
142257191
142257191
142257191
java.lang.Object
什么时候类会发生初始化
类的主动引用
1.虚拟机启动,会先初始化main方法所在的类;
2.new 一个类的对象;
3.调用类的静态成员(除了final常量)和静态方法;
4.使用Java.lang.reflect包的方法对类进行反射调用;
5.当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类;
类的被动引用不会发生类的初始化
1.当访问一个静态域,只有真正声明这个域的类才会被初始化。如:通过子类引用父类的静态变量,不会初始化子类;
public class TestStatic {
public static void main(String[] args) {
System.out.println(Son.a);
}
}
@Data
class Father{
static int a = 0;
static{
System.out.println("父类被加载");
}
}
@Data
class Son extends Father{
static{
System.out.println("子类被加载");
}
}
父类被加载
0
2.声明数组时,不会初始化
public static void main(String[] args) {
Son[] s = new Son[5];
}
}
@Data
class Son extends Father{
static{
System.out.println("子类被加载");
}
}
没有输出
3.引用常量不会初始化
通过class获得类的信息
Class<?> aClass = Class.forName("com.yuge.redistest.Father");
aClass.getMethods();
aClass.getDeclaredMethods();
aClass.getMethod("aaaa");
// 参数为方法名
aClass.getDeclaredMethod("getAaaa");
aClass.getFields();
// 获得方法、属性、构造方法等
使用newInstance()获得对象
newInstance()调用的是无参构造,当类没有无参构造方法时,会报错
public class TestStatic {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException {
// System.out.println(Son.a);
Class<?> a = Class.forName("com.yuge.redistest.Father");
Object o = a.newInstance();
System.out.println(o);
}
}
@Data
class Father{
private int b;
private String a;
// public Father(){
//
// }
public Father( String a,int b){
this.a = a;
this.b = b;
}
}
Exception in thread "main" java.lang.InstantiationException: com.yuge.redistest.Father
newInstance()使用时先获取class的构造方法,传参获取对象
public class TestStatic {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
// System.out.println(Son.a);
Class<?> a = Class.forName("com.yuge.redistest.Father");
// 参数为构造方法参数的类型class
Constructor<?> constructor = a.getConstructor( String.class, int.class);
Father o1 = (Father)constructor.newInstance("1", 2);
System.out.println(o1);
}
}
@Data
class Father{
private int b;
private String a;
public Father( String a,int b){
this.a = a;
this.b = b;
}
}
Father(b=2, a=1)
执行方法、操作属性
public class TestStatic {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {
Class<?> a = Class.forName("com.yuge.redistest.Father");
Father father = (Father) a.newInstance();
Method a1 = a.getMethod("getName", String.class);
// incoke方法,参数为实例对象、和该方法需要的参数
a1.invoke(father,"aas");
Field a2 = a.getDeclaredField("a");
// Father类中的a属性是私有的,无法直接赋值,因此需要将权限检测关闭,才能赋值
a2.setAccessible(true);
// set方法,参数为实例对象、和需要设置的值
a2.set(father,"asfs");
System.out.println(father);
}
}
@Data
class Father{
private int b;
private String a;
public void getName(String cc){
System.out.println(cc);
}
public Father(){
}
public Father( String a,int b){
this.a = a;
this.b = b;
}
}
反射操作泛型,直接百度,内容内很少
反射操作注解
获取类上的注解,就用class.getAnnotations();
获取方法上的注解就用method.getAnnotation(注解类.class);
获取属性上的注解就用field.getAnnotation(注解类.class);