JavaSE进阶 第十四章 反射机制

1.注意点

  • 反射机制的作用:操作字节码文件(class文件),让代码具有通用性,可变化的内容写到配置文件中,同时源代码不需要改动,可以实现穿件不同的对象,调用不同的方法
  • 反射机制的相关类在java.lang.reflect.*下
  • 反射机制相关的重要类
    (1)java.lang.Class:代表整个字节码,代表一个类型
    (2)java.lang.reflect.Method:代表字节码中的方法字节码
    (3)java.lang.reflect.Constructor:代表字节码中的构造方法字节码
    (4)java.lang.reflect.Field:代表字节码中的属性字节码

2.Class类

2.1获取class的三种方式

2.1.1Class.forName()

Class c = Class.forName(“完整类名带包名”);
静态方法,参数为字符串,完整类名带包名

try {
	Class c1 = Class.forName("java.util.Date");
	Class c2 = Class.forName("java.lang.String");
	String s1 = "abc";
	Class x = s1.getClass();
	System.out.println(x==c2);//ture ==判断的是对象的内存地址
} catch (ClassNotFoundException e) {
	e.printStackTrace();
}

如果只希望一个类的静态代码块执行,其他代码一律不执行,可以使用Class.forName(“完整类名”);
这个方法的执行会导致类加载,类加载时,静态代码块执行

