一、反射
1.反射
-
有对象必须先有类,static修饰类的属性与方法 在java中存储了类的内容,这个内容也应该是一个对象 java中用到的每一个类都会有一个内存,这每一块内容都是一个对象 这些对象用于记录这些类中声明了哪些方法和构造方法 java将这些类抽象为一个Class类
-
类的类对象中存储了类定义的内容 ---属性 方法 构造方法 一开始可以不知道是哪一个类(类对象),可以通过传入参数获取---框架思想
-
反射机制相关的重要的类有哪些?
答:java.lang.Class:代表整个字节码,代表一个类型,代表整个类。
java.lang.reflect.Method:代表字节码中的方法字节码,代表类中的方法。
java.lang.reflect.Constructor:代表字节码中的构造方法字节码,代表类中的构造方法。
java.lang.reflect.Field:代表字节码中的属性字节码,代表类中的成员变量(静态变量+实例变量)。 -
反射:在程序运行期间可以动态获取类中定义的属性与方法以及构造方法的机制(思想)的实现 *反射核心机制:Class类, 每一个程序中使用的类都有唯一一个对应的Class对象 *反射的API(API:可以调用的属性与方法,构造方法):Field Method Constructor *反射会破化类的封装性 (要通过特殊的场景进行分析,封装性与反射没有绝对的好与坏) * ---> setAccessible超出访问权限修饰符相应的访问范围时,就需要首先获取访问权限(设置为true)
1.1 获取类的类对象
1.通过类名获取类对象
- Class c = 任何类型.class; 调用运行时类的静态属性:class
2.通过对象获取类对象
- Class c = 对象(引用).getClass(); 调用运行时类的对象的getClass()方法
3.通过Class方法的forName方法获取类对象
- Class c = Class.forName("完整类名带包名"); 调用Class的静态方法
- ①静态方法;
- ②方法的参数是一个字符串;
- ③字符串需要的是一个完整类名;
- ④完整类名必须带有包名;java.lang包也不能省略。
// 1.通过类名获取类对象 Class clazz=EasyClassA.class; //2.通过对象获取类对象 clazz=new EasyClassA().getClass(); //3.通过Class方法的forName方法获取类对象 clazz=Class.forName("com.easy7_25.EasyColor_Enum"); System.out.println(clazz);
-
第四种:使用系统的类加载器(了解)
Class c = ClassLoader.getSystemClassLoader().loadClass("java.util.Date");
1.2获取类的属性、方法与构造方法
- 类的属性 Field ---getField getFields getDeclaredField
- 类的属性(Field):java中用来记录 类的属性的类叫做Field
- 反射访问私有属性,必须先获取访问权限(设置为true)--setAccessible(true)
- 超出访问权限修饰符相应的访问范围时,就需要首先获取访问权限(设置为true)
1.2.1 getField getFields getDeclaredField三者区别
-
getField(String name):
- 作用:获取指定名称的public公共字段(包括从父类继承的公共字段)。
- 返回值:返回一个
Field
对象,表示该类或其父类的指定公共字段。 - 异常:如果找不到指定的字段,会抛出
NoSuchFieldException
。
-
getFields():
- 作用:获取类的所有public公共字段(包括从父类继承的公共字段)。
- 返回值:返回一个
Field
数组,包含该类及其父类的所有公共字段。 - 注意:返回的字段数组中不包括非公共字段。
-
getDeclaredField(String name):
- 作用:获取指定名称的字段,不考虑字段的访问权限(public,protected,private,default)。
- 返回值:返回一个
Field
对象,表示该类的指定字段。 - 异常:如果找不到指定的字段,会抛出
NoSuchFieldException
。
总结:
getField
和getFields
只能获取公共字段,包括继承的公共字段。getDeclaredField
可以获取所有字段,不考虑访问权限,但不包括继承的字段。
//获取类对象
Class clazz=Easy.class;
//获取类的属性
//java中用来记录 类的属性的类叫做Field
//fName变量指向的对象就是Easy类中的name属性
Field fName=clazz.getField("name");
//可以获取某一个Easy类的对象的name属性的值
//--面向对象思想获取name
Easy easy=new Easy();
easy.name="zhangsan";
System.out.println(easy.name+"---------");//zhangsan---------
//--反射思想获取name
Object objectName = fName.get(easy);
System.out.println(objectName);//zhangsan
fName.set(easy,"lisi");
System.out.println(easy.name);//lisi
//getField getFields只能获取类中的public声明的属性---getDeclaredField(任何都可以)
Field fCode= clazz.getDeclaredField("code");
fCode.set(easy,"10001");
Object objCode = fCode.get(easy);
System.out.println(objCode);//10001
Field fsex = clazz.getDeclaredField("sex");
Field faddress = clazz.getDeclaredField("address");
fsex.set(easy,"男");
//反射访问私有属性,必须先获取访问权限(设置为true)--setAccessible(true)
//超出访问权限修饰符相应的访问范围时,就需要首先获取访问权限(设置为true)
faddress.setAccessible(true);
faddress.set(easy,"青岛");
System.out.println(faddress.get(easy));//青岛
1.2.2类的方法 getMethod getDeclaredMethods()
-
反射获取方法 Method---一般用于初始化时 getMethod获取public方法 getDeclaredMethod--all 调用方法 --面向对象思想:对象.方法名() // 反射:method.invoke(对象) ---让某一个对象执行此方法
-
获取方法:
-
getMethod(String name, Class<?>... parameterTypes)
:- 作用:获取指定名称和参数类型的公共方法(包括从父类继承的公共方法)。
- 返回值:返回一个
Method
对象,表示该类或其父类的指定公共方法。 - 异常:如果找不到指定的方法,会抛出
NoSuchMethodException
。
-
getMethods()
:- 作用:获取类的所有公共方法(包括从父类继承的公共方法)。
- 返回值:返回一个
Method
数组,包含该类及其父类的所有公共方法。
-
getDeclaredMethod(String name, Class<?>... parameterTypes)
:- 作用:获取指定名称和参数类型的方法,不考虑方法的访问权限(即包括私有、保护和默认访问权限的方法)。
- 返回值:返回一个
Method
对象,表示该类的指定方法。 - 异常:如果找不到指定的方法,会抛出
NoSuchMethodException
。
-
getDeclaredMethods()
:- 作用:获取类的所有声明方法,不考虑方法的访问权限。
- 返回值:返回一个
Method
数组,包含该类的所有声明方法。
-
-
方法信息:
-
获取方法的名称
getName()
-
获取方法的返回类型
getReturnType() -->
返回一个Class
对象,表示方法的返回类型。
-
-
方法调用:
invoke(对象,……对象)
反射:method对象.invoke(对象,……对象) ---让某一对象执行此方法
:
// 反射包 java.lang.reflect
//获取类对象
Class<Easy> c=Easy.class;
//反射获取方法 Method---一般用于初始化时
Easy easy=c.newInstance();
//getMethod获取public方法 getDeclaredMethod--私有
Method ma=c.getMethod("methodA");
//调用方法 --面向对象思想:对象.方法名()
// 反射:method.invoke(对象) ---让某一个对象执行此方法
ma.invoke(easy);
Method mb=c.getMethod("methodB",int.class,int.class);
mb.invoke(easy,23,45);
public class Easy {
public String name;
protected String code;
String sex;
private String address;
public static final transient String test=null;
static int maxage;
public Easy(){}
public Easy(String name){
this.name=name;
}
public void methodA(){
System.out.println("methodA");
}
public void methodB(int a,int b){
System.out.println("methodB");
System.out.println("两个参数分别是"+a+b);
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("设置setName-------");
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
System.out.println("-----setAddress");
this.address = address;
}
public static int getMaxage() {
return maxage;
}
public static void setMaxage(int maxage) {
Easy.maxage = maxage;
}
}
1.2.3 获取构造方法 getConstructor()
-
getConstructor() 反射获取构造方法--没有返回值,没有返回值类型,方法名与类名一样
-
getConstructor(Class<?>... parameterTypes)
:- 作用:获取指定参数类型的公共构造函数。
- 返回值:返回一个
Constructor
对象,表示该类的指定公共构造函数。 - 异常:如果找不到指定的构造函数,会抛出
NoSuchMethodException
。
-
getConstructors()
:- 作用:获取类的所有公共构造函数。
- 返回值:返回一个
Constructor
数组,包含该类的所有公共构造函数。
-
getDeclaredConstructor(Class<?>... parameterTypes)
:- 作用:获取指定参数类型的构造函数,不考虑构造函数的访问权限(即包括私有、保护和默认访问权限的构造函数)。
- 返回值:返回一个
Constructor
对象,表示该类的指定构造函数。 - 异常:如果找不到指定的构造函数,会抛出
NoSuchMethodException
。
-
getDeclaredConstructors()
:- 作用:获取类的所有声明构造函数,不考虑构造函数的访问权限。
- 返回值:返回一个
Constructor
数组,包含该类的所有声明构造函数
//getConstructor() 反射获取构造方法--没有返回值,没有返回值类型,方法名与类名一样
Class<Easy> c=Easy.class;
//!!!!!!!!!!!!
c.newInstance();//调用无参构造方法创建实例
//获取无参构造方法
Constructor<Easy> con = c.getConstructor();
//!!!!!!!!!!!!!!!!
con.newInstance();//调用无参构造方法创建实例
con=c.getConstructor(String.class);
//!!!!!!!!!!!
con.newInstance("zhangsan");调用有参构造方法创建实例
1.3 创建实例
调用构造函数来创建一个新的对象实例:newInstance(Object... initargs)
new
:只能访问公共构造函数。对象.newInstance
:可以访问所有构造函数(包括私有构造函数),但需要设置可访问性(setAccessible(true)
)
2.获取修饰符 getModifiers()
- 在Java反射中,
getModifiers()
方法用于获取类、方法、字段或构造函数的修饰符。修饰符是一些关键字,如public
、private
、static
等,它们定义了这些元素的访问权限和行为。 getModifiers()
方法返回一个整数,这个整数代表了修饰符的位掩码(bitmask)。每个修饰符对应一个特定的位,通过按位与(&
)操作可以判断某个修饰符是否存在。-
例如,假设
modifiers
的值是9(即public
和static
的组合),那么:
modifiers & 1
(检查public
)的结果是1,表示方法具有public
修饰符。
modifiers & 8
(检查static
)的结果是8,表示方法具有static
修饰符。
二、内省
2.1 内省定义
- 内省 :底层是通过反射实现,
- 内省获取属性的读方法和写方法(getter/setter)来获取和设置属性的内容,
- 不会破坏类的封装性
- 内省(Introspector)是java语言为javabean类提供的属性、事件处理的API
- javabean是指按照一定的规则编写的java类,它的所有字段必须是私有的、必须提供setter/getter方法、必须有公共的默认的无参构造、可序列化(实现Serializable接口),而内省就是用于操作javabean类的一套API。
2.1.1 JavaBean的特点包括:
公共类, 无参构造函数,属性私有化,Getter和Setter方法,序列化
-
公共类:JavaBean类必须是公共的(
public
),以便其他类可以访问它。 -
无参构造函数:必须有一个无参的公共构造函数。这是为了确保可以通过反射机制创建实例。
-
属性私有化:通过公共的getter和setter方法来访问和修改这些属性。
-
Getter和Setter方法:getter方法用于获取属性的值,setter方法用于设置属性的值
-
序列化:通常实现
java.io.Serializable
接口,以便可以序列化和反序列化。
2.2 内省常用API
PropertyDescriptor
:描述JavaBean的属性。MethodDescriptor
:描述JavaBean的方法。BeanInfo
:提供对JavaBean的详细信息的访问
(3)获取JavaBean的详细信息:getBeanInfo
Introspector.getBeanInfo(类对象)
- 属于
java.beans.Introspector
类,通过调用该方法可以获取一个BeanInfo
对象,该对象包含了JavaBean的属性、方法、事件等详细信息。 -
/*内省:也是通过反射实现 但不会破化封装性*/ //获取BeanInfo BeanInfo bi = Introspector.getBeanInfo(c); //获取属性写与读的方法 setter getter //getPropertyDescriptors 获取属性的 PropertyDescriptor[] pds = bi.getPropertyDescriptors(); System.out.println(Arrays.toString(pds)); //获取属性的名字 String name = pds[0].getName(); System.out.println("属性名字"+name); //获取读的方法---对应属性的getter方法 Method read = pds[0].getReadMethod(); //获取写的方法---对应属性的setter方法 Method write = pds[0].getWriteMethod(); //面向对象 -- obj.setName("zhangsan"); //反射 -- write.invoke(obj) Easy easy = c.newInstance(); write.invoke(easy,"zhangsan");