day27-Java反射/设计模式

2017-02-24  本文已影响198人  苦笑男神

27.01_类的加载概述和加载时机

* 创建类的实例
* 访问类的静态变量,或者为静态变量赋值
* 调用类的静态方法
* 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
* 初始化某个类的子类
* 直接使用java.exe命令来运行某个主类

27.02_类加载器的概述和分类

- 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包和类路径

27.03_反射概述

Class clazz1 = Class.forName("com.bean.Person");
Class<?> clazz2 = Person.class;
Class<?> clazz3 = new Person().getClass();   //加不加<?>都一样,

System.out.println(clazz1 == clazz2);

Class<?> 相当于 Class<? extends Object>
?是个通配符,可以用任何由Object派生的类型代替
反射的三个阶段.png

27.04_反射(Class.forName()读取配置文件举例)

// 反射和配置文件
BufferedReader br = new BufferedReader(new FileReader("config.plist"));
Class<?> clazz = Class.forName(br.readLine());  //从文件中读取了类名(全类名)
br.close();

Juicer j = new Juicer();
j.run( (Apple)clazz.newInstance() ); //使用 Class 创建了对象

--------------------分割线-----------------------------
class Juicer {
    public void run(Apple a) {  a.squeeze();  }
}
class Apple {
    public void squeeze() { System.out.println("炸出一杯苹果汁"); }
}

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

Class<?> clazz = Class.forName("com.bean.Person");
Constructor<?> c = clazz.getConstructor(String.class,int.class); //获取class的构造(有参)方法类
Person p = (Person) c.newInstance("张六",23); //使用有参构造方法类创建对象
System.out.println(p);
System.out.println(clazz.getConstructors());  //获取所有构造方法

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

// 通过反射,获取 成员变量
Class<?> clazz = Class.forName("com.bean.Person");
Constructor<?> c = clazz.getConstructor(String.class,int.class); //获取class的构造(有参)方法类
Person p = (Person) c.newInstance("张六",23); //使用有参构造方法类创建对象

//Field f = clazz.getField("name");  //获取name成员属性  只能获取public的成员属性

Field f = clazz.getDeclaredField("name"); //暴力反射,获取私有字段(成员属性/变量)
f.setAccessible(true);  //去除私有权限,必须这样只会,才能修改值
f.set(p, "我日,这也可以");  //修改字段的值
System.out.println(p);

27.07_通过反射获取方法并使用

Class<?> clazz = Class.forName("com.bean.Person");
Constructor<?> c = clazz.getConstructor(String.class , int.class);
Person p = (Person) c.newInstance("大叔",40);

Method m = clazz.getMethod("eat");  //获取eat方法,没有参数
m.invoke(p); //运行获取的eat方法,没有参数

Method m3 = clazz.getMethod("eat", int.class); //获取eat方法,带参数的
m3.invoke(p, 12); //运行获取的eat方法。带参数。

Method m2 = clazz.getDeclaredMethod("sleep"); //获取私有方法,没有参数
m2.setAccessible(true);  //想要运行私有方法,必须先让方法可见
m2.invoke(p); //运行获取的私有方法,没有参数

27.08_通过反射越过泛型检查)

// 1.不通过反射的办法, 泛型擦除,泛型只是在编译期做语法检查的,运行期泛型会被擦除掉
ArrayList list = null;
ArrayList<Integer> intList = new ArrayList<>();
intList.add(100);
list = intList;  //改变list的内存指向
list.add("XXOO...我是字符串...");   //实际此时已经把字符串 添加到  ArrayList<Integer> 里面了
System.out.println(intList);


// 2.通过 反射 
ArrayList<Integer> intList = new ArrayList<>();
intList.add(100);

Class<?> clazz = Class.forName("java.util.ArrayList");
Method m = clazz.getMethod("add", Object.class);  //获取add方法
m.invoke(intList, "我是字符串,我进入int泛型集合了!");
System.out.println(intList);

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

/**
 * 把某个对象的属性,改成自己想要的值
 * @param obj 对象
 * @param k 对象的属性名称,字符串
 * @param v 要改成的值
 */
public static void setPropertyByName(Object obj, String k, Object v) throws Exception {
    Class<?> clazz = obj.getClass();
    Field f = clazz.getDeclaredField(k); //不管私有方法还是public的,都能获取 暴力反射
    f.setAccessible(true);  //去除权限
    f.set(obj, v);
}

27.11_动态代理的概述和实现

interface Animal {  void eat();  }

class Dog implements Animal {
    public void eat() {
        System.out.println("狗改不了吃屎!");
    }
}

---------------分割线---------------
class MyInvocationHandler implements InvocationHandler { //自定义代理功能类
    private Object target;
    public MyInvocationHandler(Object target) {
        this.target = target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("先做一些事情...");
        method.invoke(target, args);  //执行被代理target对象的方法,多个参数本的本质是数组
        System.out.println("后做一些事情...");
        return null;
    }
}
---------------分割线---------------
Dog dog = new Dog();

MyInvocationHandler delegate = new MyInvocationHandler(dog);
ClassLoader l = dog.getClass().getClassLoader();  //固定写法
Class<?>[] inter = dog.getClass().getInterfaces(); //固定写法

Animal animal = (Animal) Proxy.newProxyInstance(l, inter, delegate);
animal.eat();  //等于是让代理类,在方法运行时 多处理了一些事情。

27.12_设计模式(模版(Template)设计模式概述和使用)

模版方法模式就是定义一个算法的骨架,而将具体的算法延迟到子类中来实现

// 一个抽象类,目的是计算一段代码运行的耗时
// 但是运行什么代码,是不知道的,需要子类去实现具体的代码
abstract class GetTime {
    public final void getTime() {  // final目的是不让子类重写
        long s = System.currentTimeMillis();
        code();
        long e = System.currentTimeMillis();
        System.out.println(e - s);
    }

    public abstract void code() ; // abstract必须让子类重写 
}

27.14_设计模式

1,装饰 : 在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。典型就是JavaIO框架。
2,单例 : 一个类有且仅有一个实例,并且自行实例化向整个系统提供。
3,简单工厂 : 专门生产势力的类,把类的实例过程抽取到一个专门的类里。
4,工厂方法 : 创建一个工厂接口和创建多个工厂实现类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了
5,适配器 : 将一个类的接口转换成客户希望的另外一个接口。典型就是GUI里各种事件的处理。
6,模版 : 定义一个操作中的算法的骨架,而将步骤延迟到子类中。
7,动态代理 : 在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。
设计模式1.png 设计模式2.png

END。
我是小侯爷。
在魔都艰苦奋斗,白天是上班族,晚上是知识服务工作者。
如果读完觉得有收获的话,记得关注和点赞哦。
非要打赏的话,我也是不会拒绝的。

上一篇 下一篇

猜你喜欢

热点阅读