博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java反射
阅读量:6840 次
发布时间:2019-06-26

本文共 14425 字,大约阅读时间需要 48 分钟。

阅读目录

1. 介绍

反射是一种能够在程序运行时动态访问、修改某个类中任意属性和方法的机制。

具体:

对于任意一个类,都能够知道这个类的所有属性和方法
对于任意一个对象,都能够调用它的任意一个方法和属性

在运行时,当加载完类之后,JVM在堆内存中会自动产生一个Class类型的对象,这个对象包含了完整的类的结构信息

这个Class对象就像一面镜子,透过这个镜子看到类的结构

 

那么,如何得到这个Class对象呢?以下可否

Class c = new Class();

答案是不行的,因为Class的构造函数定义为私有的,只有JVM可以访问

private Class(ClassLoader loader) {    classLoader = loader; }

Class对象获取的三种方式

Class c1 = Code.class; Class c2 = code1.getClass(); Class c3 = Class.forName("com.trigl.reflect.Code");

举例

public class TestStudent {    public static void main(String[] args) throws ClassNotFoundException {        Student student = new Student(1, "Jack");        Class class1 = student.getClass();        Class class2 = Student.class;        Class class3 = Class.forName("com.example.refs.Student");        System.out.println(class1);        System.out.println(class2);        System.out.println(class3);    }}

输出

class com.example.refs.Studentclass com.example.refs.Studentclass com.example.refs.Student

2. Java反射相关操作

本文以Student类为例:

接口

package com.example.refs;public interface InterFace {    void read();}

package com.example.refs;public class Student implements InterFace{    private int id;    public String name;    public Student() {}    public Student(int id, String name) {        this.id = id;        this.name = name;    }    public void setId(int id) {        this.id = id;    }    private int getId() {        return id;    }    @Override    public void read() {}}

以下具体介绍下具体的用法

2.1 类名称、包名

public class ClassName {    public static void main(String[] args) {        Class
class2 = Student.class; System.out.println("getSimpleName:" +class2.getSimpleName()); System.out.println("getName:" + class2.getName()); System.out.println("getPackage:" + class2.getPackage()); }}

输出

1
2
3
getSimpleName:Student
getName:com.example.refs.Student
getPackage:package: com.example.refs

2.2 方法

public Method getDeclaredMethod(String name, Class
...parameterTypes) // 得到本类所有的方法(public/private/proteceted...)public Method getMethod(String name, Class
...parameterTypes) //得到该类所有的public方法,包括父类

举例

public class MethodTest {    public static void main(String[] args) {        Class
class1 = Student.class; Method[] methods = class1.getMethods(); Method[] declaredMethods = class1.getDeclaredMethods(); for (Method method : methods) { System.out.println("getMethods: " + method); } System.out.println(); for (Method method : declaredMethods) { System.out.println("getDeclaredMethods: " + method); } }}

结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
getMethods:      
public 
void 
com.example.refs.Student.read()
getMethods:      
public 
void 
com.example.refs.Student.setId(
int
)
getMethods:      
public 
final 
void 
java.lang.Object.wait() throws java.lang.InterruptedException
getMethods:      
public 
final 
void 
java.lang.Object.wait(
long
,
int
) throws java.lang.InterruptedException
getMethods:      
public 
final native 
void 
java.lang.Object.wait(
long
) throws java.lang.InterruptedException
getMethods:      
public 
boolean java.lang.Object.
equals
(java.lang.Object)
getMethods:      
public 
java.lang.String java.lang.Object.toString()
getMethods:      
public 
native 
int 
java.lang.Object.hashCode()
getMethods:      
public 
final native java.lang.Class java.lang.Object.getClass()
getMethods:      
public 
final native 
void 
java.lang.Object.notify()
getMethods:      
public 
final native 
void 
java.lang.Object.notifyAll()
 
getDeclaredMethods:      
public 
void 
com.example.refs.Student.read()
getDeclaredMethods:      
private 
int 
com.example.refs.Student.getId()
getDeclaredMethods:      
public 
void 
com.example.refs.Student.setId(
int
)   

指定方法  

