类型信息

【前言】

编程思想第二遍,第二遍开始整理,希望有更深的理解。

前几天看了关于spring aop的讲解,了解到了aop的一种实现方式是通过jdk的动态代理实现的,于是又翻看了编程思想的第14章类型信息中相关内容,现在开始总结。

【正文】

运行时类型信息使得你可以在程序运行时发现和使用类型信息,即通过运行时类型信息程序能使用基类指针域引用来检查这些指针或者引用所指的对象的实际派生类型。

本章主要讨论java通过两种方式让我们在运行时识别对象和类的信息。第一种:RTTI【Run Time Type Information】。第二种:反射机制

<RTTI>

RTTI:在运行时识别一个对象的类型。【多态面型对象编程的基本目标:只与对象的一个通用打交道】

一、class对象

class对象:java使用class对象来执行RTTI。写了一个java程序,通过jvm(类加载器)运行就会得到一个class。

(1)所有的类都是在对其第一次使用时,鼎泰加载到jvm中的

(2)当程序创建第一个对类的静态成员的引用时,就会加载这个类。【这一条也说明,构造器也是类的静态方法,虽然构造器前面没有static关键字,因此new创建新对象时会被当做对类的静态成员的引用】

(3)java程序在运行之前并非被完全加载,class对象仅在用到时才会加载,static初始化是在类加载时进行的

(4)类加载器会首先检查这个类的class对象是否已经加载,如果还没有加载,默认的类加载器就会根据类名查找.class文件。

(5)Class.forName("类名"):forName是Class类的一个静态对象,对forName的调用是为了如果类还没有被加载,则这个方法会加载它,并返回这个对象的引用。需要注意的是传递                                                  给 forName的参数必须是全限定名,即要包括包名的。

(6)newInstance()来创建的类,必需带有默认的构造器。

   1.1类字面常量

(1)通过类字面常量也可以生成对class对象的引用。【Toy.class】

(2)类字面常量不仅用于普通的类,对于接口数组以及基本数据类型都是有效的。但是对于基本数据类型的包装类,boolean.class等价于Boolean.TYPE

(3)使用.class来创建class对象引用时,不会自动初始化该class对象。初始化延迟到了对静态方法或者静态域首次引用时才执行。

(4)加载【类加载器执行,来创建一个class对象】----->链接【为静态域分配内存空间】---->初始化【如果该类有父类,则对父类先进行初始化】

(5)同时被static和final修饰的确定的值称为编译器常量,即使该类没有被初始化也能读出来这个数值。

          static和finlal同时修饰的但是初始值不确定的就需要强制类初始化才可以被读出来。

          只被static修饰的也需要强制类初始化才可以被读出来。

  1.2泛化的class引用


二、类型转换前先做检查

(1)RTTI形式:传统的类型转换【如果执行了一个错误的类型转换,就会抛出一个ClassCastException异常】

                               代表对象的类型的class对象,通过查询class对象来获取运行时所需要的信息

                               关键字instanceof,返回一个布尔值,告诉我们对象是不是某个特定的类型的实例

(2)父类向基类转型,被称作是类型安全的向下转型;基类向父类转型,被称作是类型安全的向上转型。

  2.1使用类字面常量       

  2.2动态的instanceof

Class.isInstance方法提供了一种动态的测试对象的途径。

对象 instanceof 类【obj instance of class】若 class obj1=obj,则返回true

类 isInstance(对象)【class isInstance(obj)】若class obj1=obj则返回true。

  2.3递归计数

isAssignableFrom 是用来判断一个类Class1和另一个类Class2是否相同或是另一个类的超类或接口。【Class1.isAssignableFrom (Class2) 】 

三、注册工厂

四、instanceof与Class的等价性

instanceof和class在用==和equals有差别:instanceof保持类型的概念,它指的是你是这个类吗,或者你是这个类的派生类吗,而如果直接调用.getClass方法进行==和equals比较,它就不会考虑继承,即是哪个类就是哪个类。

<反射>

RTTI有一个限制,这个类型在编译时必须已知。

反射提供了一种机制,用来检查可用的方法,并返回方法名。【用invoke方法调用与Method对象关联的方法】

Class类和java.lang.reflect类库一起对反射的概念进行了支持。

主要区别:RTTI是在编译器打开和检查.class文件    反射机制则是在运行时打开和检查.class文件

Class的getMethods()和getConstructors()方法分别反悔Methods对象的数组和Constructor对象的数组

【动态代理】

/*
 *一、 创建动态代理的步骤
 * 1.创建被代理的对象(接口类型)
 * 2.通过代理类Proxy的newProxyInstance()方法创建代理对象
 * 3.newProxyInstance()方法的三个参数:
 *   3.1 ClassLoader:类加载器,即代理对象使用哪个类加载器进行加载,一般和被代理对象使用相同的.
 *   3.2 Class类型的数组,此数组中只能放接口的Class对象.若代理对象不需要实现被代理对象已经实现的接口以外的接口,则可以使用
 *   3.3 InvocationHandler一般使用匿名内部类的方式,被代理对象的类型要求是final类型的.编译器会给出提示.
 *二、InvocationHandler接口的实现类中重写的invoke()方法也有三个参数,
   proxy:正在生成的代理对象本身;
   method:正在被调用的那个方法
   args:被调用的方法中实际传递的参数;
   result是调用目标方法后的返回值,如果方法本身没有返回值,则result为null
 */
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import javax.sound.midi.SysexMessage;
//DynamicProxyHander是一个代理类,也被称作是方法调用的处理程序
class DynamicProxyHander implements InvocationHandler {
private Object proxied;
	public DynamicProxyHander(Object proxied) {
		// TODO Auto-generated constructor stub
		this.proxied=proxied;
	}
	@Override
	//在代理实例上处理方法调用invoke(在方法上调用的代理实例,接口方法,传入代理实例上方法调用的参数值的对象数组)
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
			System.out.println("****proxy: "+proxy.getClass());
			if(args!=null){
				for(Object arg:args){
					System.out.println("SometingElse的参数:"+arg);
				}
			}
			//invoke(调用底层方法的对象,用于方法调用的参数)
			return method.invoke(proxied, args);
	}
}
//RealObject和RealObject2都是被代理类
class RealObject implements Interface{
	@Override
	public int doSomething() {
		// TODO Auto-generated method stub	
		System.out.println("RealObject->doSomething()");
		return 1;
	}
	@Override
	public void SomethingElse(String arg) {
		// TODO Auto-generated method stub
		System.out.println("SomethingElse:"+arg);
	}
}
class RealObject2 implements Interface{

	@Override
	public int doSomething() {
		// TODO Auto-generated method stub
		System.out.println("RealObject2->doSomething()");
		return 2;
	}
	@Override
	public void SomethingElse(String args) {
		// TODO Auto-generated method stub
		System.out.println("SomethingElse:"+args);
	}
}
public class SimpleDynamicProxy{
	public static void consumer(Interface iface){
		System.out.println(iface.doSomething());
		iface.SomethingElse("bonon");
	}
	public static void main(String[] args) {
		RealObject real=new RealObject();
		RealObject2 real2=new RealObject2();
		consumer(real);
		//Proxy用于创建动态类和实例的静态方法
		Interface proxyInterface=(Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, new DynamicProxyHander(real));
		Interface proxyInterface2=(Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[]{Interface.class}, new DynamicProxyHander(real2));
		consumer(proxyInterface);
		consumer(proxyInterface2);
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值