这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战
⭐8月更文挑战第21天⭐,和小伙伴们一起复习巩固Java😁
Code皮皮虾 一个沙雕而又有趣的憨憨少年,和大多数小伙伴们一样喜欢听歌、游戏,当然除此之外还有写作的兴趣,emm...,日子还很长,让我们一起加油努力叭🌈
欢迎各位小伙伴们关注我的公众号:JavaCodes,名称虽带Java但涉及范围可不止Java领域噢😁,会长期分享博文或者福利,期待您的关注❤
😉毛遂自荐
毛遂自荐,给大家推荐一下自己的专栏😁,欢迎小伙伴们收藏关注😊
1、Java反射机制概述
反射机制有什么用?
通过java语言中的反射机制可以操作字节码文件。优点类似于黑客。(可以读和修改字节码文件)通过反射机制可以操作代码片段。(class文件)
反射机制的相关类在哪个包下?
java.lang.reflect.*
反射机制相关的重要的类有哪些?
java.lang.Class:代表整个字节码,代表一个类型,代表整个类。 java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法。 java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法。 java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)
2、获取Class的三种方式
2.1、第一种
Class c = Class.forName("完整类名带包名");
try {
Class c1 = Class.forName("java.lang.String"); //c1代表String类型
Class c2 = Class.forName("java.util.Date"); //c2代表Date类型
Class c3 = Class.forName("java.lang.Integer"); //c3代表Integer类型
Class c4 = Class.forName("java.lang.System"); //c4代表System类型
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Class.forName()
- 静态方法
- 方法的参数是一个字符串
- 字符串需要的是一个完整类名
- 完整类名必须带有包名。java.lang包也不能省略
2.2、第二种
Class c = 对象.getClass();
public static void main(String[] args) {
Class c1 = null;
Class c2 = null;
Class c3 = null;
try {
c1 = Class.forName("java.lang.String");
c2 = Class.forName("java.util.Date");
c3 = Class.forName("java.lang.Integer");
Class c4 = Class.forName("java.lang.System");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
String str = "abcd"; //字符串对象
Class aClass = str.getClass(); //aClass代表String.class的字节码文件,aClass代表Stirng类型·
System.out.println(aClass == c1); //true(==判断的是对象的内存地址)
Date date = new Date();
Class cdate = date.getClass();
System.out.println(cdate == c2); //true(cdate和c2两个变量中保存的内存地址都是一样的,都指向方法区中的字节码文件)
}
2.3、第三种
Class c = 任何类型.class;
public static void main(String[] args) {
Class c1 = null;
Class c2 = null;
Class c3 = null;
try {
c1 = Class.forName("java.lang.String");
c2 = Class.forName("java.util.Date");
c3 = Class.forName("java.lang.Integer");
Class c4 = Class.forName("java.lang.System");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//Java语言中任何一种类型,包括基本数据类型,它都有.class属性
Class stringClass = String.class; //stringClass代表Stirng类型
Class dateClass = Date.class; //dateClass代表Date类型
System.out.println(stringClass == c1);
System.out.println(dateClass == c2);
}
3、通过反射实例化对象
public class Main {
public static void main(String[] args) {
try {
//通过反射机制,获取Class,通过Class来实例化对象
Class aClass = Class.forName("com.dong.Person");
Object o = aClass.newInstance();
System.out.println(o);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
//Person类
class Person {
}
成功创建对象
newInstance()这个方法会调用Person这个类的无参构造方法,完成对象的创建。
class Person {
public Person() {
System.out.println("运行无参构造方法");
}
}
如果定义了有参构造方法但没有无参构造方法就会报错
class Person {
private String name;
public Person(String name) {
this.name = name;
}
}
所以,一般最好带上无参构造方法
4、通过反射机制访问对象属性
Student类
public class Student {
private String name;
protected int age;
boolean sex;
public int no;
public static final double MATH_PI = 3.1415926;
}
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class student = Class.forName("com.dong.Student");
Object o = student.newInstance(); //o就是Student对象(底层调用无参数构造方法)
//获取no属性(根据属性的名称来获取Field)
Field no = student.getDeclaredField("no");
no.set(o,123); //给obj对象的no属性赋值123
System.out.println(no.get(o));
}
获取私有属性
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class student = Class.forName("com.dong.Student");
Object o = student.newInstance(); //o就是Student对象(底层调用无参数构造方法)
//获取私有的name
Field name = student.getDeclaredField("name");
//给name属性赋值
name.set(o,"皮皮虾");
System.out.println(name.get(o));
}
访问报错
解决办法:打破封装
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class student = Class.forName("com.dong.Student");
Object o = student.newInstance(); //o就是Student对象(底层调用无参数构造方法)
//获取私有的name
Field name = student.getDeclaredField("name");
//打破封装
name.setAccessible(true);
//给name属性赋值
name.set(o,"皮皮虾");
System.out.println(name.get(o));
}
setAccessible(true)这样设置后,在外部也可以访问private
反射机制缺点:打破封装可能会给不法分子留下机会!!!
5、通过反射机制调用方法(重点)
User类
public class User {
int no;
int age;
/**
* 登陆方法
*/
public boolean login(String name,String password) {
if ("admin".equals(name) && "123".equals(password)) {
return true;
}
return false;
}
/**
* 退出
*/
public void logout() {
System.out.println("系统已经安全退出");
}
}
测试
public class Main {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class aClass = Class.forName("com.dong.User");
//创建对象
Object obj = aClass.newInstance();
//获取Method
Method login = aClass.getDeclaredMethod("login", String.class, String.class);
Object admin = login.invoke(obj, "admin", "123");
System.out.println(admin);
Method logout = aClass.getDeclaredMethod("logout");
logout.invoke(obj);
}
}
getDeclaredMethod():参数1:指明获取的方法的名称,参数2:指明获取的方法的形参列表
invoke():参数1:方法的调用者,参数2:给方法形参赋值的实参
反射机制,让代码很具有通用性,可变化的内容都是写到配置文件中,将来修改配置文件之后,创建的对象不一样了,调用的方法也不同了,但是java代码不需要任何改动。这就是发射机制能力。
6、通过反射机制调用指定构造器
public class Main {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class aClass = Class.forName("com.dong.User");
Constructor declaredConstructor = aClass.getDeclaredConstructor(int.class, int.class);
Object o = declaredConstructor.newInstance(1, 2);
System.out.println(o);
}
}
getDeclaredConstructor():参数:指明构造器的参数列表
❤最后
我是 Code皮皮虾,一个热爱分享知识的 皮皮虾爱好者,未来的日子里会不断更新出对大家有益的博文,期待大家的关注!!!
创作不易,如果这篇博文对各位有帮助,希望各位小伙伴可以==一键三连哦!==,感谢支持,我们下次再见~~~