Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。当然反射本身并不是一个新概念,它可能会使我们联想到光学中的反射概念,尽管计算机科学赋予了反射概念新的含义,但是,从现象上来说,它们确实有某些相通之处,这些有助于我们的理解。
Java反射机制主要提供下面几种用途:
二.在这里先看一下sun为我们提供了那些反射机制中的类:
java.lang.Class;一个比较特殊的类,它用于封装被装入到JVM中的类(包括类和接口)的信息。
java.lang.reflect.Constructor;
java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
很多反射中的方法,属性等操作我们可以从这四个类中查询。还是那句话要学着不断的查询API,那才是我们最好的老师。
java的Class类是java反射机制的基础,通过Class类我们可以获得一个类的相关信息。
下面我们来了解一下有关java中Class类的相关知识!
java.lang.Class是一个比较特殊的类,它用于封装被装入到JVM中的类(包括类和接口)的信息。
当一个类或接口被装入的JVM时便会产生一个与之关联的java.lang.Class对象,可以通过这个Class对象对被装入类的详细信息进行访问。
简单的说,获取某一个类所对应的Class对象可以通过如下三种途径:
1. Object的getClass方法(用于返回与调用该方法对象所属类关联的Class对象)
java.lang.Object中定义有getClass方法:public final Class getClass()
所有Java对象都具备这个方法。该方法用于返回与调用该方法对象所属类相关联的Class对象,例如:
Date date1 = new Date();
Date date2 = new Date();
Class c1 = date1.getClass();
Class c2 = date2.getClass();
System.out.println(c1.getName()); // java.util.Date
System.out.println(c1 == c2); // true
上面的代码中,调用Date对象date1的getClass方法将返回用于封装Date类信息的Class对象Date。接着调用了Class类的getName方法:
public String getName()
这个方法的含义很直观,即返回所封装的类的名称。
需要注意的是,代码中的date1和date2的getClass方法返回了相同的Class对象(c1==c2的值为true)。这是因为,对于相同的类,JVM只会载入一次,而与该类对应的Class对象也只会存在一个,无论该类实例化了多少对象。
另外,需要强调的是,当一个对象被其父类的引用或其实现的接口类型的引用所指向时,getClass方法返回的是与对象实际所属类关联的Class对象。例如:
List list = new ArrayList();
System.out.println(list.getClass().getName()); // java.util.ArrayList
上面的代码中,语句list.getClass()方法返回的是list所指向对象实际所属类java.util.ArrayList对应的 Class对象而并未java.util.List所对应的Class对象。有些时候可以通过这个方法了解一个对象的运行时类型,例如:
HashSet set = new HashSet();
Iterator it = set.iterator();
System.out.println(it.getClass().getName()); //java.util.HashMap$KeyIterator
从代码可以看出,HashSet的iterator方法返回的是实现了Iterator接口的HashMap内部类(KeyIterator)对象。
因为抽象类和接口不可能实例化对象,因此不能通过Object的getClass方法获得与抽象类和接口关联的Class对象。
2. 使用.class的方式
使用类名加“.class”的方式即会返回与该类对应的Class对象。例如:
Class clazz = String.class;
System.out.println(clazz.getName()); // java.lang.String
这个方法可以直接获得与指定类关联的Class对象,而并不需要有该类的对象存在。
3. 使用Class.forName方法
Class有一个著名的static方法forName:
public static Class forName(String className) throws ClassNotFoundException
该方法可以根据字符串参数所指定的类名获取与该类关联的Class对象。如果该类还没有被装入,该方法会将该类装入JVM。
该方法声明抛出ClassNotFoundException异常。顾名思义,当该方法无法获取需要装入的类时(例如,在当前类路径中不存在这个类),就会抛出这个异常。
例如,如果当前类路径中存在Foo类:
package org.whatisjava.reflect;
public class Foo {
public Foo() {
System.out.println("Foo()");
}
static {
System.out.println("Foo is initialized");
}
}
运行下面的代码:
Class clazz = Class.forName("org.whatisjava.reflect.Foo");
控制台会有如下输出:
Foo is initialized
Class.forName("org.whatisjava.reflect.Foo")首先会将reflection.Foo类装入JVM,并返回与之关联的Class对象。JVM装入Foo类后对其进行初始化,调用了其static块中的代码。所以控制台输出的是:Foo is initialized
,而只有当实例化Foo类对象时,才会执行其构造函数,输出:Foo()。
需要注意的是:forName方法的参数是类的完整限定名(即包含包名)。
区别于前面两种获取Class对象的方法。使用Class.forName方法所要获取的与之对应的Class对象的类可以通过字符串的方式给定。该方法通常用于在程序运行时根据类名动态的载入该类并获得与之对应的Class对象。
通过上面的文章相信你对java的反射机制有了一定的认识,同时也对java中Class类的用法有了比较清晰的理解,在我们实际工作的过程中,我们不断的运用java知识来解决实际生湖中的问题的时候我们就能对java反射机制有一个更深入的理解!
2.java访问修饰符—Modifier(英文:修饰语,修饰器) 在Class 、Field 、Constructor 等类中,可以看到有这样一个方法:getModifiers() ,它将以整数形式返回此 Constructor 对象所表示构造方法的 Java 语言修饰符.它的作用是返回一个类或者其成员的访问修饰符的int 类型常量,如需要知道返回的值所代表的意思,则需要了解java.lang.reflect.Modifier这个类, Modifier 类提供了 static
方法和常量,对类和成员访问修饰符进行解码。
如:
- import java.lang.reflect.Modifier;
- import java.lang.reflect.Field;
- public class A{
- private String str1;
- private static final String str2 = "str";
- public static void main(String[] args){
- Field[] fields = A.class.getDeclaredFields();
- for(Field f:fields){
- System.out.println("字段"+f.getName()+"访问修饰符是否包括 private:"+Modifier.isPrivate(f.getModifiers()));
- System.out.println("字段"+f.getName()+"访问修饰符是否包括 static:"+Modifier.isStatic(f.getModifiers()));
- System.out.println("字段"+f.getName()+"访问修饰符是否包括 public:"+Modifier.isPublic(f.getModifiers()));
- }
- }
- }
- //第一种方式:
- Class c1 = Class.forName("Employee");
- //第二种方式:
- //java中每个类型都有class 属性.
- Class c2 = Employee.class;
- //第三种方式:
- //java语言中任何一个java对象都有getClass 方法
- Employee e = new Employee();
- Class c3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)
- Class c =Class.forName("Employee");
- //创建此Class 对象所表示的类的一个新实例
- Object o = c.newInstance(); //调用了Employee的无参数构造方法.
3.获取属性:分为所有的属性和指定的属性:
a.先看获取所有的属性的写法:
- //获取整个类
- Class c = Class.forName("java.lang.Integer");
- //获取所有的属性
- Field[] fs = c.getDeclaredFields();
- //定义可变长的字符串,用来存储属性
- StringBuffer sb = new StringBuffer();
- //通过追加的方法,将每个属性拼接到此字符串中
- //最外边的public定义
- sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");
- //里边的每一个属性
- for(Field field:fs){
- sb.append("\t");//空格
- sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等
- sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字
- sb.append(field.getName()+";\n");//属性的名字+回车
- }
- sb.append("}");
- System.out.println(sb);
- public static void main(String[] args) throws Exception{
- <span style="white-space:pre"> </span>//以前的方式:
- /*
- User u = new User();
- u.age = 12; //set
- System.out.println(u.age); //get
- */
- //获取类
- Class c = Class.forName("User");
- //获取id属性
- Field idF = c.getDeclaredField("id");
- //实例化这个类赋给o
- Object o = c.newInstance();
- //打破封装
- idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。
- //给o对象的id属性赋值"110"
- idF.set(o, "110"); //set
- //get
- System.out.println(idF.get(o));
- }
方法关键字
含义
getDeclaredMethods()
获取所有的方法
getReturnType()
获得方法的放回类型
getParameterTypes()
获得方法的传入参数类型
getDeclaredMethod("方法名",参数类型.class,……)
获得特定的方法
构造方法关键字
含义
getDeclaredConstructors()
获取所有的构造方法
getDeclaredConstructor(参数类型.class,……)
获取特定的构造方法
父类和父接口
含义
getSuperclass()
获取某类的父类
getInterfaces()
获取某类实现的接口
这样我们就可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。
四.Java反射小结
- package com.reflection;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- import java.lang.reflect.Modifier;
- public class TestReflection {
- private String username;
- private String password;
- private int[] age;
- public void setUserName(String username) {
- this.username = username;
- }
- private void setPassWord(String password) {
- this.password = password;
- }
- public static void test01() throws ClassNotFoundException {
- Class c1 = TestReflection.class;
- Class c2 = Class.forName("com.reflection.TestReflection");
- //获取指定的包名
- String package01 = c1.getPackage().getName();
- String package02 = c2.getPackage().getName();
- System.out.println("package01 = " + package01);
- System.out.println("package02 = " + package02);
- //获取类的修饰符
- int mod = c1.getModifiers();
- String modifier = Modifier.toString(mod);
- System.out.println("modifier = " + modifier);
- //获取指定类的完全限定名
- String className = c1.getName();
- System.out.println("className = " + className);
- //获取指定类的父类
- Class superClazz = c1.getSuperclass();
- String superClazzName = superClazz.getName();
- System.out.println("superClazzName = " + superClazzName);
- //获取实现的接口
- Class[] interfaces = c1.getInterfaces();
- for (Class t : interfaces) {
- System.out.println("interfacesName = " + t.getName());
- }
- //获取指定类的成员变量
- Field[] fields = c1.getDeclaredFields();
- for (Field field : fields) {
- modifier = Modifier.toString(field.getModifiers());
- //获取每个字段的访问修饰符
- Class type = field.getType();
- //获取字段的数据类型所对应的Class对象
- String name = field.getName();
- //获取字段名
- if (type.isArray()) {
- //如果是数组类型则需要特别处理
- String arrType = type.getComponentType().getName() +"[]";
- System.out.println("" + modifier + " " + arrType + " "
- + name + ";");
- } else {
- System.out.println("" + modifier + " " + type + " " +
- name + ";");
- }
- }
- //获取类的构造方法
- Constructor[] constructors = c1.getDeclaredConstructors();
- for (Constructor constructor : constructors) {
- String name = constructor.getName();
- //构造方法名
- modifier = Modifier.toString(constructor.getModifiers());
- //获取访问修饰符
- System.out.println("" + modifier +" " + name + "(");
- Class[] paramTypes = constructor.getParameterTypes();
- //获取构造方法中的参数
- for (int i = 0; i < paramTypes.length; i++) {
- if (i > 0) {
- System.out.print(",");
- }
- if (paramTypes[i].isArray()) {
- System.out.println(paramTypes
- [i].getComponentType().getName()+"[]");
- } else {
- System.out.print(paramTypes[i].getName());
- }
- }
- System.out.println(");");
- }
- //获取成员方法
- Method[] methods = c1.getDeclaredMethods();
- for (Method method: methods) {
- modifier = Modifier.toString(method.getModifiers());
- Class returnType = method.getReturnType();
- //获取方法的返回类型
- if (returnType.isArray()) {
- String arrType = returnType.getComponentType
- ().getName()+"[]";
- System.out.print(""+modifier+" " + arrType + " " +
- method.getName() + "(");
- } else {
- System.out.print("" + modifier + " " +
- returnType.getName() + " " + method.getName() + "(");
- }
- Class[] paramTypes = method.getParameterTypes();
- for (int i = 0; i < paramTypes.length; i++) {
- if (i > 0) {
- System.out.print(",");
- }
- if (paramTypes[i].isArray()) {
- System.out.println(paramTypes
- [i].getComponentType().getName()+"[]");
- } else {
- System.out.print(paramTypes[i].getName());
- }
- }
- System.out.println(");");
- }
- }
- public static void test02() throws InstantiationException,
- IllegalAccessException, SecurityException, NoSuchMethodException,
- IllegalArgumentException, InvocationTargetException {
- //反射调用方法,可以通过Method类的invoke方法实现动态方法的调用
- //public Object invoke(Object obj, Object... args)
- //第一个参数代表对象
- //第二个参数代表执行方法上的参数
- //若反射要调用类的某个私有方法,可以在这个私有方法对应的Mehtod对象上先调用setAccessible(true)
- Class c1 = TestReflection.class;
- TestReflection t1 = (TestReflection) c1.newInstance();
- //利用反射来创建类的对象
- System.out.println("username == " + t1.username);
- System.out.println("password == " + t1.password);
- Method method = c1.getDeclaredMethod("setUserName", String.class);
- method.invoke(t1, "Java反射的学习");
- System.out.println("username == " + t1.username);
- method = c1.getDeclaredMethod("setPassWord", String.class);
- method.setAccessible(true);
- method.invoke(t1, "反射执行某个Private修饰的方法");
- System.out.println("password == " + t1.password);
- }
- public static void main(String[] args) throws ClassNotFoundException,
- SecurityException, IllegalArgumentException, InstantiationException,
- IllegalAccessException, NoSuchMethodException, InvocationTargetException {
- // test01();
- test02();
- }
- }