提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。通过java语言的反射机制可以操作字节码文件。
一、反射机制的作用
1.反编译:.class–>.java
2.通过反射机制访问java对象的属性,方法,构造方法等;
二、反射机制中相关的类
1.java.lang.Class:代表字节码文件
2.java.lang.reflect.Method:代表字节码中的方法
3. java.lang.reflect.Constructor:代表字节码中的构造方法
4. java.lang.reflecy.Field:代表字节码中的属性
三、反射机制中具体功能的实现
1.获取类Class的三种方式
代码如下(示例):
public class ReflectTest01 {
public static void main(String[] args) throws ClassNotFoundException {
//第一种:Class.forName(String string):
/*1.静态方法 2.方法的参数是一个字符串
3.字符串需要的是一个完整类名 4.完整类名必须包含有包名,java.lang包不能省略*/
Class c1 = Class.forName("java.lang.String");//c1代表String类的字节码文件,即String.class文件
Class c2 = Class.forName("java.lang.System");
//第二种:使用Object类内的getClass()方法
String s = "anc";
Class x = s.getClass();//x代表String.class字节码文件
//第三种:java语言中任何一种类型,包括基本数据类型,它都有.class属性
Class y = String.class;
}
}
Class的newInstance()用来实例化对象。但是需要注意这个方法内部调用了无参数构造方法,必须保证无参数构造方法存在。
如果只希望一个类中的静态代码块执行,其他代码不执行,则可以使用Class.forName("");这个方法会导致类加载,只要类加载,则静态方法块执行。
补充:关于路径问题
代码如下(示例):
public class ReflectTest02 {
public static void main(String[] args) {
//使用以下通用方式的前提是:这个文件必须在类路径下
//类路径是在src下的都是类路径,src是根路径
//采用以下方法可以获得一个文件的绝对路径
/*
* Thread.currentThread():当前线程对象
* getContextClassLoader():是线程对象的方法,可以获取当前线程的类加载器对象
*getResource(""):这是类加载器的方法,当前线程的类加载器默认是从类的根路径下加载资源的
hahaha是类路径下的一个文件*/
System.out.println(Thread.currentThread().getContextClassLoader().getResource("hahaha").getPath());
}
}
2.反射一个类及其中的基本属性
代码如下(示例):
public class ReflectTest044 {
public static void main(String[] args) throws ClassNotFoundException {
//创建这个是为了拼接字符串
StringBuilder s = new StringBuilder();
//获取Student这个类
Class student = Class.forName("com.bjpowernode.javase.reflect.Student");
//获取了类的修饰符与类名并且进行了拼接
s.append(Modifier.toString(student.getModifiers())+" class "+student.getSimpleName()+"{"+"\n");
//获取Student类中的所有属性
Field[] fileds = student.getDeclaredFields();
//增强for循环,用于反射Student类中的所有属性
for (Field filed:fileds) {
s.append("\t");
s.append(Modifier.toString(filed.getModifiers()));
s.append(" ");
s.append(filed.getType().getSimpleName());
s.append(" ");
s.append(filed.getName());
s.append(";");
s.append("\n");
}
s.append("}");
System.out.println(s);
}
}
2.反射一个类及其中的基本属性
通过反射机制访问一个java对象的属性
给属性赋值set
获取属性值get
代码如下(示例):
public class ReflectTest05 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
//获取Student类
Class student = Class.forName("com.bjpowernode.javase.reflect.Student");
//实例化对象
Object obj = student.newInstance();
//获取no属性
Field noo = student.getDeclaredField("no");
//给obj对象的no属性赋值
noo.set(obj,111);
//获取no属性的值
System.out.println(noo.get(obj));
Field nameField = student.getDeclaredField("name");
nameField.setAccessible(true);//因为name属性时私有属性,因此该语句用来打破封装,这也是反射机制的缺点之一
//给obj对象的name属性赋值
nameField.set(obj,"haha");
//获取obj对象name属性的值
System.out.println(nameField.get(obj));
}
}
补充:可变长参数问题
代码如下(示例):
//括号里的内容就是可变长参数,语法是类型后加三个点,例如int...;需注意类型匹配问题
public static void m(int... args){
}
//此语句错误,因为可变长参数只能放在最后一个位置上
/*public static void n(int... args,int m){
}*/
//此语句错误,可变长参数只能有一个
/*public static void n(int... args,float... arr){
}*/
3.反射一个类中的方法
代码如下(示例):
/*利用反射机制反射类中的方法*/
public class ReflectTest07 {
public static void main(String[] args) throws ClassNotFoundException {
//获取UserService类
Class uerService = Class.forName("com.bjpowernode.javase.reflect.UserService");
//获取类中的所有方法
Method[] methods = uerService.getDeclaredMethods();
//System.out.println(methods.length);
//使用增强for循环遍历Method
for (Method method:methods) {
//获取方法的修饰符
System.out.println(Modifier.toString(method.getModifiers()));
//获取方法的返回值类型
System.out.println(method.getReturnType().getSimpleName());
//获取方法名
System.out.println(method.getName());
//获取形参的类型
Class[] classes = method.getParameterTypes();
for (Class cla:classes ) {
System.out.println(cla.getSimpleName());
}
}
}
}
4.反射机制反射类中的构造方法
代码如下(示例):
public class ReflectTest10 {
public static void main(String[] args) throws ClassNotFoundException {
StringBuilder s = new StringBuilder();
Class vipClass = Class.forName("com.bjpowernode.javase.reflect.Vip");
s.append(Modifier.toString(vipClass.getModifiers()));
s.append(" class ");
s.append(vipClass.getSimpleName());
s.append("{\n");
//拼接构造方法
Constructor[] constructors = vipClass.getConstructors();
for (Constructor constructor:constructors ) {
s.append("\t");
s.append(Modifier.toString(constructor.getModifiers()));
s.append(" ");
s.append(vipClass.getSimpleName());
s.append("(");
Class[] parameterType = constructor.getParameterTypes();
for (Class parameterTypes:parameterType) {
s.append(parameterTypes.getSimpleName());
s.append(",");
}
if(parameterType.length>0){
s.deleteCharAt(s.length()-1);}
s.append("){}\n");
}
s.append("}");
System.out.println(s);
}
}
5.反射机制获取类的父类及父接口
代码如下(示例):
public class ReflectTest12 {
public static void main(String[] args) throws Exception {
Class stringClass = Class.forName("java.lang.String");
//获取String的父类
Class superClass = stringClass.getSuperclass();
System.out.println(superClass.getName());
//获取父接口
Class[] interfaces = stringClass.getInterfaces();
for (Class in:interfaces ) {
System.out.println(in.getName());
}
}
}
上述代码中用到的Student类如下:
代码如下(示例):
public class Student {
public int no;
private String name;
protected int age;
boolean sex;
}
上述代码中用到的UserService类如下:
代码如下(示例):
public class UserService {
public boolean login(String name, String password){
if("admin".equals(name) && "123".equals(password)) {
return true;
}
return false;
}
public void exit(){
System.out.println("已退出");
}
}
上述代码中用到的Vip类如下:
代码如下(示例):
public class Vip {
int no;
String name;
String birth;
boolean sex;
public Vip() {
}
public Vip(int no) {
this.no = no;
}
public Vip(int no, String name) {
this.no = no;
this.name = name;
}
public Vip(int no, String name, String birth) {
this.no = no;
this.name = name;
this.birth = birth;
}
@Override
public String toString() {
return "Vip{" +
"no=" + no +
", name='" + name + '\'' +
", birth='" + birth + '\'' +
", sex=" + sex +
'}';
}
}
总结
反射的优缺点:
1、优点:在运行时获得类的各种内容,进行反编译,对于Java这种先编译再运行的语言,能够让我们很方 便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
2、缺点:
(1)反射会消耗一定的系统资源;
(2)反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题