java反射 interface_java反射使用举例(全)

本文详细介绍了如何使用Java反射机制来查看和操作类的信息,包括构造器、方法、变量,以及如何对内部类、匿名内部类进行反射。通过示例代码展示了反射创建对象、调用私有方法、访问静态内部类和匿名内部类的方法。虽然反射功能强大,但作者建议谨慎使用,特别是在匿名内部类的情况下。
摘要由CSDN通过智能技术生成

本文将叙述如何运行时查看类信息,其中包括变量,方法,以及通过反射修改变量,执行方法等

包括如何反射匿名内部类及如何执行其方法,但是笔者强烈不建议这么做,这里只是演示反射而已

下面是一个测试类

Java代码

0818b9ca8b590ca3270a3433284dd417.png

package reflect;

public class Outer {

static{

System.out.println("Testing..");

}

TestInterface ti = new TestInterface() {

public String test() {

return "this is ti";

}

};

public Outer(String name){

System.out.println("Outer");

}

public String toString(){

System.out.println("Outer toString");

return new TestInterface() {

public String test() {

return "this is a test!";

}

}.test();

}

@SuppressWarnings("unused")

private void privateMethod(){

System.out.println("privateMethod");

}

protected void protectedMethod(){

System.out.println("protectedMethod");

}

void packageMethod(){

System.out.println("packageMethod");

}

public static void staticMethod(){

System.out.println("staticMethod");

}

public interface TestInterface {

public String test();

}

public static class StaticInner {

private static final String TAG = "StaticInnerTAG";

public StaticInner(){

System.out.println("StaticInner");

}

public String toString(){

System.out.println("StaticInner toString");

return TAG;

}

}

private class Inner{

String name;

public Inner(){

System.out.println("Inner");

}

public Inner(String name){

System.out.println("reflect.Outer.Inner.Inner(String name)");

this.name = name;

}

}

}

其中包括了普通内部类,静态内部类,内部匿名类,接口等

其中外部类Outer没有默认构造器,String reflect.Outer.Inner.getName()是private的……

外部类

Constructor,Method,Class.forName,newInstance

下面来看如何对上述的类进行反射

首先先看外部类Outer

Java代码

0818b9ca8b590ca3270a3433284dd417.png

