Java反射

简介

Reflection(反射)是Java被视为动态语言的关键。

反射机制允许程序在执行期借助Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

加载完类之后,在堆内存的方法区中就产生了一个Class类型对象(一个类只有一个Class对象)。

这个对象就包含了完整的类的结构信息,可以通过这个对象看到类的结构。

这个对象像一面镜子,透过镜子看到类的结构,所以形象的称为:反射。

img

Class类

对象照镜子后可以得到的信息:某个类的属性,方法和构造器,某个类实现的接口

  • Class本身也是一个类
  • Class对象只能由系统建立对象
  • 一个加载的类在JVM中只会有一个Class实例
  • 一个Class对象应的是一个加载到HVM的.class文件
  • 每个类的实例都会记得自己由那个Class实例所生成
  • 通过Class可以完整的得到一个类中的所有被加载的结构
  • Class类是Reflection的根源,针对任何你想动态加载,运行的类,唯有先获得相应的Class对象

Class类得常用方法

img



反射相关得主要API

Class类与java.lang.reflect类库一起对反射的概念进行了支持。

该类库包含了Field、Method以及Constructor类(每个类都实现了Member接口)。

  1. Java.lang.Class:代表一个类
  2. Java.lang.reflect.Method:代表类的方法
  3. Java.lang.reflect.Field:代表的成员变量
  4. Java.lang.reflect.Constructor:代表的构造器

这些类型的对象是由JVM在运行时创建的。



获取运行时类的完整结构

获取Class类得实例

每个类都有一个Class对象。

一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。

方式一

如果你已经拥有一个类型的对象,那就可以通过调用getClass()方法来获取Class引用了。

Student student=new Student();
Class c1=student.getClass();

方式二

使用Class.forName(),你不需要为了获得Class引用而持有该类型的对象。

可能抛出ClassNotFoundException。

Class c2=null;
try {
	c2=Class.forName("text.Student"); //text包里的Student类
} catch(ClassNotFoundException e) {
	System.out.println("运行时异常");
}

注意:在传递给Class.forName()的字符串中,你必须使用全限定名(包含包名)。

方式三

通过类名.class获得,该方法最为安全可靠,程序性能最高。

Class c3=Student.class;

注意:由.class来创建Class对象的引用时,不会自动初始化Class对象。

方式四

基本内置类型的包装类都有。

类字面常量不仅可以用于普通的类,也可以应用于接口、数组以及基本数据类型。

对于基本数据类型的包装类,还有一个标准字段TYPE。

TYPE字段是一个引用,指向对应的基本数据类型的Class对象。

Class<Integer> c4=Integer.TYPE;

获得父类类型

Class c5=c1.getSuperclass();

获取类的所有信息

//获得Class对象
Class c1=User.class;

//获得类的名称
System.out.println(c1.getName()); //获得包名 + 类名
System.out.println(c1.getSimpleName()); //获得类名

//获得类的属性
Field[] fs=c1.getFields(); //只能找到public属性
fs=c1.getDeclaredFields(); //找到全部属性
//获得指定属性
Field name= c1.getDeclaredField("name"); //参数属性名

//获得类的方法
Method[] methods = c1.getMethods(); //获得本类及其父类的所有public方法
methods=c1.getDeclaredMethods(); //获得本类的所有方法,包括私有的(private、protected、默认以及public)的方法。
//获得指定方法,如果方法有参数,就需要放入对应的参数类型
//public Method[] getMethod(methodName,parameterTypes); 
//参数methodName:表示获取的方法的名字,parameterTypes:表示获取的方法的参数的Class类型
Method shows= c1.getMethod("shows",String.class);

//获得构造器
Constructor[] constructors = c1.getConstructors();//获得本类及其父类的所有public构造器
Constructor[] declaredConstructors = c1.getDeclaredConstructors();//获取当前Class所表示的类的所有构造器(包括public、protected、private修饰的)
//获得指定构造器
Constructor declaredConstructor = c1.getDeclaredConstructor();

递归获取父类

