反射机制、枚举-Java基础学习总结

类的加载

概述:当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

  • 加载:就是指将class文件读入内存,并为之创建一个Class对象。(任何类被使用时系统都会建立一个Class对象。)
  • 连接
    验证 : 是否有正确的内部结构,并和其他类协调一致
    准备 : 负责为类的静态成员分配内存,并设置默认初始化值
    解析: 把类中的符号引用转换为直接引用
  • 初始化
类加载器的概述和分类,以及类加载器作用

概述:负责将.class文件加载到内存中,并为之生成对应的Class对象。

分类

  • Bootstrap ClassLoader 根类加载器
  • Extension ClassLoader 扩展类加载器
  • Sysetm ClassLoader 系统类加载器

类加载器作用

  • Bootstrap ClassLoader 根类加载器,也被称为引导类加载器,负责Java核心类的加载
    (比如System,String等。在JDK中JRE的lib目录下rt.jar文件中 )
  • Extension ClassLoader 扩展类加载器,负责JRE的扩展目录中jar包的加载。
    (在JDK中JRE的lib目录下ext目录)
  • Sysetm ClassLoader 系统类加载器,负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径
反射概述

反射概述: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

获取class文件对象的三种方式

方式一:Object类的getClass()方法;(先创建出类的对象,后调用getClass()方法,得到class文件对象)

student student = new student();
Class<?> aClass1 = student.getClass();

方式二:每个类都有.class属性,可以获得该类的字节码文件对象

student student = new student();
Class<?> aClass1 = student.Class();

方式三:class类中的静态方法forName(“类的全路径”) 全路径:带有包名的类;格式:包名.类名

反射获取构造方法并使用

相关方法介绍

获取所有构造方法
	public Constructor<?>[] getConstructors() 获取所有的构造方法不包含私有的
	public Constructor<?>[] getDeclaredConstructors() 获取所有的构造方法 包括私有的
获取单个构造方法
	public Constructor<T> getConstructor(Class<?>... parameterTypes) 获取单个的构造方法 不包含私有的
	public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
代码演示:
public class test {
    public static void main(String[] args) throws Exception {
        //获取字节码文件对象
        Class<?> aClass = Class.forName("aijfajvdn.sav.av.asv.student");
        //获取所有公有构造
        Constructor<?>[] c = aClass.getConstructors();
        for (Constructor<?> constructor : c) {
            System.out.println(constructor.getName());
        }
        System.out.println("------------------------0----------------------");
        //获取所有构造
        Constructor<?>[] d = aClass.getDeclaredConstructors();
        for (Constructor<?> constructor : d) {
            System.out.println(constructor.getName());
        }
        System.out.println("------------------------0----------------------");
        //获取参数为两个int型构造
        Constructor<?> c1 = aClass.getConstructor(String.class);
        Object o = c1.newInstance("nihao");
        //通过此构造创建对象
        System.out.println(o);
        System.out.println("------------------------0----------------------");
        //获取参数为两个int型的私有构造
        Constructor<?> d1 = aClass.getDeclaredConstructor( int.class,int.class);
        //解除权限检测
        d1.setAccessible(true);
        //通过此构造创建对象
        Object o1 = d1.newInstance(1,2);
        System.out.println(o1);
        System.out.println("------------------------0----------------------");
    }
}
反射获取成员变量并使用
方法介绍:
获取所有成员变量
	public Field[] getFields() 获取所有的成员变量包含从父类继承过来的
	public Field[] getDeclaredFields() 获取所有的成员变量 包含私有的 也包含从父类继承过来的成员变量
获取单个成员变量
	public Field getField(String name)
	public Field getDeclaredField(String name)
