一、Class类
Class类代表java类,它的各个实例对象对应各个类在内存中的字节码。
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是字节码,
不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间分别用一个个的对象来表示。
获取字节码实例对象Class类的方法:
方式一:
通过对象的getClass方法进行获取。
麻烦在于每次是不是都需要具体的类和该类的对象,以及调用getClass方法。
Person p = new Person();
Class clazz = p.getClass();
方式二:
任何数据类型都具备着一个静态的属性class,这个属性直接获取到该类型的对应Class对象。
比第一种简单,不用创建对象,不用调用getClass方法。
但是还是要使用具体的类,和该类中的一个静态属性class完成。
Class clazz = Person.class;
方式三:
这种方式较为简单,只要知道的类的名称即可。
不需要使用该类,也不需要去调用具体的属性和行为。
就可以获取到Class 对象了。
这种仅知道类名就可以获取该类字节码对象的方式,更有利于扩展。
String className = "cn.itheima.bean.Person";
Class clazz = Class.forName(className);
总之,只要在源程序中出现的类型,都有各自的Class实例对象。
二、反射技术概念
JAVA反射机制是在运行状态中对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,
都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射技术可以对类进行解剖。
反射就是把java类中的各种成分映射成相应的java类。
表示java类的Class类提供了一系列的方法来获得其中变量、方法、构造方法、包等信息。
变量---------Field
方法---------Method
构造方法-------Contructor
包------------Package
通过Class创建对象
以前的方法:
1、查找并加载Person.class文件进内存,并将该文件封装成Class对象。
2、在依据Class对象创建该类具体的实例。
3、调用构造函数对对象进行初始化。
Person p = new Person();
三、反射方法:
1、查找并加载指定名字的字节码文件进内存,并被封装成Class对象。
2、通过Class对象的newInstance方法创建该Class对应的类的实例。
3、调用newInstance()方法会去使用该类的空参数构造函数进行初始化。
String className = "cn.itheima.bean.Person";
Class clazz = Class.forName(className);//一下的clazz都是这个类clazz
Object obj = clazz.newInstance();
//Object obj = Class.forName("cn.itheima.bean.Person").newInstance();
如果指定的类中没有空参数的构造函数。
或者要创建的类对象需要通过指定的构造函数进行初始化。
既然要通过指定的构造函数进行对象的初始化。
就必须先获取这个构造函数。//获取指定类中的指定的构造函数。
Constructor constructor = . Class.forName( "cn.itheima.bean.Person").getConstructor(String.class,int.class);
//创建对象。对象的建立都需要构造函数的初始化。 怎么创建对象可以通过构造器对象完成。
Object obj = constructor.newInstance("lisi",20);
//获取指定类中的指定的构造函数。
Constructor constructor = clazz.getConstructor(String.class,int.class);
//创建对象。对象的建立都需要构造函数的初始化。 怎么创建对象可以通过构造器对象完成。
Object obj = constructor.newInstance("lisi",20);
获取Person类中的age字段:
Field ageField =Class.forName("cn.itcast.bean.Person").getDeclaredField("age");
改变变量赋值:
必须先要有对象
Object obj = Class.forName("cn.itcast.bean.Person").newInstance();对该私有字段进行取消权限检查的能力。
ageField.setAccessible(true);//暴力访问。ageField.set(obj, 19);
Object o = ageField.get(obj);获取类中的公共,空参数的方法
Method method = clazz.getMethod("toString", null);Object obj = clazz.newInstance();
Object returnValue = method.invoke(obj, null);带参数的方法:
Method method = clazz.getMethod("function", String.class,int.class);Object obj = clazz.newInstance();
method.invoke(obj, "haha",89);获取静态方法:
Method method = clazz.getMethod("show", null);method.invoke(null, null);//静态空参时
用反射方式执行某个类中的main方法:写一个程序,能根据用户提供的类名,去执行该类中的main方法
普通方法:TestArguments.main(new String[] ("11","22"));
反射方法:String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);方法解决一:mainMethod.invoke(null,new Object(new String[]{"11","22"});
方法解决二:mainMethod.invoke(null,(Object)(new String[]{"11","22"});
(Object) 编译器会作特殊处理,编译时不把参数当作数组看待,也就不会把数组打开散成若干个参数了。数组的反射
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用。
非基本类型的一维数组,既可以当作Object类型使用,又可以当作Object[]类型使用。Array工具类用于完成对数组的反射操作。
Array.getLength();//获取长度Array.get(obj,i);//获取元素
反射的作用:实现框架功能因为在写程序时无法知道要被调用的类名,所以在程序中无法直接new某个类的实例对象,要用反射来做。
hashCode与HashSet
HashSet就是采用哈希算法存储对象的集合,它内部采用对某个数字n进行取余的方式对哈希码进行分组和划分对象的存储区域,Object类中定义了一个hashCode()方法来返回每个java对象的哈希码,当从HashSet集合中
查找某个对象时,java系统首先调用对象的hashCode()方法获得该对象的哈希码,然后根据哈希码找到相应的存储区域,最后取出该存储区域内的每个元素与该对象进行equals方法比较,这样不用遍历集合就可以得到结论。
因为不能修改原程序,所以提供properties配置文件,只需要写入类名,就可以查找给定名称的类文件,
1、加载这个类2、创建该类的对象
3、调用类中的内容
部分代码:
InputStream ips = FileInputStream("config.properties");
Properties props = new Properties();props.load(ips);
ips.close();
String className = props.getProperty("className");
Collection collections = (Collection)Class.forName(className).newInstance();