2019-06-06 Java学习日记 day27 反射

类的加载概述和加载时机

类的加载

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

  *加载

    *就是指将class文件读入内存,并为之创建class对象。任何类被使用时系统都会建立一个class对象

  *连接

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

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

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

  *初始化 

加载时机

  *创建类的实例

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

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

  *初始化某个类的子类

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

 

类加载器和分类

 类加载器

  *负责将.class文件加载到内存中,并为之生成对应的class对象。虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行

 类加载器的分类

  *Bootstrap ClassLoader 根类加载器

  *Extension ClassLoader 扩展类加载器

  *System ClassLoader 系统类加载器

 类加载器的作用

  *Bootstrap ClassLoader 根类加载器

    也被称为引导类加载器,负责Java核心类的加载

    比如System.String等,在JDk中JRE的lib目录下rt.jar文件中

  *Extension ClassLoader 扩展类加载器

    负责JRE的扩展目录中jar包的加载

    在JDK中JRE的lib目录下ext目录

  *System ClassLoader 系统类加载器

    负责在JVM启动时加载来自java命令的class文件,以及classpath华宁变量锁指定的jar包和类路径

 

反射概述

  JAVA反射机制是在运行状态,对于任意一个类,都能够知道这个类的所有属性和方法

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

  这种动态获取的信息以及动态太哦用对象的方法的功能称为java语言的反射机制

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

  而解剖使用的就是class类中的方法,所以先要获取到每一个字节码文件对应的class类型的对象

三种方式

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

  *静态属性class,锁对象

  *Clas类中静态方法forNamme(),读取配置文件

 

import tan.jung.bean.Person;

public class demo1_Reflcet {

    public static void main(String[] args) throws ClassNotFoundException {
        Class clazz1=Class.forName("tan.jung.bean.Person");
        
        Class clazz2 =Person.class;
        Person p =new Person();
        
        Class clazz3=p.getClass();
        
        System.out.println(clazz1 == clazz2);
        System.out.println(clazz2 == clazz3);
    }

}
案例

 

 

forName配置

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;

public class demo2_Reflect {

    public static void main(String[] args) throws Exception {
        //没有反射
        //Juice j1=new Juice();  //购买榨汁机
        //j1.run(new Apple());    //向榨汁机放入苹果
        
        //j1.run(new Orange());  //Fruit f =new Orange
        
        
        //反射和配置
        BufferedReader br1=new BufferedReader(new FileReader("cofing.prt"));
        Class clazz=Class.forName(br1.readLine());
        Fruit f=(Fruit) clazz.newInstance();   //父类引用指向子类对象,水果引用指向了苹果对象
        Juice j=new Juice();
        j.run(f);
        
    }

}
interface Fruit{
    public void squeeze();
}

class Apple implements Fruit{
    public void squeeze(){
        System.out.println("榨出一杯苹果汁");
    }
}
class Orange implements Fruit{
    public void squeeze(){
        System.out.println("榨出一杯橙子汁");
    }
}
class Juice{
//     public void run(Apple a){
//         a.squeeze();
//     }
//     
//     public void run(Orange o){
//         o.squeeze();
//     }
     public void run(Fruit f){
     f.squeeze();
}
}
案例

 

通过反射获取带参构造方法并使用

  *Constructor

    *Class类的newInstance()方法是使用该类无参的构造函数创建对象,如果一个类没有无参的构造函数,就不能这样创建了,可以调用Class类的getConstructor(String.class,int.class)方法获取一个指定的构造函数然后再调用Constructor类的newInstance(“张三”,20)方法创建对象

import java.lang.reflect.Constructor;

import tan.jung.bean.Person;

public class demo3_Constructor {

    public static void main(String[] args) throws Exception {
        Class clazz =Class.forName("tan.jung.bean.Person");
        //Person p =(Person) clazz.newInstance();  //通过无参创建对象
        Constructor c =clazz.getConstructor(String.class,int.class);//获取有参构造
        Person p=(Person) c.newInstance("张三",23);  //通过有参构造创建对象
        System.out.println(p);
    }

}
案例

 

通过反射获取成员变量并使用

  *Field

    *Class.getField(String)方法介意获取类中的指定字段(可见的),如果是私有的可以用getDeclaedField(“name”)放啊获取,通过set(obj,“李四”)方法可以设置指定对象上该字段的值,如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段套用get(obj)可以获取指定对象中该字段的值

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

import tan.jung.bean.Person;

