Java反射说的是在运行状态中,对于任何一个类,咱们都可以知道这个类有哪些方法和属性。对于任何一个对象,咱们都可以对它的方法和属性进行调用。咱们把这种动态获取对象信息和调用对象方法的功能称之为反射机制。java
这里须要跟你们说一下,所谓反射实际上是获取类的字节码文件,也就是.class文件,那么咱们就能够经过Class这个对象进行获取。bash
这个方法实际上是Object的一个方法,Class继承了Object,因此咱们能够直接使用。框架
public class Test02 {
public static void main(String[] args) {
// 建立一个对象
Test02 t = new Test02();
// 获取该对象的Class对象
Class c = t.getClass();
// 获取类名称
System.out.println(c.getName()); // com.ms.Test02
}
}
复制代码
public class Test02 {
public static void main(String[] args) {
Class c = Test02.class;
// 获取类名称
System.out.println(c.getName()); // com.ms.Test02
}
}
复制代码
这里须要注意,经过类的全路径名获取Class对象会抛出一个异常,若是根据类路径找不到这个类那么就会抛出这个异常。函数
public class Test02 {
public static void main(String[] args) {
try {
// 根据类的全路径名获取
Class c = Class.forName("com.ms.Test02");
// 获取类名称
System.out.println(c.getName()); // com.ms.Test02
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
复制代码
那么这3中方式咱们通常选用哪一种方式呢?第一种已经建立了对象,那么这个时候就不须要去进行反射了,显得有点画蛇添足。第二种须要导入类的包,依赖性太强。因此咱们通常选中第三种方式。测试
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException {
// 加载Class对象
Class c = Class.forName("com.reflect.User");
System.out.println("===========================获取全部公用的构造方法==============================");
// 获取全部公用的构造方法
Constructor[] constructors = c.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("=============================获取全部的构造方法============================");
// 获取全部的构造方法
Constructor[] declaredConstructors = c.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
System.out.println("=============================获取公有 & 无参的构造方法============================");
Constructor constructor = c.getConstructor(null);
System.out.println(constructor);
System.out.println("=============================获取公有 & 有参的构造方法============================");
Constructor constructor1 = c.getConstructor(new Class[]{String.class, Integer.class, String.class});
System.out.println(constructor1);
System.out.println("=============================获取私有 & 有参 构造方法============================");
Constructor declaredConstructor1 = c.getDeclaredConstructor(new Class[]{String.class});
System.out.println(declaredConstructor1);
}
}
复制代码
结果:ui
public class Test02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
// 获取Class对象
Class<?> clazz = Class.forName("com.reflect.User");
System.out.println("=====获取全部的公共字段=====");
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("=====获取全部的字段(公开的、私有的)=====");
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("=====获取公有字段并使用=====");
// 获取指定公有字段
Field field = clazz.getField("name");
// 获取一个公有构造方法,而后实例化
Object obj = clazz.getConstructor().newInstance();
// 为属性设置值
field.set(obj, "张三");
// 测试,看设置的值是否成功
User user = (User) obj;
System.out.println(user.getName());
System.out.println("=====获取私有字段并使用=====");
Field field1 = clazz.getDeclaredField("sex");
// 获取构造函数,实例化对象
Object obj1 = clazz.getConstructor().newInstance();
// 暴力反射
field1.setAccessible(true);
// 给属性设置值
field1.set(obj1, "男");
// 测试
User u = (User) obj1;
System.out.println(u.getSex());
}
}
复制代码
结果spa
这里须要注意,在获取私有属性的时候若是没有进行暴力反射,那么会抛出下面这个异常。code
先定义几个方法cdn
public void method1(String str) {
System.out.println("public 修饰的方法");
}
private void method2() {
System.out.println("private 修饰的方法");
}
String method3(String name, Integer age, String sex) {
System.out.println("默认修饰 " + name + " " + sex + " " + age + "岁");
return name + sex + age;
}
protected void method4() {
System.out.println("protected 修饰的方法");
}
复制代码
正题对象
public class Test03 {
public static void main(String[] args) throws Exception {
// 获取Class对象
Class<?> clazz = Class.forName("com.reflect.User");
System.err.println("======获取全部的public修饰的方法=====");
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
Thread.sleep(1000);
System.err.println("======获取全部的方法=====");
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
Thread.sleep(1000);
System.err.println("======获取特定方法(带参)并使用=====");
Method method1 = clazz.getMethod("method1", String.class);
System.out.println(method1);
Thread.sleep(1000);
System.err.println("======获取特定方法(不带参)并使用=====");
Method method2 = clazz.getDeclaredMethod("method2");
System.out.println(method2);
System.err.println("======获取特定方法(多个参数)并使用=====");
Method method3 = clazz.getDeclaredMethod("method3", String.class, Integer.class, String.class);
// 获取构造方法,实例化一个对象
Object obj = clazz.getConstructor().newInstance();
// 给方法传值
Object invoke = method3.invoke(obj, "小涛", 24, "男");
// 测试
System.out.println(invoke);
}
}
复制代码
结果
这里须要注意的就是当一个方法须要传入多个参数值的时候,必定要注意。踩了一点坑。
public class Main {
public static void main(String[] args) {
System.out.println("main方法执行了");
}
}
复制代码
反射调用
public class Test04Main {
public static void main(String[] args) {
try {
// 获取Class对象
Class<?> clazz = Class.forName("com.reflect.Main");
// 获取Main方法
Method method = clazz.getMethod("main", java.lang.String[].class);
// 调用
method.invoke(null, (Object) new String[]{"a"});
} catch (Exception e) {
e.printStackTrace();
}
}
}
复制代码
这里须要告诉你们,在导String包的时候千万要看清楚,我在这填了20多分钟的坑。
5、总结
看到这里你已经对反射有了一个简单的了解,可使用反射获取一些属性方法,其实咱们平时写代码不多用到反射技术,可是在咱们使用的一些主流框架中反射技术应用是很是普遍的,因此学好反射也是很是有必要的。
今天就写到这里,下篇给你们分享一下利用反射作一些有应用型的例子。
感受不错就给小涛一个赞吧!