首页 > 编程语言 >Java反射

Java反射

时间:2022-10-18 15:55:06浏览次数:45  
标签:反射 Java name 对象 class Class c1 public

简介

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();
}

标签:反射,Java,name,对象,class,Class,c1,public
From: https://www.cnblogs.com/KeFeng/p/16772895.html

相关文章

  • java数据结构与算法
    直接在java中一直使用原生的Stack作为栈,看到大佬们都改用Deque了,因此使用Deque作为栈做一个练习。这是leetCode一个题目,我直接截个图吧  本题目可以分解为两个问题:......
  • 力扣523(java)-连续的子数组和(中等)
    题目:给你一个整数数组nums和一个整数 k,编写一个函数来判断该数组是否含有同时满足下述条件的连续子数组:子数组大小至少为2,且子数组元素总和为k的倍数。如果存......
  • Java并发编程学习7-阻塞队列
    阻塞队列介绍阻塞队列之前,先来介绍下队列Queue。Queue用来临时保存一组等待处理的元素。它提供了几种非阻塞队列实现,如下:ConcurrentLinkedQueue,这是一个传统的先进先出......
  • JavaScript 获取两个时间相差的周数
    exportfunctiongetWeek(date1,date2){letd1=newDate(date1);letd2=newDate(date2);console.log(Math.ceil(parseInt(((d2-d1)/(1000*3......
  • java学习笔记38
    面向对象什么是多态1.多态概述多态是继封装、继承之后,面向对象的第三大特性。2.多态现实意义理解:现实事物经常会体现出多种形态,如学生,学生是人的一种,则一个具体的同学......
  • Java数据结构_Collection类
     双链表结构     LinkedList可以完成队列结构栈结构(双向链表)栈对头结点进行add和removepop的底层就是pu......
  • JAVA项目中常见的异常处理汇总
    在进行JAVA项目开发时,不免会遇到一些比较常见的异常处理情况,下面是我通过在网上查询了一些相关资料进行的各种异常处理情况的总结1.字符串转化为数字的异常(Java.lang.Numb......
  • Java代码审计sql注入
    java_sec_code该项目也可以叫做JavaVulnerabilityCode(Java漏洞代码)。每个漏洞类型代码默认存在安全漏洞(除非本身不存在漏洞),相关修复代码在注释里。具体可查看每个漏......
  • JavaScript的日期对象的使用Date
    1<script>2letdate=newDate();//返回的是当前的时间3console.log(date.getFullYear());//获取的当前年份4console.log(date.getMonth()+1);......
  • Java8Stream的flatmap应用(区别map)-优化嵌套for循环条件筛选
    场景Java8新特性-Stream对集合进行操作的常用API:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/126070657前面讲Stream的常用api中讲到map的使用......