public class demo4_Fiexd {

    public static void main(String[] args) throws Exception {
        Class clazz =Class.forName("tan.jung.bean.Person");
        Constructor c =clazz.getConstructor(String.class,int.class);//获取有参构造
        Person p=(Person) c.newInstance("张三",23);  //通过有参构造创建对象
        Field f =clazz.getDeclaredField("name");
        f.setAccessible(true);//去除私有权限
        f.set(p, "李四");
        System.out.println(p);
    }

}
案例

 

通过反射获取方法并使用

  *Method

    *Class.getMethod(String,Class...)和Class.getDeclaredMethod(String,Class....)方法可以获取类中的指定方法,调用invoke(object,object...)可以调用该方法,Class.getMethod(“eat”)invoke(obj)Class.getMethod(“eat”.int.class)invoke(obj,10)

 

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

import tan.jung.bean.Person;

public class demo5_method {

    public static void main(String[] args) throws Exception {
        Class clazz =Class.forName("tan.jung.bean.Person");
        Constructor c =clazz.getConstructor(String.class,int.class);
        Person p=(Person) c.newInstance("张三",23);
        Method m =clazz.getMethod("eat");  //获取eat方法
        m.invoke(p);
        
        Method m2=clazz.getMethod("eat", int.class);    //获取有参的eat方法
        m2.invoke(p, 10);
    }

}
案例

 

 

动态代理的概述和实现

概述

  代理:本来应该自己做的事情,请人被人来做,被请的人就是代理对象

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

 

  在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)

import java.lang.reflect.Proxy;

public class Test {

    public static void main(String[] args) {
        /*userImp ui=new userImp();
        ui.add();
        ui.delete();
        System.out.println("------------");*/
        /*My m =new My(ui);
        user u=(user)Proxy.newProxyInstance(ui.getClass().getClassLoader(), ui.getClass().getInterfaces(), m);
        u.add();
        u.delete();*/
        
        StudentImp si=new StudentImp();
        si.login();
        si.submit();
        
        System.out.println("------------");
        My m =new My(si);
        Student u=(Student)Proxy.newProxyInstance(si.getClass().getClassLoader(), si.getClass().getInterfaces(), m);
        u.login();
        u.submit();
    }

}


//第二个包
public interface Student {
    public void login();
    
    public void submit();
}

//第三个包
public class StudentImp implements Student {

    @Override
    public void login() {
        System.out.println("登录");

    }

    @Override
    public void submit() {
        System.out.println("提交");

    }

}

 

设计模式

概述

  模板方法木事就是定义一个算法的骨架,而将具体的算法延迟刀子类中来实现

优点和缺点

  优点:使用模板方法木事,在定义算法骨架的同时,可以很灵活的实现具体的算法,猫族用户灵活多变的需求

  缺点:如果算法骨架有修改的话,则需要修改抽象类

装饰

单例

简单工厂

工厂方法

适配器

模板

 

JDK5的新特性

枚举概述

  是指将变量的值——列出来,变量的值只限于列出来的值的范围内。

回想单列设计模式:单例类是一个类直邮一个实例

  那么多列类就是一个类有多个实例,但不是无限个数的实例,而是有限个数的实例。这才能是枚举类

 自动拆装箱

泛型

可变参数

静态导入

增强for循环

互拆锁

枚举

 

枚举的注意事项

  定义枚举类要用关键字enum

  所有枚举类都是Enum的子类

  枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是尅省略的,但是如果枚举类其他的东西,这个分号就不能省略。建议不要省略

  枚举类可以有构造器,单必须是private的,它默认的也是private的

  枚举类也可以有抽象方法,但是枚举类必须重写该方法

  枚举类在

  switch语句中的使用

 

枚举的常见方法

  int ordinal()

  int compareTo(E o)

  String name()

  String toString(

  <T> T valueOf (Class <T> type,String name)

  values()

  此方法虽然在JDK文档中查找不到,但每个枚举类都具有该方法,它遍历枚举类的所有枚举值非常方便

 

JKD7新特性

  二进制字面量0b001

  数字字面量可以出现下划线

  switch 语句可以用字符串

  泛型简化,菱形泛型

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

  try-with-resources 语句

 

JDK8新特性

  接口中可以定义有方法体的方法,如果是非静态,必须用default修饰

  如果是静态的就不用了 

 

posted @ 2019-06-09 01:28  JungTan0113  阅读(197)  评论(0编辑  收藏  举报