JavaSE学习笔记27:反射机制(二)
反射机制(二)
Field
java.lang.reflect.Field 代表字节码中的属性字节码,代表类中的成员变量(包括静态变量、实例变量)
获取Field
package se6;
//反射属性Field
public class Student {
//Field翻译为字段,其实就是属性/成员
//4个Field,分别采用了不同的访问控制权限修饰符
public int no;
private String name;
protected int age;
boolean sex;
public static final double MATH_PI = 3.1415926;
}
package se6;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/*
反射Student类当中所有的Field
*/
public class ReflectTest07 {
public static void main(String[] args) throws Exception {
//获取整个类
Class studentClass = Class.forName("se6.Student");
//获取完整类名
String className = studentClass.getName();
System.out.println("完整类名:" + className);//se6.Student
//获取简类名
String simleName = studentClass.getSimpleName();
System.out.println("简类名:" + simleName);//Student
System.out.println("=======================");
//获取类中所有的public修饰的Field
Field[] fields = studentClass.getFields();
System.out.println(fields.length);//1
//取出这个field
Field f = fields[0];
//取出field它的名字
String fieldName = f.getName();
System.out.println(fieldName);//no
System.out.println("=======================");
//获取所有的Field
Field[] fs = studentClass.getDeclaredFields();
System.out.println(fs.length);//5
System.out.println("=======================");
//遍历
for (Field field : fs){
//获取属性的修饰符列表
int i = field.getModifiers();//返回的修饰符是一个数字,每个数字都是修饰符代号
//System.out.println(i);
//将代号转换成字符串
String modifierString = Modifier.toString(i);
System.out.println(modifierString);
//获取属性的类型
Class fieldType = field.getType();
//String fName = fieldType.getName();
String fName = fieldType.getSimpleName();
System.out.println(fName);
//获取属性的名字
System.out.println(field.getName());
System.out.println("=======================");
/**
* public
* int
* no
* =======================
* private
* String
* name
* =======================
* protected
* int
* age
* =======================
*
* boolean
* sex
* =======================
* public static final
* double
* MATH_PI
* =======================
*/
}
}
}
通过反射机制,反编译一个类的属性Field(了解即可)
package se6;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
//通过反射机制,反编译一个类的属性Field(了解即可)
public class ReflectTest08 {
public static void main(String[] args) throws Exception {
//创建这个是为了拼接字符串
StringBuilder s = new StringBuilder();
//Class studetClass = Class.forName("se6.Student");
Class studetClass = Class.forName("java.lang.String");
s.append(Modifier.toString(studetClass.getModifiers()) + "class" + studetClass.getSimpleName() + " {\n");
Field[] fields = studetClass.getDeclaredFields();
for (Field field : fields){
s.append("\t");
s.append(Modifier.toString(field.getModifiers()));
s.append(" ");
s.append(field.getType().getSimpleName());
s.append(" ");
s.append(field.getName());
s.append(";\n");
}
s.append("}");
System.out.println(s);
/**
* public finalclassString {
* private final char[] value;
* private int hash;
* private static final long serialVersionUID;
* private static final ObjectStreamField[] serialPersistentFields;
* public static final Comparator CASE_INSENSITIVE_ORDER;
* }
*/
}
}
通过反射机制访问一个java对象的属性(重点)
package se6;
//反射属性Field
public class Student {
//Field翻译为字段,其实就是属性/成员
//4个Field,分别采用了不同的访问控制权限修饰符
public int no;
private String name;
protected int age;
boolean sex;
public static final double MATH_PI = 3.1415926;
}
package se6;
import java.lang.reflect.Field;
/*
如何通过反射机制访问一个java对象的属性?(重点)
给属性赋值
获取属性的值
*/
public class ReflectTest09 {
public static void main(String[] args) throws Exception {
//不使用反射机制访问对象的属性
Student s = new Student();
//给属性赋值
s.no = 1111; /*
三要素:给s对象的no属性赋值1111
1.对象s
2.no属性
3.1111
*/
//读属性值
System.out.println(s.no);
//使用反射机制访问对象的属性
Class studentClass = Class.forName("se6.Student");
Object obj = studentClass.newInstance();//obj就是Student对象,底层调用无参数构造方法实例化对象
//获取no属性(根据属性的名称来获取Field)
Field noField = studentClass.getDeclaredField("no");
//给obj对象(Student对象)的no属性赋值
/*
虽然使用了反射机制,但是三要素还是缺一不可:
1.obj对象
2.no属性
3.001值
注意:反射机制让代码复杂了,但是为了灵活,也是值得的
*/
noField.set(obj,1);//给obj对象的no属性赋值1
//读取属性的值
//两个要素:获取Obj对象的no属性的值
System.out.println(noField.get(obj));
//可以访问私有的属性吗?
Field nameField = studentClass.getDeclaredField("name");
//打破封装(反射机制的缺点:打破封装,可能会给不法分子留下机会)
//这样设置完之后,在外部也是可以访问private的
nameField.setAccessible(true);
//给name属性赋值
nameField.set(obj,"阿波");
//获取name属性的值
System.out.println(nameField.get(obj));
}
}
可变长参数
int...args
语法是:类型...(注意:一定是3个点)
- 可变长度参数要求的参数个数是:0~N个
- 可变长度参数在参数列表中必须在最后一个位置上,而且可变长度参数只能有1个
- 可变长度参数可以当做一个数组来看待
package se6.bean;
public class ArgsTest {
public static void main(String[] args) {
m();
m(10);
m(10,20);
//m("abc");编译报错
m2(100);
m2(200,"abc");
m2(200,"abc","def");
m2(200,"abc","def","xyz");
m3("ab","de","kk","ff");
String[] strs = {"a","b","c"};
//可以传一个数组
m3(strs);
//直接传一个数组
m3(new String[]{"最","爱","琴","女","E"});//没必要,可以直接如下一行代码即可
m3("最","爱","琴","女","E");
}
public static void m(int...args){
System.out.println("m方法执行了!");
}
//public static void m2(String...args,int...args2){}报错
//必须在最后,只能有1个
public static void m2(int a,String...args1){}
public static void m3(String...args){
//args有length属性,说明args是一个数组
//可以将可变长度参数当做一个数组来看
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
}
Method
java.lang.reflect.Method 代表字节码中的方法字节码,代表类中的方法
反射Method
package se6.service;
/*
用户业务类
*/
public class UserService {
/**
* 登录方法
* @param name 用户名
* @param password 密码
* @return true表示登录成功,false表示登录失败。
*/
public boolean login(String name,String password){
if ("admin".equals(name) && "123".equals(password)){
return true;
}
return false;
}
/**
* 退出系统的方法
*/
public void logut(){
System.out.println("系统已经安全退出!");
}
}
package se6;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/*
作为了解内容:反射Method
(不需要掌握)
*/
public class ReflectTest10 {
public static void main(String[] args) throws Exception {
//获取类
Class userServiceClass = Class.forName("se6.service.UserService");
//获取所有的Method(包括私有的)
Method[] methods = userServiceClass.getDeclaredMethods();
System.out.println(methods.length);//2
System.out.println("==================================");
//遍历Method
for (Method method : methods){
//获取修饰符列表
System.out.println(Modifier.toString(method.getModifiers()));
//获取方法的返回值类型
System.out.println(method.getReturnType().getSimpleName());
//获取方法名
System.out.println(method.getName());
//方法的修饰符列表(一个方法的参数可能会有多个)
Class[] parameterTypes = method.getParameterTypes();
for (Class parameterType : parameterTypes){
System.out.println(parameterType.getSimpleName());
}
}
}
}
反编译
package se6;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/*
了解,不需要掌握
反编译一个类的方法
*/
public class ReflectTest11 {
public static void main(String[] args) throws Exception {
StringBuilder s = new StringBuilder();
Class userServiceClass = Class.forName("se6.service.UserService");
s.append(Modifier.toString(userServiceClass.getModifiers()) + "class" + userServiceClass.getSimpleName() + "{\n");
Method[] methods = userServiceClass.getDeclaredMethods();
for (Method method : methods){
//public boolean login(String name.String password){}
s.append("\t");
s.append(Modifier.toString(method.getModifiers()));
s.append(" ");
s.append(method.getReturnType().getSimpleName());
s.append(" ");
s.append(method.getName());
s.append("(");
//参数列表
Class[] parameterTypes = method.getParameterTypes();
for (Class parameterType : parameterTypes){
s.append(parameterType.getSimpleName());
s.append(",");
}
//删除指定下标位置上的字符
s.deleteCharAt(s.length() - 1);
s.append("){}\n");
}
s.append("}");
System.out.println(s);
}
}
通过反射机制调用对象的方法
重点:通过反射机制调用对象的方法
反射机制让代码具有通用性,可变化的内容都是写到配置文件当中,
将来修改配置文件之后,创建的对象不一样了,调用的方法也不同了,
但是java代码不需要做任何改动,这就是反射机制的魅力。
package se6;
import se6.service.UserService;
import java.lang.reflect.Method;
public class ReflectTest12 {
public static void main(String[] args) throws Exception {
//不使用反射机制,怎么调用方法
UserService userService = new UserService();
//调用方法
/*
要素分析:
1.对象userService
2.login方法名
3.实际参数列表
4.返回值
*/
boolean loginSuccess = userService.login("admin","123");
System.out.println(loginSuccess ? "登录成功" : "登录失败");
//使用反射机制调用对象的方法
Class userServiceClass = Class.forName("se6.service.UserService");
//创建对象
Object obj = userServiceClass.newInstance();
//获取Method(方法)
Method loginMethod = userServiceClass.getDeclaredMethod("login",String.class,String.class);
//调用方法
//invoke(调用)
//反射机制中最重要的一个方法,必须记住
/*
4要素
1.loginMethod 方法
2。Obj 对象
3。"admin","123" 实参
4.retValue 返回值
*/
Object retValue = loginMethod.invoke(obj,"admin","123");
System.out.println(retValue);//true
}
}
Constructor
java.lang.reflect.Constructor 代表字节码中的构造方法字节码,代表类中的构造方法
反编译一个类的Constructor(构造方法)
package se6;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
public class ReflectTest13 {
public static void main(String[] args) throws Exception {
StringBuilder s = new StringBuilder();
Class vipClass = Class.forName("se6.bean.Vip");
s.append(Modifier.toString(vipClass.getModifiers()));
s.append(" class ");
s.append(vipClass.getSimpleName());
s.append("{\n");
//拼接构造方法
Constructor[] constructors = vipClass.getDeclaredConstructors();
for (Constructor constructor : constructors){
s.append("\t");
s.append(Modifier.toString(constructor.getModifiers()));
s.append(" ");
s.append(vipClass.getSimpleName());
s.append("(");
//拼接参数
Class[] parameterTypes = constructor.getParameterTypes();
for (Class parameterType : parameterTypes){
s.append(parameterType.getSimpleName());
s.append(",");
}
//删除最后下标位置上的字符
if(parameterTypes.length > 0){
s.deleteCharAt(s.length() - 1);
}
s.append("){}\n");
}
s.append("}");
System.out.println(s);
/**
* public class Vip{
* public Vip(int,String,String,boolean){}
* public Vip(int,String,String){}
* public Vip(int,String){}
* public Vip(int){}
* public Vip(){}
* }
*/
}
}
通过反射机制调用构造方法实例化java对象
package se6.bean;
public class Vip {
int no;
String name;
String birth;
boolean sex;
public Vip() {}
public Vip(int no) {
this.no = no;
}
public Vip(int no, String name) {
this.no = no;
this.name = name;
}
public Vip(int no, String name, String birth) {
this.no = no;
this.name = name;
this.birth = birth;
}
public Vip(int no, String name, String birth, boolean sex) {
this.no = no;
this.name = name;
this.birth = birth;
this.sex = sex;
}
@Override
public String toString() {
return "Vip{" +
"no=" + no +
", name='" + name + '\'' +
", birth='" + birth + '\'' +
", sex=" + sex +
'}';
}
}
package se6;
import se6.bean.Vip;
import java.lang.reflect.Constructor;
/*
通过反射机制调用构造方法实例化java对象
*/
public class ReflectTest14 {
public static void main(String[] args) throws Exception {
//不使用反射机制怎么创建对象
Vip v1 = new Vip();
Vip v2 = new Vip(110,"张三","2001-10-11",true);
//使用反射机制创建对象
Class c = Class.forName("se6.bean.Vip");
//调用无参数的构造方法
Object obj = c.newInstance();
System.out.println(obj);
//Vip{no=0, name='null', birth='null', sex=false}
//调用有参数的构造方法
//第一步:先获取到这个有参数的构造方法
Constructor con = c.getDeclaredConstructor(int.class,String.class,String.class,boolean.class);
//第二步:调用构造方法new对象
Object obj2 = con.newInstance(111,"李四","1990-10-11",true);
System.out.println(obj2);
//Vip{no=111, name='李四', birth='1990-10-11', sex=true}
//获取无参数构造方法
Constructor con2 = c.getDeclaredConstructor();
Object obj3 = con2.newInstance();
System.out.println(obj3);
//Vip{no=0, name='null', birth='null', sex=false}
}
}
获取这个类的父类、实现的接口
package se6;
/*
重点:给一个类,如何获取这个类的父类,已经实现了哪些接口?
*/
public class ReflectTest15 {
public static void main(String[] args) throws Exception {
//String举例
Class stringClass = Class.forName("java.lang.String");
//获取String的父类
Class superClass = stringClass.getSuperclass();
System.out.println(superClass);//class java.lang.Object
//获取String类实现的所有接口(一个类可以实现多个接口)
Class[] interfaces = stringClass.getInterfaces();
for (Class in : interfaces) {
System.out.println(in.getName());
}
/*
java.io.Serializable
java.lang.Comparable
java.lang.CharSequence
*/
}
}