下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922
论坛 >编程语言 >java基础-反射技术浅析

java基础-反射技术浅析

Mr ken发布于 2016-11-15 16:05查看:1012

1479197107122118.jpg

在Java运行时环境中,对于任意一个类,能否知道这个类的哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java语言的反射(Reflection)机制。

反射给java提供了,运行时获取一个类实例的可能,这一点非常灵活,你仅仅传一个类的全限定名,就能通过反射,来获取对应的类实例,我们一般会用Class类,来调用这个被反射的Objcet类下的:构造方法,属性,或方法等。

反射在一些开源框架里用的非常之多,Spring,Struts,Hibnerate,MyBatics都有它的影子,反射虽然很灵活,能够使得写的代码,变的大幅精简,所以在用的时候,一定要注意具体的应用场景。

反射的优缺点如下:

优点:

A:能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。

B:与Java动态编译相结合,可以实现无比强大的功能

缺点:

A:使用反射的性能较低

B:使用反射相对来说不安全

C:破坏了类的封装性,可以通过反射获取这个类的私有方法和属性

任何事物,都有两面性,反射的优点,也同是就是它的缺点,所以,没有好与坏,只有最合适的场景,一阴一阳,才是天道平衡的条件。

在反射API中我们重点关注一下几个类:

Class — 代表类

Field — 代表属性(成员变量)

Method — 代表方法

Constructor — 代表构造方法

一、Class

Java中不论一个类产生了多少个对象,这些对象的Class对象都始终是一个。Class对象中含有该类的任何信息(属性,方法,类名,父类,包等),在Java中获取Class对象的方法有三种:

// 第一种方法:类名.class

Class cla = Student.class;

Class as = int.class; // 基本数据类型唯一能点出的就是class

// 第二种方法:通过对象调用.getClass()

Student stu = new Student();

Class c = stu.getClass();

// 第三种方法:通过类的全限定名获取

try {

Class c1 = Class.forName(“entity.Student”);

catch (ClassNotFoundException e) {

e.printStackTrace();

}

System.out.println(cla.getName()); // 全限定名

System.out.println(Modifier.toString(cla.getModifiers()));

System.out.println(cla.getSimpleName());

System.out.println(cla.getPackage().getName());

可以通过Class对象产生该类的对象,如下:

// 获取Class对象

Class cla = Student.class;

/* 1. 直接创建对象(调用默认无参构造方法),类里必须要有默认构造方法 */

Object obj1 = cla.newInstance();

System.out.println(obj1);

二、Constructor

如果想通过有参构造方法来创建对象,那么这时候就得先获取有参构造方法,再通过有���构造方法来创建对象:

// 获取Class对象

Class cla = Student.class;

/* 1. 直接创建对象(调用默认无参构造方法),类里必须要有默认构造方法 */

Object obj1 = cla.newInstance();

System.out.println(obj1);

/* 2. 通过无参构造方法创建对象,和第一种方法效果一样 */

Constructor no = cla.getConstructor(); // 先获取无参构造方法

Object obj2 = no.newInstance();

System.out.println(obj2);

/* 3. 通过有参构造方法创建对象 */

Constructor has = cla.getDeclaredConstructor(String.class, int.class); // 形参

Object obj3 = has.newInstance(“老李”, 23); // 传入的是实参

System.out.println(obj3);

三、Field

Field代表是类中的属性,我们可以获取属性,并修改其值(注:先得有对象才能修改值,另:修改没权限的属性时,需要先打开该属性的权限)。

// 获取Class对象

Class cla = new Student().getClass();

// 获取构造方法

Constructor con = cla.getConstructor(String.classint.class);

// 创建对象

Object obj = con.newInstance(“如来”, 222);

// 获取要操作的属性

Field name = cla.getDeclaredField(“name”);

// 反射操作private属性的时候,需要打开权限

name.setAccessible(true);

// 获取obj的name属性值

System.out.println(name.get(obj));

// 把obj的name属性值改为:菩提

name.set(obj, “菩提”);

System.out.println(name.get(obj));

// 把id设置为10086

Field id = cla.getDeclaredField(“id”);

id.set(obj, 10086);

System.out.println(id.get(obj))

四、Method

Method代表类中的方法,和Field操作类型:

// 获取Class对象

Class cla = Student.class;

// 创建对象

Object obj = cla.getDeclaredConstructor(String.classint.class).newInstance(“达摩”, 666);

// 获取要操作的方法

Method showNo = cla.getDeclaredMethod(“show”);

Method showHas = cla.getDeclaredMethod(“show”, String.class);

Method calc = cla.getDeclaredMethod(“calc”, int.classdouble.class);

calc.setAccessible(true);

// 调用方法

showNo.invoke(obj);

showHas.invoke(obj, “老衲”);

Object value = calc.invoke(obj, 10086, Math.PI);

System.out.println(value);

我们可以用反射来改进简单工厂模式:

package demo08;

import java.io.FileInputStream;

import java.util.Properties;

public class PetFactory {

public static void main(String[] args) {

System.out.println(getInstance(“dog”)); // demo08.Dog@67a9b034

}

// 工厂方法

public static Pet getInstance(String tag) {

Properties p = new Properties();

try {

p.load(new FileInputStream(“conf/pet.properties”));

catch (Exception e) {

System.out.println(“加载配置文件错误!”);

}

String className = p.getProperty(tag);

try {

// 利用反射创建对象

Class<?> cla = Class.forName(className);

return (Pet)cla.newInstance();

catch (ClassNotFoundException e) {

System.out.println(“无法识别您的标识!”);

catch (InstantiationException e) {

e.printStackTrace();

catch (IllegalAccessException e) {

e.printStackTrace();

}

return null;

}

}

class Pet {}

class Dog extends Pet {}

class Cat extends Pet {}

class Penguin extends Pet {}

conf/pet.properties文件内容如下:

dog=demo08.Dog

cat=demo08.Cat

penguin=demo08.Penguin

这里的配置文件为.properties,称作属性文件。通过反射读取里边的内容。这样代码是固定的,但是配置文件的内容我们可以改,这样使我们的代码灵活了很多!

综上JAVA反射的再次学习,灵活的运用它,能够使我们的代码更加灵活,但是它也有它的缺点,就是运用它会使我们的软件的性能降低,复杂度增加,所以还要我们慎重的使用它。


收藏(0)0
查看评分情况

全部评分

此主贴暂时没有点赞评分

总计:0

回复分享

版主推荐

    共有0条评论

      • IT宅男
      • mr jack
      • Mr ken
      • Mright
      • cappuccino
      • YUI
      • 课课家运营团队
      • 课课家技术团队1
      • 酸酸~甜甜
      • 选择版块:

      • 标题:

      • 内容

      • 验证码:

      • 标题:

      • 内容

      • 选择版块:

      移动帖子x

      移动到: