类反射是指在程序运行期间,对于任意一个类都能够知道这个类的所有属性与方法,并且对于任意一个对象,都能够任意调用他的一个方法,这种动态获取信息与动态调用对象方法的功能是JAVA语言的反射机制
反射机制是目前众多JAVA框架实现的基础
1. 使用JDBC连接数据库(解析XML中的类名,驱动器,bean等)
2. Servlet在Web容器中的加载和运行
类的执行过程:
1. 编译(.java文件生成.class二进制字节码文件)
2. 加载(.class二进制字节码文件加载到内存中)
3. 连接(包含三步:验证.class文件格式是否规范,语义是否正确;准备类变量分配内存并赋予初始值即系统原值;解析是将符号引用转换直接引用,举例String s=aaa,s则为符号引用,aaa为直接引用,解析就是把指向s的地址指向aaa)
4. 初始化(将用户的赋值再覆盖系统默认的值)
类加载步骤:
1. 将.class文件读到内存中的方法区
2. 为.class生成唯一对应的Class对象,并将该对象放到堆里(此处相当于入口,可对应检查方法区的对应类型数据)
Class是一个类,可反向读取类中的信息,生成实例等功能
举例 Good商品类使用反射:
Goods goods=(Goods)Class.forName(className).newInstance();
Class.forName(className) : 获取Class对象,将完整的类名(比如在包中,就是包.类)通过参数className传递
newInstance(): 新实例
Java反射API常用的类
java.lang包:无需导入
java.lang.Class: 反射的核心类,可获取类的方法,属性等信息,生成类的实例
java.lang.reflect包:无需导入
Method类:表示类的方法,可用来获取类中的方法信息或执行方法
Constructor类:表示类的构造方法
Field类:表示类的成员变量,可用来获取和设置类的属性值
通过Class类的对象,我们可以
a. 获取类的属性,方法
b. 生成类的实例
c. 调用实例的方法,属性
反射,通过操作Class类的对象
a. 实现对类的操作
b. 实现对对象的操作
生成类的实例三种方法代码:
package exercise;
/**
* Created by LL on 2021/11/30 14:48
*/
//获取person类对应的class对象
public class Person {
public static void main(String[] args){
//方式1: 通过Class.forName()获取,更常用,对于编译器
//并不知道对象类型,在运行期对未知类型进行操作时更常用
try {
Class c = Class.forName("exercise.Person");
System.out.println(c.getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//方法2:通过对象实例的getClass()获取
Person p = new Person();
Class c2 = p.getClass();
System.out.println(c2.getName());
//方式3: 通过类的class属性获取
Class c3 = Person.class;
System.out.println(c3.getName());
}
}
获取属性(Field——getName()):
getFields() 所有可访问的公共字段
getDeclareFields() 所有字段
getField(String name) 返回一个特定的公共字段对象
获取方法(Method——getName()):
getMethods() 所有公共方法,包括从超类和超接口继承的声明
getDeclareMethods() 所有方法,包括公共,包含,默认(包)访问和私有方法,但不包括继承的方法
getMethod(String name, Class[] parameterTypes) 返回一个方法对象
Person类具体信息如下
package exercise;
/**
* Created by LL on 2021/11/30 14:48
*/
//获取person类对应的class对象
public class Person {
private int age;
private String name;
public String address;
public Person(){};
public Person(int age, String name, String address) {
this.age = age;
this.name = name;
this.address = address;
}
private void privateMethor1(){
}
public void showInfo(){
System.out.println(this.getName()+"-"+
this.getAge()+"-"+this.getAddress());
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
通过反射获取属性与方法
package exercise;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* Created by LL on 2021/11/30 15:24
*/
public class testPerson {
public static void main(String[] args) {
//第一步:获取Class对象
Class c=null;
try {
c=Class.forName("exercise.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//第二步:调用Class的相应方法
//获取Person类的相关属性
Field[] field1=c.getFields();//获取所有可访问的公共字段
Field[] field2=c.getDeclaredFields();//获取所有字段
try {
Field a=c.getField("address"); //返回一个特定的公共Field对象
System.out.println("获取到特定的公共字段为"+a.getName());
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
// 获取Person类的相关方法
Method[] method1=c.getMethods();//所有公共方法,包括继承来的方法
Method[] method2=c.getDeclaredMethods();//所有公共方,私有,默认等方法,不包括继承方法
//第三步:调用相应反射API,完成需求
System.out.println("*****所有可访问的公共字段*********");
for(Field f:field1){
System.out.println(f.getName());
}
System.out.println("**********获取所有字段*********");
for(Field f:field2){
System.out.println(f.getName());
}
System.out.println("*********所有公共方法,包括继承来的方法****************");
for(Method m:method1){
System.out.println(m.getName());
}
System.out.println("*********所有公共方,私有,默认等方法,不包括继承方法****************");
for(Method h:method2){
System.out.println(h.getName());
}
}
}
输出结果如下
获取到特定的公共字段为address
*****所有可访问的公共字段*********
address
**********获取所有字段*********
age
name
address
*********所有公共方法,包括继承来的方法****************
getAddress
getName
setName
showInfo
getAge
setAge
setAddress
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll
*********所有公共方,私有,默认等方法,不包括继承方法****************
getAddress
getName
setName
showInfo
getAge
privateMethor1
setAge
setAddress
反射获取构造方法
获取构造方法:getConstructor(Class[] parameterTypes) 返回一个构造方法对象
如参数区域Class[] parameterTypes空白,则属于无参构造
Class[] parameterTypes拥有内容,会传回对应的构造方法
通过Constructor —newInstance(object[] initargs) 可生成类的实例
通过Method—invoke(Object obj, Object[] args) 可在具有指定参数的方法对象上,调用此方法对象表示的基础方法
package exercise;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Created by LL on 2021/11/30 15:24
*/
public class testPerson {
public static void main(String[] args) {
//获取Class对象
Class c=null;
try {
c=Class.forName("kb16.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//获取构造方法对象
System.out.println("*******利用构造方法实例化对象,并调用对象的方法*******");
try {
//获取Person的无参构造方法
Constructor constructor=c.getConstructor();
//根据构造方法对象完成类的对象实例化
try {
Object obj=constructor.newInstance();
//通过实例,调用相应方法
//a.获取相应方法Method对象,第一个参数:方法名称,第二个参数:方法中的参数类型
//无参-null,带参分别有int,String参数,输入new Class[]{int.class,String.class}
Method method=c.getMethod("showInfo",null);
//b.调用相应方法
method.invoke(obj,null);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
System.out.println("*******获取带参构造*******");
try {
Constructor constructor2=c.getConstructor(new Class[]{int.class,String.class,String.class});
try {
Object obj2=constructor2.newInstance(new Object[]{
18,"张三","北京"
});
Method method=c.getMethod("showInfo",null);
method.invoke(obj2,null);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
节日促销方案:
package exercise;
/**
* Created by LL on 2021/11/30 16:54
*/
public class ChildrenDayPS {
public ChildrenDayPS(){}
public double promoteSales(String productID){
System.out.println("编号"+productID+"的商品打六折");
return 0.6;
}
}
package exercise;
/**
* Created by LL on 2021/11/30 16:56
*/
public class NationalDayPS {
public NationalDayPS(){}
public double promoteSales(String productID){
System.out.println("编号"+productID+"的商品打七折");
return 0.7;
}
}
package exercise;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Created by LL on 2021/11/30 17:02
*/
public class ProductSales {
//className 不同促销类方案的类名(完整限定名)
public void productsaleByRef(String productID, String className){
try {
//获得相应类的Class对象
Class c=Class.forName(className);
//根据Class去获取构造方法对象
try {
Constructor b=c.getConstructor();
//根据构造方法去完成对象实例化
try {
Object obj=b.newInstance();
//调用相应对象的商品打折方法
Method method=c.getMethod("promoteSales",String.class);
Double discount=(Double)method.invoke(obj,productID);
System.out.println("节日折扣"+discount);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
ProductSales ps=new ProductSales();
ps.productsaleByRef("p001","kb16.ChildrenDayPS");
ps.productsaleByRef("p001","kb16.NationalDayPS");
}
}