反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。
1、静态加载:编译时加载相关的类,如果没有就报错,依赖性强。
2、动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性。
静态加载
静态加载
静态加载
动态加载
可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支持。
使用反射基本基于解释执行,对执行速度有影响。
1.反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性和方法。反射在设置模式和框架底层都会用到。
2、加载完类之后,在堆中就产生了一个class类型的对象,一个类只有一个Class对象,这个对象包括了类的完整结构信息,通过这个对象得到类的结构。这个Class对象就想一面镜子,透过这个镜子可以看到类的结构,所以形象的成为反射。
1、第一阶段编译阶段,此阶段内我们在Ide中编译代码,编译后通过javac生成class字节码,进而形成jar包。
2、程序运行阶段,程序运行阶段,使用到某一个对象时,会首先通过类加载器加载Class对象。Class对象中会将.class字节码中的属性和方法都对象化。
3、类加载器加载对象后,会在对中创建对应的对象(Cat对象),Cat对象与class对象具有特定的关联。
4、反射则是通过java特有的方式调用类加载器生成class类,并根据生成的class类对对象进行操作。
1、class类也是类,继承自Object类
2、Class类不是new出来的,是系统通过类加载器生成的。
3、对于某个类的类对象,在堆中仅存在一份Class类对象,因为类仅会加载一次。
Class cls = Class.forName(props.getProperty("className"));
// 获取声明的类之后,创建类对应的对象
Object o = cls.newInstance();
Class cls2 = Class.forName(props.getProperty("className"));
Log.i(TAG, String.valueOf(cls.hashCode() == cls2.hashCode()));
输出结果:
2023-03-22 15:52:41.438 27368-27368/cn.jj.reflectionkk I/JJWorld.MainActivity: true
4、每个对象都会记录自己是哪个Class类对象生成的。
5、通过Class对象,可以完整的得到一个类的完整结构。
6、class类对象存在于堆中。
7、类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法代码、变量名、方法名、访问权限等)
public class MainActivity extends AppCompatActivity {
private static String TAG = "JJWorld.MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Properties props = new Properties();
try {
props.load(getAssets().open("re.properties"));
// 1、通过java的反射创建配置文件中配置的类
// >表示不确定的Java类型
Class<?> cls = Class.forName(props.getProperty("className"));
// 2、输出cls
Log.i(TAG, "cls:" + cls);
// 3、输出运行类型
Log.i(TAG, "cls运行时对象:" + cls.getClass());
// 4、得到包名
Log.i(TAG, "包名:" +cls.getPackage().getName());
// 5、输出全类名
Log.i(TAG,"全类名:"+ cls.getName());
// 6、通过cls创建实例对象
Cat cat = (Cat) cls.newInstance();
Log.i(TAG,"cat:" + cat);
// 7、通过反射获取属性
Field field = cls.getField("name");
if (BuildConfig.DEBUG) Log.d(TAG, "field.get(cls):" + field.get(cat));
// 8、通过反射给属性赋值
field.set(cat,"大黄");
if (BuildConfig.DEBUG) Log.d(TAG, "field.get(cls):" + field.get(cat));
// 9、获取所有的属性
Field[] fields = cls.getFields();
for (Field field1 : fields) {
if (BuildConfig.DEBUG) Log.d(TAG, field1.getName() + "--------" + field1.get(cat));
}
} catch (Exception e) {
Log.e(TAG, "Exception " + e.getMessage());
}
}
}
输出结果
2023-03-22 17:43:38.733 20737-20737/cn.jj.reflectionkk I/JJWorld.MainActivity: cls:class cn.jj.reflectionkk.Cat
2023-03-22 17:43:38.733 20737-20737/cn.jj.reflectionkk I/JJWorld.MainActivity: cls运行时对象:class java.lang.Class
2023-03-22 17:43:38.733 20737-20737/cn.jj.reflectionkk I/JJWorld.MainActivity: 包名:cn.jj.reflectionkk
2023-03-22 17:43:38.733 20737-20737/cn.jj.reflectionkk I/JJWorld.MainActivity: 全类名:cn.jj.reflectionkk.Cat
2023-03-22 17:43:38.733 20737-20737/cn.jj.reflectionkk I/JJWorld.MainActivity: cat:cn.jj.reflectionkk.Cat@32a447b
2023-03-22 17:43:38.733 20737-20737/cn.jj.reflectionkk D/JJWorld.MainActivity: field.get(cls):大橘
2023-03-22 17:43:38.733 20737-20737/cn.jj.reflectionkk D/JJWorld.MainActivity: field.get(cls):大黄
2023-03-22 17:43:38.733 20737-20737/cn.jj.reflectionkk D/JJWorld.MainActivity: age--------13
2023-03-22 17:43:38.733 20737-20737/cn.jj.reflectionkk D/JJWorld.MainActivity: name--------大黄
Field对象,表示某个类的成员变量。
1、反射只能获取public属性。
Cat类如下:
public class Cat {
private static final String TAG = "JJWorld.Cat";
public String name = "大橘";
public void hi(){
Log.d(TAG,"cat say hello");
}
public void cry(){
Log.d(TAG,"cat cry");
}
}
public class MainActivity extends AppCompatActivity {
private static String TAG = "JJWorld.MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Properties props = new Properties();
try {
props.load(getAssets().open("re.properties"));
// 通过java的反射创建配置文件中配置的类
Class cls = Class.forName(props.getProperty("className"));
// 获取声明的类之后,创建类对应的对象
Object o = cls.newInstance();
// 通过反射,可以获取对象的属性,Android运行环境与jdk不同。
// 对于没有的属性,java获取时会报错,android获取时如果没有则输出 className:属性
Field nameField = cls.getField("name");
Log.i(TAG, nameField.get(o).toString());
}catch (Exception e){
Log.e(TAG, "className:" + e.getMessage());
}
}
}
输出
2023-03-22 11:22:09.111 21288-21288/cn.jj.reflectionkk I/JJWorld.MainActivity: 大橘
Method对象代表某个类的方法。
代表类的构造方法,Constructor对象表示构造器
public class MainActivity extends AppCompatActivity {
private static String TAG = "JJWorld.MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Properties props = new Properties();
try {
props.load(getAssets().open("re.properties"));
// 通过java的反射创建配置文件中配置的类
Class cls = Class.forName(props.getProperty("className"));
// 获取声明的类之后,创建类对应的对象
Object o = cls.newInstance();
// 无形参的构造器
Constructor constructor = cls.getConstructor();
Log.i(TAG,constructor.toString());
// String.class表示的是String类的class对象
Constructor constructor1 = cls.getConstructor(String.class);
Log.i(TAG,constructor1.toString());
}catch (Exception e){
Log.e(TAG, "className:" + e.getMessage());
}
}
}
输出:
2023-03-22 11:43:22.873 21999-21999/cn.jj.reflectionkk I/JJWorld.MainActivity: public cn.jj.reflectionkk.Cat()
2023-03-22 11:43:22.873 21999-21999/cn.jj.reflectionkk I/JJWorld.MainActivity: public cn.jj.reflectionkk.Cat(java.lang.String)
1、已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能会抛出ClassNotFoundException
应用场景:多用于配置文件,读取类全路径,加载类
具体实现如下:
public class MainActivity extends AppCompatActivity {
private static String TAG = "JJWorld.MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Properties props = new Properties();
try {
// 获取class对象的方式
// 1、已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能会抛出ClassNotFoundException
// 应用场景:多用于配置文件,读取类全路径,加载类
props.load(getAssets().open("re.properties"));
// 通过java的反射创建配置文件中配置的类
Class<?> cls = Class.forName(props.getProperty("className"));
Log.i(TAG,"cls:" + cls + " hashcode:" + cls.hashCode());
// 2、类型.class
Class cls2 = Cat.class;
Log.i(TAG,"cls2:" + cls2 +" hashcode:" + cls2.hashCode());
// 3、通过对象.getClass获取 对象的运行类型就是对应的 Class类对象对应类型
Cat cat = new Cat();
Class<?> cls3 = cat.getClass();
Log.i(TAG,"cls3:" + cls3 + " hashcode:" + cls3.hashCode());
// 4 通过类加载器来获取类的Class对象
// 先得到类加载器 car
ClassLoader classLoader = cat.getClass().getClassLoader();
// 通过类加载去获得class对象
Class<?> cls4 = classLoader.loadClass(props.getProperty("className"));
Log.i(TAG,"cls4:" + cls4 + " hashcode:" + cls4.hashCode());
// 5、基本数据类型的hashCode
Class<Integer> type1 = int.class;
Class<String> stringClass = String.class;
Log.i(TAG,"type1:" + type1 + " hashcode:" + type1.hashCode());
Log.i(TAG,"stringClass:" + stringClass + " hashcode:" + stringClass.hashCode());
// 6、包装数据类型的hashCode
Class<Integer> type2 = Integer.TYPE;
Log.i(TAG,"type2:" + type2 + " hashcode:" + type2.hashCode());
} catch (Exception e) {
Log.e(TAG, "Exception " + e.getMessage());
}
}
}
输出:
2023-03-22 18:11:02.267 23876-23876/cn.jj.reflectionkk I/JJWorld.MainActivity: cls:class cn.jj.reflectionkk.Cat hashcode:53101691
2023-03-22 18:11:02.268 23876-23876/cn.jj.reflectionkk I/JJWorld.MainActivity: cls2:class cn.jj.reflectionkk.Cat hashcode:53101691
2023-03-22 18:11:02.268 23876-23876/cn.jj.reflectionkk I/JJWorld.MainActivity: cls3:class cn.jj.reflectionkk.Cat hashcode:53101691
2023-03-22 18:11:02.268 23876-23876/cn.jj.reflectionkk I/JJWorld.MainActivity: cls4:class cn.jj.reflectionkk.Cat hashcode:53101691
2023-03-22 18:11:02.268 23876-23876/cn.jj.reflectionkk I/JJWorld.MainActivity: type1:int hashcode:110363710
2023-03-22 18:11:02.268 23876-23876/cn.jj.reflectionkk I/JJWorld.MainActivity: stringClass:class java.lang.String hashcode:201249432
2023-03-22 18:11:02.268 23876-23876/cn.jj.reflectionkk I/JJWorld.MainActivity: type2:int hashcode:110363710
public class MainActivity extends AppCompatActivity {
private static String TAG = "JJWorld.MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Properties props = new Properties();
try {
props.load(getAssets().open("re.properties"));
// 通过java的反射创建配置文件中配置的类
Class cls = Class.forName(props.getProperty("className"));
// 获取声明的类之后,创建类对应的对象
Object o = cls.newInstance();
new Thread(new Runnable() {
@Override
public void run() {
Method hi = null;
try {
long startTime = System.currentTimeMillis();
hi = cls.getMethod("hi");
for (int i = 0; i < 900000; i++) {
hi.invoke(o);
}
long endTime = System.currentTimeMillis();
Log.i(TAG,"反射耗时:" + (endTime - startTime));
Cat cat = new Cat();
startTime = System.currentTimeMillis();
for (int i = 0; i < 900000; i++) {
cat.hi();
}
endTime = System.currentTimeMillis();
Log.i(TAG,"正常调用耗时:" + (endTime - startTime));
startTime = System.currentTimeMillis();
hi = cls.getMethod("hi");
hi.setAccessible(true);
for (int i = 0; i < 900000; i++) {
hi.invoke(o);
}
endTime = System.currentTimeMillis();
Log.i(TAG,"反射优化耗时:" + (endTime - startTime));
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}catch (Exception e){
Log.e(TAG, "Exception " + e.getMessage() );
}
}
}
耗时结果:
2023-03-22 12:10:14.315 31796-32430/cn.jj.reflectionkk I/JJWorld.MainActivity: 反射耗时:92
2023-03-22 12:10:14.318 31796-32430/cn.jj.reflectionkk I/JJWorld.MainActivity: 正常调用耗时:3
2023-03-22 12:10:14.397 31796-32430/cn.jj.reflectionkk I/JJWorld.MainActivity: 反射优化耗时:79
2023-03-22 12:10:21.420 32286-32537/cn.jj.reflectionkk I/JJWorld.MainActivity: 反射耗时:97
2023-03-22 12:10:21.423 32286-32537/cn.jj.reflectionkk I/JJWorld.MainActivity: 正常调用耗时:3
2023-03-22 12:10:21.497 32286-32537/cn.jj.reflectionkk I/JJWorld.MainActivity: 反射优化耗时:74
通过外部文件配置,在不修改源码的情况下,来控制程序,也符合设计模式的ocp原则(开闭原则)
例如:使用Properties类,可以读取配置文件,程序中根据读取的文件内容更改程序的逻辑。
public class Cat {
private static final String TAG = "JJWorld.Cat";
public void hi(){
Log.d(TAG,"cat say hello");
}
public void cry(){
Log.d(TAG,"cat cry");
}
}
className = com.example.myapplication.Cat
classMethod = cry
public class MainActivity extends AppCompatActivity {
private static String TAG = "JJWorld.MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Properties props = new Properties();
try {
props.load(getAssets().open("re.properties"));
// 通过java的反射创建配置文件中配置的类
Class cls = Class.forName(props.getProperty("className"));
// 获取声明的类之后,创建类对应的对象
Object o = cls.newInstance();
// 可以打印创建的类的运行类型
Log.e(TAG, "className:" + o.getClass());
// 即在反射中,可以把方法视作对象,获取方法对象之后,通过invoke的方式可以使用此方法
Method method = cls.getMethod(props.getProperty("classMethod"));
// 反射,方法.invoke对象
method.invoke(o);
}catch (Exception e){
Log.e(TAG, "className:" + e.getMessage());
}
}
}