一、反射简介

Java让我们在运行时识别对象和类的信息,主要有2种方式:一种是传统的RTTI,它假定我们在编译时已经知道了所有的类型信息;另一种是反射机制,它允许我们在运行时发现和使用类的信息。

1、反射的描述

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象

反射就是动态的从内存加载一个指定的类,把java类中的各种成分映射成一个个的Java对象,获取该类中的所有的内容。

2、反射的功能

1.在运行时判断任意一个对象所属的类;

2.在运行时构造任意一个类的对象;

3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);

4.在运行时调用任意一个对象的方法

重点:是运行时而不是编译时

反射的优点:增加程序的灵活性;增强了程序的扩展性。

反射的缺点:运用反射会使我们的软件的性能降低,复杂度增加。

二、反射的使用

1、获取Class对象

1:通过每个对象都具备的方法getClass来获取。弊端:必须要创建该类对象,才可以调用getClass方法。

2:每一个数据类型(基本数据类型和引用数据类型)都有一个静态的属性class。弊端:必须要先明确该类。

  前两种方式不利于程序的扩展,因为都需要在程序使用具体的类来完成。

3:使用的Class类中的方法,静态的forName方法。指定什么类名,就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可。

示例代码如下:

package com.luis.test;
public class User {
private long id;
private String name;
public int age; public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
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;
} @Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
}
} public class GetClass {
public static void main(String[] args) {
//1、通过对象调用 getClass() 方法来获取,通常应用在:比如你传过来一个 Object
// 类型的对象,而我不知道你具体是什么类,用这种方法
User user = new User();
Class c1 = user.getClass(); //2、直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高
// 这说明任何一个类都有一个隐含的静态成员变量 class
Class c2 = User.class; //3、通过 Class 对象的 forName() 静态方法来获取,用的最多,
//抛出 ClassNotFoundException 异常
Class c3;
try {
c3 = Class.forName("com.luis.test.User");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}

2、获取类中的方法,属性,构造函数。

public class GetClass {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.luis.test.User");
Constructor con = clazz.getConstructor(new Class[]{});
User instance = (User) con.newInstance();
instance.toString();
//获得类完整的名字
String className = clazz.getName();
System.out.println("---------完整类名----------");
System.out.println(className); //获得类的public类型的属性。
Field[] fields = clazz.getFields();
System.out.println("---------public属性----------");
for(Field field : fields){
System.out.println("public类:"+field.getName());
} //获得类的所有属性包括私有的
Field [] allFields = clazz.getDeclaredFields();
System.out.println("---------所有属性----------");
for(Field field : allFields){
System.out.println(field.getName());
} //获得类的public类型的方法。这里包括 Object 类的一些方法
Method [] methods = clazz.getMethods();
System.out.println("---------public方法----------");
for(Method method : methods){
System.out.println(method.getName());
} //获得类的所有方法。
Method [] allMethods = clazz.getDeclaredMethods();
System.out.println("---------所有方法----------");
for(Method method : allMethods){
System.out.println(method.getName());
} //获得指定的属性
Field f1 = clazz.getField("age");
System.out.println("---------指定属性----------");
System.out.println(f1);
//获得指定的私有属性
System.out.println("---------指定私有属性----------");
Field f2 = clazz.getDeclaredField("name");
//启用和禁用访问安全检查的开关,值为 true,则表示反射的对象在使用时应该取消 java 语言的访问检查;反之不取消
f2.setAccessible(true);
System.out.println(f2); //创建这个类的一个对象
Object p2 = clazz.newInstance();
//将 p2 对象的 f2 属性赋值为 Bob,f2 属性即为 私有属性 name
f2.set(p2,"luis");
//使用反射机制可以打破封装性,导致了java对象的属性不安全。
System.out.println("---------创建对象----------");
System.out.println(f2.get(p2)); //Bob //获取构造方法
Constructor [] constructors = clazz.getConstructors();
System.out.println("---------获取构造方法----------");
for(Constructor constructor : constructors){
System.out.println(constructor.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

运行结果:

---------完整类名----------
com.luis.test.User
---------public属性----------
public类:age
---------所有属性----------
id
name
age
---------public方法----------
toString
getName
getId
setName
getAge
setId
setAge
wait
wait
wait
equals
hashCode
getClass
notify
notifyAll
---------所有方法----------
toString
getName
getId
setName
getAge
setId
setAge
---------指定属性----------
public int com.luis.test.User.age
---------指定私有属性----------
private java.lang.String com.luis.test.User.name
---------创建对象----------
luis
---------获取构造方法----------
public com.luis.test.User()

3、反射获取父类属性

可以通过反射获取父类的私有属性,代码如下:

public class Parent {
public String publicField = "parent_publicField";
protected String protectField = "parent_protectField";
String defaultField = "parent_defaultField";
private String privateField = "parent_privateField";
} package com.luis.test;
public class Admin extends Parent{
} public class GetClass {
public static void main(String[] args) {
try {
Class clazz = Class.forName("com.luis.test.Admin");
//获取父类私有属性值
System.out.println(getFieldValue(clazz.newInstance(),"privateField"));
} catch (Exception e) {
e.printStackTrace();
}
} public static Field getDeclaredField(Object obj,String fieldName) {
Field field = null;
Class c = obj.getClass();
for(; c != Object.class ; c = c.getSuperclass()){
try {
field = c.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
}catch (Exception e){
//如果这里的异常打印或者往外抛,则就不会执行c = c.getSuperclass(),最后就不会进入到父类中了
}
}
return null;
}
public static Object getFieldValue(Object object,String fieldName) throws Exception{
Field field = getDeclaredField(object,fieldName);
return field.get(object);
}
}

运行结果:parent_privateField

要注意:直接通过反射获取子类的对象是不能得到父类的属性值的,必须根据反射获得的子类 Class 对象在调用 getSuperclass() 方法获取父类对象,然后在通过父类对象去获取父类的属性值。

三、动态代理

代理类在程序运行时创建的代理方式被成为动态代理。代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。

接口和实现类:

public interface Interface {
void doSomething();
void somethingElse(String arg);
} public class RealObject implements Interface { @Override
public void doSomething() {
System.out.println("doSomething.");
} @Override
public void somethingElse(String arg) {
System.out.println("somethingElse " + arg);
}
}

动态代理对象处理器:

public class DynamicProxyHandler implements InvocationHandler {
private Object proxyed; public DynamicProxyHandler(Object proxyed) {
this.proxyed = proxyed;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理工作了.");
return method.invoke(proxyed, args);
}
}

测试类:

public class Main {
public static void main(String[] args) {
RealObject real = new RealObject();
Interface proxy = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(),
new Class[] {Interface.class},new DynamicProxyHandler(real));
proxy.doSomething();
proxy.somethingElse("luis");
}
}

反射极大地增强了代码的灵活性,广泛应用于各种框架中,因而对于反射的掌握是非常重要的。

本文参考了:

https://www.cnblogs.com/ysocean/p/6516248.html

https://www.cnblogs.com/luoxn28/p/5686794.html

https://blog.csdn.net/ShadowySpirits/article/details/79756259

理解Java反射的更多相关文章

  1. 深入理解Java反射+动态代理

    答:   反射机制的定义: 是在运行状态中,对于任意的一个类,都能够知道这个类的所有属性和方法,对任意一个对象都能够通过反射机制调用一个类的任意方法,这种动态获取类信息及动态调用类对象方法的功能称为j ...

  2. 理解Java反射机制

    理解Java反射机制 转载请注明出处,谢谢! 一.Java反射简介 什么是反射? Java的反射机制是Java特性之一,反射机制是构建框架技术的基础所在.灵活掌握Java反射机制,对学习框架技术有很大 ...

  3. 由浅到深理解java反射

    1.基础概念 class类: 1.1java是面向对象的,但是在java中存在两种东西不是面向对象的 一种是普通的数据类型,这也是封装数据类存在的原因. 二种是静态静态成员. 1.2所以我们首先要理解 ...

  4. 由浅入深理解----java反射技术

    java反射机制详解 java反射机制是在运行状态下,对任意一个类可以获取该类的属性和方法,对任意一个对象可以调用其属性和方法.这种动态的获取信息和调用对象的方法的功能称为java的反射机制 clas ...

  5. 深入理解Java反射

    要想理解反射的原理,首先要了解什么是类型信息.Java让我们在运行时识别对象和类的信息,主要有2种方式:一种是传统的RTTI,它假定我们在编译时已经知道了所有的类型信息:另一种是反射机制,它允许我们在 ...

  6. Java复习总结——详细理解Java反射机制

    反射是什么 反射的作用用一句简单的话来讲就是可以对代码进行操作的代码,这个特性经常在被用于创建JavaBean中,通常造轮子的人会用到这个特性,而应用程序员用到这个特性的场景则较少. 能够分析类能力的 ...

  7. 如何理解java反射?

    一.反射基本概念 反射之中包含了一个"反"的概念,所以要想解释反射就必须先从"正"开始解释,一般而言,当用户使用一个类的时候,应该先知道这个类,而后通过这个类产 ...

  8. 深入理解 Java 反射和动态代理

  9. Java知识总结:Java反射机制(用实例理解)

    概念理解: 反射是指一类应用,它们能够自描述和自控制.也就是说,这类应用通过采用某种机制来 实现对自己行为的描述( self-representation )和检测( examination) ,并能 ...

随机推荐

  1. Mongodb--基础(连接,增删改查,数据类型)

    mongodb 日常启动命令 mongod --dbpath D:\data\db 一.启动,连接 mongodb是一个非关系型数据库 1. 启动MongoDB服务: 安装时我并没有将mongodb服 ...

  2. solr 下载 有dist目录的(6需要8)

    http://archive.apache.org/dist/lucene/solr/ solr6 需要java8

  3. 复习 C++ 中类的函数指针

    函数指针这种东西,平时工作中基本上不会用到. 那函数指针会用在哪里? 下面是一些基本的用法,根据消息号调到对应的函数: #include <iostream> #include <m ...

  4. iOS开发手记-iOS8中使用定位服务解决方案

    问题描述: 在iOS8之前,app第一次开始定位服务时,系统会弹出一个提示框来让用户选择是否允许使用定位信息.但iOS8后,app将不会出现这个弹窗.第一次运行之后,在设置->隐私->定位 ...

  5. Sentry有什么作用

    Sentry是一个异常日志集中收集系统,它可以捕捉到 stack trace, stack locals, preceding events和引发该异常的commit号.而当bug fix后,sent ...

  6. JS获取客户端IP地址、MAC和主机名的7个方法汇总

    今天在搞JS(javascript)获取客户端IP的小程序,上网搜了下,好多在现在的系统和浏览器中的都无效,很无奈,在Chrome.FireFox中很少搞到直接利用ActiveX获取IP等的JS脚本. ...

  7. 跨站请求伪造(CSRF攻击)理解

    一  概念 你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求.CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的 ...

  8. 【从0到1学Web前端】CSS定位问题三(相对定位,绝对定位) 分类: HTML+CSS 2015-05-29 23:01 842人阅读 评论(0) 收藏

    引子: 开始的时候我想先要解决一个问题,怎么设置一个div盒子撑满整个屏幕? 看下面的html代码: <body> <div id="father-body"&g ...

  9. Javac常量池的解读

    interface IA{ public void md(); } public class Test07 implements IA{ final double d = 2.0d; final fl ...

  10. Jquery初体验一

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...