public class ReflectTest04 {
    public static void main(String[] args) {
        try {
            Class.forName("com.pjpowernode.javase.reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
class Person {
    static {System.out.println("HelloWorld");}
}
2.1.2对象.getClass()
String s1 = "abc";//x代表Sting.class字节码,代表String类型
Class x = s1.getClass();

在这里插入图片描述

2.1.3任何类型.class
Class y = String.class;//y代表String类型
Class z = Date.class;//z代表Date类型
System.out.println(y == c2);//true

2.2通过反射实例化对象

通过Class的newInstance()方法来实例化对象。内部实际上调用了无参构造方法,必须保证无参构造方法存在

public class ReflectTest02 {
    public static void main(String[] args) {
        Class c = null;
        try {
            c = Class.forName("com.pjpowernode.javase.reflect.User");
            Object obj = c.newInstance();
            System.out.println(obj);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}
class User{}

放射机制的灵活性:不改变java源代码的基础之上,通过修改配置文件,可以做到不同对象的实例化,符合OCP原则(对扩张开放,对修改关闭)。学会了房设计值有利于理解破鞋高级框架底层的源代码

public class ReflectTest03 {
    public static void main(String[] args) throws Exception {
        //IO流读取配置文件
        FileReader reader = new FileReader("chapter25/classinfo.properties");
        //穿件属性对象的Map
        Properties pro = new Properties();
        pro.load(reader);//加载
        reader.close();//关闭流
        String className = pro.getProperty("className");
        Class c = Class.forName(className);//通过反射机制实例化对象
        Object obj = c.getName();
        System.out.println(obj);
    }
}

3.Filed类

3.1获取Filed

Field为属性/成员

public class FiledTest01 {
    public static void main(String[] args) throws Exception {
        Class studentClass = Class.forName("com.pjpowernode.javase.filed.Student");
        String className = studentClass.getName();
        System.out.println(className);//完整类名
        String simpleName = studentClass.getSimpleName();
        System.out.println(simpleName);//简类名

        //获取类中所有的public消失的Field
        Field[] files = studentClass.getFields();
        System.out.println(files.length);//1
        Field f = files[0];//取出这个Field
        String fieldName = f.getName();
        System.out.println(fieldName);//no
        System.out.println("==========");

        //获取所有的Field
        Field[] fs = studentClass.getDeclaredFields();
        
        for (Field field : fs) {
            //获取属性的名字
            System.out.println(field.getName());

            //获取Field的属性的类型
            Class fieldType = field.getType();
            String fName = fieldType.getName();
            System.out.println(fName);

            //获取属性的修饰符列表
            int i = field.getModifiers();
            //返回的修饰符是一个数字,每个数字代表一种修饰符
            String modifierString = Modifier.toString(i);
            System.out.println(modifierString);
            System.out.println("==========");
        }
    }
}
class Student {
    private String name;
    protected int age;
    boolean sex;
    public int no;
}

3.2反编译Filed

了解

public class Animal {
    //5个Filed
    private  String name;
    protected int age;
    boolean sex;
    public int no;
    public static final double MATH_PI = 3.14;
}
public class ReflectTest05 {
    public static void main(String[] args) throws Exception {
        //反编译一个类的属性Filed
        StringBuilder s = new StringBuilder();
        Class animalClass = Class.forName("com.pjpowernode.javase.reflect.Animal");
        s.append(Modifier.toString(animalClass.getModifiers()) +
                " class " + animalClass.getSimpleName() + "{\n");

        Field[] fields = animalClass.getDeclaredFields();
        for (Field field : fields) {
            s.append("\t");
            s.append(Modifier.toString(field.getModifiers()));
            s.append(" ");
            s.append(field.getType().getSimpleName());
            s.append(" ");
            s.append(field.getName());
            s.append(";\n");
        }
        s.append("}");
        System.out.println(s);
    }
}

3.3通过反射机制访问对象属性

重点

public class ReflectTest06 {
    public static void main(String[] args) throws Exception {
        //不通过反射机制访问对象的属性
        Animal animal = new Animal();
        animal.no = 100;
        System.out.println(animal.no);

        Class animalClass = Class.forName("com.pjpowernode.javase.reflect.Animal");
        Object obj = animalClass.newInstance();
        //获取no属性
        Field noField = animalClass.getDeclaredField("no");
        //给obj对象(Animal对象)的no赋值,三要素:obj对象,no属性,值
        noField.set(obj, 222);
        //读取属性值,两要素:获取obj对象,no属性
        System.out.println(noField.get(obj));

        //可以访问对象的私有属性
        Field nameField = animalClass.getDeclaredField("name");
        nameField.setAccessible(true);
        nameField.set(obj, "Kitty");
        System.out.println(nameField.get(obj));
    }
}

4.Method类

4.1可变长度参数

  • 可变长度参数要求的参数个数为:0~N个
  • 可变长度参数在参数列表中必须在最后一个位置上,并且可变长度参数只能有一个
  • 可变长度参数可以当做一个数组来看待
    语法:类型…
package com.pjpowernode.javase.reflect.Method;

public class MethodTest01 {
    public static void main(String[] args) {
        m(1,2,3);
        int[] arr ={4,5,6};
        m(arr);
        m(new int[]{7,8,9});
    }
    public static void m(int...args){
        for (int i = 0; i <args.length; i++) {
            System.out.println(args[i]);
        }
    }
    public static void m2(int a,String...args){}
}

4.2反射Method

了解

public class MethodTest02 {
    public static void main(String[] args) throws Exception {
        Class userServiceClass = Class.forName("com.pjpowernode.javase.reflect.Method.UserService");
        Method[] methods = userServiceClass.getDeclaredMethods();
        for (Method method : methods) {
            //获取修饰符列表
            System.out.println(Modifier.toString(method.getModifiers()));
            //获取方法的返回值类型
            System.out.println(method.getReturnType().getSimpleName());
            //获取方法名
            System.out.println(method.getName());
            //获取方法的修饰符列表
            Class[] parameterTypes = method.getParameterTypes();
            for (Class parameterType : parameterTypes) {
                System.out.println(parameterType.getSimpleName());
            }
        }
    }
}

4.3反编译Method

与Field的反编译类似,了解

public class MethodTest03 {
    public static void main(String[] args) throws Exception {
        StringBuilder s = new StringBuilder();
        Class userServiceClass = Class.forName("com.pjpowernode.javase.reflect.Method.UserService");
        s.append(Modifier.toString(userServiceClass.getModifiers()) + " class " + userServiceClass.getSimpleName() + "{\n");
        Method[] methods = userServiceClass.getDeclaredMethods();
        for (Method method : methods) {
            s.append("\t");
            s.append(Modifier.toString(method.getModifiers()));
            s.append(" ");
            s.append(method.getReturnType().getSimpleName());
            s.append(" ");
            s.append(method.getName());
            s.append("(");
            Class[] parameterTypes = method.getParameterTypes();
            for (Class parameterType : parameterTypes) {
                s.append(parameterType.getSimpleName());
                s.append(",");
            }
            s.deletCharAt(s.length()-1);
            s.append("){}\n");
        }
        s.append("}");
        System.out.println(s);
    }
}

4.4通过反射机制调用方法

重点

public class UserService {
    public boolean login(String name,String password){
        if("admin".equals(name)&&"123".equals(password)){
            return true;
        }
        return false;
    }
}
public class MethodTest04 {
    public static void main(String[] args) throws  Exception{
        //不使用反射机制
        UserService userService = new UserService();
        boolean loginSuccess=userService.login("admin","123");
        System.out.println(loginSuccess);

        Class userServiceClass = Class.forName("com.pjpowernode.javase.reflect.Method.UserService");
        //创建对象
        Object obj =userServiceClass.newInstance();
        //获取Method
        Method loginMethod = userServiceClass.getDeclaredMethod("login", String.class, String.class);
        //调用方法,四要素:对象,方法名,实参列表,返回值
        Object reValue = loginMethod.invoke(obj,"admin","123");
        System.out.println(reValue);
    }
}

5.Constructor类

5.1反编译构造方法

了解

public class Vip {
    int no;
    String name;
    int age;
    public Vip() {}
    public Vip(int no, String name, int age) {
        this.no = no;
        this.name = name;
        this.age = age;
    }
}
public class ConstructorTest01 {
    public static void main(String[] args) throws  Exception{
       StringBuilder s =new StringBuilder();
       Class vipClass = Class.forName("com.pjpowernode.javase.reflect.Constructor.Vip");
       s.append(Modifier.toString(vipClass.getModifiers())+" class "+vipClass.getSimpleName()+"{\n");
        Constructor[] constructors = vipClass.getDeclaredConstructors();
        for (Constructor constructor:constructors){
            s.append("\t");
            s.append(Modifier.toString(constructor.getModifiers()));
            s.append(" ");
            s.append(vipClass.getSimpleName());
            s.append(" ");
            s.append("(");
            Class[] parameterTypes = constructor.getParameterTypes();
            for(Class parameterType:parameterTypes){
                s.append(parameterType.getSimpleName());
                s.append(",");
            }
            if(parameterTypes.length>0){
                s.deleteCharAt(s.length()-1);
            }
            s.append("){}\n");
        }
        System.out.println(s);
    }
}

5.2通过反射机制构造方法

比5.1重要一些,但都不是重点

public class ConstructorTest02 {
    public static void main(String[] args) throws Exception{
        //不适用反射创建对象
        Vip vip1 = new Vip();
        Vip vip2 = new Vip(001,"zhangsan",34);

        //使用反射机制创建对象
        Class c =Class.forName("com.pjpowernode.javase.reflect.Constructor.Vip");
        //调用无参构造方法
        Object obj =c.newInstance();//JDK1.8任然可以使用
        System.out.println(obj);

        //调用有参构造方法
        //第一步:获取这个有参数的构造方法
        Constructor con = c.getDeclaredConstructor(int.class,String.class,int.class);
        //第二步:调用构造方法new对象
        Object newObj = con.newInstance(002,"lisi",36);
        System.out.println(newObj);
    }
}

6.获取父类与接口

重点

public class ReflectTest07 {
    public static void main(String[] args) throws Exception {
        Class stringClass = Class.forName("java.lang.String");
        //获取父类
        Class superClass = stringClass.getSuperclass();
        System.out.println(superClass.getName());
        //获取实现了的接口
        Class[] interfaces = stringClass.getInterfaces();
        for (Class in : interfaces) {
            System.out.println(in.getName());
        }
    }
}

路径问题

FileReader reader = new FileReader(“charper25/classinfor2.properties”);
IDEA中默认的当前路径是project的根,离开了IDEA,可能当前路径就不是了
通用的编写模式:这个文件必须在类路径下,src是类的根路径

//获取当前线程对象的类加器对象getContextClassLoader()
//从类加载的根路径下加载资源jgetResource()
String path = Thread.currentThread().getContextClassLoader()
                .getResource("classinfo.properties").getPath();
System.out.println(path);
//String path = Thread.currentThread().getContextClassLoader()
                .getResource("classinfo.properties").getPath();
//FileReader reader = new FileReader(path);
//直接以流的形式返回
InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("classinfo.properties");
Properties pro =new Properties();
pro.load(stream);
stream.close();
String className = pro.getProperty("className");
System.out.println(className);

java.uitl下提供了一个资源绑定器,便于获取配置文件的内容,使用以下方法时XXX.properties必须放到类路径下,路径扩展名不写

ResourceBundle bundle = ResourceBundle.getBundle("classinfo");
String className = bundle.getString("className");
System.out.println(className);

类加载器

ClassLoader 类加载器是负责加载类的工具/命令
JDK中自带了三的类加载器

  • 启动类加载器:rt.jar
  • 扩展类加载器:ext/*.jar
  • 应用类加载器:classpath
    代码在执行之前,会将所有需要的类全部加载到JVM中。首先通过类加载器加载JDK·中最核心的类库;在启动类加载器找不到的时候,通过扩展类加载器加载;如果扩展类加载器没有加载到,通过应用类加载器加载
    java中未来保证类加载的安全,使用了双亲委派机制:
    优先从父(启动类加载器)中加载,如果无法加载到,从母(扩展类加载器)中加载。如果都加载不到,才会考虑从应用类加载器中加载

传送门

上一章:JavaSE进阶 第十三章 多线程
下一篇:JavaSE进阶 第十五章 注解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值