反射机制(下)
传送门:反射机制(上)
8. 反射属性Field
(1)常用方法
Student类
public class Student {
//4个Field,分别采用了不同的访问控制权限修饰符
private String name;
protected int id;
boolean sex;
public int no;
}
注:其实一个属性就代表一个Field,即private String name是一个Field,boolean sex是一个Field
Test类
public class Test {
public static void main(String[] args) throws Exception {
//获取整个类
Class studentClass = Class.forName("com.study.www.field.Student");
String className = studentClass.getName();
//com.study.www.field.Student
System.out.println(className);
String classSimpleName = studentClass.getSimpleName();
//Student
System.out.println(classSimpleName);
//获取类中所有public修饰的Field
Field[] fields = studentClass.getFields();
System.out.println(fields.length); //1
//取出这个Field
Field f = fields[0];
System.out.println(f.getName()); //no
//获取类中所有Field
Field[] fieldsAll = studentClass.getDeclaredFields();
System.out.println(fieldsAll.length); //4
for(Field field : fieldsAll){
//获取属性的修饰符列表
//返回的修饰符是一个数字,每个数字是修饰符的代号,多个修饰符也会有一个代号
int i = field.getModifiers();
String modifierString = Modifier.toString(i);
//private protected public
System.out.println(modifierString);
//获取属性的类型
Class fieldType =field.getType();
System.out.println(fieldType.getName());//java.lang.String int boolean int
System.out.println(fieldType.getSimpleName()); //String int boolean int
//获取属性的名字
System.out.println(field.getName());//name id sex no
}
}
}
(2)反编译Field实例
public class Test {
public static void main(String[] args) throws Exception {
StringBuilder sb = new StringBuilder();
Class studentClass = Class.forName("com.study.www.field.Student");
sb.append(Modifier.toString(studentClass.getModifiers()) + " class " + studentClass.getSimpleName() + "{\n");
Field[] fields = studentClass.getDeclaredFields();
for(Field field : fields){
String modifierString = Modifier.toString(field.getModifiers());
sb.append("\t" + modifierString + " ");
sb.append(field.getType().getSimpleName()+" ");
sb.append(field.getName()+";\n");
}
sb.append("}");
System.out.println(sb);
}
}
输出结果:
(3)通过反射机制访问对象属性
-
在不使用反射机制之前,我们访问对象属性的方式
public class Test { public static void main(String[] args) throws Exception { Student stu = new Student(); stu.no = 1111; System.out.println(stu.no); } }
-
通过反射机制访问对象属性
public class Test { public static void main(String[] args) throws Exception { Class studentClass = Class.forName("com.study.www.field.Student"); //obj就是Student对象,底层调用无参构造 Object obj = studentClass.newInstance(); //获取属性no Field noField = studentClass.getDeclaredField("no"); //给obj对象(Student对象)的属性no赋值,赋值1111 noField.set(obj,1111); //获取obj对象的属性no的值 System.out.println(noField.get(obj)); } }
如果是私有属性怎么办?通过反射机制可以访问到吗?
可以,需要调用setAccessible(true)方法
public class Test { public static void main(String[] args) throws Exception { Class studentClass = Class.forName("com.study.www.field.Student"); //obj就是Student对象,底层调用无参构造 Object obj = studentClass.newInstance(); //获取属性name Field nameField = studentClass.getDeclaredField("name"); //打破封装,在外部也可以访问私有属性,不安全 nameField.setAccessible(true); nameField.set(obj,"lisi"); System.out.println(nameField.get(obj)); } }
9. 反射方法Method
(1)常用方法
public class Test {
public static void main(String[] args) throws Exception {
//获取类
Class userServiceClass = Class.forName("com.study.www.field.UserService");
//获取所有的Method(包括私有的)
Method[] methods = userServiceClass.getDeclaredMethods();
System.out.println(methods.length);//2
for(Method method : methods){
//获取修饰符列表
System.out.println(Modifier.toString(method.getModifiers())); //public
//获取方法的返回类型
System.out.println(method.getReturnType().getSimpleName());//void boolean
//获取方法的名字
System.out.println(method.getName());//logout login
//方法的参数修饰符列表(一个方法可能有多个参数)
Class[] parameterTypes= method.getParameterTypes();
for(Class parameterType : parameterTypes){
System.out.println(parameterType.getSimpleName()); //String String
}
}
}
}
(2)反编译Method
public class Test {
public static void main(String[] args) throws Exception {
StringBuilder sb = new StringBuilder();
Class userService = Class.forName("com.study.www.field.UserService");
sb.append(Modifier.toString(userService.getModifiers())+" class "+userService.getSimpleName()+" {\n");
Method[] methods = userService.getDeclaredMethods();
for(Method method : methods){
sb.append("\t"+Modifier.toString(method.getModifiers())+" ");
sb.append(method.getReturnType().getSimpleName()+" ");
sb.append(method.getName()+"(");
Class[] parameterMethod = method.getParameterTypes();
for(Class parameterClass : parameterMethod){
sb.append(parameterClass.getSimpleName()+", ");
}
//删除末尾多余的符号
if(", ".equals(sb.substring(sb.length()-2,sb.length()))){
sb.delete(sb.length()-2,sb.length());
}
sb.append("){}\n");
}
sb.append("}");
System.out.println(sb);
}
}
输出结果:
(3)通过反射机制调用方法
-
不采用反射机制时
public class Test { public static void main(String[] args) throws Exception { UserService userService = new UserService(); System.out.println(userService.login("admin","123")); userService.logout(); } }
-
采用反射机制时
public class Test { public static void main(String[] args) throws Exception { Class userServiceClass = Class.forName("com.study.www.field.UserService"); Object obj = userServiceClass.newInstance(); //获取Method //参数列表:方法的名字,两个方法参数的Class(如果int直接int.class 参数类型.class) Method loginMethod = userServiceClass.getMethod("login",String.class,String.class); //loginMethod是获取的方法,obj是创建的对象 //"admin","123"是传进方法的两个实参 //retValue是方法的返回值 Object retValue = loginMethod.invoke(obj,"admin","123"); System.out.println(retValue); //true } }
-
总结
反射机制,让代码具有通用性,可变化的内容都是写到配置文件当中,将来修改配置文件之后,创建的对象就不一样了,调用的方法也不同了,但是Java代码不需要任何的改动
10. 反射构造器Constructor
Student类
public class Student {
private String name;
private int id;
private int no;
public Student() {
}
public Student(String name) {
this.name = name;
}
public Student(String name, int id) {
this.name = name;
this.id = id;
}
public Student(String name, int id, int no) {
this.name = name;
this.id = id;
this.no = no;
}
}
(1)反编译Constructor
public class Test {
public static void main(String[] args) throws Exception {
StringBuilder sb = new StringBuilder();
Class studentClass = Class.forName("com.study.www.field.Student");
sb.append(Modifier.toString(studentClass.getModifiers())+ " class "+studentClass.getSimpleName()+"{\n");
Constructor[] constructors = studentClass.getDeclaredConstructors();
for(Constructor constructor : constructors){
//构造器没有返回类型,且命名都和类一样
sb.append("\t" + Modifier.toString(constructor.getModifiers())+ " "+ studentClass.getSimpleName()+"(");
Class[] parameterTypes = constructor.getParameterTypes();
for(Class c : parameterTypes){
sb.append(c.getSimpleName()+",");
}
if(parameterTypes.length>0)
sb.deleteCharAt(sb.length()-1);
sb.append("){}\n");
}
sb.append("}");
System.out.println(sb);
}
}
运行结果:
(2)通过反射机制调用构造器
-
不使用反射机制
public class Test { public static void main(String[] args) throws Exception { //不使用反射机制调用构造器创建对象 Student student = new Student(); Student student1 = new Student("lisi",111); Student student2 = new Student("zhangsan",222,2); } }
-
使用反射机制
public class Test { public static void main(String[] args) throws Exception { //不使用反射机制调用构造器创建对象 Student student = new Student(); Student student1 = new Student("lisi",111); Student student2 = new Student("zhangsan",222,2); Class studentClass = Class.forName("com.study.www.field.Student"); //调用无参数构造方法 Object obj = studentClass.newInstance(); System.out.println(obj); //调用无参数构造方法的第二种方式 Constructor c1 = studentClass.getDeclaredConstructor(); Object obj1 = c1.newInstance(); System.out.println(obj1); //调用有参数的构造方法 //先获取这个有参数的构造方法 Constructor c = studentClass.getDeclaredConstructor(String.class,int.class,int.class); //调用构造方法new对象 Object obj2 = c.newInstance("wangwu",333,3); System.out.println(obj2); } }
运行结果:
11. 获取父类以及实现的接口
-
获取一个类的父类:getSuperclass()
public class Test { public static void main(String[] args) throws Exception { Class stringClass = Class.forName("java.lang.String"); //获取String父类 Class superClass = stringClass.getSuperclass(); //java.lang.Object System.out.println(superClass.getName()); } }
-
获取一个类实现的接口:getInterfaces()
由于一个类可以实现多个接口,所以一定返回的是一个数组
public class Test { public static void main(String[] args) throws Exception { Class stringClass = Class.forName("java.lang.String"); //获取String类实现的接口 Class[] interfaces = stringClass.getInterfaces(); for(Class c : interfaces){ System.out.println(c.getName()); } //java.io.Serializable //java.lang.Comparable //java.lang.CharSequence } }