miracle just wanna be better

jdk1.5新特性

2019-07-27
miracle

jdk1.5新特性:

自动拆箱和装箱

增强for循环

可变参数:

  • 用…来定义
  • 本质是一个数组
  • 可以传入任意个参数
  • 可变参数只能放在方法参数的最后一个位置

静态导入

  • 用import static 包名.类名.静态属性名或静态方法名
  • 可以提高加载效率
  • 降低了可读性,建议慎用

枚举(enum)

当取值为几个(有限)固定的值,可以使用枚举类型
枚举是一个数据类型 普通的枚举 public enum requestMethod{ GET,POST,DELETE,PUT

} public enum Week{ Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday } 枚举也可以有方法和属性和构造方法,但是构造方法必须是私有的
枚举还可以实现接口,不能继承,枚举也可以包含抽象方法
所有自定义的枚举都默认继承自java.lang.Enum类
String name(); int ordinal();

反射

java中的提供的一套类库,通过这套类库可以

  • 运行时动态获取类中的信息
  • 运行时动态的调用构造函数,创建对象
  • 运行时动态的访问(调用)对象的方法和属性 这种运行期间动态获取类中的信息(属性,方法,包,注解等),以及动态调用对象的方法和属性的功能称为java的反射机制
    通俗理解:在运行期间,对类的内容进行操作

Class类

要想使用反射,就要获取到类中的所有信息(属性,方法等…)
在java中,有一个特殊的类类型是Class,此类型的对象中存储的是某个类中的信息
比如:
Class clazz1 = Class.forName(“cn.tedu.Student”);
clazz1是一个对象,此对象中存储的都是数据,这些数据都是Student中的属性和方法
属性:访问修饰符,类型,属性名
方法:访问修饰符,返回类型,方法名(参数列表)
Class Clazz2 = Class.forName(“cn.tedu.User”);
Clazz2也是一个对象,对象中存储的是User类中的属性和方法

Class类是java提供的,这个Class类可以表达任意一个类的信息(属性,方法等类中的信息)

  • 每个类加载后(方法区),系统都会为该类生成一个对应的Class类类型的对象,这个对象是存储在堆区中,通过该Class对象,可以访问方法区类中的信息
  • 一旦获取了某个类Class类型的对象之后,程序员可以写程序调用Class对象中的api方法,获取给Class对象中的类的信息
  • 所有的基本数据类型也有Class对象

如何获取Class类型的对象

  • 对象.getClass(); 比如
    User user=new User();
    Class clazz1 = user.getClass();
  • 类名.Class
    比如
    有一个类是User类型
    Class clazz = User.class;
  • Class.forName(“包名.类名”);
    比如
    Class clazz1 = Class.forName(“cn.miralce.User”)
    此种情况分为两步
    1. 加载类User,进方法区,创建Class类型的对象
    2. 把返回Class类型的对象
 public  void testMethod1(){
        //传统做法,在编译期间确定调用的关系
        User user = new User();
        user.setUserName("张三");
        user.setUserPassword("zs");
        System.out.println(user.getUserName()+user.getUserPassword());
    }
    //反射的做法,首要要得到Class类型的对象
    //此对象,在类加载后自动有jvm创建,并把对象放在堆中
    //程序员只是通过api获取Class对象
    public void testMethod2()throws Exception{
        //方式一
        User user = new User();
        Class clazz1 = user.getClass();
        //方式二
        Class clazz2 = User.class;
        //方式三
        Class clazz3 = Class.forName("cn.tedu.day20.reflect.User");
        //输出
    }

用以上的三种方式,可以获取到Class类型的对象
通过Class类型的对象获取如下:

  • Filed类
    代表成员变量,即属性
  • Method类
    代表方法
  • Constructor类
    代表构造函数
  • Annotation类
    代表注解

通过上面的类的api获取对应的信息

  • 可以获取Field中的信息,获取类的属性,属性的修饰符,属性的类型,属性的名称
  • 可以获取Method中的信息,获取类的方法,修饰符,返回类型,方法名,参数列表
  • 可以获取Constructor中的信息,获取构造函数,修饰符,参数列表
  • 可以获取Annotation中的信息,获取注解,获取注解的名称,注解属性值
    结论:在运行期间,通过Class对象调用反射的api,可以反射实例化对象,可以反射访问属性和反射调用方法,总之,编译期间能写的代码,用反射也能实现. —

下面例子用到的User.java类

import java.util.Date;

