java反射 int_深入理解Java反射(一)

1、什么是反射?

我们先给一个比较官方的说法:反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。

简单的说就是:

通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。

我们知道我们在写代码的时候,对象类型一般都是在编译期确定下来的。反射机制允许我们动态的创建对象并且调用其相关属性。即使类型在编译期是未知的,反射机制也能通过加载类型信息,创建相关对象。

反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

2、Java反射框架提供的相关功能

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

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

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

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

判断任意一个对象所属的类(获取Class对象)

有3种方法可以获取Class对象,我们来依次介绍

Class类的Class.forName静态方法。

Class> personClass=Class.forName("com.learn.example.Person");

复制代码

直接获取某一类型的class

Class> personClass=Person.class;

复制代码

通过调用对象的getClass()方法

Person createPerson=new Person();

personClass=createPerson.getClass();

复制代码

判断是否是某一个类的实例

通常这类操作我们是通过instanceof关键字来进行判断的,不过通过Class对象,我们可以通过isInstance方法来进行判断。

Class> personClass=Person.class;

personClass.isInstance(obj);

复制代码

通过isInstance方法我们可以判断obj对象是否是Person类的实例。

通过反射来创建实例

通过反射来创建实例主要有两种方法。

使用Class对象的newInstance()方法来创建Class对象对应类的实例

Class> personClass=Person.class;

Person createPerson;

createPerson=(Person)personClass.newInstance();

复制代码

注意:通过这种方法只能调用默认的构造函数。

先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。

//调用无参构造函数

createPerson=(Person)personClass.getConstructor().newInstance();

createPerson.sayInfo();

//调用有两个参数的构造函数

createPerson=(Person)personClass.getConstructor(String.class,int.class).newInstance("gong",27);

createPerson.sayInfo();

复制代码

通过这种方式我们既可以调用默认的构造函数,也可以调用指定的构造函数,这种方式的灵活性更好一些。

获取一个类的方法

在讨论这个议题之前,我们先把Person类的代码贴出来

class Person {

private String name;

private int age;

public Person() {

this("init",88);

}

public Person(String name,int age) {

this.name=name;

this.age=age;

}

private void setName(String name) {

this.name=name;

}

private void setAge(int age) {

this.age=age;

}

public void sayInfo() {

System.out.println("name:"+this.name);

System.out.println("age:"+this.age);

}

}

复制代码

获取一个类的方法集合,有三种方法。

getDeclaredMethods()方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

//不包含继承的方法

Method[] declareMethods=personClass.getDeclaredMethods();

if(declareMethods!=null &&declareMethods.length>0) {

for (Method method : declareMethods) {

System.out.println(method);

}

}

复制代码

我们看输出:

public void com.learn.example.Person.sayInfo()

private void com.learn.example.Person.setAge(int)

private void com.learn.example.Person.setName(java.lang.String)

复制代码

从输出结果我们看到,getDeclaredMethods()方法只会返回当前类或接口定义的所有方法。

getMethods()方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。

//类的所有公用(public)方法,包括其继承类的公用方法

Method[] methods=personClass.getMethods();

for (Method method : methods) {

System.out.println(method);

}

复制代码

我们看输出:

public void com.learn.example.Person.sayInfo()

public final void java.lang.Object.wait() throws java.lang.InterruptedException

public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException

public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException

public boolean java.lang.Object.equals(java.lang.Object)

public java.lang.String java.lang.Object.toString()

public native int java.lang.Object.hashCode()

public final native java.lang.Class java.lang.Object.getClass()

public final native void java.lang.Object.notify()

public final native void java.lang.Object.notifyAll()

复制代码

从结果里面我们看到,getMethods()方法只返回Person类中public方法sayInfo()。剩下的就是继承自Object基类的所有public方法。

获取一个类的字段

Java反射机制也提供了相关方法来获取一个类的相关字段。

主要是这几个方法:

getFiled: 访问公有的成员变量

getDeclaredField:类中已声明的private成员变量。但不能得到其父类的成员变量

getFileds和getDeclaredFields用法同上(参照Method)

请看下面的例子:

Field field=personClass.getDeclaredField("name");

//允许访问private字段

field.setAccessible(true);

field.set(createPerson, "XXXXXXX");

createPerson.sayInfo();

复制代码

我们通过getDeclaredField方法来动态修改了实例的name属性值。这样输出的时候createPerson对象的name属性值就被我们动态的修改为“XXXXXXX”了。

在运行时调用任意一个对象的方法(invoke方法)

我们前面通过getMethods()方法和getDeclaredMethods()方法获取了类的方法列表。其实反射还支持动态执行类方法,下面我们通过例子来看下:

//动态执行方法

Method method=personClass.getDeclaredMethod("setName",String.class);

method.setAccessible(true);

method.invoke(createPerson,"WWWWW");

createPerson.sayInfo();

复制代码

我们在例子里面,我们看到我们通过getDeclaredMethod方法来动态调用setName方法。第一个参数是方法名,后面的参数是方法的参数。细心的朋友可能发现setName是private方法啊,这也能调用?的确,默认情况是不能调用的。但是我们可以通过setAccessible来设置是否允许调用private(私有)的方法。

注意:

getDeclaredMethod()方法和getDeclaredMethods()方法功能是对应的,这个方法只能获取到类自己定义的方法。

getMethod()方法和getMethods()方法功能是对应的。这个方法只能访问所有的public方法。

使用反射来创建数组

数组在Java里是比较特殊的一种类型,它可以赋值给一个Object Reference。下面我们看一看利用反射创建数组的例子:

public static void testArray() throws ClassNotFoundException {

Class> cls = Class.forName("java.lang.String");

Object array = Array.newInstance(cls,10);

//往数组里添加内容

Array.set(array,0,"Java");

Array.set(array,1,"C++");

Array.set(array,2,"JavaScript");

Array.set(array,3,"Python");

Array.set(array,4,"Kotlin");

//获取某一项的内容

System.out.println(Array.get(array,3));

}

复制代码

其中的Array类为java.lang.reflect.Array类。我们通过Array.newInstance()创建数组对象。第一个参数是数组的类型,第二个参数是数组的长度。

3、反射的作用

反射最重要的用途就是开发各种通用框架。

很多框架(如Spring)都是配置化的(比如通过XML文件配置JavaBean,Action之类的),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射--运行时动态加载需要加载的对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值