共计 9661 个字符,预计需要花费 25 分钟才能阅读完成。
反射的基本概念
- 什么是反射:反射就是把 java 中的各个局部,映射成一个个的 java 对象,也能够了解为这是一种创建对象的形式,而后利用这个对象来做一些事件。既然说反射是反射 java 类中的各个组成部分,那么一个类的组成部分都有些啥呢,例如一个类中有:成员办法、成员变量、构造方法等信息。利用反射技术咱们能够把这些组成部分映射成一个个对象。
- Class ; 一个类对象
- Constuructor; 类中的构造方法
- Method;类中的办法
- Field;类中的属性
获取 class 文件的三种形式
- 应用 Class 类中的静态方法 forName(“文件名”)来获取 class 文件。(如果是 java 原生态的类,就要写上在那个包外面)
- 间接用文件名获取
- 调用 Object 外面的 getclass()办法。援用.getclass();
@java
public class Test01 {public static void main(String[] args) throws Exception {
// 第一种获取 class 文件的形式
Class c1 = Class.forName("java.util.Date");
// 第二种获取 class 文件的形式。Class c2 = Date.class;
// 第三种获取 class 文件的形式
Date date = new Date();
Class c3 =date.getClass();
System.out.println(c1==c2);
System.out.println(c2==c3);
}
}
验证获取的是不是同一个 class 文件,就去判断是否指向同一个内存地址。
运行后果:
@java
true
true
Process finished with exit code 0
利用反射创立实例
newInstance(); 创立此类对象示意类的新实例。就是创立一个无参的构造方法。
如果此类对象没有无参的构造方法,会报 java.lang.InstantiationException(类实例化失败)异样。
@java
public class ReflectTest01 {public static void main(String[] args) throws Exception {
// 执行了动态块,A 这个类加载了,阐明这个办法能够将 A 类扔到 java 虚拟机外面。// Class.forName("com.qh. 利用反射创立实例.A");
// 不执行动态块
// Class c1= A.class;
//newInstance ; 创立一个新的实例
Object o = Class.forName("com.qh. 利用反射创立实例.A").newInstance();
if (o instanceof A){A a = (A)o;
a.m1();}
}
}
class A{
// 动态块,类加载的时候加载,而且只加载一次
static <u>{</u>
System.out.println("Just I miss you !");
}
public void m1(){System.out.println("张三!");
}
}
利用可变参数创立多个类的实例
@java
public class ReflectTest02 {public static void m1(Class...c) throws Exception{for (int i = 0; i < c.length; i++) {Object o = c[i].newInstance();
System.out.println(o);
}
}
public static void main(String[] args) throws Exception {
<u>Class</u> a = <u>Date</u>.class;
<u>Class</u> b= Exception.class;
m1(a,b);
}
}
运行后果
@java
Thu Oct 08 15:42:25 CST 2020
java.lang.Exception
Process finished with exit code 0
通过反射机制获取类的属性(Field)
- Class 类 Api:
String getSimplename(); 返回源代码中给出的根底类的简略名称。
int getModifiers()返回此类或接口的 Java 语言修饰符,以整数编码。
Field getDeclaredField(String name)返回一个 Field 对象,它反映此示意的类或接口的指定已申明字段 类对象。
Field [] getDeclaredFields()返回的数组 Field 对象反映此示意的类或接口申明的所有字段 类对象。
Field getField(String name)返回一个 Field 对象,它反映此示意的类或接口的指定 公共成员 字段类对象。
Field[] getFields()返回蕴含一个数组 Field 对象反射由此示意的类或接口的所有可拜访的 公共成员 字段类对象。
- Field 类 Api:
String getName(); 返回由此 Field 对象示意的字段的名称。
Class<?> getType()返回一个类对象标识了此示意的字段的申明类型 Field 对象。
int getModifiers()返回此类或接口的 Java 语言修饰符,以整数编码。
- Modifier 类 Api:
String toString()返回对象的字符串示意模式。
反编译一个类的所有属性包含修饰符、申明类型
@java
public class ReflectTest03 {public static void main(String[] args) throws Exception {
//1. 获取一个类
Class c = Class.forName("java.util.Date");
//2. 利用类获取一个属性数组
<u>Field</u>[] fie = c.getDeclaredFields();
StringBuffer sb = new StringBuffer();
sb.append(<u>Modifier</u>.toString(c.getModifiers())+"class"+c.getSimpleName());
sb.append("{\n");
for (<u>Field</u> field:
fie) {
//3. 获取属性的修饰符
sb.append("\t"+<u>Modifier</u>.toString(field.getModifiers())+" ");
//4. 获取属性的类型
sb.append(field.getType().getSimpleName()+" ");
//5. 获取属性的名字
sb.append(field.getName()+"\n");
}
sb.append("}");
System.out.println(sb.toString());
}
}
class Person {
private String <u>name</u> ;
public int age;
protected String sex;
boolean hird;
}
运行后果:
public class Date{
private static final BaseCalendar gcal
private static BaseCalendar jcal
private transient long fastTime
private transient Date cdate
private static int defaultCenturyStart
private static final long serialVersionUID
private static final String[] wtb
private static final int[] ttb}
利用反射机制获取类的单个属性:
- Field 类 Api:
void set(Object o,Object valut); 给对象的属性赋值
Object get(Object o); 查看这个对象的属性值
- Field 继承 AccessibleObject 类 Api:
void setAccessible(boolean b); 突破属性的封装性。
@java
public class ReflectFieldTest01 {public static void main(String[] args) throws Exception {Properties p = new Properties();
Reader rea = new FileReader("D:\\Fieldreflect.properties");
p.load(rea);
rea.close();
String fieldName = p.getProperty("FieldName");
// 获取一个类
Class c = Class.forName("com.qh. 利用反射取得类中的属性.Persion");
Field field = c.getDeclaredField(fieldName);
Object o = c.newInstance();
// 突破属性的封装性
field.setAccessible(true);
// 给 o 对象外面的属性赋值。Scanner input = new Scanner(System.in);
System.out.println("请为该属性赋值:");
field.set(o,input.next());
// 输入 o 对象外面的 field 属性值
System.out.println("该属性的值:"+field.get(o));
}
}
运行后果:
请为该属性赋值:男
该属性的值:男
利用反射机制获取一个类的办法(Method)
1. 利用反射机制获取一个类的所有办法
Class 类 Api:
Method[] getDeclaredMethods(); 返回一个 Method 类型的数组
Method getDeclaredMethod(String name, 类 <?>… parameterTypes); 返回一个 办法对象,它反映此表 示的类或接口的指定申明的办法 类对象。
Method getMethod(String name, 类 <?>… parameterTypes) 返回一个 办法对象,它反映此示意的类或接口的指定公共成员办法 类对象。
Method getMethods(); 返回蕴含一个数组 办法对象反射由此示意的类或接口的所有公共办法 类对象,包含那些由类或接口和那些从超类和超接口继承的申明。
Method 类 Api:
int Modifiers();返回一个办法修饰符所代表的 int 类型的值
String getname(); 返回办法的名字
String getReturnType(); 返回办法的返回值
String getParameterTypes(); 返回一个办法内的形式参数类型数组
@java
public class MethodReflectTest01 {public static void main(String[] args) throws Exception {
// 获取一个类
Class c= Class.forName("com.qh. 利用反射取得类中的办法.Register");
// 通过一个类获取所有办法
Method[] m = c.getDeclaredMethods();
// 将所有的办法遍历
for (Method me:
m) {
// 办法的修饰符
int modifiers = me.getModifiers();
System.out.println(Modifier.toString(modifiers));
// 办法的返回值
Class returnType = me.getReturnType();
System.out.println(returnType.getSimpleName());
// 办法名字
System.out.println(me.getName());
// 办法的参数类型
Class[] parameterTypes = me.getParameterTypes();
for (Class parameterType:
parameterTypes) {System.out.println(parameterType.getSimpleName());
}
}
}
}
运行后果:
public
void
love
public
boolean
login
String
String
通过反射机制获取特定的指定办法:
Object invoke(Object o,Object..age);运行 o 对象的办法,传入 age 参数,返回一个 Object 后果。
@java
public class MethodReflectTest03 {public static void main(String[] args) throws Exception {
// 获取一个类
Class c= Class.forName("com.qh. 利用反射取得类中的办法.Register");
// 获取指定的办法, 与获取属性不同的是,属性非凡的属性名,而调用单个办法是办法名和形参列表
Method m = c.getDeclaredMethod("login",String.class,String.class);
// 运行 login 办法
Object autonomo = m.invoke(c.newInstance(), "Autonomo", "123");
System.out.println(autonomo);
}
}
外面的办法名,传入的参数都能够写一个 properties 配置文件来代替,这样写不会吧代码写死,反射就是考究代码的灵活性。
运行后果:
true
运行了 login 办法
利用反射机制获取一个类的构造方法(Constuructor)
反编译一个类的所有构造方法
所用的办法与 Method 类外面的一样
@java
public class ConstructorReflectTest02 {public static void main(String[] args) throws Exception {
// 获取一个类
Class c = Class.forName("java.lang.String");
// 获取这个类外面所有的构造方法,返回一个 Constructor 类型的数组
Constructor[] co = c.getDeclaredConstructors();
// 创立一个 StringBuffer 进行间断的字符串拼接
StringBuffer sb = new StringBuffer();
sb.append(Modifier.toString(c.getModifiers())+ "class"+c.getSimpleName()+"{\n");
for (Constructor con:
co) {sb.append("\t");
// 获取办法的修饰符
sb.append(Modifier.toString(con.getModifiers())+" ");
// 获取办法名,办法名就是类名,能够间接获取类名
sb.append(c.getSimpleName()+"(");
// 形参列表类型
Class[] parameterTypes = con.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++){if (i<parameterTypes.length-1){sb.append(parameterTypes[i].getSimpleName()+",");
}else{sb.append(parameterTypes[i].getSimpleName());
}
}
sb.append("){}\n");
}
sb.append("}");
System.out.println(sb.toString());
}
}
这里是输入了 String 类外面所有的构造方法,只输入了构造,并没有输入具体内容
运行后果:
public final class String{public String(byte[],int,int){}
public String(byte[],Charset){}
public String(byte[],String){}
public String(byte[],int,int,Charset){}
public String(byte[],int,int,String){}
String(char[],boolean){}
public String(StringBuilder){}
public String(StringBuffer){}
public String(byte[]){}
public String(int[],int,int){}
public String(){}
public String(char[]){}
public String(String){}
public String(char[],int,int){}
public String(byte[],int){}
public String(byte[],int,int,int){}}
获取一个类特有的构造方法
Constructor:Object newInstance(Object…args); 应用此 Constructor 对象示意的构造函数,应用指定的初始化参数来创立和初始化构造函数的申明类的新实例。
(调用了构造方法就是调用了 tostring 办法)
@java
public class ConstructorReflectTest03 {public static void main(String[] args) throws Exception {
// 获取一个类
Class c = Class.forName("com.qh. 利用反射取得类中的构造方法.Person");
// 获取指定的构造方法,构造方法名字都一样,只是参数不一样
Constructor con = c.getDeclaredConstructor(String.class,int.class);
//
Object con1 = con.newInstance("张三", 15);
System.out.println(con1);
运行后果
Person{name='张三', age=15}
利用反射机制获取类的父接口和父类
Class 类:
Class getSuperclass(); 返回 类示意此所示意的实体(类,接口,根本类型或 void)的超类 类。
Class[] getInterfaces(); 确定由该对象示意的类或接口实现的接口。
@java
public class ConstructorReflectTest03 {public static void main(String[] args) throws Exception {
// 获取一个类
Class c = Class.forName("com.qh. 利用反射取得类中的构造方法.Person");
// 获取指定的构造方法,构造方法名字都一样,只是参数不一样
Constructor con = c.getDeclaredConstructor(String.class,int.class);
//
Object con1 = con.newInstance("张三", 15);
System.out.println(con1);
}
}
运行后果:
继承的父类:Object
实现的父接口:Serializable
Comparable
CharSequence