美文网首页
Java基础笔记总结(19)-反射,枚举类 JDK1.7 1.8

Java基础笔记总结(19)-反射,枚举类 JDK1.7 1.8

作者: 吵吵先生 | 来源:发表于2019-02-04 12:43 被阅读0次

    反射

    类的加载概述

    程序要使用某个类,如果类还未加载到内存中,系统会通过加载,连接,初始化来实现对这个类进行初始化

    加载,将class文件读入内存,并创建一个Class对象。任何类被使用时系统都会创建一个Class对象

    连接

    验证:是否有正确的内部结构,并和其他类协调一致

    准备 负责为类的静态成员分配内存,并且设置默认值

    解析 将类的二进制数据符号引用替换为直接引用

    加载时机

    创建类的实例

    访问类的静态变量,或者为静态变量赋值

    调用类的静态方法

    使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

    初始化某个子类

    直接使用java.exe来运行某个主类

    --------------------------------------------------------------------------------------

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

    类加载器分类:

    Bootstrap ClassLoader 根类加载器 引导类加载器 java核心类的加载System String 在jdk下的jre中的rt.jar

    Extension ClassLoader 扩展类加载器 负责jre扩展目录下的jar包的加载,在JDK中JRT的lib目录下的ext目录加载

    System ClassLoader 系统类加载器 负责在JVM启动时候加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径

    ------------------------------------------------------------------------------------

    反射概述

    JAVA反射机制就是在运行过程中,对任意一个类,都能知道这个类所有的属性和方法

    对于任意的一个对象,都能够调用它的任意一个方法和属性

    这种动态获取信息以及动态调用对象方法的方式成为JAVA的反射机制

    想要解刨一个类,必须要获取到该类的字节码文件对象

    而解刨使用的就是Class类中的方法,所以要获取每一个字节码文件对应的Class文件

    三种方式

    Object类的getClass()方法,判断两个对象是否是同一个字节码文件

    静态对象class,锁对象

    Class类中的静态方法,读取配置文件

    源文件阶段      字节码文件          创建配置文件

    Person.java    Person.class        Person p = new Person();

    Class clazz = class.forName("类名");

    Class clazz = Person.class;

    Class clazz = p.getClass();

    读取配置文件,只改配置文件就可以获取不同的属性和方法

    字节码文件 当作静态方法锁对象

    判断是否是同一个字节码对象

    ------------------------------------------------------------------------------------

    Class.forName()读取配置文件

    榨汁机Juicer榨汁,分别有水果 苹果 香蕉 橘子 榨汁

    package com.ysu.reflect;

    import java.io.BufferedReader;

    import java.io.FileNotFoundException;

    import java.io.FileReader;

    import java.io.IOException;

    public class Reflect {

    public static void main(String[] args) throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException {

    //没用反射,只在使用动态

    // Juicer juicer = new Juicer();

    // juicer.run(new Apple());

    // 用发射和配置文件

    BufferedReader br = new BufferedReader(new FileReader("config.properties"));

    Class clazz = Class.forName(br.readLine());

    Fruit f = (Fruit) clazz.newInstance(); //父类引用指向子类对象

    Juicer juicer = new Juicer();

    juicer.run(f);

    }

    }

    interface Fruit{

    public void squeeze();

    }

    class Juicer {

    public void run(Fruit f){

    f.squeeze();

    }

    }

    class Apple implements Fruit{

    @Override

    public void squeeze(){

    System.out.println("榨出一杯苹果汁");

    }

    }

    class Orange implements Fruit{

    public void squeeze(){

    System.out.println("榨出橘子酱");

    }

    }

    ------------------------------------------------------------------------------------

    反射获取构造方法

    Constructor

    Class类的newInstance()方法是使用该类无参数的构造方法创建对象,一个类没有无参数构造函数,不能使用该方法,但是可以调用Class类的getConstructor()创建

    获取有参构造创建对象

    Class clazz = Class.forName("com.ysu.reflect.Person");

    Constructor c= clazz.getConstructor(int.class,String.class);

    Person p = (Person) c.newInstance(23,"张三");

    System.out.println(p);

    ----------------------------------------------------------------------------------

    通过反射获取成员变量

    Class clazz = Class.forName("com.ysu.reflect.Person");

    Method method = clazz.getMethod("eat");

    Person p = (Person) clazz.newInstance();

    method.invoke(p);

    Method method2 = clazz.getMethod("eat", int.class);

    method2.invoke(p, 10);

    ------------------------------------------------------------------------------------

    通过反射越过泛型检查(泛型擦除)

    ArrayList<Integer> 中添加一个字符串对象

    ArrayList<Integer> list = new ArrayList<>();

    list.add(11);

    //泛型只在编译器有效,在运行期会被擦除掉

    // list.add("abc");

    Class clazz = Class.forName("java.util.ArrayList"); //获取字节码对象

    Method m = clazz.getMethod("add", Object.class);//获取add方法

    m.invoke(list, "abc");

    System.out.println(list);

    --------------------------------------------------------------------------------

    修改通用属性方法

    package com.ysu.reflect;

    import java.lang.reflect.Field;

    public class Tool {

    public void setProperty(Object obj,String propertyName,Object value) throws Exception, Exception{

    // 获取字节码对象

    Class clazz = obj.getClass();

    // 暴力反射获取字段

    Field f = clazz.getDeclaredField(propertyName);

    f.setAccessible(true);

    f.set(obj, value);

    }

    }

    -------------------------------------------------------------------------------------

    1、xxx.properties获取属性类

    2、利用反射获取相关属性,并运行方法

    -------------------------------------------------------------------------------------反射的动态代理

    package com.ysu.reflect;

    import java.lang.reflect.InvocationHandler;

    import java.lang.reflect.Method;

    public class MyInvocationHandler implements InvocationHandler {

    private Object target;

    public MyInvocationHandler(Object target) {

    this.target = target;

    }

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    System.out.println("1111");

    // 執行被代理的Target

    method.invoke(target, args);

    System.out.println("2222");

    return null;

    }

    }

    -----------------------------------------------------------------------------------

    package com.ysu.reflect;

    import java.lang.reflect.Proxy;

    public class Test4 {

    public static void main(String[] args) {

    UserImp ui = new UserImp();

    //动态代理

    // 本来自己要做的请别人做,被请的人就是代理对象

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

    // Proxy 和 InvocationHandler接口,通过类和接口可以生成动态代理对象

    MyInvocationHandler m = new MyInvocationHandler(ui);

    User u = (User) Proxy.newProxyInstance(ui.getClass().getClassLoader(), ui.getClass().getInterfaces(), m);

    u.add();

    u.delete();

    }

    }

    -----------------------------------------------------------------------------------

    末班模式

    就是定义一个算法的骨架,将具体的算法延迟到子类实现,抽象类不希望被重写的方法用final修饰

    如果有算法骨架需要被修改的话,有抽象类

    ------------------------------------------------------------------------------------

    枚举抽象类

    一共有三种方法

    利用单例模式

    class Week {

      public staitc  Week MON = new Week();

      private Week(){}

    }

    class abstract Week2{

      public staitc final Week MON = new Week(){

    public void show(){

    System.out.println();

    }

        }

      private Week(){}

      public abstract void show();

    }

    --------------------------------------------------------------

    第一种 创建Enum类,直接写入对象就可以实现

    第二种 public enum Week2{

    MON("")

    private String name;

    private Week2(String name){

    this.name = name;

    }

    }

    //可以写入get set方法

    测试 Week mon = Week.MON ;

    第三种是写入方法,用匿名实现子类方法

    public enum Week3{

    MON(""){

    public void show(){

    System.out.println("xxxxxxx");

    }

    };

    private String name;

    private Week2(String name){

    this.name = name;

    }

    }

    测试 Week mon = Week.MON ;

    mon.show();

    注意 枚举项要放在第一行,枚举类可以有抽象方法,但是枚举项必须重写该方法

    -----------------------------------------------------------------------------

    枚举类的常见方法

    ordinal() 返回枚举常量的序数 (枚举项都是有编号的)

    compareTo() 枚举项比较的是编号

    name() 获取枚举项的名称

    toString()  也是打印名称,

    valueOf Week mon = Week.value(Week.class,"MON");

    System.out.println(mon);通过字节码文件

    -------------------------------------------------------------------------------

    JDK7的新特性

    二进制字面量

    数字字面量出现下划线

    switch 语句可以用字符串

    泛型简化,菱形泛型

    异常的多个catch合并,每个异常就用或|

    try with resources语句(自动关闭流)

    -----------------------------------------------------------------------------

    JDK1.8 接口中可以书写具有方法体的方法。如果不是静态方法 必须要用default修饰

    用default修饰的就要采用实现类调用该方法,而静态方法可以接口名直接调用

    局部内部类:

    相关文章

      网友评论

          本文标题:Java基础笔记总结(19)-反射,枚举类 JDK1.7 1.8

          本文链接:https://www.haomeiwen.com/subject/dfdpsqtx.html