java学习笔记---类型信息(type information)、反射机制与动态代理

(1)Class对象

       要理解RTTI在java 中的工作原理,首先必须知道类型信息在运行时是如何表示的,这项工作是由成为Class对象的特殊对象完成的,它包含了与类有关的信息。

Class.forName(String classname):Class类的静态方法,参数字符串必须包含包名,返回Class对象。

package cp14;

interface HasBatteries{}
class Toy
{
	Toy(){}
	Toy(int i ){}
	void play()
	{
		System.out.println("Play it!");
	}
}
class FancyToy extends Toy implements HasBatteries
{
	FancyToy(){super(1);}
} 
public class ToyTest 
{
	static void printInfo(Class c)
	{
		System.out.println("Class name: "+c.getName());//得到该类的全名,包括包名
		System.out.println("Is interface()? "+c.isInterface());//判断该类是否为接口
		System.out.println("Simple name: "+c.getSimpleName());//得到该类的的简单名字,也就是类名
		System.out.println("Canonical name: "+c.getCanonicalName());//得到该类的全名,包括包名
		
	}
	public static void main(String[] args)
	{
		Class c=null;
		try
		{
			c=Class.forName("cp14.FancyToy");
		}
		catch(ClassNotFoundException e)
		{
			System.out.println("Class not found!");
			System.exit(1);
		}
		printInfo(c);
		for(Class face:c.getInterfaces())//得到该类实现的所有接口
		{
			printInfo(face);
		}
		Class up=c.getSuperclass();
		Object obj=null;
		try
		{
			//使用newInstance()来创建的类必须带有默认的构造器
			obj=(Toy)up.newInstance();//由该类的Class对象创建该类的实例,必须满足该类有一个午餐构造方法
		}
		catch(Exception e)
		{
			e.printStackTrace();
			System.exit(1);
		}
		printInfo(obj.getClass());
		//此时Toy对象向上转型为了Object对象,必须向下转型后才能调用Toy特有的方法
		//obj.play();
		((Toy)obj).play();
	}
}

运行结果:

Class name: cp14.FancyToy
Is interface()? false
Simple name: FancyToy
Canonical name: cp14.FancyToy
Class name: cp14.HasBatteries
Is interface()? true
Simple name: HasBatteries
Canonical name: cp14.HasBatteries
Class name: cp14.Toy
Is interface()? false
Simple name: Toy
Canonical name: cp14.Toy
Play it!



 

       

        java还提供了另一种方法来生成Class对象的引用,即使用类字面常量。类字面常量不仅可以应用于普通的类,也可以应用于接口、数组以及基本数据类型。另外对于基本数据类型的包装类,还有一个标准字段TYPE。TYPE字段是一个引用,指向对应的基本数据类型的Class对象,如下所示:

boolean.classBoolean.TYPE
char.classCharacter.TYPE
byte.classByte.TYPE
short.classShort.TYPE
int.classInteger.TYPE
long.classLong.TYPE
float.classFloat.TYPE
double.classDouble.TYPE
void.classVoid.TYPE


       当使用“.class”来创建对Class对象的引用时,不会自动的初始化该Class对象。为了使用类而坐的准备工作实际包含三个步骤:

       1)加载,这是由类加载器执行的。该步骤查找字节码,并从这些字节码中创建一个Class对象。

       2)链接。在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必须的话,将解析这个类创建的对其他类的所有引用。

       3)初始化。如果该类具有超累,则对其初始化,执行静态初始化器和静态初始化块。

       如果一个static final值是“编译器常量”,那么这个值不需要对其所属类进行初始化就可以被读取。但是只是将一个域设置为static或者final的,还不足以确保这种行为。

 

      

        Class引用所指向的Class对象可以进行限定,这里使用了Class的泛化语法。

        当将泛型语法用于Class对象时,newInstance ()方法将返回该对象的确切类型,而不仅仅是在ToyTest.java中看到的基本的Object。

public class GenericToyTest
{
	public static void main(String[] args) throws Exception
	{
		Class<FancyToy> ftClass=FancyToy.class;
		FancyToy fancyToy=ftClass.newInstance();
		Class <? super FancyToy> up=ftClass.getSuperclass();
        Object obj=up.newInstance();
		//写成下面这种形式将无法编译,这简直不可思议
		//Class <Toy> up3=ftClass.getSuperclass();
		Class <Toy> up3=(Class<Toy>) ftClass.getSuperclass();
		Toy obj3=up3.newInstance();
		obj3.play();
	}
}


 

 

 

(2)类型转换前先做检查

         某个对象是不是某个类的实例

         静态检查:instanceof() 

