java反射
java反射
什么是反射?
一种动态实例化对象,并且可以获取到实例对象的属性,方法,并对其进行一些操作
- 常规调用对象
在 Java 中创建对象,获取属性,调用对象的方法通常都是通过 Object o = new Object(), 然后通过 o.getXXX(), o.setXXX() o.doSomething()来实现。
- 反射调用对象
Class<?> classBook = Class.forName("com.android.peter.reflectdemo.Book");
Object objectBook = classBook.newInstance();
Book book = (Book) objectBook;
反射的例子
- 底层组件,调用上层业务对象
- spring
反射的优缺点
优点
增加程序的灵活性,避免将固有逻辑写死
代码简洁,可读性强,可提高代码的复用率
缺点
相比较于直接调用,在访问量较大的情况下,反射会导致系统性能明显下降
打破了类的封装性,存在一定的安全隐患
为什么反射慢?
-
反射调用会进行一系列的安全性校验
-
反射需要调用一系列的native方法来实现
-
寻找Class字节码的过程,比如通过ClassName找到对应的字节码Class,然后进行加载、解析,也会比较慢,而new的方式则无需寻找,因为在Linking的解析阶段已经将符号引用转为了直接引用
-
入参校验
反射代码例子
被反射类Book.java
public class Book{
private final static String TAG = "BookTag";
private String name;
private String author;
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
'}';
}
public Book() {
}
private Book(String name, String author) {
this.name = name;
this.author = author;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
private String declaredMethod(int index) {
String string = null;
switch (index) {
case 0:
string = "I am declaredMethod 1 !";
break;
case 1:
string = "I am declaredMethod 2 !";
break;
default:
string = "I am declaredMethod 1 !";
}
return string;
}
}
创建对象
try {
Class<?> classBook = Class.forName("com.android.peter.reflectdemo.Book");
Object objectBook = classBook.newInstance();
Book book = (Book) objectBook;
book.setName("Android进阶之光");
book.setAuthor("刘望舒");
Log.d(TAG,"reflectNewInstance book = " + book.toString());
} catch (Exception ex) {
ex.printStackTrace();
}
反射私有的构造方法
try {
Class<?> classBook = Class.forName("com.android.peter.reflectdemo.Book");
Constructor<?> declaredConstructorBook = classBook.getDeclaredConstructor(String.class,String.class);
declaredConstructorBook.setAccessible(true);
Object objectBook = declaredConstructorBook.newInstance("Android开发艺术探索","任玉刚");
Book book = (Book) objectBook;
Log.d(TAG,"reflectPrivateConstructor book = " + book.toString());
} catch (Exception ex) {
ex.printStackTrace();
}
反射私有属性
try {
Class<?> classBook = Class.forName("com.android.peter.reflectdemo.Book");
Object objectBook = classBook.newInstance();
Field fieldTag = classBook.getDeclaredField("TAG");
fieldTag.setAccessible(true);
String tag = (String) fieldTag.get(objectBook);
Log.d(TAG,"reflectPrivateField tag = " + tag);
} catch (Exception ex) {
ex.printStackTrace();
}
反射私有方法
try {
Class<?> classBook = Class.forName("com.android.peter.reflectdemo.Book");
Method methodBook = classBook.getDeclaredMethod("declaredMethod",int.class);
methodBook.setAccessible(true);
Object objectBook = classBook.newInstance();
String string = (String) methodBook.invoke(objectBook,0);
Log.d(TAG,"reflectPrivateMethod string = " + string);
} catch (Exception ex) {
ex.printStackTrace();
}
参考: https://www.jianshu.com/p/9be58ee20dee
获取成员变量并调用
1.批量的
1).Field[] getFields():获取所有的"公有字段"
2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
2.获取单个的:
1).public Field getField(String fieldName):获取某个"公有的"字段;
2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)
获取成员方法并调用
1.批量的:
public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)
public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)
2.获取单个的:
public Method getMethod(String name,Class<?>... parameterTypes):
参数:
name : 方法名;
Class ... : 形参的Class类型对象
public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
调用方法:
Method --> public Object invoke(Object obj,Object... args):
参数说明:
obj : 要调用方法的对象;
args:调用方式时所传递的实参;
参考: https://blog.csdn.net/qq_36226453/article/details/82790375
Spring IOC 和 DI
也是利用的反射
IOC(Inversion of Control)
控制反转是一种设计思想,并非实际的技术,最核心的思想就是将预先设计的对象实例创建的控制权交给程序(IOC容器)。
注:IOC容器大家可以简单认为是一个KV的Map集合
DI(Dependency Injection)
依赖注入,对象的构建过程中,IOC容器动态提供这个对象所需要的其他对象.