public class User {
    private String userName;
    private String userPassword;
    String userAddress;
    protected int age;
    public String desc;
    public int weight;
    public User(){}
    public User(String userName, String userPassword){
        this.userName = userName;
        this.userPassword = userPassword;
    }
    public User(String userName, String userPassword, String userAddress, int age, String desc) {
        this.userName = userName;
        this.userPassword = userPassword;
        this.userAddress = userAddress;
        this.age = age;
        this.desc = desc;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserPassword() {
        return userPassword;
    }

    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }

    public String getUserAddress() {
        return userAddress;
    }

    public void setUserAddress(String userAddress) {
        this.userAddress = userAddress;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
    private float xxx(int a,float b){
        return 0f;
    }
    protected void yyy(String a,double b){

    }
    String zzz(String a, Date data){
        return null;
    }

}

反射方式创建对象

  1. 用无参数构造创建对象
    Class对象.new Instance();//常用
/**
     * 创建对象
     * 方式一 调用无参数构造实例化对象
     * @throws Exception
     */
    public  void testMethod5_1() throws Exception{
        Class clazz = Class.forName("cn.tedu.day21.reflect.User");
        Object obj = clazz.newInstance();
    }
  1. 用有参构造创建对象
    Class对象.getConstructor(new Class[]{若干参数的类类型}).newInstance(构造函数的参数);
/**
     * 调用有参构造
     * @throws Exception
     */
    public void testMethod5_2() throws Exception{
        Class clazz = Class.forName("cn.tedu.day21.reflect.User");
        //获取构造函数
        Constructor constructor = clazz.getConstructor(String.class,String.class);
       // Constructor constructor = clazz.getConstructor(new Class[]{String.class,String.class});
        Object obj = constructor.newInstance("张三","zs");
        Field field1 = clazz.getDeclaredField("userName");
        Field field2 = clazz.getDeclaredField("userPassword");
        field1.setAccessible(true);
        field2.setAccessible(true);
        System.out.println("userName="+field1.get(obj));
        System.out.println("userPassword="+field2.get(obj));

    }

反射方式获取Filed中的信息

  1. 获取当前类以及长辈类的公有属性
    Field[] field = Class对象.getFields();
/**
     * 从Class对象中获取Field
     * 当前类以及长辈类中的公有属性
     * @throws Exception
     */
    public void testMethod4_1()throws Exception{
        Class clazz  = Class.forName("cn.tedu.day21.reflect.User");
        Field[] fields = clazz.getFields();
        for(Field field:fields){
            System.out.print(field.getModifiers()+" ");//返回值是int,int值代表不同的访问修饰符
            System.out.print(field.getType()+" ");
            System.out.println(field.getName());
        }
    }
  1. 获取当前类的类中所有的属性
    Field[] fields = Class对象.getDeclaredFields();
 /**
     * 从Class对象中获取Field
     * 当前类中的所有属性
     * @throws Exception
     */
    public static void testMethod4_2() throws Exception{
        Class clazz = Class.forName("cn.tedu.day21.reflect.User");
        Field[] fields = clazz.getDeclaredFields();
        for(Field field:fields){
            System.out.print(field.getModifiers()+" ");//int值代表不同的访问修饰符
            System.out.print(field.getType()+" ");
            System.out.println(field.getName());
        }
    }
  1. 获取当前类以及长辈类中指定的公有属性
    Field field = Class.对象.getField(String fieldName);
    /**
     * 当前类以及长辈类的指定的公有属性
     * @throws Exception
     */
    public static void testMethod4_3()throws Exception{
        Class clazz  = Class.forName("cn.tedu.day21.reflect.User");
        Field field = clazz.getField("desc");
            System.out.print(field.getModifiers()+" ");//int值代表不同的访问修饰符
            System.out.print(field.getType()+" ");
            System.out.println(field.getName());
    }
  1. 获取当前类中指定的属性
    Field field = Class.对象.getDeclaredField(String fieldName);
 /**
     * 当前类中的指定的属性
     * @throws Exception
     */
    public static void testMethod4_4() throws Exception{
        Class clazz = Class.forName("cn.tedu.day21.reflect.User");
        Field field = clazz.getDeclaredField("userName");

            System.out.print(field.getModifiers()+" ");//int值代表不同的访问修饰符
            System.out.print(field.getType()+" ");
            System.out.println(field.getName());

    }
  1. 通过反射设定Field属性的值
    Field对象.set(Object obj,Object value);
    如果Field是私有,必须先执行:Field对象.setAccessable(true);//设置属性可以访问
 /**
     * 给Field存值
     * @throws Exception
     */
    public static void testMethod4_5() throws Exception{
        Class clazz = Class.forName("cn.tedu.day21.reflect.User");
        Field field = clazz.getDeclaredField("userName");

        System.out.print(field.getModifiers()+" ");//int值代表不同的访问修饰符
        System.out.print(field.getType()+" ");
        System.out.println(field.getName());
        //创建对象
        Object obj = clazz.newInstance();
        //设置Field的可访问性
        field.setAccessible(true);
        //给Field存储数据

        field.set(obj,"zhangsan");
        if(obj instanceof User){
            User user = (User)obj;
            System.out.println(user);
        }

    }
  1. 通过反射动态获取Field的值
    Object value = Field对象.get(Object obj);
    如果Field是私有,必须先执行:Field对象.setAccessable(true);//设置属性可以访问
    /**
     * 给Field存值取值
     * @throws Exception
     */
    public static void testMethod4_6() throws Exception{
        Class clazz = Class.forName("cn.tedu.day21.reflect.User");
        Field field = clazz.getDeclaredField("userName");

        System.out.print(field.getModifiers()+" ");//int值代表不同的访问修饰符
        System.out.print(field.getType()+" ");
        System.out.println(field.getName());
        //创建对象
        Object obj = clazz.newInstance();
        //设置Field的可访问性
        field.setAccessible(true);
        //给Field存储数据

        field.set(obj,"zhangsan");
        //从Field中取出数据
        Object value = field.get(obj);
        System.out.println(value);
    }

反射方式获取Method方法的信息