public class MethodChangeVal {    public static void main(String[] args) throws IllegalAccessException, InstantiationException,        NoSuchMethodException, InvocationTargetException {        Class clazz = Student.class;        Object obj = clazz.newInstance();        Method methodGet = clazz.getDeclaredMethod("getId");        Method methodSet = clazz.getDeclaredMethod("setId", int.class);        methodSet.invoke(obj, 123);        System.out.println(methodGet.invoke(obj));    }}

异常

Exception in thread "main" java.lang.IllegalAccessException: Class com.example.refs.MethodChangeVal can not access a member of class com.example.refs.Student with modifiers "private"

原因:setId为私有方法,利用反射时会进行安全检查,用setAccessible(true)不进行安全检查,可以直接对调用私有方法、修改私有变量

public class MethodChangeVal {    public static void main(String[] args) throws IllegalAccessException, InstantiationException,        NoSuchMethodException, InvocationTargetException {        Class clazz = Student.class;        Object obj = clazz.newInstance();        Method methodGet = clazz.getDeclaredMethod("getId");        Method methodSet = clazz.getDeclaredMethod("setId", int.class);        methodGet.setAccessible(true);        methodSet.invoke(obj, 123);        System.out.println(methodGet.invoke(obj));    }}

2.3 构造函数

public Constructor
getDeclaredConstructor(Class
... parameterTypes) public Constructor
getConstructor(Class
... parameterTypes) Constructor
[] allConstructors = class1.getDeclaredConstructors();//获取class对象的所有声明构造函数 Constructor
[] publicConstructors = class1.getConstructors();//获取class对象public构造函数 Constructor
constructor = class1.getDeclaredConstructor(String.class);//获取指定声明构造函数 Constructor publicConstructor = class1.getConstructor(String.class);//获取指定声明的public构造函数

举例

public class ConstuctorTest {    public static void main(String[] args) {        Class class2 = Student.class;        Constructor
[] constructors = class2.getConstructors(); for (Constructor
constructor : constructors) { System.out.println(constructor + ", Name:" + constructor.getName()); } }}

结果

public com.example.refs.Student(), Name:com.example.refs.Studentpublic com.example.refs.Student(int,java.lang.String), Name:com.example.refs.Student

2.4 成员变量

getDeclaredFields()获得某个类的所有申明的字段,即包括public、private和proteced,但是不包括父类的申明字段。

getFields()获得某个类的所有的公共(public)的字段,包括父类。

举例

public class FieldTest {    public static void main(String[] args) {        Class
aClass = Student.class; Field[] declardFields = aClass.getDeclaredFields(); Field[] fields = aClass.getFields(); for (Field field : declardFields) { System.out.println("declaredField: " + field); } System.out.println(); for (Field field : fields) { System.out.println("field: " + field); } }}

结果

declaredField: private int com.example.refs.Student.iddeclaredField: public java.lang.String com.example.refs.Student.namefield: public java.lang.String com.example.refs.Student.name

2.5 修饰符

举例

public class ModifierTest {    public static void main(String args[]) {        Class aClass = Student.class;        int modifier = aClass.getModifiers();        System.out.println("modifier:" + modifier);        System.out.println(String.format("isAbstract: %s", Modifier.isAbstract(modifier)));        System.out.println(String.format("isPublic: %s", Modifier.isPublic(modifier)));        System.out.println(String.format("isStatic: %s", Modifier.isStatic(modifier)));        System.out.println(String.format("isFinal: %s", Modifier.isFinal(modifier)));        System.out.println(String.format("isSynchronized: %s", Modifier.isSynchronized(modifier)));    }}

结果

modifier:1isAbstract: falseisPublic: trueisStatic: falseisFinal: falseisSynchronized: false

2.6 父类

public class GetParent {public static void main(String[] args) {    Class class2 = Student.class;    System.out.println(class2.getSuperclass());    }}

结果

class java.lang.Object

2.7 接口

public class InterfaceTest {    public static void main(String[] args) {        Class
clazz = Student.class; Class
[] inters = clazz.getInterfaces(); for(Class
classIn : inters) { System.out.println(classIn); } }}

输出

interface com.example.refs.InterFace

