玩转java(2)— 泛型type体系与反射

一、Type类型

Type是Java编程语言中所有类型的普通的父接口。这些类型包括原生类型(raw types)参数化类型(parameterized types)数组类型(array types)类型变量(type variables)和 原始类型(primitive types)。我们一般不直接操作Type类型,但了解一下Type类型的层次结构还是有必要的。

1、Type层次结构

玩转java(2)— 泛型type体系与反射

2、Class,Method和Field的继承体系

玩转java(2)— 泛型type体系与反射

二、Type与反射

反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,容许程序在运行时加载、探知、使用编译期间未知的class。即Java的反射机制可以加载一个运行时才得知名称的class,获得其完整结构。

1、反射的基础:Class

在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息保存着每个对象所属的类足迹。虚拟机利用运行时信息选择相应的方法执行。然而,可以通过专门的Java类访问这些信息。保存这些信息的类称为Class,泛型形式为Class<T>。Class是反射机制的基础,反射API通过操作Class来获取其完整结构。

获取Class的常用方式:

调用getClass()(Object类中的getClass()方法返回一个Class类型的实例)

Boolean var1 = true;Class<?> classType2 = var1.getClass();System.out.println(classType2);输出:class java.lang.Boolean 

运用T.class 语法(T是任意的Java类型)

Class<?> classType4 = Boolean.class;System.out.println(classType4);输出:class java.lang.Boolean 

运用static method Class.forName()(使用时应该提供异常处理器)

Class<?> classType5 = Class.forName("java.lang.Boolean");System.out.println(classType5);输出:class java.lang.Boolean 

运用primitive wrapper classes的TYPE 语法这里返回的是原生类型,和Boolean.class返回的不同

Class<?> classType3 = Boolean.TYPE;System.out.println(classType3);输出:boolean 


注:一个Class对象实际上表示的是一个类型,而这个类型未必一定是一种类。例如,int不是类,但int.class是一个Class类型的对象。虚拟机为每个类型管理一个Class对象。因此,可以用==运算符实现两个类对象比较的操作。

Class常用的方法:

方法

说明

例子

getName()

 

返回类的名字

String.class.getName();

返回: "java.lang.String"

newInstance()

 

快速地创建一个类的实例(调用默认构造器,如果该类没有默认构造器,抛出异常)(如果要为构造器提供参数,使java.lang.reflect.Constructor中的newInstance方法)

String s = "java.util.Date";

Object m = Class.forName(s).newInstance();

getSuperclass()

返回超类

 

getFields() getMethods() getConstructors()(还有带字符串参数,给定名称的形式)

分别返回类支持的public、方法和构造器数组,其中包括超类的公有成员

 

getDeclaredFields()

getDeclaredMethods()

getDeclaredConstructors()(还有给定名称的形式)

分别返回类中声明的全部域、方法和构造器数组。其中包括私有和保护成员,但不包括超类的成员

 


2、使用反射分析类

一个类主要由修饰符,域,构造器,方法组成,而 Field、Method、Constructor类,分别用于描述类的域、方法和构造器。另外java.lang.reflect包中的Modifier类可以分析访问修饰符。那么用它们就可以分析类。

分析类常用的方法:

方法 作用
Field
Method
Constructor
Class getDeclaringClass() 返回一个用于描述类中定义的构造器、方法或域的Class对象
String getName() 返回相应条目的名称
int getModifiers() 返回整型数值,用不同的位开关描述访问修饰符的使用状况

Method

Constructor

Class[] getExceptionTypes()

返回一个用于描述方法抛出的异常类型的Class对象数组

Class[] getParameterTypes()

返回一个用于描述参数类型的Class对象数组

Field

Class getType()

用于返回描述域所属类型的Class类型对象

Modifier

static String toString(int modifiers)

返回对应modifiers位设置的修饰符的字符串表示

Static boolean isXXX(int modifiers)

检测方法名中对应的修饰符在modifiers中的值

访问权限问题:

由于反射机制的默认行为受限于Java的访问控制,比如,访问私有的方法,字段,除非拥有访问权限,否则Java安全机制允许查看任意对象有哪些域,而不允许读它们的值(读取将抛异常)。然而如果一个Java程序没有受到安全管理器的控制,就可以覆盖访问控制。为了达到这个目的,就需要调用Field、Method、Constructor对象的setAccessible()方法。