  1. 获取当前类以及长辈类的公有方法
    Method[] method = Class对象.getMethods();
/**
     * 从Class中取出Method方法
     * 从当前类及其长辈类中获取的所有的公有方法
     * @throws Exception
     */
    public static void testMethod6_1()throws Exception{
        Class clazz = Class.forName("cn.tedu.day21.reflect.User");
        Method[] methods = clazz.getMethods();
        for(Method method:methods){
            System.out.print(method.getModifiers()+" ");//获取访问修饰符
            System.out.print(method.getReturnType()+" ");//获取返回类型
            System.out.println(method.getName()+"(");//获取方法名称
            //获取参数列表
            Class[] claxxs = method.getParameterTypes();
            if(claxxs!=null&&claxxs.length>0){
                for(int i = 0;i<claxxs.length-1;i++){
                    System.out.print(claxxs[i]+",");
                }
                System.out.println(claxxs[claxxs.length-1]);
            }
            System.out.println(")");
        }
    }
  1. 获取当前类中的所有的方法
    Method[] method = Class对象.getDeclaredMethods();
/**
         * 从Class中取出Method方法
         * 从当前类中获取的所有的方法
         * @throws Exception
         */
        public static void testMethod6_2()throws Exception{
            Class clazz = Class.forName("cn.tedu.day21.reflect.User");
            Method[] methods = clazz.getDeclaredMethods();
        for(Method method:methods){
            System.out.print(method.getModifiers()+" ");//获取访问修饰符
            System.out.print(method.getReturnType()+" ");//获取返回类型
            System.out.println(method.getName()+"(");//获取方法名称
            //获取参数列表
            Class[] claxxs = method.getParameterTypes();
            if(claxxs!=null&&claxxs.length>0){
                for(int i = 0;i<claxxs.length-1;i++){
                    System.out.print(claxxs[i]+",");
                }
                System.out.println(claxxs[claxxs.length-1]);
            }
            System.out.println(")");//为了防止最后一个有逗号
        }
    }
  1. 获取当前类以及长辈类中的指定的公有的方法
    Method method = Class对象.getMethod(String methodName,new Class[]{methodName的参数类型});
/**
     * 从Class中取出Method方法
     * 从当前类及其长辈类中获取指定的公有方法
     * @throws Exception
     */
    public static void testMethod6_3()throws Exception{
        Class clazz = Class.forName("cn.tedu.day21.reflect.User");
        Method method = clazz.getMethod("setUserName",String.class);

            System.out.print(method.getModifiers()+" ");//获取访问修饰符
            System.out.print(method.getReturnType()+" ");//获取返回类型
            System.out.print(method.getName()+"(");//获取方法名称
            //获取参数列表
            Class[] claxxs = method.getParameterTypes();
            if(claxxs!=null&&claxxs.length>0){
                for(int i = 0;i<claxxs.length-1;i++){
                    System.out.print(claxxs[i]+",");
                }
                System.out.print(claxxs[claxxs.length-1]);
            }
            System.out.println(")");

    }
  1. 获取当前类中的指定的方法
    Method method = Class对象.getDeclaredMethod(String methodName,new Class[]{methodName的参数类型});
/**
     * 从Class中取出Method方法
     * 从当前类中获取指定的方法
     * @throws Exception
     */
    public static void testMethod6_4()throws Exception{
        Class clazz = Class.forName("cn.tedu.day21.reflect.User");
        Method method = clazz.getDeclaredMethod("xxx" ,int.class,float.class);
        System.out.print(method.getModifiers()+" ");//获取访问修饰符
        System.out.print(method.getReturnType()+" ");//获取返回类型
        System.out.print(method.getName()+"(");//获取方法名称
        //获取参数列表
        Class[] claxxs = method.getParameterTypes();
        if(claxxs!=null&&claxxs.length>0){
            for(int i = 0;i<claxxs.length-1;i++){
                System.out.print(claxxs[i]+",");
            }
            System.out.print(claxxs[claxxs.length-1]);
        }
        System.out.println(")");

    }
  1. 通过反射动态调用指定的Method
    Object returnValue = Method对象.invoke(Object obj,Object…args);
    解释:Method对象是确定的方法,给这个方法传递args参数,没有参数就不传,obj是实例化对象
    返回值是基本类型的封装类,比如int类型会装箱为Integer.
public void testMethod6_5()throws Exception{
        //传统方式
        User user = new User();
        user.setUserName("张三");
        user.getUserName();
        //反射的方式
        Class clazz = Class.forName("cn.tedu.day21.reflect.User");
        Object obj = clazz.newInstance();
        Method method = clazz.getMethod("setUserName",String.class);
        Object returnValue = method.invoke(obj,"张三");
        Method Method = clazz.getMethod("getUserName")
        Object returnValue = method.invoke(obj);
    }

反射获取Construction构造函数

/**
     * 遍历所有的构造,用反射方式
     * @throws Exception
     */
    public  void testMethod7_1()throws Exception{
        Class clazz = Class.forName("cn.tedu.day21.reflect.User");
        Constructor[] cons = clazz.getDeclaredConstructors();
        for (Constructor con:cons){
            System.out.print(con.getModifiers()+" ");//访问修饰符
            System.out.print(con.getName()+"(");//构造函数的名字
            //获取构造的参数类型
            Class[] claxxs = con.getParameterTypes();

                if(claxxs!=null&&claxxs.length>0){
                    for (int i = 0; i < claxxs.length-1; i++) {
                        System.out.print(claxxs[i]+",");
                    }
                    System.out.print(claxxs[claxxs.length-1]);
                }
            System.out.println(")");
        }
    }

反射获取Annotation注解

反射应用场景