成员变量赋值:得到成员变量对象,调用set(类对象,值)方法,调用get(类对象)方法,查看内容
私有变量赋值:获得私有变量对象,调用SetAccessible(true)方法,调用set方法
代码演示:
public class test1 {
    public static void main(String[] args) throws Exception {
        Class<?> aClass = Class.forName("aijfajvdn.sav.av.asv.student");
        Constructor<?> a = aClass.getConstructor();
        Object o = a.newInstance();
        System.out.println("------------------------0----------------------");
        //获取所有公开变量
        Field[] fields = aClass.getFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        System.out.println("------------------------0----------------------");
        //获取所有变量
        Field[] fields1 = aClass.getDeclaredFields();
        for (Field field : fields1) {
            System.out.println(field.getName());
        }
        System.out.println("------------------------0----------------------");
        //通过变量名获取公有变量,并赋值
        Field scord = aClass.getField("scord");
        scord.setLong(o,123);
        Object o1 = scord.get(o);
        System.out.println(o1);
        System.out.println("------------------------0----------------------");
        //通过变量名获取siyou变量,并赋值
        Field scord1 = aClass.getDeclaredField("name");
        scord1.setAccessible(true);
        scord1.set(o,"嚯嚯嚯");
        Object o2 = scord1.get(o);
        System.out.println(o2);

    }
}
反射获取成员方法并使用
方法介绍:
获取所有成员方法
	public Method[] getMethods() //获取所有的公共的成员方法不包含私有的 包含从父类继承过来的过来的公共方法
	public Method[] getDeclaredMethods()//获取自己的所有成员方法 包含私有的
获取单个成员方法
	//参数1: 方法名称  参数2:方法行参的class 对象
	public Method getMethod(String name,Class<?>... parameterTypes) //获取单个的方法 不包含私有的
	public Method getDeclaredMethod(String name,Class<?>... parameterTypes) 获取单个方法包括私有的
方法执行:调用invoke(类的对象,变量)方法,使方法执行;
调用私有方法:获得私有方法对象,调用setAccessible取消权限检查,调用invoke()方法,执行
代码实现:
public class test2 {
    public static void main(String[] args) throws Exception {
        Class<?> aClass = Class.forName("aijfajvdn.sav.av.asv.student");
        Constructor<?> a = aClass.getConstructor();
        Object o = a.newInstance();
        System.out.println("------------------------0----------------------");
        //由于只定义两个方法,所以就直接进行单个,不进行所有的
        //获取公有方法,并执行
        Method add = aClass.getMethod("add", int.class, int.class);
        Object invoke = add.invoke(o, 123, 321);
        System.out.println(invoke);
        System.out.println("------------------------0----------------------");
        //获取私有方法,并执行
        Method show = aClass.getDeclaredMethod("show", String.class, int.class, long.class);
        show.setAccessible(true);
        show.invoke(o, "嚯嚯嚯", 23, 1234);


    }
}
反射运行配置文件内容 (避免代码改动)
student类实现:
public class Student {
    private  void  show(String name,int age,double scored){
        System.out.println("姓名:"+name +"\t\t"+"年龄:"+age +"\t\t"+"分数:"+scored);
    }
}
配置文件内容:
class=practice.Demo2.Student
method=show
测试类实现:
public class test {
    public static void main(String[] args) throws Exception {


        Properties properties = new Properties();
        //与文件关联
        properties.load(new FileReader("file.txt"));

        //通过文件获得Student类的全路径
        Class<?> aClass = Class.forName(properties.getProperty("class"));
        //通过无参构造创建类的对象
        Object o = aClass.getConstructor().newInstance();
        //获得该类的方法
        String method1 = properties.getProperty("method");
        Method method = aClass.getDeclaredMethod( method1,String.class,int.class,double.class);
        method.setAccessible(true);  //取消权限监测
        method.invoke(o, "张三", 24, 525); //执行方法
    }
}
反射越过泛型检查
public class test {
    public static void main(String[] args) throws Exception {
        //往Integer类型的集合中,加入String类型,泛型只是在编译期有效,运行期无效
        ArrayList<Integer> list = new ArrayList<>();
        list.add(520);
        Class<? extends ArrayList> aClass = list.getClass();
        Method add = aClass.getDeclaredMethod("add",Object.class);
        add.invoke(list,"你好吗?");
        System.out.println(list);
    }
}

#####反射写一个通用的设置某个对象的某个属性为指定的值

student实现
public class Student {
    private  String name;
    private int age;
}
方法类实现
public class MyUtils {
    public MyUtils() {
    }

//通过反射向Student私有变量赋值
    public  static   void setDate(Object a, String name,Object Values) throws NoSuchFieldException, IllegalAccessException {
        Class<?> aClass = a.getClass();
        Field declaredField = aClass.getDeclaredField(name);
        declaredField.setAccessible(true);
        declaredField.set(a,Values);
    }
    //通过反射获得Student私有变量赋值
    public  static   Object getDate(Object a, String name) throws NoSuchFieldException, IllegalAccessException {
        Class<?> aClass = a.getClass();
        Field declaredField = aClass.getDeclaredField(name);
        declaredField.setAccessible(true);
        Object o = declaredField.get(a);
        return o;
    }
}