public static void main(String[] args) {

try {

Class> outer = Class.forName("reflect.Outer");

outer = Outer.class;

Constructor>[] constructors = outer.getConstructors();

for (Constructor> constructor : constructors) {

Class>[] types = constructor.getParameterTypes();

System.out.println(constructor.getName() + "(" + arrayToString(types) + ")");

}

Constructor> outerConstructor = outer.getConstructor(String.class);

Outer outerInstance = (Outer) outerConstructor.newInstance("a outer");

System.out.println(outerInstance);

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (SecurityException e) {

e.printStackTrace();

} catch (NoSuchMethodException e) {

e.printStackTrace();

} catch (IllegalArgumentException e) {

e.printStackTrace();

} catch (InstantiationException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

}

}

public static String arrayToString(Class>[] classes){

StringBuilder stringBuilder = new StringBuilder();

for (Class> type : classes) {

stringBuilder.append(type.getCanonicalName());

stringBuilder.append(",");

}

if(classes.length > 0){

stringBuilder.deleteCharAt(stringBuilder.length() - 1);

}

return stringBuilder.toString();

}

打印结果

Java代码

0818b9ca8b590ca3270a3433284dd417.png

Testing..

reflect.Outer(java.lang.String)

Outer

Outer toString

this is a test!

下面简单分析下

Java代码

0818b9ca8b590ca3270a3433284dd417.png

Class> outer = Class.forName("reflect.Outer");

//outer = Outer.class;

我们对类reflect.Outer进行反射,这里使用Outer.class也可以获得Class对象

之前说过使用类字面量不会初始化该类,而Class.forName则会初始化,当使用Outer.class时候log如下

Java代码

0818b9ca8b590ca3270a3433284dd417.png

reflect.Outer(java.lang.String)

Testing..

Outer

Outer toString

this is a test!

顺序改变了,打印的时候Testing..实际是下面这句触发的

Java代码

0818b9ca8b590ca3270a3433284dd417.png

Outer outerInstance = (Outer) outerConstructor.newInstance("a outer");

这时候加载Outer这个类,然后进行初始化

接下来我们查看了Outer的所有构造器Constructor,并打印出所需要的参数(与普通方法区别开来)

构造器只有一个,参数是String

如何执行这个带有String作为参数的构造器来返回一个Outer实例

Java代码

0818b9ca8b590ca3270a3433284dd417.png

Constructor> outerConstructor = outer.getConstructor(String.class);

Outer outerInstance = (Outer) outerConstructor.newInstance("a outer");

System.out.println(outerInstance);

我们先取得我们需要的Constructor,然后,Constructor提供了newInstance方法,这样就可以获得Outer实例

最后打印实例,调用了toString函数

如果你尝试调用

Java代码

0818b9ca8b590ca3270a3433284dd417.png

outer.newInstance();

则会看到如下异常

java.lang.InstantiationException: reflect.Outer

at java.lang.Class.newInstance0(Class.java:357)

at java.lang.Class.newInstance(Class.java:325)

at reflect.Test.main(Test.java:30)

这是因为Outer没有提供默认构造器

在获得Constructor时其实是有下面两个选择的,至于区别,我们放在Method里说

Java代码

0818b9ca8b590ca3270a3433284dd417.png

outer.getConstructors();

outer.getDeclaredConstructors()

现在看看如何获得类的方法,顺便看看Declared的作用

不如直接打印出来,这样比较直观

Java代码

0818b9ca8b590ca3270a3433284dd417.png

Method[] methods = outer.getMethods();

for (Method method : methods) {

Class>[] types = method.getParameterTypes();

System.out.println(method.getReturnType().getName() + " " + outer.getName() + "." + method.getName() + "(" + arrayToString(types) + ")");

}

System.out.println("--------------------------------------");

methods = outer.getDeclaredMethods();

for (Method method : methods) {

Class>[] types = method.getParameterTypes();

System.out.println(method.getReturnType().getName() + " " + outer.getName() + "." + method.getName() + "(" + arrayToString(types) + ")");

}Class> outer = Outer.class;

结果如下

Java代码

0818b9ca8b590ca3270a3433284dd417.png

void reflect.Outer.staticMethod()

java.lang.String reflect.Outer.toString()

void reflect.Outer.wait(long)

void reflect.Outer.wait()

void reflect.Outer.wait(long,int)

boolean reflect.Outer.equals(java.lang.Object)

int reflect.Outer.hashCode()

java.lang.Class reflect.Outer.getClass()

void reflect.Outer.notify()

void reflect.Outer.notifyAll()

--------------------------------------

void reflect.Outer.privateMethod()

void reflect.Outer.protectedMethod()

void reflect.Outer.packageMethod()

void reflect.Outer.staticMethod()

java.lang.String reflect.Outer.toString()

调用getMethods时,Outer的方法只打印出了toString,其余结果均为父类Object的公有方法

调用getDeclaredMethods时,则只打印出在Outer中声明定义的方法

他们均打印出了公共的静态方法

所有带Declared和不带Declared的成对的方法都和上面的类似

如何利用反射执行一个方法,下面以void reflect.Outer.privateMethod()为例

Java代码

0818b9ca8b590ca3270a3433284dd417.png

Method method = outer.getDeclaredMethod("privateMethod");

method.setAccessible(true);

method.invoke(outerInstance, (Object[])null);

method.setAccessible(false);

首先privateMethod是私有方法,所以为了能得到对应的Method对象,我们需要调用getDeclaredMethod

为了能访问私有方法,我们需要进行setAccessible(true)的设置

然后需要有个对象来执行,我们选择刚才的outerInstance

这时控制台输出

Java代码

0818b9ca8b590ca3270a3433284dd417.png

privateMethod

干完活后,恢复其设置setAccessible(false)

下面是静态方法的执行

Java代码

0818b9ca8b590ca3270a3433284dd417.png

Method method = outer.getDeclaredMethod("staticMethod");

method.setAccessible(true);

method.invoke(Outer.class, (Object[])null);

method.setAccessible(false);

ps:使用method.invoke(outerInstance, (Object[])null);也能执行,但是不该这样

内部类

isInterface,Field,isAccessible,setAccessible,getModifiers,Modifier.toString()

下面看看内部类的反射

Java代码

0818b9ca8b590ca3270a3433284dd417.png

Class>[] classes = outer.getDeclaredClasses();

for (Class> clazz : classes) {

if(clazz.isInterface()){

System.out.println("interface : " + clazz.getName());

}else{

System.out.println("class : " + clazz.getName());

}

}

输出

Java代码

0818b9ca8b590ca3270a3433284dd417.png

class : reflect.Outer$Inner

class : reflect.Outer$StaticInner

interface : reflect.Outer$TestInterface

看来反射提供的api功能还是很全的

下面是如何反射静态内部类

Java代码

0818b9ca8b590ca3270a3433284dd417.png

try {

Class staticInner = StaticInner.class;

StaticInner staticInnerInstance = staticInner.newInstance();

}catch (SecurityException e) {

e.printStackTrace();

} catch (IllegalArgumentException e) {

e.printStackTrace();

} catch (InstantiationException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

也可以使用Class.forName方式,如果StaticInner是不可见的,那么上面的代码则无法编译,下面看看Class.forName

Java代码

0818b9ca8b590ca3270a3433284dd417.png

try {

Class staticInner = (Class) Class.forName("reflect.Outer.StaticInner");

StaticInner staticInnerInstance = staticInner.newInstance();

}catch (SecurityException e) {

e.printStackTrace();

} catch (IllegalArgumentException e) {

e.printStackTrace();

} catch (InstantiationException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

如果你和上面的写法一样,那么很不幸,运行时会得到如下错误

java.lang.ClassNotFoundException: reflect.Outer.StaticInner

at java.net.URLClassLoader$1.run(URLClassLoader.java:217)

at java.security.AccessController.doPrivileged(Native Method)

at java.net.URLClassLoader.findClass(URLClassLoader.java:205)

at java.lang.ClassLoader.loadClass(ClassLoader.java:321)

at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)

at java.lang.ClassLoader.loadClass(ClassLoader.java:266)

at java.lang.Class.forName0(Native Method)

at java.lang.Class.forName(Class.java:186)

at reflect.Test.main(Test.java:11)

我们去bin目录下可以发现这样的文件Outer$StaticInner.class

反射代码只需做如下改动

Java代码

0818b9ca8b590ca3270a3433284dd417.png

Class staticInner = (Class) Class.forName("reflect.Outer$StaticInner");

.变成了$

这里newInstance之所以能执行,是因为StaticInner有默认构造器

下面看看StaticInner中生命了哪些变量

Java代码

0818b9ca8b590ca3270a3433284dd417.png

Class staticInner = StaticInner.class;

Field[] fields = staticInner.getDeclaredFields();

for (Field field : fields) {

Class> type = field.getType();

field.setAccessible(true);

System.out.println(Modifier.toString(field.getModifiers()) + " " + type.getName() + " " + field.getName());

}

StaticInner StaticInnerInstance = staticInner.newInstance();

Field field = staticInner.getDeclaredField("TAG");

boolean accessible = field.isAccessible();

if(!accessible){

field.setAccessible(true);

}

System.out.println(field.get(StaticInnerInstance));

field.set(StaticInnerInstance, "TAG");

System.out.println(field.get(StaticInnerInstance));

if(!accessible){

field.setAccessible(false);

}

结果如下

Java代码

0818b9ca8b590ca3270a3433284dd417.png

private java.lang.String TAG

StaticInner

StaticInnerTAG

TAG

StaticInner只声明了一个变量,名字为TAG,类型为String

即使是private变量,设置setAccessible(true)之后也能改变其值

普通内部类的反射和上面类似

最后说下匿名内部类

匿名内部类的作用是仅仅使用一次,所以也没有必要进行反射,实际上也很难进行反射

例子中有两个匿名内部类

Java代码

0818b9ca8b590ca3270a3433284dd417.png

TestInterface ti = new TestInterface() {

public String test() {

return "this is ti";

}

};

public String toString(){

System.out.println("Outer toString");

return new TestInterface() {

public String test() {

return "this is a test!";

}

}.test();

}

在bin目录下发现有Outer$1.class和Outer$2.class

getDeclaredClasses发现也没有匿名内部类的信息

Java代码

0818b9ca8b590ca3270a3433284dd417.png

try {

Class outer = Outer.class;

Class>[] classes = outer.getDeclaredClasses();

for (Class> clazz : classes) {

System.out.println(clazz.getName());

}

}catch (SecurityException e) {

e.printStackTrace();

} catch (IllegalArgumentException e) {

e.printStackTrace();

}

结果

Java代码

0818b9ca8b590ca3270a3433284dd417.png

reflect.Outer$Inner

reflect.Outer$StaticInner

reflect.Outer$TestInterface

只有这三个,包括一个接口

如果非要对匿名内部类进行反射,也不是不可能

下面演示如何反射一个匿名内部类,仅仅是演示,没有任何意义,也不推荐这么做

我们以上面的toString方法里面的内部类做例子

Java代码

0818b9ca8b590ca3270a3433284dd417.png

try {

Class> clazz = Class.forName("reflect.Outer$2");

Constructor>[] constructors = clazz.getDeclaredConstructors();

constructors[0].setAccessible(true);

Class>[] types = constructors[0].getParameterTypes();

for (Class> type : types) {

System.out.println("Parameter Types:" + type.getName());

}

TestInterface testInterface = (TestInterface) constructors[0].newInstance(new Outer(""));

Method[] methods = clazz.getDeclaredMethods();

for (Method method : methods) {

Class>[] parameterTypes = method.getParameterTypes();

System.out.println(method.getName() + "(" + arrayToString(parameterTypes) + ")");

}

Method method = clazz.getDeclaredMethod("test");

String string = (String)method.invoke(testInterface);

System.out.println(string);

}catch (SecurityException e) {

e.printStackTrace();

} catch (IllegalArgumentException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

} catch (InvocationTargetException e) {

e.printStackTrace();

} catch (InstantiationException e) {

e.printStackTrace();

} catch (NoSuchMethodException e) {

e.printStackTrace();

}

结果如下

Java代码

0818b9ca8b590ca3270a3433284dd417.png

Parameter Types:reflect.Outer

Testing..

Outer

test()

this is a test!

下面看看代码都做了什么,依次说明

首先获取Outer$2的Class

然后获取其构造器,查看所需要的参数,我们发现内部匿名类也需要一个外部类的支持

然后我们newInstance生成实例,声明为一个接口,由于要传入外部类,这里我们直接new一个,所以会初始化外部类,打印第2,3句

接下来查看内部类的方法,找到test(),这是第4句打印的结果

最后用实例化好的内部匿名类执行这个方法,所以打印出了最后一句

执行第一个匿名内部类的方法代码简单些,同样不推荐这么做

Java代码

0818b9ca8b590ca3270a3433284dd417.png

try {

Class clazz = Outer.class;

Outer o = new Outer("");

//System.out.println(o.ti.test());

Field field = clazz.getDeclaredField("ti");

TestInterface testInterface = (TestInterface) field.get(o);

System.out.println(testInterface.test());

}catch (SecurityException e) {

e.printStackTrace();

} catch (IllegalArgumentException e) {

e.printStackTrace();

} catch (NoSuchFieldException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IllegalAccessException e) {

e.printStackTrace();

}

为了演示反射,这里没有使用System.out.println(o.ti.test());

至此,反射演示结束

由于写本篇blog的时候多次修改代码,所以上面可能有些地方不太一致,如果发现,敬请指正

来源于:

转贴请保留以下链接

本人blog地址

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值