  • 用反射实现jdbc通用的查询和通用更新
  • 用反射解析注解
  • 单元测试就是用反射实现
  • 常见的框架.spring框架,springmvc框架等都是用反射实现
  • EL表达式

反射的优点:

大幅度提高开发效率,框架就是用反射实现的,框架提高了开发效率

反射的缺点:

反射的执行效率比非反射的方式效率低
反射可以暴露类中的所有细节,突破了封装

理解题目

通过Method对象可以获取方法的信息 访问修饰符 返回数据类型 方法名称(参数列表的类型)
通过Method对象还可以调用方法,用反射的方式,可以调用任意方法
Object returnValue = Method对象.invoke(调用方法的对象名,方法参数);//可以调用任意方法,通用的方法调用
需求:
给一个对象中的私有数据赋值
实现方案一:传统的静态的方式,在编译期间确定好的调用关系
对象名.setXXX(参数);
实现方案二:用反射的方式调用setXXX方法,在运行期间才能确定调用此方法

setMethod()

 /**
     * 通用的存储数据的方法,主要目的是为了要演示反射调用方法invoke
     * 演示反射能做出通用的功能,提高了开发效率
     * @param propertyName 属性名称
     * @param obj 对象名
     * @param args 方法参数
     *     分析步骤:
     *             1.获取Class对象
     *             2.根据属性的名称构建一个方法名(骆驼命名法)
     *             3.通过class对象反射获取所有的方法
     *             4.遍历所有的方法,匹配第二部的方法名
     *             5.如果匹配到就调用
     *    结论:     在运行期间根据原则寻找方法,如果找到方法就调用,不是在编译期间调用的
     */
    private void setMethod(String propertyName,Object obj,Object...args)throws Exception{
        //获取Class对象
        Class clazz = obj.getClass();
        //set+U+serName == setUserName
        String setterName = "set"+propertyName.substring(0,1).toUpperCase()+propertyName.substring(1);
        //根据Class对象反射出类中的所有的方法
       /* Method[] methods = clazz.getDeclaredMethods();
        //循环遍历
        for(Method method:methods){
            //寻找类中是否有对应的set方法
            if(setterName.equals(method.getName())){
                method.setAccessible(true);//保证方法能够被访问
                method.invoke(obj,args);
            }
        }*/
       Field field = clazz.getDeclaredField(propertyName);//循环效率低,直接通过参数来得到类型

       Method method = clazz.getDeclaredMethod(setterName,field.getType());
       method.setAccessible(true);
       method.invoke(obj,args);
    }

getMethod()