Class tempClass = c.class;
//获取自己和所有父类的属性(包括Object类的属性)
while (tempClass != null) {//当父类为null的时候说明到达了最上层的父类(Object类).
      fieldList.addAll(Arrays.asList(tempClass .getDeclaredFields()));
      tempClass = tempClass.getSuperclass(); //得到父类,然后赋给自己
}
//想屏蔽Object类的影响,可以为while循环再添加一个条件
!tmpClass.getName().toLowerCase().equals("java.lang.object") 


动态的创建对象,通过反射

//获得Class对象
Class c1=User.class;
//构造一个对象
User user1 =(User)c1.newInstance(); //本质是调用类的无参构造器
//通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class);
User user2 =(User)constructor.newInstance("wkf");

//通过反射调用普通方法
User user3=(User)c1.newInstance();
//通过反射获取一个方法
Method show= c1.getDeclaredMethod("show",String.class);
//invoke:激活(对象,方法参数)
show.invoke(user3, "锵锵锵");
		
//通过反射操作属性
User user4=(User)c1.newInstance();
Field name=c1.getDeclaredField("name");
//不能直接操作私有属性,需要关闭程序的安全检测,属性或者方法的setAccessible(true)
name.setAccessible(true);//关闭权限检测
name.set(user4,"wkf");

创建类的对象:调用Class对象的newInstance()方法

  1. 类必须有一个无参构造方法
  2. 类的构造方法访问权限需要足够

img

setAccessible

Method和Field,Constructor对象都有setAccessible(true)方法

作用:启动和禁用访问安全检查的开关

参数为true则指示的对象在使用时取消Java语言访问检查

  • 提高反射的效率
  • 使得原本无法访问的私有成员也可以访问

参数值为false则指示的对象应该实施Java语言访问检查

性能对比分析

img

反射操作泛型

Java采用泛型擦除的机制来引入泛型

Java中的泛型仅仅是给编译器Javac使用的,确保数据的安全和免区强制类型转换问题

但是,一旦编译完成,所有和泛型有关的类型全部擦除。

为了通过反射操作这些类型,Java新增了ParameteizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型

但是又和原始类型齐名的类型

ParameterizedType //表示一种参数化类型,比如Collection<String>
GenericArrayType  //表示一种元素类型是参数化类型或者类型变量的数组类型
TypeVariable      //是各种类型变量的公共接口
WildcardType      //代表一种通配符类型表达式

示例

//获取方法
Method method = User.class.getMethod("test01",Map.class,List.class);
//获取泛型的参数类型
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type t : genericParameterTypes) {
    System.out.println(t);
    //判断是否是结构化参数类型
    if (t instanceof ParameterizedType) {
		//强转,获得真实参数信息
		Type[] actualTypeArguments = ((ParameterizedType)t).getActualTypeArguments();
           for (Type tt:actualTypeArguments) {
			System.out.println(tt);
           }
    }
}


反射操作注解

//通过反射获得注解
public class Test12 {
   public static void main(String[] args) throws NoSuchFieldException, SecurityException {
      Tablex annotation = People.class.getAnnotation(Tablex.class);//获得指定注解
      //通过反射获得注解
      Annotation[] annotations = People.class.getAnnotations();
      for (Annotation annotation2 : annotations) {
         System.out.println(annotation2);
      }
      System.out.println(annotation.value());
      Field field = People.class.getDeclaredField("id");
      Fieldx f = field.getAnnotation(Fieldx.class);
      System.out.println(f.col());
      System.out.println(f.type());
      System.out.println(f.legth());
   }
}
@Tablex("db_People")
class People{
   @Fieldx(col="id",type="int",legth = 10)
   private int id;
   @Fieldx(col="name",type="varcher",legth = 3)
   private String name;
   @Fieldx(col="age",type="int",legth = 10)
   private int age;
   public People() {
      super();
   }
   public People(int id, String name, int age) {
      super();
      this.id = id;
      this.name = name;
      this.age = age;
   }
   public int getId() {
      return id;
   }
   public void setId(int id) {
      this.id = id;
   }
   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;
   }
   @Override
   public String toString() {
      return "People [id=" + id + ", name=" + name + ", age=" + age + "]";
   }
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Tablex{
   String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Fieldx{
   String col();
   String type();
   int legth();
}

posted @ 2022-10-19 09:07  克峰同学  阅读(15)  评论(0编辑  收藏  举报