Pet pet=new Pet();
if(pet instanceOf Pet)
{
        System.out.println("true");
}

             动态检查:isInstance()

Pet pet=new Pet();
Class<? extends Pet> cla=Pet.class;
if(cla.isInstance(pet)){}

 

 

(3)instanceof与Class的等价性

class Base{}
class Derived extends Base{}
public class FamilyVsExactType 
{
	static void test(Object x)
	{
		System.out.println("Testing x of type "+x.getClass());
		System.out.println("x instanceof Base "+(x instanceof Base));
		System.out.println("x instanceof Derived "+(x instanceof Derived));
		System.out.println("Base isInstance(x)  "+Base.class.isInstance(x));
		System.out.println("Derived isInstance(x)  "+Derived.class.isInstance(x));
		System.out.println("x.getClass()==Base.class "+(x.getClass()==Base.class));
		System.out.println("x.getClass()==Derived.class "+(x.getClass()==Derived.class));
		System.out.println("x.getClass().equals(Base.class) "+(x.getClass().equals(Base.class)));
		System.out.println("x.getClass().equals(Derived.class) "+(x.getClass().equals(Derived.class)));
	}
	public static void main(String[] args)
	{
		test(new Base());
		test(new Derived());
	}
}

输出结果是:

Derived isInstance(x)  false
x.getClass()==Base.class true
x.getClass()==Derived.class false
x.getClass().equals(Base.class) true
x.getClass().equals(Derived.class) false
Testing x of type class cp14.Derived
x instanceof Base true
x instanceof Derived true
Base isInstance(x)  true
Derived isInstance(x)  true
x.getClass()==Base.class false
x.getClass()==Derived.class true
x.getClass().equals(Base.class) false
x.getClass().equals(Derived.class) true

        instanceof()和isInstance()结果完全一样,equals()和==也一样。instanceof保持了类型的概念,它指的是“你是这个类吗?或者你是这个类的派生类吗?”而如果使用==比较实际的Class对象,就没有考虑继承----它或者是这个确切类型,或者不是。

 

 

(4)动态代理

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

interface Interface
{
	void doSomething();
	void doSomethingElse();
}
class RealObject implements Interface
{
	public void doSomething()
	{
		System.out.println("do something.");
	}
	public void doSomethingElse()
	{
		System.out.println("do something else.");
	}
}
class SimpleProxy implements Interface
{
	private Interface proxied;
	public SimpleProxy(Interface proxied)
	{
		this.proxied=proxied;
	}
	public void doSomething()
	{
		System.out.println("SimpleProxy do something.");
		proxied.doSomething();
	}
	public void doSomethingElse()
	{
		System.out.println("SimpleProxy do something else.");
		proxied.doSomethingElse();
	}
}

public class SimpleProxyDemo 
{
	static void consumer(Interface iface)
	{
		iface.doSomething();
		iface.doSomethingElse();
	}
	public static void main(String[] args)
	{
		consumer(new RealObject());
		consumer(new SimpleProxy(new RealObject()));
	}
}

输出结果是:

do something.
do something else.
SimpleProxy do something.
do something.
SimpleProxy do something else.
do something else.

        java的动态代理比代理的思想要向前迈进了一步,因为它可以动态创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器(InvocationHandler),他的工作是解释调用的类型并确定相应的对策。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface SomeMethods
{
	void boring1();
	void boring2();
	void interesting();
	void boring3();
}
class Implementation implements SomeMethods
{
	public void boring1()
	{
		System.out.println("boring1");
	}
	public void boring2()
	{
		System.out.println("boring2");
	}
	public void boring3()
	{
		System.out.println("boring3");
	}
	public void interesting()
	{
		System.out.println("interesting");
	}
}
class MethodSelector implements InvocationHandler
{
	private Object proxied;
	public MethodSelector(Object proxied)
	{
		this.proxied=proxied;
	}
	@Override
	public Object invoke(Object proxy,Method method,Object[] args) throws Throwable
	{
		if(method.getName().equals("interesting"))
		{
			System.out.println("Proxy detected interesting method!");
		}
		return method.invoke(proxied, args);
	}
}
public class SelectingMethod 
{
	public static void main(String[] args)
	{
		SomeMethods proxy=(SomeMethods)Proxy.newProxyInstance
				(SomeMethods.class.getClassLoader(), 
				new Class[]{SomeMethods.class},
				new MethodSelector(new Implementation()));
		proxy.boring1();
		proxy.boring2();
		proxy.boring3();
		proxy.interesting();
	}
}

输出结果是:

boring1
boring2
boring3
Proxy detected interesting method!
interesting

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



 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值