 /**
     * 通用取值的方式
     * @param propertyName 属性名称
     * @param obj 调用方法的对象名
     * @return 方法的返回值
     *          分析:
     *          1.获取Class对象
     *          2.根据属性名称拼装一个get方法的名称
     *           把属性名第一个字母大写,前面加上get
     *          3.根据Class对象反射出类中的所有的方法
     *          4.遍历所有的方法,匹配第二步的方法名称
     *          5.如果匹配就调用getter方法,并把值返回
     *
     */
    private Object getMethod(String propertyName,Object obj)throws Exception{
        Object returnValue = null;
        //获取Class对象
        Class clazz = obj.getClass();
       //拼装方法名称
        String getterMethod = "get"+propertyName.substring(0,1).toUpperCase()+propertyName.substring(1);
       /*  //根据Class对象反射出所有的方法
        Method[] methods = clazz.getDeclaredMethods();
        //循环遍历所有的方法,匹配方法名称
        for (Method method:methods){
            if(getterMethod.equals(method.getName())){
                method.setAccessible(true);
                returnValue = method.invoke(obj);
            }
        }*/
       Method method = clazz.getDeclaredMethod(getterMethod);
       method.setAccessible(true);
       returnValue = method.invoke(obj);
        return  returnValue;
    }

调用上面两个方法为user赋值

 public  void testMethod6_6()throws Exception{
        //反射方式
        Class clazz = Class.forName("cn.tedu.day21.reflect.User");
        //反射的方式获取创建对象
        Object obj = clazz.newInstance();
        //通用set方法
        setMethod("userName",obj,"张三");
        setMethod("age",obj,20);
        setMethod("userPassword",obj,"zs");
        //通用get方法
        Object username = getMethod("userName",obj);
        Object userpassword = getMethod("userPassword",obj);
        Object userage = getMethod("age",obj);
        System.out.println(userage+" "+username+" "+userpassword);
    }

反射例子

PropertyUtil.java

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

/**
 * 此类专门用来解析.properties文件的
 */
public class PropertyUtil {
    //java.util.Properties类专门用来存储key和value的数据
    //key和value是存储在.properties文件中
    //有人把java.util.Properties类当成集合看待
    private Properties p = new Properties();
    public PropertyUtil(String fileName){
        //把指定的属性文件中的key和value装载到p对象中
        //1.获取属性文件的输入流
        InputStream is = PropertyUtil.class//Class类型的对象
                .getClassLoader()//返回类的类加载器,变相的得到类路径
                .getResourceAsStream(fileName);//从类路径下寻找fileName的文件
        //2.把is输入流对象中的数据加载给p对象
        try {
            p.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    //根据key的值,从p中取出key所对应的value.并返回
    public String getPropertyValue(String key){
        return p.getProperty(key);
    }
}

Product.java

package cn.tedu.day21.reflect;

public class Product {
    private int id;
    private String name;
    private double price;
    private int num;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}

test.java

public void test throws Exception{
        PropertyUtil pu = new PropertyUtil("resource/classname.properties");
        Object obj = Factory.getObject(pu.getPropertyValue("user"));
        System.out.println(obj.getClass());
    }

classname.properties

#这是一个属性文件key=value,不能有空格和空行
user=cn.tedu.day21.reflect.User
product=cn.tedu.day21.reflect.Product

内省:

自查,本质是反射,利用反射自省类中的属性,方法和属性

自省的实现方式有两种

1. jdk(jre)中自带的一套自省的类库

类库中包含的是api方法,侧重属性和属性的值,以及属性所对象的getter和setter方法

例子

User.java

public class User {
    private String userName;
    private String userPassword;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserPassword() {
        return userPassword;
    }

    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }
}

TestIntrospectorClass.Java

public class TestJdkIntrospectorClass {
    /**
     * 演示获取BeanInfo对象
     * @throws Exception
     */
    public void testMethod1()throws Exception{
    Class clazz = User.class;
    //通过自省类获取类中的所有的信息(底层还是反射)
        // 把反射出来的信息封装BeanInfo
    BeanInfo bi = Introspector.getBeanInfo(clazz);
    //原来使用反射的api操作类中的信息
        //用自省的BeanInfo中的api来操作类中的信息
    }

