类型信息RTTI
来源:互联网 发布:700套微信小游戏源码 编辑:程序博客网 时间:2024/05/29 15:11
类型信息主要讲述的是:在运行时类型信息使得你可以在程序运行时发现和使用类型信息
也就是 RTTI(运行时类型识别)
如何在运行时识别对象和类的信息?主要有两种方式:一种是传统的RTTI,它假定我们在编译时已经知道了所有的类型;另一种是反射机制,它允许我们在运行时发现和使用类的信息。
为什么需要RTTI?
答:java中需要在运行时知道对象的具体类型,所以需要用到RTTI
类型信息在运行时如何表示?
由class对象的特殊对象完成,它包含类的相关信息。这里是怎么存呢?①Class.forName("对象名"),这样会返回一个Class对象,②还有一种方法就是:对象.class,具有同样的效果,这种方法叫:类的字面常量。③然而实际java存储类相关信息是使用了一个叫泛化的Class引用(Class<Integer> intclass=int.class) 限定Class引用必须是Integer类型。
类型转换前要先做检查
目前RTTI形式有:传统的类型装换(会抛类型转换异常)、代表对象类型的Class对象(用Class存储对象信息)
RTTI在java中第三中形式是instanceof,告诉我们对象是不是某个特定类型的实例,并返回boolean值
InstanceOf与Class的等价性
查询类型信息时,可以用InstanceOf与Class,那么两者有什么区别?
(x InstanceOf 类A)(x.getClass==类A.class)
InstanceOf比较的是你是不是这个类A或是不是这个类A的派生类,而Class比较则是确切的问你是不是这个类A。
什么是反射?
能够分析类能力的程序(java.lang.reflect)
通过反射我们能对一个类知道哪些内容?如下表所示
get() set()方法读取和修改与Field对象关联的字段Method代表类的方法。 用invoke()方法调用与此类关联的方法Constructor代表类的构造方法。
反射用法例子:
try {
String name = "com.reflect.Employee";
Class c = Class.forName(name);
/**
* c.getModifiers():返回此类或接口以整数编码的 Java 语言修饰符。
* Modifier.toString将整数编码转换成字符串 例如 public class Employee{}
* 返回class往前部分public public final class Employee{} 返回class往前部分public
* final
*/
String modifier = Modifier.toString(c.getModifiers());
/**
* 返回构造器数组,该对象反映此 Class 对象所表示的类或接口的指定构造方法。
*/
Constructor[] constructor = c.getDeclaredConstructors();
for (Constructor c1 : constructor) {
System.out.println(c1.getName());// 构造器方法名:com.reflect.Employee
for (int i = 0; i < c1.getParameterTypes().length; i++) {
System.out.println(c1.getParameterTypes()[i]);// 构造器参数类型
}
System.out.println();
}
/**
* 返回方法数组,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
*/
Method[] method = c.getDeclaredMethods();
for (Method m1 : method) {
System.out.println(m1.getReturnType());// 方法返回值类型
System.out.println(m1.getName());// 方法名
System.out.println(Modifier.toString(m1.getModifiers()));// 方法修饰符
// m1.getParameterTypes():返回方法参数数组
for (int i = 0; i < m1.getParameterTypes().length; i++) {
System.out.println(m1.getParameterTypes()[i]);
}
}
/**
* 返回域对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段
*/
Field[] field = c.getDeclaredFields();
for (Field f1 : field) {
System.out.println(f1.getType());// 变量类型
System.out.println(f1.getName());// 变量名
System.out.println(Modifier.toString(f1.getModifiers()));// 变量修饰符
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
运行时使用反射分析对象
String str = "hello"; // 实例化一个String类对象
String s = str; // 用于后面的比较测试
// 打印字符串和hashCode编码
System.out.println(str + "::" + str.hashCode());// hello::99162322
//开始反射动作
Class<?> cls = String.class;
Field value = cls.getDeclaredField("value");//获取value这个域
value.setAccessible(true);//开启运行时动态反射,
// 反射取得str对象的字符数组
char[] arr = (char[]) value.get(str);
// 修改字符数组的内容
arr[0] = 's';
// 打印字符串和hashCode编码
System.out.println(str + "::" + str.hashCode());// sello::99162322
// 比较两次是否相同
System.out.println(s == str);// true
}
反射:运行时的类信息
通过反射能在运行时确定匿名对象的类信息,开头有说过RTTI可以识别对象和类的信息,传统RTTI就是默认运行前已经知道了所有类型,但是假设你获取一个指向某个并不存在你程序空间的对象的引用,或者在网络链接上获得一串字节,并告诉你这个字节是一个类,那怎样才能使用这些类型的类呢?
这时反射就起了作用,Class类和reflect类库一起对反射概念进行了支持,反射可以在运行时获取该类的域、方法、构造器,这样,匿名对象的类信息就能在运行时被确定下来。
RTTI与反射的区别?
RTTI编译时类型必须已知。编译器在编译时打开和检查 .class文件
对于反射,.class文件在编译时是不可获取的,所以是在运行时打开和检查.class文件。
java代理
代理是基本设计模式之一,用来提供额外或不同的操作,
void doSomething();
void somethingElse(String arg);
}
class RealObject implements Interface{ @Override
public void doSomething() {
System.out.println("doSomething");
} @Override
public void somethingElse(String arg) {
System.out.println("somethingElse"+arg);
}
}
class SimpleProxy implements Interface{
private Interface proxied; public SimpleProxy(Interface proxied) {
this.proxied = proxied;
} @Override
public void doSomething() {
System.out.println("SimpleProxy doSomething");
proxied.doSomething();
} @Override
public void somethingElse(String arg) {
System.out.println("SimpleProxy somethingElse"+arg);
proxied.somethingElse(arg);
}
}
public class ProxyDemo {
//一、consumer参数是一个Interface,它不知道具体是RealObject还是SimpleProxy,因为两者都实现Interface
public static void consumer(Interface iface){
iface.doSomething();
iface.somethingElse("aaa");
} public static void main(String[] args) {
//二、这里consumer接收的是一个RealObject对象,所以运行RealObject的doSomething和somethingElse方法
consumer(new RealObject());
//三、这里consumer接收的是一个SimpleProxy对象,
// 但是SimpleProxy对象中的方法用到了RealObject对象的的doSomething和somethingElse方法
consumer(new SimpleProxy(new RealObject()));
}
}
上面这个例子主旨目的是想要通过SimpleProxy对象去调用RealObject两个实际方法,目的是提供额外的或不同的操作,比如代码中打印的两句话,灵活一点的话,这时我们可以在SimpleProxy对象的方法中做一些额外的操作,这种想法就叫代理。代理通常充当一个中间人的角色,好比我想买个包,但是我不太熟悉包的质量,所以想找个代购帮我买,代购帮我买的时候会帮我查看包的质量,并帮我把包买好。
动态代理
private Object proxied; public DynmicProxyHandler(Object proxied) {
this.proxied = proxied;
} @Override
/**
* 动态代理可以将所有调用重定向到调用处理器(下面的invoke方法),
* 因此通常会向调用处理器的构造器传递一个实际对象的引用(上面的proxied),
* 从而使得调用处理器在执行其中介任务时,将请求转发
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//下面是代理的中介任务,打印一下
System.out.println("****proxy:"+proxy.getClass()+",method: "+method+" ,args: "+args);
if (args!=null)
for (Object o:args)
System.out.println(" "+o);
//请求转发,调用proxied对象的method方法
return method.invoke(proxied,args);
}
}public class SimpleDynamicProxy {
public static void consumer(Interface iface){
iface.doSomething();
iface.somethingElse(" aaa ");
}
public static void main(String[] args) {
RealObject real=new RealObject();
consumer(real);
//创建动态代理。需要一个类加载器、该代理实现的接口、以及InvocationHandler接口的实现
Interface proxy= (Interface) Proxy.newProxyInstance(
Interface.class.getClassLoader(),
new Class[]{Interface.class},
new DynmicProxyHandler(real));
consumer(proxy);
}
}
空对象
当你使用内置对象为null表示缺少对象时,必须在每次引用时都得测试是不是null,不然就有可能报空指针异常,但是有时候空对象思想会很有用,比如我有一个空对象(这里说的空对象不是指A a=null,后面会讲如何实现空对象),他可以接受任何传递给他对象消息,但是这个空对象并不作为,通过这种方式我可以假设所有对象都是有效的,所以就不需要去对他进行判空。
空对象例子:
public interface Null {
}interface Operation {//操作
String description();//描述
void command();//指令
}interface Robot{//机器人
String name();//名字
String model();//模型
List<Operation> operations();//描述机器人行为能力
class Test{
public static void test(Robot robot){
//判空
if (robot instanceof Null)
System.out.println("【NULL ROBOT】");
System.out.println("robot name: "+robot.name());
System.out.println("robot model: "+robot.model());
for (Operation operation:robot.operations()){
System.out.println(operation.description());
operation.command();
}
}
}
}class NullRobotProxyHandler implements InvocationHandler{//定义一个空的机器人的代理
private String nullName;
private Robot proxied =new NullRobot();
//构造器,传入一个继承Robot对象的引用
public NullRobotProxyHandler(Class<? extends Robot> type) {
nullName=type.getSimpleName()+" NULL Robot";
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(proxied,args);
}
class NullRobot implements Null,Robot{//定义一个空的机器人
public String name() {
return nullName;
}
public String model() {
return nullName;
}
public List<Operation> operations() {
return Collections.emptyList();
}
}
}class SnowRemovalRobot implements Robot{//定义一个扫雪的机器人
private String name;
public SnowRemovalRobot(String name) {this.name = name;}
public String name() {return name;}
public String model() {return "扫雪机器人一号";} public List<Operation> operations() {
return Arrays.asList(new Operation() {
public String description() {
return name+" 会扫雪";
}
public void command() {
System.out.println(name+" 正在扫雪");
}
},new Operation() {
public String description() {
return name+" 会除冰";
}
public void command() {
System.out.println(name+" 正在除冰");
}
});
}
}class Test{
public static Robot newNullRobot(Class<? extends Robot> type){
return (Robot) Proxy.newProxyInstance(NullRobotProxyHandler.NullRobot.class.getClassLoader(),
new Class[]{Null.class,Robot.class},
new NullRobotProxyHandler(type));
} public static void main(String[] args) {
Robot robot1=new SnowRemovalRobot("扫雪号");
Robot.Test.test(robot1);
Robot robot2=newNullRobot(SnowRemovalRobot.class);
Robot.Test.test(robot2);
}
}输出: robot name: 扫雪号
robot model: 扫雪机器人一号
扫雪号 会扫雪
扫雪号 正在扫雪
扫雪号 会除冰
扫雪号 正在除冰
【NULL ROBOT】
robot name: SnowRemovalRobot NULL Robot
robot model: SnowRemovalRobot NULL Robot
总结:
RTTI允许通过匿名基类的引用来发现类型信息,但不可以滥用RTTI,面向对象的目的是让我们凡是可以使用的地方都是用多态,但要在必需的时候使用RTTI。
0 0
- Java类型信息:RTTI
- 类型信息RTTI
- RTTI 运行时类型信息
- 运行时类型信息RTTI
- 了解运行时类型信息(RTTI)
- 了解运行时类型信息(RTTI)
- Delphi RTTI(运行时类型信息)
- java思想总结9--类型信息 RTTI
- Thinking in Java -- 类型信息RTTI
- C++之运行时类型信息(RTTI)
- chart14 类型信息RTTI(需加强理解)
- chart14 类型信息RTTI(需加强理解)
- Rtti 单元(3): 获取有序类型的信息
- C++ - RTTI(RunTime Type Information)运行时类型信息 详解
- Java编程思想(十四) —— 类型信息RTTI基本概念
- 黑马程序员--类型信息(RTTI 和 反射 )
- RTTI 运行时类型信息 与 Reflect 反射
- C++ 类型信息获取 RTTI traits nest 大杂烩
- PAT1054 求平均值
- 关于股权激励方案建议参考
- C#调用 opencv cv::Mat 图像
- RecycleView 禁止滑动
- instanceof 运算符
- 类型信息RTTI
- java 访问控制修饰符总结详解
- web前端开发学习视频教程下载(百G)
- 数据存储:数据备份:键/值备份
- 员工股权激励方案设计
- 一例一个实体对象不能由多个 IEntityChangeTracker 实例引用的解决
- 1075. PAT Judge 解析
- getAttribute()与getParameter的区别
- NIO通讯框架之Mina