Java学习52天--类加载,反射课堂案例

1,Servlet3.0

package t1.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "Demo01Servlet",
        urlPatterns = "/demo01",
        loadOnStartup = 1,
        initParams = @WebInitParam(name="username",value="root")
)
public class Demo01Servlet extends HttpServlet {
    @Override
    public void init() throws ServletException {
        System.out.println("Demo01Servlet init");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Demo01Servlet处理请求");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

2,类加载图例
在这里插入图片描述
3,反射
在这里插入图片描述
获取Class对象的三种方式
在这里插入图片描述
这里clazz01,clazz02,clazz03都是同一个对象–同一个类的Class对象
4运用反射的课堂案例
写程序过程中为了避免耦合度太高,可以通过工厂模式降低耦合,结合使用多态,使可拓展性增强,运用反射,又可以减少代码。用水果工厂的案例来模拟一下;
在这里插入图片描述
创建Fruit父类,使用继承,解决Apple类、Banana类的代码复用性

package t3.bean;

public class Fruit {
    private String fruitName;

    public Fruit(){}

    public Fruit(String fruitName) {
        this.fruitName = fruitName;
    }

    public String getFruitName() {
        return fruitName;
    }

    public void setFruitName(String fruitName) {
        this.fruitName = fruitName;
    }

    @Override
    public String toString() {
        return "Fruit{" +
                "fruitName='" + fruitName + '\'' +
                '}';
    }
}

package t3.bean;

public class Apple extends Fruit{
    private int height;

    public Apple() {
    }

    public Apple(String fruiName,int height) {
        super(fruiName);
        this.height = height;
    }
}

package t3.bean;

public class Banana extends Fruit {
    private int width;

    public Banana() {
    }

    public Banana(String fruitName, int width) {
        super(fruitName);
        this.width = width;
    }
}

使用工厂模式,解决Banana、Apple和其他模块耦合较高

package t3.factory;

import t3.bean.Fruit;

public class FruitFactory {

    public static Fruit getFruit(String fruitName) throws Exception {
       return (Fruit) Class.forName(fruitName).newInstance();
    }
}

使用反射机制,* * 解决工厂的getFruit方法中if…else代码过多

package t3.demo;

import t3.bean.Apple;
import t3.bean.Banana;
import t3.bean.Fruit;
import t3.factory.FruitFactory;

public class Demo {
    public static void main(String[] args) throws Exception {
        Apple apple = (Apple) FruitFactory.getFruit("t3.bean.Apple");
        Banana banana = (Banana)FruitFactory.getFruit("t3.bean.Banana");

    }
}

5,反射操作构造器

package t3.demo;

import java.lang.reflect.Constructor;

/**
 * 反射操作构造方法
 */
public class Demo02 {
    public static void main(String[] args) throws Exception {
        //获取User类对应的Class对象
        Class<?> clazz = Class.forName("t3.bean.User");
        //获取无参构造方法对象
        Constructor<?> c1 = clazz.getConstructor();
        //使用无参创建User类对象
        Object obj1 = c1.newInstance();
        System.out.println(obj1);

        System.out.println("---------------");

        //获取User类对应的有参构造方法对象
        Constructor<?> c2 = clazz.getConstructor(Integer.class, String.class, String.class);
        //使用有参创建User对象
        Object obj2 = c2.newInstance(1, "小明", "root");
        System.out.println(obj2);

        System.out.println("---------------");

        //通过该方法可以获取私有构造方法对象
        Constructor<?> c3 = clazz.getDeclaredConstructor(String.class, String.class);
        //暴力反射,让私有构造器对象可以被外界访问
        c3.setAccessible(true);
        Object obj3 = c3.newInstance("小王", "root123");
        System.out.println(obj3);

    }
}

6,反射操作成员变量

package t3.demo;

import t3.bean.User;

import java.lang.reflect.Field;

/**
 * 反射操作成员变量
 */
public class Demo03 {
    public static void main(String[] args) throws Exception {
        //获取User类的Class对象
        Class<User> clazz = User.class;
        User user = clazz.newInstance();
        //操作public修饰的成员变量
        Field idField = clazz.getField("id");
        //设置该成员变量值
        //obj:需要设置的对象
        //value:需要设置的值
        //给user对象的id属性设置值为250
        idField.set(user,250);
        System.out.println(user);
        //获取该成员变量值
        Object idValue = idField.get(user);
        System.out.println(idValue);
        System.out.println("---------------------");

        //操作非public修饰的成员变量
        Field usernameField = clazz.getDeclaredField("username");
        usernameField.setAccessible(true);
        usernameField.set(user,"小王");
        System.out.println(user);
        Object usernameValue = usernameField.get(user);
        System.out.println(usernameValue);


    }
}

**7,反射操作成员方法

package t3.demo;

import t3.bean.User;

import java.lang.reflect.Method;

public class Demo04 {
    public static void main(String[] args) throws Exception {
        //获取User类的Class对象
        Class<User> clazz = User.class;
        User user = clazz.newInstance();
        //获取public修饰的成员方法
        Method method01 = clazz.getMethod("setPassword", String.class);
        //使用方法对象
        //obj:哪个对象在执行该方法
        //args:方法执行时所需的参数值
        method01.invoke(user,"123456");
        System.out.println(user);

        System.out.println("--------------");

        //操作非public修饰的成员方法
        Method method02 = clazz.getDeclaredMethod("show");
        method02.setAccessible(true);
        Object result = method02.invoke(user);
        //invoke方法返回值,就是操作方法的返回值
        System.out.println(result);
    }
}

反射越过泛型检查

package t3.demo;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class Demo05 {
    public static void main(String[] args) throws Exception {
        //创建List集合对象
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        System.out.println(list);

        //泛型只在编译期有效!!!
        //反射越过泛型检查
        //反射可以在程序运行时,动态地调用List中的add方法去添加元素
        Class<? extends List> clazz = list.getClass();
        Method add = clazz.getDeclaredMethod("add", Object.class);
        add.setAccessible(true);
        Object result = add.invoke(list, "hello , generic type !");
        System.out.println(result);
        System.out.println(list);
    }
}

9,反射通用方法案例
给指定对象的指定字段设置指定值

package t3.demo;

import t3.bean.User;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Demo06 {
    public static void main(String[] args) throws Exception {
        User user = new User();
        setValue(user,"id" , 123);
        System.out.println(user);
    }

    /**
     * 给指定对象的指定属性设置指定值
     * @param obj : 指定对象
     * @param fieldName : 指定属性
     * @param value : 指定值
     */
    public static void setValue(Object obj , String fieldName , Object value) throws Exception {
        Class<?> clazz = obj.getClass();
        //根据属性名称获取对应的set方法名称
//        String methodName = "set" + "U" + "sername";(0,1)表示从下标0开始的第一个,(1)表示下标1开始往后的内容
        String methodName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
        Field field = clazz.getDeclaredField(fieldName);
        //获取字段的数据类型
        Class<?> fieldType = field.getType();
        //获取到set方法对象
        Method method = clazz.getMethod(methodName, fieldType);
        //执行set方法
        method.invoke(obj , value);
    }

}

10,反射结合配置文件
编写bean.properties,配置对象的唯一标识及对象的全类名,根据这段配置创建一个对象

读取配置文件

    bean01=t3.bean.User
    bean02=t3.bean.Banana

根据配置文件中的className生成对象

package t3.demo;

import java.io.InputStream;
import java.util.Properties;

public class Demo07 {
    public static void main(String[] args)throws Exception{
        //需求:编写bean.properties,配置对象的唯一标识及对象的全类名,根据这段配置创建一个对象
        Properties properties = new Properties();
        //将bean.properties中的数据存储到inputStream中
        InputStream inputStream = Demo07.class.getClassLoader().getResourceAsStream("bean.properties");
        //将bean.properties中的数据绑定到了Properties中!
        properties.load(inputStream);
        //获取全类名
        String className = properties.getProperty("bean01");
        //根据上述全类名创建了一个对象!
        Object obj = Class.forName(className).newInstance();
        System.out.println(obj);

        String className2 = properties.getProperty("bean02");
        Object obj2 = Class.forName(className2).newInstance();
        System.out.println(obj2);
    }

}

反思水果工厂获取水果对象存在的问题:
在这里插入图片描述
com.qfedu.bean.Apple对应的对象
将以上"com.qfedu.bean.Apple"字符串写到java代码中,合适吗?
不合适!!!全类名发生改变了,那你就必须修改java源代码,必须要重新部署项目!
"com.qfedu.bean.Apple"字符串和java程序的耦合性非常高!!
"com.qfedu.bean.Apple"字符串不能放到java代码中,而应该放置到配置文件中!!
仅仅修改配置文件,是不需要重新部署工程的!
这也就是为什么要将"com.mysql.jdbc.Driver"配置到jdbc.properties中!
解耦!!降低耦合!!
总结:
配置文件+工厂模式+反射+注解+xml解析 就是spring框架的核心原理!!!

12,静态代理设计模式–增强被代理类的功能
步骤

  • 自定义类实现和被代理类相同的接口
  • 在代理类中声明被代理类的对象
  • 在代理类的方法中使用被代理类调用方法
package t3.dao;
//1,自定义一个代理类(增强类)实现和被代理类(被增强类)相同的接口
/**
 *  代理类(增强类)
 *  完成非必要功能
 *  权限校验
 *  日志记录
 */
public class UserDaoImplProxy implements UserDao{

    //2,在代理类中声明被代理类的引用
    private UserDao userDao ;
    public UserDaoImplProxy(){
        userDao = new UserDaoImpl();
    }

    @Override
    public void addUser() {
        //3,在代理类的方法中使用被代理类调用方法
        System.out.println("权限校验");
        userDao.addUser();
        System.out.println("日志记录");
    }

    @Override
    public void deleteUser() {
        userDao.deleteUser();
    }

    @Override
    public void updateUser() {
        userDao.updateUser();
    }

    @Override
    public void selectUser() {
        userDao.selectUser();
    }

}

package t3.demo;

import t3.dao.UserDaoImplProxy;

public class Demo08 {
    public static void main(String[] args) {
        //静态代理设计模式
        //实现步骤
        //自定义一个代理类(增强类)实现和被代理类(被增强类)相同的接口
        //在代理类中声明被代理类的引用
        //在代理类的方法中使用被代理类调用方法
        UserDaoImplProxy userDaoImplProxy = new UserDaoImplProxy();
        userDaoImplProxy.addUser();

    }
}

特点

  • 缺点:必须要重写被代理类接口的所有的方法(包括不需要增强的方法,增高了耦合性)
  • 作用:增强被代理类的功能
  • 特点:可以控制被代理类对象
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值