Java之反射详解

反射API在java是非常强大和有用的, 比如现在流行的框架Spring, Hibernate, Junit 等等这些J2EE框架中都有大量使用,而且是作为核心功能!先来了解一下反射的用处,本文中会结合实例一起来实战练习这些API的使用
反射机制是java一直在进步的原因之一,它可以:
1、在应用程序运行时查看和修改程序的行为
2、可以查看类、接口、枚举、得到类的内部结构、方法和运行时的信息
3、通过反射来实例化他的对象来改变字段的值和调用方法执行
==================================华丽的分割线==================================
目录:
1、前言
2、类的反射

  • 获取类对象
  • 获取超类
  • 获取类的公共成员
  • 获取声明的类
  • 获取声明的当前类
  • 获取包名
  • 获取类的修饰符
  • 获取类的参数类型
  • 获取实现类的接口
  • 获取所有的公共方法
  • 获取类所有的公共构造函数
  • 获取所有的公共字段
  • 获取所有的注解

3、字段的反射
  • 获取公共字段
  • 获取当前字段所在类
  • 获取字段类型
  • Set/Get公共字段
  • Set/Get私有字段

4、方法的反射
  • 获取公共方法
  • 调用公共方法
  • 调用私有方法

5、构造函数反射
  • 获取公共方法的构造函数
  • 通过构造函数实例化对象

==================================华丽的分割线==================================
一、前言
我们正常的程序就不用使用发射了,因为对象啥都有了! 我这里要提的是反射在访问类和接口时的一些弊端:
1、性能:由于是动态的去解析类型,要先去查找类路径和加载类信息导致性能下降
2、安全问题:由于反射是可以访问类的所有方法,当有一些私有的方法被访问到,就存在了一定的风险了;会出现异常!
3、维护难:反射的代码一般都比较难维护和调试
二、类的反射
在Java中每个对象都可以是基本类型或者引用, 类、接口、数组、枚举等的引用都继承自Object对象,基本类型:【int chart double boolean byte short float long】

对于反射操作, java.lang.class是他的入口点, JVM为每一个对象类型都保存了一个不可变的对象实例, 该实例提供一些方法来检查对象的属性和创建新的方法, 还可以调用方法去修改属性字段值等

为了验证这些我先创建一个类继承接口的多层次结构类
BaseInterface.java 
package com.gyj.reflection;

public interface BaseInterface {
	public int interFaceInt = 0;
	
	void method1();
	
	int method2(String str);
}


BaseClass.java
package com.gyj.reflection;

public class BaseClass {

	private int baseInt;
	
	private static void method3() {
		System.out.println("method3");
	}
	
	private int method4() {
		System.out.println("method4");
		return 0;
	}
	
	public static void method5() {
		System.out.println("method5");
	}

	void method6() {
		System.out.println("method6");
	}
	
	//内部类
	public class BaseClassInnerClass{}
	
	//枚举
	public enum BaseClassMemberEnum{}
}

Concrete.java
package com.gyj.reflection;



import javax.annotation.Resource;

@Resource
public class Concrete extends BaseClass implements BaseInterface{
	public int publicInt;
	private String privateString = "private string";
	protected boolean protectedBoolean;
	Object defaultObject;
	
	public Concrete(int i) {
		this.publicInt = i;
	}
	
	/**
	 * @param args
	 * @throws ClassNotFoundException 
	 */
	public static void main(String[] args) throws ClassNotFoundException {
		
		
	}

	@Override
	public void method1() {
		System.out.println("method1 impl");
	}

	@Override
	public int method2(String str) {
		System.out.println("method2 impl");
		return 0;
	}
	
	public int method4() {
		System.out.println("重写 method4 ");
		return 0;
	}
	
	public int method5(int i) {
		System.out.println("重写 method4 ");
		return 0;
	}
	
	// 内部类
	public class ConcreteClassPublicClass{}
	private class ConcreteClassPrivateClass{}
	protected class ConcreteClassProtectedClass{}
	class ConcreteClassDefualtClass{}
	
	// 枚举
	enum ConcreteClassDefultEnum{}
	public enum ConcreteClassPublicEnum{}
	
	// 接口
    public interface ConcreteClassPublicInterface{}

    
    
    
    
    
    
    
	public int getPublicInt() {
		return publicInt;
	}

	public void setPublicInt(int publicInt) {
		this.publicInt = publicInt;
	}

	public String getPrivateString() {
		return privateString;
	}

	public void setPrivateString(String privateString) {
		this.privateString = privateString;
	}
    
    
}



