Dog.java
package com.clown.reflection;
public class Dog {
//属性
public String name;
private int age;
private String ownerName;
//无参构造
public Dog() {
}
//有参构造
public Dog(String name, int age, String ownerName) {
this.name = name;
this.age = age;
this.ownerName = ownerName;
}
//get() & set()
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
//重写 toString()
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", ownerName='" + ownerName + '\'' +
'}';
}
public void run() {
System.out.println(this.getName() + "正在奔跑");
}
protected void eat() {
System.out.println(this.getName() + "正在吃东西");
}
private void pee() {
System.out.println(this.getName() + "正在尿尿");
}
}
Dog
类中的信息:Test08.java
package com.clown.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
//获得类的信息
public class Test08 {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.clown.reflection.Dog");
//获得类的名字
System.out.println("=============================== 获得类的名字 ===============================");
System.out.println("包名+类名: " + c1.getName()); //getName(); 获得包名 + 类名
System.out.println("--------------------------------------------------------------");
System.out.println("类名: " + c1.getSimpleName()); //getSimpleName(); 获得类名
//获得类的属性
System.out.println("=============================== 获得类的属性 ===============================");
Field[] fields = c1.getFields(); //getFields(); 获得本类的所有 public属性
for (Field field : fields) {
System.out.println("public属性: " + field);
}
System.out.println("--------------------------------------------------------------");
fields = c1.getDeclaredFields(); //getDeclaredFields(); 获得本类的所有属性
for (Field field : fields) {
System.out.println("所有属性: " + field);
}
System.out.println("--------------------------------------------------------------");
Field name = c1.getDeclaredField("age"); //getDeclaredField(String name); 获得本类中指定的属性
System.out.println("指定属性: " + name);
//获得类的方法
System.out.println("=============================== 获得类的方法 ===============================");
Method[] methods = c1.getMethods(); //getMethods(); 获得本类及其父类的所有 public方法
for (Method method : methods) {
System.out.println("public方法: " + method);
}
System.out.println("--------------------------------------------------------------");
methods = c1.getDeclaredMethods(); //getDeclaredMethods(); 获得本类的所有方法
for (Method method : methods) {
System.out.println("所有方法: " + method);
}
System.out.println("--------------------------------------------------------------");
Method getName = c1.getMethod("getName", null); //getMethod("XXX", XXX); 获得本类中指定的方法
System.out.println("指定方法: " + getName);
Method setName = c1.getMethod("setName", String.class);
System.out.println("指定方法: " + setName);
/*
getMethod(String name, Class>... parameterTypes); 获得本类中指定的方法
参数:
name参数是一个 String,它指定了所需方法的简单名称。
parameterTypes参数是以声明顺序标识方法的形式参数类型的类对象的数组。
如果 parameterTypes是 null ,它被视为一个空数组。
*/
//获得类的构造器
System.out.println("============================== 获得类的构造器 ==============================");
Constructor[] constructors = c1.getConstructors(); //getConstructors(); 获得本类的 public构造器
for (Constructor constructor : constructors) {
System.out.println("public构造器: " + constructor);
}
System.out.println("--------------------------------------------------------------");
constructors = c1.getDeclaredConstructors(); //getDeclaredConstructors(); 获得本类的所有构造器
for (Constructor constructor : constructors) {
System.out.println("所有构造器: " + constructor);
}
System.out.println("--------------------------------------------------------------");
Constructor constructor = c1.getConstructor(String.class, int.class, String.class); //getConstructor(xxx) 获得本类中指定的构造器
System.out.println("指定构造器: " + constructor);
/*
getConstructor(Class>... parameterTypes); 获得本类中指定的构造器
参数:
parameterTypes参数是以声明顺序标识构造函数的形式参数类型的类对象的数组
*/
}
}
调用Class
对象的newlnstance()
方法
思考:难道没有无参的构造器就不能创建对象了吗?
只要在操作的时候明确的调用类中的构造器,调用构造器对象的newInstance(Object ... initargs)
方法,并将参数传递进去,就可以实例化对象了。具体步骤如下:
Class
类的getConstructor(Class>... parameterTypes)
取得本类的指定形参类型的构造器Constructor
)实例化对象通过Method
类完成。
Class
类的getMethod(String name, Class>... parameterTypes)
方法取得一个Method
对象,并设置此方法操作时所需要的参数类型。public Object invoke(Object obj, Object... args)
方法进行调用,并向方法中传递要设置的obj
对象的参数信息。Object invoke(Object obj, Object … args)
Object
对应原方法的返回值,若原方法无返回值,此时返回null
Object obj
可为null
Object[] args
为null
private
,则需要在调用此invoke()
方法前,显式调用方法对象的setAccessible(true)
方法,将可访问private
的方法。setAccessible(boolean flag)
Method
、Fied
和Constructor
对象都有setAccessible()
方法。setAccessible()
的作用是启动和禁用访问安全检查的开关。true
则指示反射的对象在使用时应该取消 Java 语言访问检查。
true
。false
则指示反射的对象应该实施 Java 语言访问检查。通过Field
类完成。
Class
类的getDeclaredField(String name)
方法取得一个Field
对象。public void set(Object obj, Object value)
方法将obj
对象参数上的此Field
对象表示的属性设置为指定的新值。下面我们来写一段程序来测试一下通过反射创建类的对象、调用类中的方法以及操作类中的属性。我们使用上面创建的Dog
类创建Class
对象:
package com.clown.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test09 {
public static void main(String[] args) throws Exception {
//获得 Class对象
Class c1 = Class.forName("com.clown.reflection.Dog");
//通过反射,动态的创建对象
//通过调用 Class对象的 newInstance()创建对象
System.out.println("================== 通过Class对象的newInstance()方法创建对象 ==================");
//newInstance(); 创建由此类对象表示的类的新实例
// Object obj = c1.newInstance();
// Dog dog1 = (Dog)obj;
Dog dog1 = (Dog)c1.newInstance(); //本质上是调用了 Dog类的无参构造器
System.out.println(dog1);
//通过构造器对象的 newInstance(Object ... initargs)方法创建对象
System.out.println("=============== 通过构造器对象的newInstance(参数值)方法创建对象 ===============");
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, String.class);
//newInstance(Object ... initargs); 使用由此 Constructor对象表示的构造函数,用指定的初始化参数创建和初始化构造函数的声明类的新实例
Dog dog2 = (Dog)constructor.newInstance("旺财", 5, "张三");
System.out.println(dog2);
//通过反射调用普通方法
System.out.println("============================= 通过反射调用方法 ==============================");
Dog dog3 = (Dog)c1.newInstance();
Method setName = c1.getDeclaredMethod("setName", String.class);
//invoke(Object obj, Object... args); 在具有指定参数的 Method对象上调用此 Method对象表示的基础方法。
//参数: obj - 从底层方法被调用的对象 args - 用于方法调用的参数值
setName.invoke(dog3, "大黄");
System.out.println(dog3.getName());
Method pee = c1.getDeclaredMethod("pee", null);
//注意: 不能直接操作私有(private)的方法或属性,我们需要先关闭程序的安全检测 - setAccessible(true)
//setAccessible(boolean flag); 将此对象的 accessible标志设置为指定的布尔值
//当值为 true时表示反射对象应该在使用时抑制程序的的安全检查。 值为 false时表示反射的对象应该强制执行程序的的安全检查。
pee.setAccessible(true);
pee.invoke(dog3, null);
//通过反射操作属性
System.out.println("============================= 通过反射操作属性 ==============================");
Dog dog4 = (Dog)c1.newInstance();
Field age = c1.getDeclaredField("age");
age.setAccessible(true); //关闭程序的安全检测
//set(Object obj, Object value); 将指定对象参数上的此 Field对象表示的字段设置为指定的新值
age.set(dog4, 8);
System.out.println(dog4.getAge());
}
}
setAccessible(boolean flag)
方法关闭程序的检测能提高反射的效率,那么是否真是如此呢?又大概提高了多少呢?下面我们就写一段程序来测试一下使用不同的方式调用方法对性能的影响:package com.clown.reflection;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//测试性能
public class Test10 {
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
test01();
test02();
test03();
}
//普通方式调用
public static void test01() {
Dog dog = new Dog();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
dog.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方式执行10亿次的时间: " + (endTime - startTime) + "毫秒");
}
//反射方式调用
public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Dog dog = new Dog();
//获取 Class对象
Class c1 = dog.getClass();
//获取 Method对象
Method getName = c1.getDeclaredMethod("getName", null);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(dog, null); //调用方法
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式执行10亿次的时间: " + (endTime - startTime) + "毫秒");
}
//反射方式调用,关闭检测
public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Dog dog = new Dog();
//获取 Class对象
Class c1 = dog.getClass();
//获取 Method对象
Method getName = c1.getDeclaredMethod("getName", null);
getName.setAccessible(true); //关闭检测
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
getName.invoke(dog, null); //调用方法
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式并关闭检测执行10亿次的时间: " + (endTime - startTime) + "毫秒");
}
}
ParameterizedType
,GenericArrayType
,TypeVariable
和WildcardType
几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。
ParameterizedType
:表示一种参数化类型,比如Collection
。GenericArrayType
:表示一种元素类型是参数化类型或者类型变量的数组类型。TypeVariable
:是各种类型变量的公共父接口。WildcardType
:代表一种通配符类型表达式。package com.clown.reflection;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
//通过反射获取泛型
public class Test11 {
public static void main(String[] args) throws NoSuchMethodException {
System.out.println("=========================== 获取方法test01()的形式参数类型 ============================");
Method method1 = Test11.class.getDeclaredMethod("test01", Map.class, List.class);
//getGenericParameterTypes(); 返回一个 Type对象的数组,Type[]以声明顺序表示由该 Method对象表示的方法的形式参数类型
Type[] genericParameterTypes = method1.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println("test01()方法的形式参数的类型: " + genericParameterType);
//ParameterizedType接口: 表示一个泛型,如 Collection
if (genericParameterType instanceof ParameterizedType) { //判断该形式参数是否为泛型
//getActualTypeArguments(); 返回一个表示此类型的实际类型参数的数组 Type对象
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("此泛型的实际类型参数类型: " + actualTypeArgument);
}
}
}
System.out.println("============================ 获取方法test02()的返回值类型 ============================");
Method method2 = Test11.class.getDeclaredMethod("test02", null);
//getGenericReturnType(); 返回一个 Type对象,它表示由该 Method对象表示的方法的正式返回类型
Type genericReturnType = method2.getGenericReturnType();
System.out.println("test02()方法的返回值的类型: " + genericReturnType);
if (genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("此泛型的实际类型参数类型: " + actualTypeArgument);
}
}
}
//定义一个方法,它的形式参数为泛型
public void test01(Map<String, Dog> map, List<Dog> list) {
System.out.println("test01");
}
//定义一个方法,它的返回值类型类型为泛型
public Map<String, Dog> test02() {
System.out.println("test02");
return null;
}
}
Class
类的getAnnotations()
方法可以获取该类的所有注解。Filed
)的注解,那我们只需要先获得该属性的Filed
对象,然后再使用该Filed
对象的getAnnotation(Class annotationClass)
方法,并传入我们想要获取的注解的Class
对象,即可获得该注解。同理,若我们想获得某个类(Class
)/方法(Method
)等的指定的注解也是使用getAnnotation(Class annotationClass)
方法。package com.clown.reflection;
import java.lang.annotation.*;
import java.lang.reflect.Field;
//通过反射操作注解
//ORM
public class Test12 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
//获得 Class对象
Class c1 = Class.forName("com.clown.reflection.Student2");
//通过反射获得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//获得注解的 value的值
TableClown tableClown = (TableClown) c1.getAnnotation(TableClown.class);
String value = tableClown.value();
System.out.println(value);
System.out.println("===================================================");
//获得类中的指定的注解
Field f = c1.getDeclaredField("id");
FiledClown filedClown = f.getAnnotation(FiledClown.class);
System.out.println(filedClown);
//获取并打印注解的参数的值
System.out.println(filedClown.columnName());
System.out.println(filedClown.type());
System.out.println(filedClown.length());
}
}
//创建一个实体类 --> 学生类
@TableClown("db_student")
class Student2 {
//属性
@FiledClown(columnName = "bd_id", type = "int", length = 10)
private int id;
@FiledClown(columnName = "bd_age", type = "int", length = 3)
private int age;
@FiledClown(columnName = "bd_name", type = "varchar", length = 4) //在数据库中,"String" 一般用 "varchar" 表示
private String name;
//无参构造
public Student2() {
}
//有参构造
public Student2(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
//get() & set()
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//重写 toString()
@Override
public String toString() {
return "Student2{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
//自定义创建一个【类】的注解
@Target(ElementType.TYPE) //@TableClown可以放在【类】上
@Retention(RetentionPolicy.RUNTIME) //@TableClown在源码时、编译为 class时以及运行时都有效
@interface TableClown {
String value(); //参数: 数据库名
}
//自定义创建一个【属性】的注解
@Target(ElementType.FIELD) //@FiledClown可以放在【属性】上
@Retention(RetentionPolicy.RUNTIME) //@FiledClown在源码时、编译为 class时以及运行时都有效
@interface FiledClown {
String columnName(); //参数: 列名
String type(); //参数: 类型
int length(); //参数: 长度
}