函数

作用

void setAccessible(boolean flag)

为反射对象设置可访问标志,flag为true表明屏蔽Java语言的访问检查,使得对象的私有属性也可以被查询和设置

boolean isAccessible()

返回反射对象的可访问标志的值

static void setAccessible(AccessibleObject[] array, boolean flag)

一种设置对象数组可访问标志的快捷方法

3、一个经典的反射工具类

package study.java.core.util;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 反射工具类
 * @author qbg
 *
 */
public abstract class ReflectUtil {
	
	/**
	 * 获取某个对象的属性
	 */
	public Object getProperty(Object owner,	String fieldName) throws Exception {
		//1、得到该对象的Class。
		Class<?> ownerClass = owner.getClass();
		//2、通过Class得到类声明的属性。
		Field field = ownerClass.getField(fieldName);
		//3、通过对象得到该属性的实例,如果这个属性是私有的,这里就会抛出IllegalAccessException。
		Object property = field.get(owner); //此处获取的是对象的属性,所以传递的是owner。
		return property;
	}
	
	/**
	 * 获取某个类的静态属性
	 */
	public Object getStaticProperty(String className,String fieldName) throws Exception{
		//1、得到该类的Class。
		Class<?> ownerClass = Class.forName(className);
		//2、通过Class得到类声明的属性。
		Field field = ownerClass.getField(fieldName);
		//3、由于获取的是静态属性,此处传递的为Class,直接从Class中获取静态属性。
		Object property = field.get(ownerClass); 
		return property;
	}
	
	/**
	 * 执行某对象的方法
	 */
	public Object invokeMethod(Object owner,String methodName,Object[] args) throws Exception{
		//1、获取对象的Class。
		Class<?> ownerClass = owner.getClass();
		//2、组装参数的Class数组,用于匹配Method的条件
		Class<?>[] argsClass = new Class<?>[args.length];
		for(int i=0; i<args.length; i++){
			argsClass[i] = args[i].getClass();
		}
		//3、通过Method名和参数的Class数组得到要执行的Method
		Method method = ownerClass.getMethod(methodName, argsClass);
		//4、调用invoke执行Method.由于执行的是对象的方法,此处传递的为owner。
		return method.invoke(owner, args);
	}
	
	/**
	 * 执行类的静态方法
	 */
	public Object invokeStaticMethod(String className,String methodName,Object[] args) throws Exception{
		//1、获取类的Class。
		Class<?> ownerClass = Class.forName(className);
		//2、组装参数的Class数组,用于匹配Method的条件
		Class<?>[] argsClass = new Class<?>[args.length];
		for(int i=0; i<args.length; i++){
			argsClass[i] = args[i].getClass();
		}
		//3、通过Method名和参数的Class数组得到要执行的Method
		Method method = ownerClass.getMethod(methodName, argsClass);
		//4、调用invoke执行Method.由于执行的是类的静态方法,不需要借助对象实例,此处传递的为null。
		return method.invoke(null, args);
	}
	
	/**
	 * 新建实例。调用带参构造函数。
	 */
	public Object newInstance(String className,Object[] args) throws Exception{
		//1、获取要构造实例的Class
		Class<?> newOneClass = Class.forName(className);
		//2、得到参数的Class数组
		Class<?>[] argsClass = new Class<?>[args.length];
		for(int i=0; i<args.length; i++){
			argsClass[i] = args[i].getClass(); 
		}
		//3、得到构造器
		Constructor<?> ctor = newOneClass.getConstructor(argsClass);
		//4、新建实例
		return ctor.newInstance(args);
	}
	
	/**
	 * 判断是否为某个类的实例
	 */
	public boolean isInstance(Object obj,Class<?> clazz){
		return clazz.isInstance(obj);
	}
	
	/**
	 * 得到数组中的某个元素
	 */
	public Object getByArray(Object array,int index){
		return Array.get(array, index);
	}
}

玩转java(2)— 泛型type体系与反射,布布扣,bubuko.com

玩转java(2)— 泛型type体系与反射

上一篇:《linux多线程服务端编程--muduo网络库的使用》读后感


下一篇:Android App 自动更新版本