    /**
     * 内省指定的bean类中的属性信息
     * 然后根据属性信息获取属性的getter方法和setter方法
     * @throws Exception
     */
    public void testMethod2()throws Exception{
        User user = new User();
        //获取bean类中的信息
        BeanInfo bi = Introspector.getBeanInfo(user.getClass());
        //解析BeanInfo类的对象,能解析出属性和方法

        PropertyDescriptor[] pds = bi.getPropertyDescriptors();
        //遍历所有的属性描述器,每一个属性描述器代表一个属性Field
        for(PropertyDescriptor pd:pds){

            Method writeMethod = pd.getWriteMethod();
            if(writeMethod!=null){
                writeMethod.invoke(user,"zhangsan");
            }

            Method readMethod = pd.getReadMethod();
            if(readMethod!=null){
               Object returnValue =  readMethod.invoke(user);
                System.out.println(returnValue);
            }

        }
    }
    public void testMethod3()throws Exception{
        User user = new User();
        //获取指定属性的setter方法
        // 获取指定属性的getter方法
        PropertyDescriptor pd = new PropertyDescriptor("userName",User.class);
        Method getReadMethod = pd.getReadMethod();
        Method getWriteMethod = pd.getWriteMethod();
        String propertyname = pd.getName();
        Object value = pd.getValue(propertyname);
    }
    public static void main(String[] args) {
        TestJdkIntrospectorClass testJdkIntrospectorClass  = new TestJdkIntrospectorClass();
    }
}
  1. Apache基金会提供的一套公共的自省类库Commons-BeanUtils.jar

commons-BeanUtils工具,此工具中包含若干工具

  • MethodUtils工具类
  • ConstructorUtils工具类
  • PropertyUtils工具类

例子

User.java

public class User {
    private String userName;
    private String userPassword;

    public User(String userName, String userPassword) {
        this.userName = userName;
        this.userPassword = userPassword;
    }
    public User(){}

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserPassword() {
        return userPassword;
    }

    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }
}

TestBeanUtilsClass.java

public class TestBeanUtilsClass {
    /**
     * 演示MethodUtils工具类
     */
    public void testMethod1()throws Exception{
        User user = new User();
        //用MethodUtils的api查找方法
        Method method = MethodUtils.getAccessibleMethod(User.class,"setUserName",String.class);
        //找到方法就可以调用方法
        if (method!=null){
           Object returnValue =  method.invoke(user,"zhangsan");
        }
        //查找到了就直接调用
        Object returnValue = MethodUtils.invokeMethod(user,"setUserName","zhangsan");
        Object value = MethodUtils.invokeMethod(user,"getUserName",null);
        System.out.println(returnValue+" "+user.getUserName()+" "+value);
    }
    /**
     * 演示ConstructorUtils工具类
     */
    public void testMethod2() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {

        //用ConstructorUtils方式查找构造函数
        Constructor<User>  constructor = ConstructorUtils.getAccessibleConstructor(User.class,new Class[]{String.class,String.class});
        User user = constructor.newInstance("张三","zs");
        //用ConstructorUtils方式查找构造函数后直接实例化对象
        User user1 = ConstructorUtils.invokeConstructor(User.class,new Object[]{"wangwu","ww"});
    }
    /**
     * 演示PropertyUtils工具类工具类
     */
    public void testMethod3() throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        User user1 = new User("zhangsan","zs");
        User user2 = new User();
        //复制属性的值
        PropertyUtils.copyProperties(user2,user1);
        System.out.println(user2.getUserName()+" "+user2.getUserPassword());
        //设置属性的值
        PropertyUtils.setProperty(user2,"userName","haha");
    }
    public static void main(String[] args) throws Exception {
    TestBeanUtilsClass t = new TestBeanUtilsClass();
    t.testMethod3();
    }
}

注解

从JDK5.0开始, Java增加了对元数据(MetaData)的支持,也就是 Annotation(注解)。 Annotation其实就是代码里的特殊标记,它用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。

使用注解的步骤

1.如何定义注解。 2.把注解应用到对应的目标上 3.通过反射的api,反射注解,并根据反射的注解信息, 决定如何去运行类

1.如何定义注解。

