java反射机制

反射

1.反射机制

  • 概念:
    • 简述:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性==;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
    • 详述:Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过ReflectionAPIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static等)、superclass(例如Object),实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。
    • 类型信息在jvm里也是作为一个对象 只保留一份

2.反射机制功能

  • 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

3. Reflection API

  • 当然JDK提供了反射API,我们可以学习里面的方法来取得任何已知名称的类的内部信息。

Class对象的获取

  • 对象的getClass()方法;
  • 类的.class(最安全/性能最好)属性;
  • 运用Class.forName(String className)动态加载类,className需要是类的全限定名(最常用).

对象创建

  • 通过反射来生成对象的方式有两种:
    • 使用Class对象的newInstance() 方法来创建该Class对象对应类的实例(这种方式要求该Class对象的对应类有默认构造器).
    • 先使用Class对象获取指定的Constructor对象, 再调用Constructor对象的newInstance() 方法来创建该Class对象对应类的实例(通过这种方式可以选择指定的构造器来创建实例).

从Class中获取信息

  • 获取类内信息
内容 方法 说明
构造器 类对象.getConstructors() 获取所有public修饰的构造方法, 返回数组
构造器 类对象.getDeclareConstructors() 获取本类所有构造方法,返回数组
构造器 类对象.getConstructor(参数) 获取指定的构造方法,返回对象
构造器 类对象.getConstructor() 获取无参构造,返回对象
包含的方法 类对象.getMethods() 获取所有public方法,包括继承的 返回数组
包含的方法 类对象.getDeclaredMethods() 获取本类的所有方法,返回数组
包含的方法 类对象.getMethod(String name, Class… parameterTypes) 获取指定的公共方法 ,返回对象
包含的方法 getDeclaredMethod(String name, Class… parameterTypes) 返回一个Method对象,该对象反映此Class对象表示的类或接口的指定声明方法 。
获取属性信息 类对象.getFields() 获取所有的公共属性 (包括继承)
获取属性信息 类对象.getDeclareFields() 获取本类属性
获取属性信息 类对象.getField(属性名) 根据属性名找属性 公共的 包括继承
获取属性信息 类对象.getDeclaredField(属性名)

本类所有属性

  • 上面的仅是一些使用基础API,具体的请参照Reflection API

4.调用方法

  • 当获取到某个类对应的Class对象之后, 就可以通过该Class对象的getMethod来获取一个Method数组或Method对象.每个Method对象对应一个方法,在获得Method对象之后,就可以通过调用invoke方法来调用该Method对象对应的方法.
    • 缺点:调用复杂,效率底
    • 优点:可以调用私有方法

5.setAccessible方法(性能)

  • Method/Constructor/Field/Element都继承了AccessibleObject,AccessibleObject类中有一个setAccessible方法
  • 该方法有两个作用:
    • 启用/禁用访问安全检查开关:值为true,则指示反射的对象在使用时取消Java语言访问检查;值为false,则指示应该实施Java语言的访问检查;
    • 可以禁止安全检查, 提高反射的运行效率.

6.代码–方便理解

代码摘自大神博客敬业的小码哥


package fanshe;
/**
 * 获取Class对象的三种方式
 * 1 Object ——> getClass();
 * 2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
 * 3 通过Class类的静态方法:forName(String  className)(常用)
 *
 */
public class Fanshe {
	public static void main(String[] args) {
		//第一种方式获取Class对象  
		Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。
		Class stuClass = stu1.getClass();//获取Class对象
		System.out.println(stuClass.getName());
		
		//第二种方式获取Class对象
		Class stuClass2 = Student.class;
		System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
		
		//第三种方式获取Class对象
		try {
			Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名
			System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
	}
}

```java
注意:在运行期间,一个类,只有一个Class对象产生。
三种方式常用第三种,第一种对象都有了还要反射干什么。第二种需要导入类的包,依赖太强,不导包就抛编译错误。一般都第三种,一个字符串可以传入也可写在配置文件中等多种方法。


```java

package fanshe;
 
public class Student {
	
	//---------------构造方法-------------------
	//(默认的构造方法)
	Student(String str){
		System.out.println("(默认)的构造方法 s = " + str);
	}
	
	//无参构造方法
	public Student(){
		System.out.println("调用了公有、无参构造方法执行了。。。");
	}
	
	//有一个参数的构造方法
	public Student(char name){
		System.out.println("姓名:" + name);
	}
	
	//有多个参数的构造方法
	public Student(String name ,int age){
		System.out.println("姓名:"+name+"年龄:"+ age);//这的执行效率有问题,以后解决。
	}
	
	//受保护的构造方法
	protected Student(boolean n){
		System.out.println("受保护的构造方法 n = " + n);
	}
	
	//私有构造方法
	private Student(int age){
		System.out.println("私有的构造方法   年龄:"+ age);
	}
 
}
package fanshe;
 
import java.lang.reflect.Constructor;
 
 
/*
 * 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
 * 
 * 1.获取构造方法:
 * 		1).批量的方法:
 * 			public Constructor[] getConstructors():所有"公有的"构造方法
            public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
     
 * 		2).获取单个的方法,并调用:
 * 			public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
 * 			public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
 * 		
 * 			调用构造方法:
 * 			Constructor-->newInstance(Object... initargs)
 */
public class Constructors {
 
	public static void main(String[] args) throws Exception {
		//1.加载Class对象
		Class clazz = Class.forName("fanshe.Student");
		
		
		//2.获取所有公有构造方法
		System.out.println("**********************所有公有构造方法*********************************");
		Constructor[] conArray = clazz.getConstructors();
		for(Constructor c : conArray){
			System.out.println(c);
		}
		
		
		System.out.println("************所有的构造方法(包括:私有、受保护、默认、公有)***************");
		conArray = clazz.getDeclaredConstructors();
		for(Constructor c : conArray){
			System.out.println(c);
		}
		
		System.out.println("*****************获取公有、无参的构造方法*******************************");
		Constructor con = clazz.getConstructor(null);
		//1>、因为是无参的构造方法所以类型是一个null,不写也可以:这里需要的是一个参数的类型,切记是类型
		//2>、返回的是描述这个无参构造函数的类对象。
	
		System.out.println("con = " + con);
		//调用构造方法
		Object obj = con.newInstance();
	//	System.out.println("obj = " + obj);
	//	Student stu = (Student)obj;
		
		System.out.println("******************获取私有构造方法,并调用*******************************");
		con = clazz.getDeclaredConstructor(char.class);
		System.out.println(con);
		//调用构造方法
		con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
		obj = con.newInstance('男');
	}
	
}

  • 输出
**********************所有公有构造方法*********************************
public fanshe.Student(java.lang.String,int)
public fanshe.Student(char)
public fanshe.Student()
************所有的构造方法(包括:私有、受保护、默认、公有)***************
private fanshe.Student(int)
protected fanshe.Student(boolean)
public fanshe.Student(java.lang.String,int)
public fanshe.Student(char)
public fanshe.Student()
fanshe.Student(java.lang.String)
*****************获取公有、无参的构造方法*******************************
con = public fanshe.Student()
调用了公有、无参构造方法执行了。。。
******************获取私有构造方法,并调用*******************************
public fanshe.Student(char)
姓名:男

其他代码还请参考上面大神的博客:多多练习

你可能感兴趣的:(java思想,编程语言,jvm原理,java反射,反射机制)