反射

1java代码的阶段

一段java代码在程序运行期间会经历三个阶段: source-->class-->runtime

 

2) Class 对象

java中用一个Class对象来表示一个java类的class阶段

Class对象封装了一个java类中定义的成员变量、成员方法、构造方法、类名、包名等

获得class对象的三种方式和区别

// 1. 根据给定的类名来获得  用于类加载

String classname = "cn.itcast.reflect.Person"; // 来自配置文件

Class clazz = Class.forName(classname); // 此对象代表Person.class

 

// 2. 如果拿到了对象,不知道是什么类型   用于获得对象的类型

Object obj = new Person();

Class clazz1 = obj.getClass(); // 获得对象具体的类型

 

// 3. 如果是明确地获得某个类的Class对象  主要用于传参

Class clazz2 = Person.class;

// java中所有的类型都会对应一个Class对象 int Integer

Class intClazz = int.class;

Class intarrClazz = int[].class;

Class voidClazz = void.class;

 

3)反射

反射就是获得一个java类的各个组成部分

// 反射类的成员方法

Class clazz = Person.class;

Method method = clazz.getMethod(methodName, new Class[]{paramClazz1, paramClazz2});

method.invoke();

 

// 反射类的构造函数

Constructor con = clazz.getConstructor(new Class[]{paramClazz1, paramClazz2,...})

con.newInstance(params...)

 

// 反射类的属性

Field field = clazz.getField(fieldName);

field.setAccessible(true);

field.setObject(value);

 

4) 反射用在哪里

到底框架是什么?  框架就是将开发中大量重复的代码集中起来写个通用的程序

框架就是用反射来实现的

框架需要现在的类调用将来写的类

 

框架是将来的程序员调用的,框架不能实现完整的功能,框架只是一些一些通用的代码

框架要运行一定会依赖将来写的类

现在写的类要调用将来写的类,我们先针对接口进行调用,将来的类需要实现接口,那么方法就固定了

但是将来写的类的类名我们无法获知,这时就需要调用者通过配置文件告诉框架具体的类名

 

1. 理解Class

   对象都是根据类创建出来的—>创建一个对象代表李四这个人—>李四(跑起来)

Person.class(描述所有和李四类似的事物的信息à Person对象 à 李四(赵六、王五)

Class.class(描述字节码这类事物的特征–> Class对象—> Person.class字节码(Student.class Boy.class String.class)

 

所有的Person对象能做的事情都用方法来描述,例如跑步用run方法描述

所有的Class对象(字节码)能做的事情用方法来描述,例如创建对象用newInstance来描述

 

2. 通过反射获得Class对象

三种方式获得

// 1. 根据给定的类名来获得

String methodname = "run";

String classname = "cn.itcast.reflect.Person"; // 来自配置文件

Class clazz = Class.forName(classname); // 此对象代表Person.class

Object obj = clazz.newInstance(); // 创建对象

 

 

// 2. 如果拿到了对象,不知道是什么类型

Object obj = new Person();

Class clazz1 = obj.getClass(); // 获得对象具体的类型

 

// 3. 如果是明确地获得某个类的Class对象

Class clazz2 = Person.class; // 主要用于传参

 

// java中所有的类型都会对应一个Class对象 int Integer

Class intClazz = int.class;

Class intarrClazz = int[].class;

Class voidClazz = void.class;

 

3. 反射能做什么事情

// 调用任何一个对象的任何方法

// 读取配置文件获得如下信息

String classname = "cn.itcast.reflect.Student";

String methodname = "study";

 

 

// Personrun方法调用

// 1.创建Person对象

Class clazz = Class.forName(classname); // 此对象代表Person.class

Object obj = clazz.newInstance(); // 创建对象

// 2.获得表示run方法的对象

Method runMethod = clazz.getMethod(methodname);

// 3.通过Person对象来调用run方法

 

4. 通过反射获得类的成员变量

// 获得代表某个属性的Field对象

Class clazz = Person.class;

 

Field[] fields = clazz.getDeclaredFields();

for(Field field : fields) {

String name = field.getName(); // 获得属性名

Class type = field.getType(); // 获得属性的类型

System.out.println("属性名:" + name + "属性类型:" + type);

}

 

// 获得对象的某个指定的属性,并为该属性赋值

// 明确告诉你,获得name属性

String fieldname = "name";

Object obj = new Person();

 

// 1. 获得Class对象()

Class clazz1 = obj.getClass();

// 2. 获得指定的属性

Field nameField = clazz1.getDeclaredField(fieldname);

// 3. 为属性赋值

// 私有属性不行,因为java虚拟机会检查访问权限

// 如果一定要访问,就需要取消java访问检查

nameField.setAccessible(true);

nameField.set(obj, "zhangsan");

/*

Person p = (Person) obj;

System.out.println(p.getName());*/

Object value = nameField.get(obj); // 获得指定对象上该字段的值

System.out.println(value);

5. 通过反射获得类的构造方法

// 获得类

Class clazz = Person.class;

 

// 获得类的所有构造函数

Constructor[] constructors = clazz.getConstructors();

for(Constructor con : constructors) {

// 遍历参数类型

Class[] parameterTypes = con.getParameterTypes();

for(Class type : parameterTypes)

System.out.print(type.getName() + "   ");

System.out.println();

}

 

// 获得指定的构造函数,创建对象

// 要求调用参数为 String int 的构造函数

// 1. 反射出指定的构造函数

Constructor con = clazz.getConstructor(String.class, int.class);

// 2. 调用构造函数创建对象

Object obj = con.newInstance("wangwu", 23);

System.out.println(obj); // toString

6. 通过反射获得类的成员方法

Class clazz = Person.class;

 

// 获得类的所有方法

Method[] methods = clazz.getDeclaredMethods();

for(Method m : methods) {

String name = m.getName(); // 方法名

System.out.print("方法名:" + name);

// 参数类型

System.out.print(", 参数类型依次为:");

Class[] types = m.getParameterTypes();

for(Class type : types)

System.out.print(type.getName() + "  ");

// 返回值类型

Class returnType = m.getReturnType();

System.out.print(",返回值类型:" + returnType.getName());

System.out.println();

}

 

// 反射出指定的方法,调用

// 创建一个对象

Object obj = clazz.newInstance();

// 调用play方法

Method playMethod = clazz.getMethod("play", String.class);

playMethod.invoke(obj, "zhangsan");

// 调用eat方法

Method eatMethod = clazz.getMethod("eat");

eatMethod.invoke(null);

// 调用sleep方法

Method sleepMethod = clazz.getMethod("sleep", String[].class);

String[] arr = {"a","b"};

sleepMethod.invoke(obj, (Object)arr); // 符合1.41.5的语法

 

// 什么情况下用哪个?

// 1. 如果我们需要加载一个类

Class.forName("cn.itcast.reflect.Person"); // 去加载一个类

// 2. 如果我们要判断一个对象的类型

Object obj = new Person();

 

// 判断obj对象是不是Person类型对象

 

if(obj.getClass() == Person.class)

System.out.println("是一个Person对象");

else

System.out.println("不是一个Person对象");

 

 

obj = new Student();

// 把子类当做父类来用,不能调用子类的方法,此时需要强转

// 强转之前需要判断类型

// instanceof 判断对象是否实现了指定的接口(或继承了指定的类)

if(obj instanceof Person) {

Person p = (Person) obj;

p.run();

}

 

// 3. 如果我们在调用方法时,方法需要的参数是Class类型,

doXX(Person.class);

原文地址:https://www.cnblogs.com/qq809306794/p/3183193.html