元注解详解:

  • @Target(ElementType.METHOD):被修饰的注解能够在什么地方使用
    (注解、类/接口、字段、方法、构造方法、参数上..)上面使用。
    ElementType:
  • ANNOTATION_TYPE 注解类型声明
  • CONSTRUCTOR 构造方法声明
  • FIELD字段声明(包括枚举常量)
  • LOCAL_VARIABLE局部变量声明
  • METHOD 方法声明
  • PACKAGE 包声明
  • PARAMETER 参数声明
  • TYPE 类、接口(包括注释类型)或枚举声明

  • @Retention(RetentionPolicy.RUNTIME)
  • 被它修饰的注解保留域。 编译器 类加载器 JVM
  • .java-> .class->加载->运行
  • SOURCE:源码级别,给编译器看的,编译完之后直接丢弃该种策略的注解。
  • 生成的.class字节码文件中没有该类型的注解
  • CLASS:给类加载器看的,在类加载时可以做一系列引导操作。编译器编译后存在,类加载器加载完之后,丢弃该保留域的注解。
  • RUNTIME: 给JVM看的,在程序运行的过程中做相关的操作。编译器编译后保留,类加载器加载后保留,在JVM运行时通过反射技术反射使用的是什么注解,注解属性的值是什么,根据他们两个的值做对应的操作。
  • @Documented: 自定义的注解如果使用Documented注解,生成的doc文档上,使用该自定义注解的地方会显示注解信息;如果去掉@Documented,生成的doc文档上将不再有注解信息。 注解中的属性详解
  • a.注解定义属性和接口中定义方法类似,缺省默认是public。
    public 类型 属性名称();
  • b.定义属性时,如果没有使用default指定默认值, 使用当前注解必须为该属性赋值(可以利用该特点,设置必须赋值的属性不要使用default指定默认值)。 使用default指定默认之后,该属性在注解使用时可以赋值,也可以不赋值。
  • c.注解中的属性类型是有要求的, 可以是八种基本数据类型,可以是枚举类型、Class类型、String等,以及以上类型的“一维”数组 比如:String[] likes() default {}; 在注解使用时,如果数组类型的属性的值是一个值得话,赋值时可以把“{}”省略掉。@Anno1(name=”zs”,likes=”fb”)
  • d.存在一个特殊的属性:value, 如果只为该属性赋值,value=可以省略; 但是如果为注解中多个属性同时赋值的话, value=是不可以省

2.把注解应用到对应的目标上

在对应的目标写
@注解的名称(属性名=属性值)
@注解的名称(属性名1=属性值1,属性名2=属性值2,….属性名n=属性值n)

3. 反射注解(注解的运行原理)

参见项目代码

MyAnnotation.java(注解)

//代表此注解可以修饰的目标
@Target({ElementType.TYPE,ElementType.METHOD})
//此注解保留策略,在运行期间能使用此注解
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    //在注解中可以放置注解的属性,注解不是方法
    public String value()default "";
    public String name() default "abc";
    public String[] colors() default {"red","blue"};

}

Demo1.java

/**
 * 需求:
 *  如果方法上修饰了@MyAnnotation注解,且value的值为xxx,则调用此方法
 *  需求2:
 *  如果方法上修饰了@MyAnnotation注解,且name的值为bcd,则调用此方法
 */
@MyAnnotation(value = "aaa",name="bbb",colors = {"green","pink"})
public class Demo1 {
    private String xxx;
    @MyAnnotation(value = "abc",name="bcd",colors={"red","blue"})
    public void method1(){
        System.out.println("method1");
    }
    @MyAnnotation("xxx")
    public void method2(){
        System.out.println("method2");
    }
    @MyAnnotation("yyy")
    public void method3(){
        System.out.println("method3");
    }
}

TestAnnotationClass.java

public class TestAnnotationClass {
    /**
     * 此测试方法专门用来解析类上是否有注解,且获取类上的注解的属性值
     * 可以根据属性的值来决定如何运行程序
     */
    public void testMethod1()throws Exception{
        Class clazz = Class.forName("cn.tedu.day22.jdk5.annotation.Demo1");
        //查找并判断类上是否有指定的注解
        boolean flag = clazz.isAnnotationPresent(MyAnnotation.class);
        if(flag){
            //说明类上有@MyAnnotation注解
            //获取注解的对象
           MyAnnotation myAnnotation =  (MyAnnotation)clazz.getAnnotation(MyAnnotation.class);
            //通过注解的对象获取注解对象中的属性的值
            String value = myAnnotation.value();
            String name = myAnnotation.name();
            String[] colors = myAnnotation.colors();
            System.out.println(value);
            System.out.println(name);
            System.out.println(colors[0]+colors[1]);
            //根据value的值,根据name的值,根据colors的值,写if来决定运行哪些代码
            if("aaa".equals(value)&&"bbb".equals(name)){
                System.out.println("doSomething");
            }
        }
    }

    /**
     * 解析方法上的注解,然后根据指定的值,决定是否调用方法
     */
    public void testMethod2()throws Exception{

        Class clazz = Class.forName("cn.tedu.day22.jdk5.annotation.Demo1");
        //new对象,有对象,才可以调用方法
        Object obj = clazz.newInstance();
        //过去类中的所有方法
        Method[] methods = clazz.getDeclaredMethods();
        for(Method method:methods){
            //判断方法上是否有注解
            boolean flag = method.isAnnotationPresent(MyAnnotation.class);
            if(flag){
                //说明方法上有@MyAnnotation注解
                //获取方法上的注解的对象
                MyAnnotation myAnnotation = (MyAnnotation)method.getDeclaredAnnotation(MyAnnotation.class);
                //从注解对象中获取属性的数据
                String value = myAnnotation.value();
                String name = myAnnotation.name();
                String[] colors = myAnnotation.colors();
                if("xxx".equals(value)||"bcd".equals(name)){

                    method.invoke(obj);
                }
            }
        }
    }