动态代理的概述和实现

动态代理概述
代理:本来应该自己做的事情,却请了别人来做,被请的人就是代理对象。
特点:字节码随用随创建,随用随加载
作用:不修改源码的基础上对方法增强


	动态代理:在程序运行过程中产生的这个对象
	而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理

    在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,
	通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。
	我们有更强大的代理cglib,Proxy类中的方法创建动态代理类对象
	public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
	最终会调用InvocationHandler的方法
	InvocationHandler Object invoke(Object proxy,Method method,Object[] args)
loader: 			类加载器  和被代理对象的类加载器相同
//user.getClass().getClassloader()
interfaces:			接口对应的一个Class数组
//user.getClass().getClassinterfaces()
InvocationHandler:	这个其实就是要代理对象所做的事情的一个类的封装
//InvocationHandler
new InvocationHandler() {
                    /**
                     * 作用:执行被代理对象的任何接口方法都会经过该方法
                     * 方法参数的含义
                     * @param proxy   代理对象的引用
                     * @param method  当前执行的方法
                     * @param args    当前执行方法所需的参数
                     * @return        和被代理对象方法有相同的返回值
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    }
                }
接口实现
public interface User {
    public void insert();
    public void delete();
    public void update();
    public void seek();
}
继承实现
public class userdao implements User {
    @Override
    public void insert() {
        System.out.println("加入数据");
    }
    @Override
    public void delete() {
        System.out.println("删除数据");
    }
    @Override
    public void update() {
        System.out.println("更新数据");
    }
    @Override
    public void seek() {
        System.out.println("查找数据");
    }
}
获得代理对象
public class getProxy {
     /*getproxy.delete();//增加记录原先数据
       getproxy.insert();记录插入位置
       getproxy.seek();  保存数据
       getproxy.update();
       */

     //获得代理人,对功能进行增强
    public  static  User getproxy(User userdao){
        User o = (User) Proxy.newProxyInstance(userdao.getClass().getClassLoader(), userdao.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object invoke=null;
               if (method.getName().equals("delete")){
                   System.out.println("记录原先数据");
                   invoke = method.invoke(userdao);
               }else if (method.getName().equals("insert")){
                   System.out.println("记录插入位置");
                    invoke = method.invoke(userdao);
               }else  if (method.getName().equals("seek")){
                   System.out.println("保存数据");
                    invoke = method.invoke(userdao);
               }else {
                   invoke = method.invoke(userdao);
               }
                return invoke;
            }
        });
        return o;
    }
}
测试类实现
public class test {
    public static void main(String[] args) {
        userdao u = new userdao();
        User getproxy = getProxy.getproxy(u);//Proxy.newProxyInstance返回值类型必须为接口类型
        getproxy.delete();
        System.out.println("----------------");
        getproxy.insert();
        System.out.println("----------------");
        getproxy.seek();
        System.out.println("----------------");
        getproxy.update();
    }
}

注:JDK动态代理必须针对接口
Proxy.newProxyInstance返回值需要是接口类型
JDK动态代理的原理是根据定义好的规则,用传入的接口创建一个新类,这就是为什么采用动态代理时为什么只能用接口引用指向代理,而不能用传入的类引用执行动态类。

枚举

概述: 就是一个类只能存在几个固定的对象,那么这个就是枚举.我们就可以使用这些对象可以表示一些固定的值

注意事项

  • 定义枚举类要用关键字enum
  • 所有枚举类都是Enum的子类
  • 枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。
  • 枚举类可以有构造器,但必须是private的,它默认的也是private的。
  • 枚举类也可以有抽象方法,但是枚举项必须重写该方法
  • 枚举在switch语句中的使用
代码实现:
枚举实现:
public enum haha {
    front("前"){
        @Override
        public void show(String name) {
            System.out.println(name);
        }
    },behind("后"){public void show(String name) {
        System.out.println(name);
    }},left("左"){public void show(String name) {
        System.out.println(name);
    }},right("右"){public void show(String name) {
        System.out.println(name);
    }};
    public String name;
   private haha(String s) {
        this.name=s;
    }
    public abstract void show(String name);
}
测试类实现:
public class ttesT {
    public static void main(String[] args) {
        haha behind = haha.behind;
        behind.show("nuha");
        System.out.println(behind.name);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值