=============================================================================================================================================
  • 获取类对象
  •    通常获取类的对象有三种方法,一种是直接使用类的静态变量, 一种是对象的.class()
       还有就是java.lang.class.forName方法,对于基本数据类型我们用类的静态变量,具体看demo实例;
    Class<?> concreteClass = Concrete.class.getClass();
    concreteClass = new Concrete(5).getClass();
    try {
    	concreteClass = Class.forName("com.gyj.reflection.Concrete");
       } catch (ClassNotFoundException e) {
    	e.printStackTrace();
    }
    System.out.println(concreteClass.getCanonicalName());
    //============对于基本类型、包装类、数组===========
    Class<?> booleanClass = boolean.class;
    System.out.println(booleanClass.getCanonicalName());
    		
    Class<?> cDouble = Double.TYPE;
    System.out.println(cDouble.getCanonicalName());
    		
    Class<?> cDoubleArray = Class.forName("[D");
    System.out.println(cDoubleArray.getCanonicalName());
    		
    Class<?> twoDStringArray = String[][].class;
    System.out.println(twoDStringArray.getCanonicalName());
    		
    //out put========================
    com.gyj.reflection.Concrete
    boolean
    double
    double[]
    java.lang.String[][]
    

  • 获取超类
  • getSuperclass()方法返回当前类的超类,如果当前类是object 则返回null 数组、接口返回Object 类

    Class<?> superClass = Class.forName("com.gyj.reflection.Concrete").getSuperclass();
    System.out.println("===========得到超类==========");
    System.out.println(superClass);
    System.out.println(Object.class.getSuperclass());
    System.out.println(String[][].class.getSuperclass());
    
    out put===========
    class com.gyj.reflection.BaseClass
    null
    class java.lang.Object
    

  • 获取类的公共成员
  • getClasse()方法返回一个类中所有公共类、接口、枚举的数组,包括了从父类中继承过来的,如果没有则返回长度为0的数组

    Class<?>[] classes = Concrete.class.getClasses();
    System.out.println(Arrays.toString(classes));
    
    //out put=================
    [class com.gyj.reflection.Concrete$ConcreteClassPublicClass, 
    class com.gyj.reflection.Concrete$ConcreteClassPublicEnum,
    interface com.gyj.reflection.Concrete$ConcreteClassPublicInterface,
    class com.gyj.reflection.BaseClass$BaseClassInnerClass, 
    class com.gyj.reflection.BaseClass$BaseClassMemberEnum]
    
  • 获取全部声明的类
  • getDeclaredClasses() 方法返回当前Class类中声明的类,包括继承和接口的类
    Class<?>[] explicitClasses = Class.forName("com.gyj.reflection.Concrete").getDeclaredClasses();
    System.out.println(Arrays.toString(explicitClasses));
    
    //out put================
    [class com.gyj.reflection.Concrete$ConcreteClassDefualtClass, 
    class com.gyj.reflection.Concrete$ConcreteClassDefultEnum, 
    class com.gyj.reflection.Concrete$ConcreteClassPrivateClass, 
    class com.gyj.reflection.Concrete$ConcreteClassProtectedClass, 
    class com.gyj.reflection.Concrete$ConcreteClassPublicClass, 
    class com.gyj.reflection.Concrete$ConcreteClassPublicEnum, 
    interface com.gyj.reflection.Concrete$ConcreteClassPublicInterface]
    
    


  • 获取当前声明的类
  • getDeclaringClass()方法返回一个当前被其声明的类成员对象

    Class<?> innerClass = Class.forName("com.gyj.reflection.Concrete$ConcreteClassPublicInterface");
    System.out.println(innerClass.getEnclosingClass().getCanonicalName());
    System.out.println(innerClass.getDeclaringClass().getCanonicalName());
    
    //out put================
    com.gyj.reflection.Concrete
    com.gyj.reflection.Concrete
    

  • 获取包名
  • System.out.println(Class.forName("com.gyj.reflection.Concrete").getPackage().getName());
    out put================
    com.gyj.reflection


  • 获取类的修饰符
  • System.out.println(Modifier.toString(Concrete.class.getModifiers()));
    System.out.println(Modifier.toString(Class.forName("com.gyj.reflection.Concrete").getModifiers()));
    System.out.println((Modifier.toString(Concrete.class.getModifiers())).equals(Modifier.toString(Class.forName("com.gyj.reflection.Concrete").getModifiers())));
    
    //out put================
    public
    public
    true


  • 获取类的参数类型
  • 就以HashMap为例子,大家知道他的参数类型是‘K V’
    TypeVariable<?>[] typeVariables = Class.forName("java.util.HashMap").getTypeParameters();
    for (TypeVariable<?> typeVariable : typeVariables) {
    	System.out.println(typeVariable.getName() + ",");
    }
    
    //out put===============
    K,
    V,
    


  • 获取实现类的接口
  • System.out.println(Arrays.toString(Class.forName("java.util.HashMap").getInterfaces()));
    
    //out put===============
    [interface java.util.Map, interface java.lang.Cloneable, interface java.io.Serializable]
    

  • 获取所有的公共方法
  • getMethods()返回的是包括该类以及他的父类和接口所有的公共方法的数组集合

    Method[] publicMethods = Class.forName("com.gyj.reflection.Concrete").getMethods();
    System.out.println("=========类的公共方法==========");
    System.out.println(Arrays.toString(publicMethods));
    
    //out put==============
    [public static void com.gyj.reflection.Concrete.main(java.lang.String[]) throws java.lang.ClassNotFoundException, public java.lang.String com.gyj.reflection.Concrete.getPrivateString(), 
    public void com.gyj.reflection.Concrete.setPrivateString(java.lang.String), 
    public void com.gyj.reflection.Concrete.method1(), 
    public int com.gyj.reflection.Concrete.method2(java.lang.String), 
    public int com.gyj.reflection.Concrete.method4(), 
    public int com.gyj.reflection.Concrete.method5(int), 
    public int com.gyj.reflection.Concrete.getPublicInt(), 
    public void com.gyj.reflection.Concrete.setPublicInt(int), 
    public static void com.gyj.reflection.BaseClass.method5(),
    public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException,
    public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException,
    public final void java.lang.Object.wait() throws java.lang.InterruptedException, 
    public boolean java.lang.Object.equals(java.lang.Object), 
    public java.lang.String java.lang.Object.toString(), 
    public native int java.lang.Object.hashCode(), 
    public final native java.lang.Class java.lang.Object.getClass(), 
    public final native void java.lang.Object.notify(), 
    public final native void java.lang.Object.notifyAll()]
    
    //ps:大家可以数数看是不是有这么多,自己试试!
    


  • 获取类所有的公共构造函数
  • Constructor<?>[] publicConstructors = Class.forName("com.gyj.reflection.Concrete").getConstructors();
    System.out.println(Arrays.toString(publicConstructors));
    
    //out put==============
    [public com.gyj.reflection.Concrete(int)]
    

  • 获取所有的公共字段
  • getFields()得到包括接口以及父类的所有公共字段

    Field[] publicField = Class.forName("com.gyj.reflection.Concrete").getFields();
    System.out.println(Arrays.toString(publicField));
    
    //out put==============
    [public int com.gyj.reflection.Concrete.publicInt,
     public static final int com.gyj.reflection.BaseInterface.interFaceInt]
    



  • 获取所有的注解
  • Annotation[] annotations = Class.forName("com.gyj.reflection.Concrete").getAnnotations();
    System.out.println(Arrays.toString(annotations));
    
    //out put==============
    [@javax.annotation.Resource(shareable=true, mappedName=, description=, name=, type=class java.lang.Object, authenticationType=CONTAINER, lookup=)]
    


    三、字段的反射
  • 获取公共字段
  • try {
    	Field field = Class.forName("com.gyj.reflection.Concrete").getField("interFaceInt");
    	System.out.println(field.getName());
    } catch (NoSuchFieldException e) {
    	e.printStackTrace();
    } catch (SecurityException e) {
    	e.printStackTrace();
    }
    
    //out put============
    interFaceInt
    

  • 获取当前字段所在类
  • try {
    	Field field = Class.forName("com.gyj.reflection.Concrete").getField("interFaceInt");
    	Class<?> fieldClass = field.getDeclaringClass();
    	System.out.println(fieldClass.getCanonicalName());
    } catch (NoSuchFieldException e) {
    	e.printStackTrace();
    } catch (SecurityException e) {
    	e.printStackTrace();
    }
    
    //out put============
    com.gyj.reflection.BaseInterface
    

  • 获取字段类型
  • try {
    	Field field = Class.forName("com.gyj.reflection.Concrete").getField("interFaceInt");
    	Class<?> fieldClass = field.getType();
    	System.out.println(fieldClass.getCanonicalName());
    } catch (NoSuchFieldException e) {
    	e.printStackTrace();
    } catch (SecurityException e) {
    	e.printStackTrace();
    }
    
    //out put=============
    int
    

  • Set/Get公共字段
  • try {
    	Field field = Class.forName("com.gyj.reflection.Concrete").getField("publicInt");
    	Concrete obj = new Concrete(5);
    	try {
    		Object o = field.get(obj);
    		System.out.println("字段值 = " + o);
    		field.setInt(obj, 10);
    		System.out.println("字段值 = " + field.get(obj));
    	} catch (IllegalArgumentException | IllegalAccessException e) {
    		e.printStackTrace();
    	}
    } catch (NoSuchFieldException | SecurityException e) {
    	e.printStackTrace();
    }
    //out put===============
    字段值 = 5
    字段值 = 10
    //get()  方法返回的是一个对象,如果字段是基本类型则返回他的基本包装类。
    //设置值的时候,如果该字段是final类型则会抛异常java.lang.IllegalAccessException
    


  • Set/Get私有字段
  • try {
    	Field privateField = Class.forName("com.gyj.reflection.Concrete").getDeclaredField("privateString");
    	privateField.setAccessible(true);
    	Concrete concrete = new Concrete(12);
    	try {
    		System.out.println(privateField.get(concrete));
    		privateField.set(concrete, "update string");
    		System.out.println(privateField.get(concrete));
    	} catch (IllegalArgumentException | IllegalAccessException e) {
    		e.printStackTrace();
    	}
    } catch (NoSuchFieldException | SecurityException e) {
    	e.printStackTrace();
    }
    
    //out put==============
    private string
    update string
    
    


    四、方法的反射
  • 获取公共方法
  • getMethod()获取类的公共方法,其中参数形式为(方法名,参数类型) 如果在当前类中没有找到相应的方法,则会在父类中需找;

    try {
    	Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);
    	System.out.println("===========HashMap 方法的参数类型是============");
    	System.out.println("方法参数类型 " + Arrays.toString(method.getParameterTypes()));
    	System.out.println("方法返回类型 " + method.getReturnType());
    	System.out.println("方法修饰类型 " + Modifier.toString(method.getModifiers()));
    } catch (NoSuchMethodException | SecurityException e) {
    	e.printStackTrace();
    }
    
    //out put=============
    方法参数类型 [class java.lang.Object, class java.lang.Object]
    方法返回类型 class java.lang.Object
    方法修饰类型 public
    

  • 调用公共方法
  • try {
    	Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);
    	Map<String, Object> map = new HashMap<String, Object>();
    	try {
    		method.invoke(map, "key", "value");
    		System.out.println("===========调用公共方法===========");
    		System.out.println("map = " + map);
    	} catch (IllegalAccessException | IllegalArgumentException
    			| InvocationTargetException e) {
    		e.printStackTrace();
    	}
    } catch (NoSuchMethodException | SecurityException e) {
    	e.printStackTrace();
    }
    
    //out put==============
    map = {key=value}
    //如果方法是静态的,则把参数传递为NULL
    


  • 调用私有方法
  • try {
    	Method method;
    	try {
    		method = Class.forName("com.gyj.reflection.BaseClass").getDeclaredMethod("method3", null);
    		method.setAccessible(true);
    		System.out.println("===========调用静态私有方法===========");
    		method.invoke(null, null);
    	} catch (NoSuchMethodException | SecurityException e) {
    		e.printStackTrace();
    	}
    } catch (IllegalAccessException | IllegalArgumentException
    		| InvocationTargetException e) {
    	e.printStackTrace();
    }
    
    //out put==============
    ===========调用静态私有方法===========
    method3
    
    


    五、构造函数反射
  • 获取公共方法的构造函数
  • getConstructor() 方法来得到对象类具体的公共构造函数方法,并且可以获取到对象之后在创建类的实例;

    try {
    	Constructor<?> constructor = Class.forName("com.gyj.reflection.Concrete").getConstructor(int.class);
    	System.out.println(Arrays.toString(constructor.getParameterTypes()));
    	
    	Constructor<?> hashMapConstructor = Class.forName("java.util.HashMap").getConstructor(null);
    	System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes()));
    } catch (NoSuchMethodException | SecurityException e) {
    	e.printStackTrace();
    }
    
    //out put===============
    [int]
    []
    


  • 通过构造函数实例化对象
  • newInstance()方法得到一个类的实例,然后就可以去调用方法或访问字段的值

    try {
    	Constructor<?> constructor = Class.forName("com.gyj.reflection.Concrete").getConstructor(int.class);
    	System.out.println(Arrays.toString(constructor.getParameterTypes()));
    	Object myObject;
    	try {
    		myObject = constructor.newInstance(12);
    		Method method = myObject.getClass().getMethod("method1", null);
    		method.invoke(myObject, null);
    	} catch (InstantiationException | IllegalAccessException
    			| IllegalArgumentException | InvocationTargetException e) {
    		e.printStackTrace();
    	}
    } catch (NoSuchMethodException | SecurityException e) {
    	e.printStackTrace();
    } 
    
    try {
    	Constructor<?> hashMapConstructor = Class.forName("java.util.HashMap").getConstructor(null);
    	System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes()));
    	Map<String, Object> map = (Map<String, Object>) hashMapConstructor.newInstance(null);
    	map.put("key", "value");
    	System.out.println(map);
    } catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
    	e.printStackTrace();
    }
    
    
    //out put================
    [int]
    method1 impl
    []
    {key=value}
    

    ================================================================完毕==================================================================

    你可能感兴趣的:(java,反射)