    public static void main(String[] args) throws Exception {
        TestAnnotationClass testAnnotationClass = new TestAnnotationClass();
        testAnnotationClass.testMethod2();
    }
}

总结:用注解就是根据注解和注解上的属性值,来决定是否做一些事 可以是指行指定的功能,也可以是调用一个具体方法

泛型

一种参数化的类型

public static void main(String[] args) {
 //非泛型,不是参数化类型

        ArrayList list0 = new ArrayList();
        list0.add("abc");
        list0.add(10);
        //泛型标准做法,参数化类型,参数是String类型
        ArrayList<String> list1 = new ArrayList<String>();
        list1.add("abc");
        list1.add("bcd");
        //泛型,不推荐
        ArrayList list2 = new ArrayList<String>();
        list2.add("abc");
        list2.add("bcd");
       // list2.add(10);
        new Demo1().xxx(list2);
        //泛型,不推荐
        ArrayList<String> list3 = new Demo1().yyy();
        list3.add("abc");
        list3.add("bcd");
        //下列的做法是错误的做法,编译报错,两端的泛型必须一致
        //ArrayList<Object> list4 = new ArrayList<String>();
    }

         /**
     * 此方法模拟jdk1.5之前的方法
     */
    public void xxx(List list){

    }
    /**
     * 此方法模拟jdk1.5之前的方法
     */
    public ArrayList yyy(){
        return new ArrayList();
    }

类上的泛型,泛型类

泛型一定要先定义,后使用,在类的名字后面定义
泛型的类型一定要引用数据类型,不能是基本数据类型
不能对确切的泛型类型使用instanceof关键字
比如 if(num instanceof Generic){ } 定义在类上,在类的内部起作用,在整个类范围内类型一致 类上的泛型的具体类型需要在创建类的对象的时候指定泛型的具体类型 如果在使用类上的泛型不指定泛型的具体类型,默认的具体的类型为泛型的上边界

class Dog extends Animal{}
class Person extends Animal{}
class Animal{}
/**
 * T : type 类型
 * E : Element 元素
 * K : Key 键
 * V : value 值
 * 程序员可以自定义
 */
public class Doctor<T extends Animal> {



    /**
     * 此方法不是泛型方法,只是普通的方法
     * @param t
     */
    public T save(T t){
        System.out.println("救治"+t);
        return t;
    }

    public static void main(String[] args) {
        //演示泛型类
        //医生只能救治dog
        Doctor<Dog> doctor1 = new Doctor<Dog>();
        doctor1.save(new Dog());
        //医生可以救治任何对象
        Doctor doctor2 = new Doctor();
        doctor1.save(new Dog());
        //医生只能救治person
        Doctor<Person> doctor3 = new Doctor<Person>();
        doctor3.save(new Person());


    }

}

方法上的泛型,泛型方法

泛型要先定义后使用
在返回值之前定义,通常用一个大写字母来定义一个泛型,可以定义多个,且定义在方法上,在方法内部起作用,方法上的泛型,在方法被调用的时候自动推断出具体的泛型,无论何时,尽量使用泛型方法,因为作用域小,只局限于方法. 比如: public T save(T t){ return t; }

就是标志,标志此方法是一个泛型方法,放在修饰符和返回类型之间,可以放置多个符号,<T,E>,说明有两个类型需要参数化确定 ```java public class Doctor1 { /** * 此方法是泛型方法 * 根据在修饰符和返回值之间 */ public T save(T t){ System.out.println("救治"+t); return t; } public static void main(String[] args) { //演示泛型方法 Doctor doctor = new Doctor(); Person p = new Person(); doctor.save(p); } } ``` ### 泛型的上边界 泛型所取的类型是上边界类型或上边界类型的子孙类型,如果不指定泛型,默认上边界是Object ### 泛型擦除 泛型在编译期间起作用,真正执行期间,泛型已经被擦除了 在编译阶段,编译器会将所有使用泛型的地方替换为该泛型的上边界,并在必要的时候增加上必须的类型强制转换和类型检查,所以在执行期间没有泛型的概念 泛型在编译期间就被擦除了,此过程就叫泛型擦除

上一篇 线程池

下一篇 jdk1.8新特性

Comments

Content