2.8 创建对象实例

举例用2种方法创建

public class NewInstanceTest {    public static void main(String[] args) throws IllegalAccessException, InstantiationException,        NoSuchMethodException, InvocationTargetException {        Class clazz = Student.class;        Object obj = clazz.newInstance();        Constructor
constructor = clazz.getDeclaredConstructor(); Object obj2 = constructor.newInstance(); Constructor
constructor2 = clazz.getDeclaredConstructor(int.class, String.class); Object obj3 = constructor2.newInstance(1, "HanMeimei"); System.out.println(obj); System.out.println(obj2); System.out.println(obj3); }}

结果

1
2
3
com.example.refs.Student@72ea2f77
com.example.refs.Student@33c7353a
com.example.refs.Student@681a9515

2.9 注解

自定义一个注解

@Retention(RetentionPolicy.RUNTIME)@interface MyAnnotation {    public String name();    public String value();

:RetentionPolicy.RUNTIME 这个表示运行期注解,这样在反射的时候才能取到

举例

public class AnnotationTest {    @MyAnnotation(name="someName",  value = "Hello World")    public void doSomething() {    }    @Deprecated    public void delFunc() {        System.out.println("Hello");    }    public static void main(String[] args) throws NoSuchMethodException {        Class clazz = AnnotationTest.class;        Method method = clazz.getMethod("doSomething");        Annotation[] declaredAnnotations = method.getDeclaredAnnotations();        for (Annotation annotation : declaredAnnotations) {            if (annotation instanceof MyAnnotation) {                MyAnnotation myAnnotation = (MyAnnotation)annotation;                System.out.println("name:" + myAnnotation.name());                System.out.println("value:" + myAnnotation.value());            } else {                System.out.println(annotation);            }        }    }}

结果

name:someNamevalue:Hello World

2.10 泛型

参数类型、返回值类型举例

public class GenericTest {    public void test01(Map
map, List
list) { System.out.println("test01"); } public Map
test02() { System.out.println("test02"); return null; } public static void main(String[] args) throws NoSuchMethodException { Method method = GenericTest.class.getMethod("test01", Map.class, List.class); Type[] types = method.getGenericParameterTypes(); for (Type type : types) { System.out.println("#:" + type); if (type instanceof ParameterizedType) { Type[] genericType = ((ParameterizedType)type).getActualTypeArguments(); for (Type ontGenericType : genericType) { System.out.println("泛型类型:" + ontGenericType); } } } Method method2 = GenericTest.class.getMethod("test02"); Type returnType = method2.getGenericReturnType(); System.out.println("\nReturntype" + returnType); if (returnType instanceof ParameterizedType) { Type[] genericTypes = ((ParameterizedType)returnType).getActualTypeArguments(); for (Type type : genericTypes) { System.out.println("返回值,泛型类型:" + type); } } }}

结果

1
2
3
4
5
6
7
8
9
#:java.util.Map<java.lang.String, com.example.refs.Student>
泛型类型:class java.lang.String
泛型类型:class com.example.refs.Student
#:java.util.List<com.example.refs.Student>
泛型类型:class com.example.refs.Student
 
Returntypejava.util.Map<java.lang.Integer, com.example.refs.Student>
返回值,泛型类型:class java.lang.Integer
返回值,泛型类型:class com.example.refs.Student

2.11 数组

public class ArrayTest {    public static void main(String[] args) {        int[] intArray = (int[])Array.newInstance(int.class, 3);        Array.set(intArray, 0, 123);        Array.set(intArray, 1, 124);        Array.set(intArray, 2, 125);        for (int i = 0; i < Array.getLength(intArray); ++i) {            System.out.println(String.format("array[%s]:%s", i, Array.get(intArray, i)));        }        Class aClass = intArray.getClass();        System.out.println("intArray是否是数组类型:" + aClass.isArray());        System.out.println("intArray成员类型:" + aClass.getComponentType());    }}

结果

1
2
3
4
5
array[0]:123
array[1]:124
array[2]:125
intArray是否是数组类型:
true
intArray成员类型:int 

3. 分析

3.1 使用场景

  • 操作因访问权限限制的属性和方法
  • 实现自定义注解
  • 动态加载第三方jar包
  • 按需加载类,节省编译和初始化APK的时间

3.2 优缺点

优点:灵活、自由度高:不受类的访问权限限制

缺点

  • 性能问题:通过反射访问、修改类的属性和方法时会远慢于直接操作,但性能问题的严重程度取决于在程序中是如何使用反射的。如果使用得很少,不是很频繁,性能将不是问题
  • 安全性问题:反射可以随意访问和修改类的所有状态和行为,破坏了类的封装性,如果不熟悉被反射类的实现原理,随意修改可能导致潜在的逻辑问题
  • 兼容性问题:因为反射会涉及到直接访问类的方法名和实例名,不同版本的API如果有变动,反射时找不到对应的属性和方法时会报异常

3.3 说明

  • 通过反射访问方法比实例慢很多
  • 有用到反射的类不能被混淆
  • 反射存在性能问题,但使用不频繁、按需使用时,对程序性能影响并不大
  • 反射存在安全性问题,因为可以随意修改类的所有状态和行为(包括private方法和实例)
  • 使用反射访问Android的API时需要注意因为不同API版本导致的兼容性问题

3.4 性能对比

不使用反射、启用安全检查、启用安全检查进行对比

public class TestReflect {    @Test    public void testNoneReflect() {        Student oneStudent = new Student(1, "HanMeimei");        long start = System.currentTimeMillis();        for (long i = 0; i < Integer.MAX_VALUE; ++i) {  oneStudent.setId(1);     }        long count = System.currentTimeMillis() - start;        System.out.println("没有反射, 共消耗 <" + count + "> 毫秒");    }    @Test    public void testNotAccess() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException,        InvocationTargetException {        Student oneStudent = new Student(1, "HanMeimei");        Method method = Class.forName("com.example.refs.Student").getMethod("setId", int.class);        long start = System.currentTimeMillis();        for (long i = 0; i < Integer.MAX_VALUE; ++i) {   method.invoke(oneStudent, 1);      }        long count = System.currentTimeMillis() - start;        System.out.println("启用安全检查, 共消耗 <" + count + "> 毫秒");    }    @Test    public void testUseAccess() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {        Student oneStudent = new Student(1, "HanMeimei");        Method method = Class.forName("com.example.refs.Student").getMethod("setId", int.class);        method.setAccessible(true);        long start = System.currentTimeMillis();        for (long i = 0; i < Integer.MAX_VALUE; ++i) {  method.invoke(oneStudent, 1);       }        long count = System.currentTimeMillis() - start;        System.out.println("取消安全检查, 共消耗 <" + count + "> 毫秒");    }}

结果对比

差异 耗时(ms)
没用反射 952
取消安全检查 4283
启用安全检查 14892

 

本文转自jihite博客园博客,原文链接:http://www.cnblogs.com/kaituorensheng/p/7398069.html,如需转载请自行联系原作者

你可能感兴趣的文章
面试笔记(2.JS
查看>>
在标签使用onclick(this)来传递参数
查看>>
做数据科学领域的「召唤师」,组织一场人人可参与的数据科学比赛
查看>>
Express 搭建web服务器
查看>>
Github 的 Pull Request 教程
查看>>
SmartRules让MindManager的交互图变得更加智能
查看>>
如何使用React动态添加/删除class来改变样式
查看>>
mysql-连接查询
查看>>
Axure RP9 自学之路2-基础操作篇
查看>>
GMS(cts、gsi、vts、gts、ctsv)问题总结
查看>>
runtime 关联对象objc_setAssociatedObject
查看>>
比较某两个时间的时间戳相等
查看>>
外墙清洗这件事,到底怎样才算安全?
查看>>
java B2B2C Springcloud多租户电子商城系统-spring-cloud-eureka
查看>>
11月29日云栖精选夜读:阿里传奇工程师多隆的程序世界
查看>>
推荐一些学习软件编程的网站
查看>>
Throwable
查看>>
三栏布局 五中解决方式
查看>>
ES6手册
查看>>
Go学习之-用vscode写go代码遇到的问题
查看>>