您的位置:首页 > 编程语言 > Java开发

Java编程思想之类型信息(反射)

2017-09-02 11:51 495 查看
反射:运行时的类信息

反射提供了一种机制——用来检查可用的方法,并返回方法名。Class类与 java.lang.reflect 类库一起对反射的概念进行了支持,该类库包含了Field、Method以及Constructor类(每个类都实现了Member接口)。这些类是由JVM在运行时创建的,用以表示未知类里对应的成员。匿名对象的类信息就能在运行时被完全确定下来,而在编译时不需要知道任何事情。

当通过反射与一个未知类型的对象打交道时,JVM只是简单地检查这个对象,看它属于哪个特定的类(就像RTTI那样)。在用它做其它事情之前必须先加载那个类的Class对象。因此,那个类的.class文件对于JVM虚拟机来说必须是可获得的。

RTTI和反射之间真正的区别在于:

对RTTI来说,编译器在编译时打开和检查.class文件。(换句话说,我们可以用“普通”方式调用对象的所有方法。)而对于反射机制来说,.class文件在编译时是不可获取的,所以是在运行时打开和检查.class文件。

类方法提取器

反射在Java中是用来支持其它特性的,例如对象序列化和JavaBean。但是,如果能动态地提取某个类的信息有的时候还是很有用的。

/*
* Using reflection to show all the methods of a class, even if the methods are
* defined in the base class.
*/

import java.lang.reflect.*;
import java.util.regex.*;

public class ShowMethods{
private static String usage =
"Usage:\n ShowMethods qualified.class.name\n To show all methods in class or:\n "+
"ShowMethods qualified.class.name word\n To search for methods involving 'word' or:\n"+
"using \"-n\" as the second parameter for detailed output";
private static Pattern p = Pattern.compile("\\w+\\.");
public static void main(String[] args){
if(args.length<1){
System.out.println(usage);
System.exit(0);
}
int lines = 0;
try{
Class<?> c = Class.forName(args[0]);
Method[] methods = c.getMethods();
Constructor[] ctors = c.getConstructors();
if(args.length == 1){
for(Method m : methods ){
System.out.println(p.matcher(m.toString()).replaceAll(""));
}
for(Constructor ctor : ctors)
System.out.println(p.matcher(ctor.toString()).replaceAll(""));
lines = methods.length + ctors.length;
}else if(args.length == 2 && args[1].equals("-n")){
for(Method m : methods ){
System.out.println(m.toString());
}
for(Constructor ctor : ctors)
System.out.println(ctor.toString());
lines = methods.length + ctors.length;
}else{
for(Method m : methods ){
if(m.toString().indexOf(args[1])!=-1){
System.out.println(p.matcher(m.toString()).replaceAll(""));
lines++;
}
}
for(Constructor ctor : ctors)
if(ctor.toString().indexOf(args[1])!=-1){
System.out.println(p.matcher(ctor.toString()).replaceAll(""));
lines++;
}
}
System.out.println("Total : "+lines);
}catch(ClassNotFoundException e){
e.printStackTrace();
}
}
}
/*
运行结果:
命令行: java ShowMethods ShowMethods wait
public final void wait() throws InterruptedException
public final void wait(long,int) throws InterruptedException
public final native void wait(long) throws InterruptedException
Total : 3

命令行: java ShowMethods ShowMethods -n
public static void ShowMethods.main(java.lang.String[])
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()
public ShowMethods()
Total : 11

命令行: java ShowMethods ShowMethods
public static void main(String[])
public final void wait() throws InterruptedException
public final void wait(long,int) throws InterruptedException
public final native void wait(long) throws InterruptedException
public boolean equals(Object)
public String toString()
public native int hashCode()
public final native Class getClass()
public final native void notify()
public final native void notifyAll()
public ShowMethods()
all : 11
*/


2 动态代理

代理是基本的设计模式之一,它是你为了提供额外的或不同的操作,而插入的用来代替“实际”对象的对象。这些操作通常涉及与“实际”对象的通信,因此代理通常充
b959
当着中间人的角色。

interface Interface{
void doSomething();
void somethingElse(String arg);
}

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

class SimpleProxy implements Interface{
private Interface proxied;
public SimpleProxy(Interface proxied){
this.proxied = proxied;
}
public void doSomething(){
System.out.println("SimpleProxy doSomething");
proxied.doSomething();
}
public void somethingElse(String arg){
System.out.println("SimpleProxy somethingElse "+arg);
proxied.somethingElse(arg);
}
}

public class SimpleProxyDemo{
public static void consumer(Interface i){
i.doSomething();
i.somethingElse("example");
}
public static void main(String[] args){
consumer(new RealObject());
consumer(new SimpleProxy(new RealObject()));
}
}
/*
运行结果:
doSomething
somethingElse example
SimpleProxy doSomething
doSomething
SimpleProxy somethingElse example
somethingElse example
*/


Java的动态代理比代理的思想就更向前迈进了一步。因为它可以动态地创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的对策。下面是动态代理重写的SimpleProxyDemo.java:

import java.lang.reflect.*;
import java.lang.reflect.Proxy;

interface Interface{
void doSomething();
void somethingElse(String arg);
}

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

class DynamicProxyHandler implements InvocationHandler{
private Object proxied;
public DynamicProxyHandler(Object proxied){
this.proxied = proxied;
}
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
System.out.println("proxy: "+proxy.getClass()+" method: "+method+" args: "+args);
return  method.invoke(proxied,args);
}
}

public class SimpleDynamicProxy{
public static void consumer(Interface iface){
iface.doSomething();
iface.somethingElse("example 2");
}
public static void main(String[] args){
RealObject real = new RealObject();
consumer(real);
//Insert a proxy and call again:
Interface proxy = (Interface)Proxy.newProxyInstance(
Interface.class.getClassLoader(),
new Class[]{Interface.class},new DynamicProxyHandler(real));
consumer(proxy);
}
}
/*
运行结果为:
doSomething
somethingElse example 2
proxy: class $Proxy0 method: public abstract void Interface.doSomething() args: null
doSomething
proxy: class $Proxy0 method: public abstract void Interface.somethingElse(java.lang.String) args: [Ljava.lang.Object;@6bc7c054
somethingElse example 2
*/


通过调用静态方法Proxy.newProxyInstance() 可以创建动态代理,这个方法需要得到一个类加载器(你通常可以从已经被加载的对象中获取其类加载器,然后传递给它),一个你希望该代理实现的接口列表(不是类或抽象类),以及InvocationHandler接口的一个实现。

动态代理可以将所有调用重定向到调用处理器,因此通常会像调用处理器的构造器传递给一个“实际”对象的引用,从而使得调用处理器在执行其中介任务时,可以将请求转发。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: