深入java--类型信息(反射)
来源:互联网 发布:c语言缺陷与陷阱 编辑:程序博客网 时间:2024/06/04 22:41
本节讨论的是Java如何让我们知道如何在运行时知道对象和类的信息。只要方式有两种,一种是传统的RTTI(在运行时,识别一个对象的类型信息),它假定我们在编译时已经知道了所有的类型,另一种是反射机制,它允许我们在运行时发现和使用类型信息。
1Class相当于类的类型一样,无论何时,如果想在运行时使用类型信息,就必须先获得恰当对象的引用(参照第三条String 例子,也是RTTI的例子)。如果你有一个Class对象,还可以使用getSuperclass()方法来查询其直接基类,将返回你可以用来直接查询的Class对象(类),这样就能在运行时发现一个完整的类继承结构,还有可以调用getSimpleName()返回类名,getCanonicalName()返回一个完整的名称(含有包名),getInterfaces()返回一个Class类型的数组。getClass是获得Class对象,也就是一个类。
Class对象就是用来创建所有常规对象的,类是程序的一部分,每个类都有一个Class对象,(更确切的说是被保存在一个同名的.class文件中)。为了运行程序,JVM虚拟机会使用“类加载器”的子系统。原生的类加载器加载的是所谓的 可信类,包括JAVA API类,他们通常是从本地加载的。如果你有特殊的需求,需要以某种特殊的方式加载类,那么你有一种特殊的方式可以加载额外的类加载器。 构造器也是类的静态方法,虽然没有static修饰。
2 Java程序在它开始运行之前不是被全部加载的,它在必需是才会被加载,动态加载的使能行为,在静态加载语言c++是根本不可能做到的。类加载器首先会检查这个类的Class对象是否加载,如果没有,默认的类加载器会根据类名查找.class文件。某个附加类加载器可能会从数据库中查找字节码。一旦某个类的Class对象被载入类存,它就被用来创建这个类的所有对象。
3 jvm会执行静态代码段,你要记住一个概念,静态代码是和class绑定的,class装载成功就表示执行了你的静态代码了。而且以后不会再走这段静态代码了。
Class.forName(xxx.xx.xx) 返回的是一个类 注意类名要完整(包含包名.类名),加载时会加载静态初始化块和静态初始化器
Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段
动态加载和创建Class 对象,比如想根据用户输入的字符串来创建对象
String str = 用户输入的字符串
Class t = Class.forName(str);
t.newInstance();
4 使用newInstance()方法时Class并不知道你确切的类型,但是无论如何都会正确的创建,这是实现虚拟构造器的一种途径。注意:使用newInstance创建的类必须拥有默认的构造器。
5 java还提供了一个方法来生成对Class对象的引用(即类字面常量) 例如FancyToy.class 这样做不仅简单而且更安全,因为它在编译时就受到检查(因此不需要放在try语句块中),并且根除了它对forName()方法的调用,所以也更高效。
类字面常量不仅可以用于普通类, 还可以用于数组 接口 基本类型 以及包装类
boolean.class等价于Boolean.TYPE
char.class等价于Character.TYPE
byte.class等价于Byte.TYPE
int.class等价于Integer.TYPE
short.class等价于Short.TYPE
long.class等价于Long.TYPE
float.class等价于Float.TYPE
double.class等价于Double.TYPE
void.class等价于boolean.class等价于Void.TYPE
有一点注意:当使用.class来创建class对象时,不会自动的初始化该class对象 注意是类.class 普通对象是 对象.getClass 比如 int.class User.class u.getClass
6 为了在Class中使用泛型时放松限制,使用了通配符?,它也是泛型的一部分,表示 任何事物 例如:Class<?>=int.class 注意:Class<?>优于普通不加泛型的class 即便他们是等价的。为了创建一个Class引用,被限定在某种范围,或该类型的任何子类,需要将通配符和extends结合,创建一个范围。例如 Class<? extends User>=user.class
7对于newInstance()方法 加了泛型之后可能返回的不是确定类型 也可能返回的是确定类型
例如:
Class<FancyToy> ftClass=FancyToy.class;
FancyToy fancyToy=ftClass.newInstance;//这里newInstance出来的就是确切的类型
Class<? extends FancyToy> up=ftClass.getSuperclass;
这里泛型不能直接写FancyToy的父类 要模糊的写 这样也导致了newInstance出来不知道是一个什么类型 不是精确地
Object obj=up.newInstance();
8 反射机制在Java中是用来支持其他跳特性的,例如对象序列化和JavaBean(MVC中的数据库层model)。
javaBean在MVC设计模型中是model,又称模型层,在一般的程序中,我们称它为数据层,就是用来设置数据的属性和一些行为,然后我会提供获取属性和设置属性的get/set方法9重要P334thinking in java RTTI与反射的真正区别在于:对RTTI来说,编译器在编译时打开和检查.class文件(
当你创建好一个java类的时候,他会编译一次,之后就是在你每次修改这个文件的时候,单击保存或是CTR+S的时候都会编译一次,这是eclipse为自动编译的),换句话说我们可以用普通的方式调用对象的所有方法;而对于反射的方式,.class文件在编译的时候是不可以获取的,所以是在运行时打开和检查.class文件。(对运行时的理解看第三条的代码String例子)。对于想要运行时运算的动机看第三条的代码String例子和334页的分布式计算,把许多Java对象分布在各处,分为许多的小的计算单元,分布到空闲的机器上运行。
10通常不会直接使用反射工具,但是反射在你要创建更加动态的代码的时候会很有用。
11 一个类,你不写任何构造方法时,会自动存在一个无参构造方法
但是如果你已经写了有参的构造方法了,那么那个默认存在的无参构造方法就不存在了
你如果还需要一个无参构造方法,那就要自己写一个
那为什么一般都需要一个无参构造方法呢?
1)、子类构造方法需要调用父类构造方法,而默认情况下是隐式调用父类无参构造方法,如果父类没有无参构造方法,那就要显式调用一个有参构造方法
2)、反射需要它,反射生成对象时,是调用的无参构造方法,如果没有无参构造方法,就不能反射 newInstance 生成一个该类的对象
10 如果在多态中,B extends A ,A a=new B() 其中B实现A a中的方法只有实现的也就是公共的方法,a是一个B.class 也就是B的类型,但是如果想要调用B中特有的方法,必须对a向下转型(强转)才可以调用B特有的方法,
注意:default和private的类及时在import导入包的时候也不能在另外一个包中命名,假设C设一个default的类,在另一个包中C c=...这样是不对的,即使import了,所以此时没办法强制转换,因为连(C)都写不出来(提示不可见),这时候把对应的类改为public就可以或者还有另外一种方法就是通过反射,压制java的安全性检查,在另一个包中来调用C(即使C不是公开的类)中的任何方法,包括private方法。 即使import了也不能使得default的类在其包中被使用,包可以规范命名,还可以使得在不用包使用相同的名字,import进来只是使用其public和protected的部分类,相当于把一系列的类给导入进来的作用。
下面举例:
结构截图:
package typeinfo.interfacea;public interface A{ /* * thinking in java page346 */ void f();}package typeinfo.packageaccess;import typeinfo.interfacea.*;class C implements A{ @Override public void f() { System.out.println("public C.f()"); } public void g() { System.out.println("public C.g()"); } void u() { System.out.println("package C.u()"); } protected void v() { System.out.println("protected C.v()"); } private void w() { System.out.println("private C.w()"); } }package typeinfo.packageaccess;import typeinfo.interfacea.*;public class HiddenC{ public static A makeA() { return new C(); }}package type;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import typeinfo.interfacea.A;import typeinfo.packageaccess.HiddenC;public class Test{ public static void main(String[] args) { //这是在typeinfo.packageaccess.HiddenC里面调用new C() A a=HiddenC.makeA(); a.f(); /* 这个能成功是因为A时public ,C重写了f方法 动态链接到C的public方法 a中只有f方法,还没有向下转型,转型之后才有的其他方法 */ System.out.println(a.getClass().getName());//a是C类型 但是此时a自己不能C自己特有的方法 只能调用 //必须向下转型(此时不允许 因为不能在包的外部命名C,default), 只能调用父接口共有的方法(可用) /* * 导包之后即使原本是default的类仍然是无法可见的 * 只有public protected才行 包作用一是规范,方便整合 二是在不同包内部可以有相同的类的名字、 * 此处C是default 在包外是不可见 即使导入包了之后也是,不能在package typeinfo.packageaccess * 不能在包的外部命名C */// if(a instanceof C)//// {// C c=(C)a;// c.g();// } //此时可以使用反射解决这个不能向下转型从而调用C自己方法的问题,我们可以通过反射来压制java的安全性检查 callHiddenMethods(a,"g"); callHiddenMethods(a,"f"); callHiddenMethods(a,"v"); callHiddenMethods(a,"w"); } static void callHiddenMethods(Object object,String methodName) { try { Method m=object.getClass().getDeclaredMethod(methodName); m.setAccessible(true); m.invoke(object); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } }输出:
public C.f()
typeinfo.packageaccess.C
public C.g()
public C.f()
protected C.v()
private C.w()
- 深入java--类型信息(反射)
- 「深入Java」类型信息:RTTI和反射
- 「深入Java」类型信息:RTTI和反射
- 深入理解Java类型信息(Class对象)与反射机制
- 深入理解Java类型信息(Class对象)与反射机制
- 深入理解Java类型信息(Class对象)与反射机制
- 深入理解Java类型信息(Class对象)与反射机制
- java反射---获取类型信息
- java进阶(三)-- 类型信息与反射机制
- Java编程思想之类型信息(反射)
- Java深入(反射)
- java基础-反射2(反射,反射操作对象,Class对象的使用,类型信息的获取)
- 类型信息:反射-Class
- java学习笔记一 java类型信息(RITI和反射)
- 重温《JAVA编程思想》----2017.1.20 类型信息+反射(完结)
- java基础-反射1(类型信息,Class对象简介,Class对象初始化)
- Java编程思想(十五) —— 类型信息之反射
- Java编程思想 - 类型信息与反射机制
- cygwin常用命令
- storm文档(12)----自己搭建storm集群
- [译转]为开发人员提供的五种错误报告工具
- Ubuntu下搭建Django平台
- (转载)CCTMXTiledMap使用的几个事项
- 深入java--类型信息(反射)
- 泛泛之笔、、、点点(微软crm2013)
- 挂载根文件系统
- 设计模式---观察者模式
- PHP中判断某个函数是否被支持
- IAP破解原理
- 黑马程序员----Java反射
- snprintf函数
- Mac 数码测色计