反射
1.反射可以操作Java字节码,创建对象,让程序更加灵活
2.反射相关类在java.lang.reflect.包下
3.反射相关的类有哪些呢?
java.lang.Class代表整个字节码文件,类似Java类
java.lang.reflect.Method代表Java字节码中的方法,类似类中的方法
java.lang.reflect.Constructor:代表Java字节码中的构造方法,类似类的构造方法
java.lang.reflect.Field代表字节码中的属性字节码,代表Java类中的成员变量
4.获取字节码java.lang.Class实例(注意:字节码文件加载到了方法区,只会存在一份)
(1)Class类–java.lang.Class
Class.forName(完整包名+类名)-----------------获取类的字节码文件
(2)java中的任何一个对象都有getClass方法获取它的字节码文件
对象.getClass();
(3)Class c= String.class属性获取
Class<String> stringClass = String.class;
5.反射小案例:反射更灵活,该配置文件就可以生成不同对象
classInfo.properties
className=java.util.Date
利用反射访问:创建对象
public class test {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, IOException {
FileReader fileReader = new FileReader("src/classInfo.properties");
Properties properties = new Properties();
properties.load(fileReader);
fileReader.close();
String className = properties.getProperty("className");
Class<?> aClass = Class.forName(className);
Date date = (Date) aClass.newInstance();
System.out.println(date);
}
}
6.class.forName的作用
class.forName 会导致类的加载,导致静态代码块的执行
newInstance实例化会调用对象的无参构造方法
className=User
class User{
private int age;
private String name;
public User(){
System.out.println("无参构造");
}
static {
System.out.println("我是静态代码块");
}
}
public class test {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, IOException {
FileReader fileReader = new FileReader("src/classInfo.properties");
Properties properties = new Properties();
properties.load(fileReader);
fileReader.close();
String className = properties.getProperty("className");
Class<?> aClass = Class.forName(className);
User user = (User) aClass.newInstance();
System.out.println(user);
}
}
我是静态代码块
无参构造
User@16b98e56
7.src下的文件—获取文件的绝对路径
src 是类的根路径,我们获取路径,必须从类的根路径src下获取(文件不能在src外面)
参数写src下的路径com/bj/classInfo.properties(相对路径)
//拿到一个文件的绝对路径
String path = Thread.currentThread().getContextClassLoader().getResource("com/bj/classInfo.properties").getPath();
System.out.println(path);
/D:/MyAppClass/IDEA2019/test/out/production/test/com/bj/classInfo.properties
8.反射的方法(获取属性—操作属性)
class Student{
private int age;
private String name;
protected int no;
public boolean sex;
}
getFields()获取所有public修饰的属性
Class<?> student = Class.forName("Student");
Field[] fields = student.getFields();
System.out.println(fields.length);
System.out.println(fields[0]);
结果:
1
public boolean Student.sex
getDeclaredFilelds()获取所有的属性
Field[] declaredFields = student.getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++) {
System.out.println(declaredFields[i]);
}
结果
private int Student.age
private java.lang.String Student.name
protected int Student.no
public boolean Student.sex
注意,declaredFields[i]数组中的每一个类型是private int Student.age这个整体
Field[] declaredFields = student.getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++) {
System.out.println(declaredFields[i].getName() +" "+ declaredFields[i].getType());
}
结果:
age int
name class java.lang.String
no int
sex boolean
获取访问修饰符getModifiers()
public static void main(String[] args) throws ClassNotFoundException {
Class<?> student = Class.forName("Student");
Field[] declaredFields = student.getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++) {
int modifiers = declaredFields[i].getModifiers();
System.out.println(modifiers);
System.out.println(Modifier.toString(modifiers));
}
结果:
2
private
2
private
4
protected
1
public
我们可以看出我们的getModifiers方法返回的是int类型的整数,代表访问修饰符的代号
4是protect 2 是private 1是public 我们可以调用Modifier的静态方法将代号转为字符串
**8.反射—反编译:**强大:
public static void main(String[] args) throws ClassNotFoundException {
StringBuilder stringBuilder = new StringBuilder();
Class<?> stringClass = Class.forName("java.lang.String");
stringBuilder.append(
Modifier.toString(stringClass.getModifiers()) +" class " +stringClass.getSimpleName() +"{"
);
Field[] fields = stringClass.getDeclaredFields();
for (Field field : fields) {
stringBuilder.append("\n");
stringBuilder.append("\t");
stringBuilder.append(Modifier.toString(field.getModifiers()));
stringBuilder.append(" ");
stringBuilder.append(field.getType().getSimpleName());
stringBuilder.append(" ");
stringBuilder.append(field.getName());
stringBuilder.append(";\n");
}
stringBuilder.append("}");
System.out.println(stringBuilder);
}
结果:
public final class String{
private final byte[] value;
private final byte coder;
private int hash;
private static final long serialVersionUID;
static final boolean COMPACT_STRINGS;
private static final ObjectStreamField[] serialPersistentFields;
public static final Comparator CASE_INSENSITIVE_ORDER;
static final byte LATIN1;
static final byte UTF16;
}
9.通过反射机制访问Java对象的属性,给属性赋值
import java.lang.reflect.Field;
public class reflect4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
Class<?> user2 = Class.forName("User2");
User2 user = (User2) user2.newInstance();
Field name = user2.getDeclaredField("name");
name.setAccessible(true);
name.set(user,"xiaohong");
System.out.println(user);
}
}
class User2{
private String name;
private int age;
@Override
public String toString() {
return "User2{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
结果:User2{name='xiaohong', age=0}
注意:
当我们访问私有的属性的时候我们会发现无法进行赋值,因为有保护,我们必须打破封装,将属性设为可以访问的,我们才能进行赋值
name.setAccessible(true);
name.set(user,"xiaohong");
属性赋值: 属性.set(所属对象,值) ----------- 注意和 对象.set属性(值)的区别
我们通过类对象获取实例----------通过类对象获取到属性
Class<?> user2 = Class.forName("User2");
User2 user = (User2) user2.newInstance();
Field age = user2.getDeclaredField("age");
age.setAccessible(true);
age.set(user,12);
10.可变长度的参数:
可变长度的参数只能在方法的最后面,可以传入不同长度的参数,只能有一个,可以当作一个数组来看待(也可以传入一个数组作为参数)
public class reflectMethod {
public static void main(String[] args) {
method(12);
method(12,154);
method();
}
public static void method(int ... args){
for (int arg : args) {
System.out.println(arg);
}
}
}
结果:
12
12
154
11.通过反射获得方法
public class reflect4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
Class<?> user2 = Class.forName("User2");
Method[] methods = user2.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
System.out.println(method.getName() + "---"+method.getReturnType().getName() + "--"+ Modifier.toString(method.getModifiers()));
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter.getName());
System.out.println(parameter.getType().getSimpleName());
}
}
}
}
class User2{
private String name;
private int age;
public void method(int age,String name){
System.out.println(this.age+"----"+this.name);
}
}
结果:
private void User2.method(int,java.lang.String)
method—void–private
arg0
int
arg1
String
12.通过反射机制调用方法
import java.lang.reflect.*;
public class reflect4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<?> user2 = Class.forName("User2");
Method method = user2.getDeclaredMethod("method", int.class, String.class);
User2 user = (User2) user2.newInstance();
method.setAccessible(true);
Object result = method.invoke(user, 34, "小明");
System.out.println(user);
System.out.println(result);
}
}
class User2{
private String name;
private int age;
private int method(int age,String name){
System.out.println(age+ "--" +name);
System.out.println(this.age+"----"+this.name);
return 12;
}
}
结果:
34–小明
0----null
User2@3d494fbf
12
重点:
(1)invoke方法调用方法执行, 格式 方法.invoke(对象,参数)
Object result = method.invoke(user, 34, “小明”);
(2)因为方法可能存在重载现象,所以我们获取方法的时候应该指定参数的类型
Method method = user2.getDeclaredMethod(“method”, int.class, String.class);
(3)私有方法,还要设置可访问
13.通过反射得到构造方法,构造方法创建对象
Class<?> user2 = Class.forName("User2");
Constructor<?> con = user2.getDeclaredConstructor(String.class, int.class);
Object xioahua = con.newInstance("xioahua", 12);
System.out.println(xioahua.toString());
}
结果:User2{name=‘xioahua’, age=12}