浅谈Java的反射机制

 概述

Java反射是可以让我们在运行时获得类的方法、属性、父类、接口等类的内部信息的机制。也就是说反射本身是一个“反着来”的过程。我们通过new创建类的实例时实际上是JVM在运行时根据这个类的class对象构建出来的,而反射是在运行时通过类的class对象获得他的内部定义信息。

Class类

我们知道使用javac能够将.java文件编译成.class文件,这个.class文件包含了我们对类的原始定义信息(构造函数、方法、属性、父类、接口等)。我们又知道.class文件在运行时会被类加载器(ClassLoader)加载到JVM中,当一个.class文件被加载后,JVM会为之生成一个class对象,我们在程序中通过new实例化的对象实际上是在运行时根据相应的class对象构造出来的。确切的说这个class对象是java.lang.Class<T>泛型类的一个实例比如Class<Human>对象即为一个封装了Human类的定义信息的Class<T>实例。由于java.lang.Class<T>类不存在公有构造函数,因此我们不能直接实例化这个类,我们可以通过一下方法获得一个class对象。例如我们定义了一个Human类

class Human {
    private String sex;//性别
    private Integer age;//年龄
   public Human(String sex,Integer age){
       this.sex=sex;
       this.age=age;
   }
  public void eat(){//吃饭行为
    	System.out.println("吃早餐");
    }
}

1)通过类名获取其class对象

Class<Human> humanClass=Human.class;
2)通过类的完整路径名获取其class对象

try {
  Class<Human> humanClass2=(Class<Human>) Class.forName("javaBasic.Human");
} catch (ClassNotFoundException e) {
  e.printStackTrace();
  }
3)通过对象本身获取其class对象
Human h=new Human();
Class<Human> humanClass3=(Class<Human>) h.getClass();
通过反射获取类中定义的内部信息

1) 获取类构造器

一旦我们获得了Human的class对象,我们就能够通过这个class对象获得Human类的原始定义信息,首先我们来获取Human类的构造器对象,有了构造器对象我们就能够构造出一个Human对象出来。注意,当通过反射获取到类的 Constructor、Method、Field对象后,在调用这些对象的方法之前,先将此对象的 accessible 标志设置为 true,以取消 Java 语言访问检查,可以提升反射速度。

Class<Human> humanClass=Human.class;
try {
	Constructor<Human> c=humanClass.getConstructor(String.class,Integer.class);
        c.setAccessible(true);
       Human human=c.newInstance("男","21");
	human.eat();
} catch (Exception e) {
	e.printStackTrace();
} 

2) 获取类中定义的方法

要获取当前类中定义的方法可以用Class中的getDeclareMethods函数,他会获得当前类中定义的所有的方法(包括public、private、static等方法),它会返回一个Method对象数组,其中每一个Method的对象即表示类中定义的一个方法。要想获得类中定义的指定的方法可以用getDeclareMethod(Stirng name,Class...<T>parameterType)。

try {
		Class<Human> humanClass=Human.class;
		Human human=humanClass.newInstance();//初始化对象
		Method[] methods=humanClass.getDeclaredMethods();
		for(Method method:methods){
			System.out.println("方法名:"+method.getName());
		}
		//获得指定的方法
			Method eat=humanClass.getDeclaredMethod("eat", String.class);
			if(Modifier.isPrivate(eat.getModifiers())){//判断eat()的作用域是否为私有
				System.out.println("private");
			}
			eat.invoke(human);//调用eat()方法
		} catch (Exception e) {
			e.printStackTrace();
		} 
3)获取类中定义的属性

获取属性和获取方法类似,只不过将getMethod()换成了getField(),getDeclaredMethod()换成了getDeclareField()。

try {
		Class<Human> humanClass=Human.class;
		Field[] fields=humanClass.getDeclaredFields();
		for(Field field:fields){
			System.out.println("属性名:"+field.getName());
		}
		//获得指定的属性
		Field sex=humanClass.getDeclaredField("sex");
		} catch (Exception e) {
			e.printStackTrace();
		} 
4)获取父类和接口
我们先定义一个子类Man去继承Human类,如下,

class Man extends Human{
	private String beard;//有胡子
	@Override
	 public void eat(){//吃饭行为
    	System.out.println("只吃午餐");
    }
}
然后通过class对象的getSuperClass()得到man的父类,通过getInterFaces获取接口。

Class<Man> manClass=Man.class;
Class<?> humanClass= manClass.getSuperclass();
Class<?>[] interfaces = manClass.getInterfaces();
for (Class<?> i : interfaces) {
   System.out.println(i.getName());
}
总结
Java 反射是可以让我们在运行时获取类的函数、属性、父类、接口等 Class 内部信息的机制。通过反射还可以让我们在运行期实例化对象,调用方法,通过调用 get/set 方法获取变量的值,即使方法或属性是私有的的也可以通过反射的形式调用,这种“看透 class”的能力被称为内省,这种能力在框架开发中尤为重要。 有些情况下,我们要使用的类在运行时才会确定,这个时候我们不能在编译期就使用它,因此只能通过反射的形式来使用在运行时才存在的类(该类符合某种特定的规范,例如 JDBC),这是反射用得比较多的场景。
还有一个比较常见的场景就是编译时我们对于类的内部信息不可知,必须得到运行时才能获取类的具体信息。比如 ORM 框架,在运行时才能够获取类中的各个属性,然后通过反射的形式获取其属性名和值,存入数据库。这也是反射比较经典应用场景之一。



  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java反射机制是指在运行时动态地获取一个类的信息,并可以操作类的属性、方法和构造器等。Java反射机制可以使程序员在运行时动态地调用类的方法和属性,扩展类的功能,并可以实现注解、工厂模式以及框架开发等。 Java反射机制的原理如下:首先,Java编译器将Java源代码编译为字节码文件,字节码文件中包含着类的信息,这些信息包括类的名称、方法、属性和构造器等等。接着,Java虚拟机将字节码文件加载到内存中,然后通过类加载器将类加载到内存中形成一个类对象,这个类对象可以操作字节码文件中的信息。 使用Java反射机制的过程如下:首先获取类对象,通过类对象来获取类的构造器、属性、方法等信息,然后调用构造器来创建对象,通过属性获取和设置类的成员属性,通过方法调用类的方法等。 Java反射机制的优点是可以在运行时动态地得到类的信息,使得程序员在程序运行时能够对类进行更加灵活的操作,并可以使得程序更加通用化,同时也存在着一定的性能问题,因为Java反射机制需要Java虚拟机进行一定的额外处理,所以在程序运行时需要进行额外的时间和资源消耗。 总之,Java反射机制Java语言的一项重要特性,在Java开发中广泛应用,在代码编写、框架开发以及API开发中具有重要作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值