反射
类字节码文件是在硬盘上存储的,是一个个的.class文件。我们在new一个对象时,JVM会先把字节码文件的信息读出来放到内存中,第二次用时,就不用在加载了,而是直接使用之前缓存的这个字节码信息。
字节码的信息包括:类名、声明的方法、声明的字段等信息。在Java中“万物皆对象”,这些信息当然也需要封装一个对象,这就是Class类、Method类、Field类。
通过Class类、Method类、Field类等等类可以得到这个类型的一些信息,甚至可以不用new关键字就创建一个实例,可以执行一个对象中的方法,设置或获取字段的值,这就是反射技术。
Class类
获取Class对象的三种方式
Java中有一个Class类用于代表某一个类的字节码。
Java提供了三种方式获取类的字节码
forName()。forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装
类名.class
对象.getClass()
/*** 加载类的字节码的3种方式
*@throwsException
**/
public void test1() throwsException {//方式一
Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");//方式二
Class clazz2 = Person.class;//方式三
Person p1 = newPerson();
Class clazz3=p1.getClass();
}
通过Class类获取类型的一些信息
1. getName()类的名称(全名,全限定名)
2 getSimpleName()类的的简单名称(不带包名)
3. getModifiers(); 类的的修饰符
4.创建对象
无参数构造创建对象
newInstance()
5. 获取指定参数的构造器对象,并可以使用Constructor对象创建一个实例
Constructor getConstructor(Class>... parameterTypes)
/*** 通过Class对象获取类的一些信息
*
*@throwsException
**/
private static void test2() throwsException {
Class clazz1= Class.forName("cn.itcast.gz.reflect.Person");//获取类的名称
String name =clazz1.getName();
System.out.println(name);//cn.itcast.gz.reflect.Person//获取类的简单名称
System.out.println(clazz1.getSimpleName()); //Person//获取类的修饰符
int modifiers =clazz1.getModifiers();
System.out.println(modifiers);//构建对象(默认调用无参数构造.)
Object ins =clazz1.newInstance();
Person p=(Person) ins;
System.out.println(p);//cn.itcast.gz.reflect.Person@c17164//获取指定参数的构造函数
Constructor> con = clazz1.getConstructor(String.class, int.class);//使用Constructor创建对象.
Object p1 = con.newInstance("jack", 28);
System.out.println(((Person) p1).getName());
}
通过Class类获取类型中的方法的信息
1.获取公共方法包括继承的父类的方法
getMethods()返回一个数组,元素类型是Method
2.获取指定参数的公共方法
getMethod("setName", String.class);
3.获得所有的方法,包括私有
Method[] getDeclaredMethods()
4.获得指定参数的方法,包括私有
Method getDeclaredMethod(String name, Class>... parameterTypes)
/*** 获取公有方法.
*@throwsException
**/
private static void test3() throwsException {
Class clazz1= Class.forName("cn.itcast.gz.reflect.Person");//1.获取非私用方法(包括父类继承的方法)
Method[] methods =clazz1.getMethods();
System.out.println(methods.length);for(Method m : methods) {//System.out.println(m.getName());
if ("eat".equals(m.getName())) {
m.invoke(clazz1.newInstance(),null);
}
}
}
/*** 获取指定方法签名的方法
*
*@throwsException
**/
private static void test4() throwsException {
Class clazz1= Class.forName("cn.itcast.gz.reflect.Person");//获取指定名称的函数
Method method1 = clazz1.getMethod("eat", null);
method1.invoke(new Person(), null);
}
/*** 获取指定方法名且有参数的方法
*
*@throwsException
**/
private static void test5() throwsException {
Class clazz1= Class.forName("cn.itcast.gz.reflect.Person");
Method method= clazz1.getMethod("eat", String.class);
method.invoke(new Person(), "包子");
}/*** 获取指定方法名,参数列表为空的方法.
*
*@throwsException
**/
private static void test4() throwsException {
Class clazz1= Class.forName("cn.itcast.gz.reflect.Person");//获取指定名称的函数
Method method1 = clazz1.getMethod("eat", null);
method1.invoke(new Person(), null);
}
/*** 反射静态方法
*@throwsException
**/
private static void test7() throwsException {
Class clazz1= Class.forName("cn.itcast.gz.reflect.Person");
Method method= clazz1.getMethod("play", null);
method.invoke(null, null);
}/*** 访问私有方法 暴力反射
*@throwsException
**/
private static void test6() throwsException {
Class clazz1= Class.forName("cn.itcast.gz.reflect.Person");
Method method= clazz1.getDeclaredMethod("movie", String.class);
method.setAccessible(true);
method.invoke(new Person(), "苍老师");
}
通过Class类获取类型中的字段的信息
1.获取公共字段
Field[] getFields()
2.获取指定参数的公共字段
Field getField(String name)
3.获取所有的字段
Field[] getDeclaredFields()
4.获取指定参数的字段,包括私用
Field getDeclaredField(String name)
/*** 获取公有的字段
**/
private static void test8() throwsException {
Class clazz1= Class.forName("cn.itcast.gz.reflect.Person");
Field[] fields=clazz1.getFields();
Person p= newPerson();
System.out.println(fields.length);for(Field f : fields) {
System.out.println(f.getName());if ("name".equals(f.getName())) {
System.out.println(f.getType().getName());
f.set(p,"jack");
}
}
System.out.println(p.getName());
}
/*** 获取私有的字段
*@throwsException
**/
private static void test9() throwsException {
Class clazz1= Class.forName("cn.itcast.gz.reflect.Person");
Field field= clazz1.getDeclaredField("age");
System.out.println(field.getName());
field.setAccessible(true);
Person p= newPerson();
field.set(p,100);
System.out.println(p.getAge());
}
工厂模式
Factory
例如:汽车销售商场
该模式将创建对象的过程放在了一个静态方法中来实现.在实际编程中,如果需要大量的创建对象,该模式是比较理想的.
public classDemo1 {public static voidmain(String[] args) {
System.out.println("买宝马");
Car bmw= CarFactory("BMW");
bmw.run();
System.out.println("买大奔");
Car benz= CarFactory("Benz");
benz.run();
}public staticCar CarFactory(String carName) {if ("BMW".equals(carName)) {return newBMW();
}else if ("Benz".equals(carName)) {return newBenz();
}else{throw new RuntimeException("车型有误");
}
}
}abstract classCar {public abstract voidrun();
}class BMW extendsCar {
@Overridepublic voidrun() {
System.out.println("BMW跑跑");
}
}class Benz extendsCar {
@Overridepublic voidrun() {
System.out.println("Benz跑跑");
}
}
模拟spring工厂:
importjava.io.BufferedReader;importjava.io.FileReader;importjava.io.IOException;importjava.lang.reflect.Constructor;importjava.lang.reflect.Field;classStudent{private intid;privateString name;public Student(intid , String name){this.id =id;this.name =name;
}publicStudent(){
}public intgetId() {returnid;
}public void setId(intid) {this.id =id;
}publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}
@OverridepublicString toString() {return this.id +"-"+this.name;
}
}classPerson{private intage;publicPerson(){
}
@OverridepublicString toString() {return this.age+"";
}
}public classDemo1 {public static void main(String[] args) throwsException {
Object o=getInstance();
System.out.println(o);
}public static Object getInstance() throwsException{
FileReader fileReader= new FileReader("src/info.txt");
BufferedReader bufferedReader= newBufferedReader(fileReader);
String line=bufferedReader.readLine();
Class clazz=Class.forName(line);
Constructor c= clazz.getConstructor(null);
Object c1= c.newInstance(null);while((line=bufferedReader.readLine())!=null){
String[] datas= line.split("=");
Field f= clazz.getDeclaredField(datas[0]);
f.setAccessible(true);if(f.getType()==int.class){
f.set(c1, Integer.parseInt(datas[1]));
}else{//f.setAccessible(true);
f.set(c1,datas[1]);
}
}returnc1;
}
}