• JAVA Class25


    学习内容:

    1.反射

    反射目的是在不修改代码的情况下,只需修改外部配置文件,实现调用不同类的不同方法。

    (1)类的载入

    当我们需要使用一个类时,我们要将这个类载入JVM,这里就要用到类载入的方法:

    在我们实例化一个对象时,类会自动载入,另外,实例化一个子类对象会导致父类自动载入

    public class Person {
        public String name;
        private int age;
        static {//注意这个静态代码块!
            System.out.println("静态代码块");
        }
        public Person() {
            super();
        }
        public Person(String name,int age) {
            super();
            this.name = name;
            this.age = age;
        }
    } 
    public class TestPerson {
    
        @SuppressWarnings({"rawtypes","unchecked"})//忽略多类型警告
        public static void main(String[] args) {
            try {
                Class c1 = Class.forName("edu.java.reflection.Person");//包名.类名
                Class c2 = new Person().getClass();
                //上述两种方式都会初始化静态属性,且只会执行一次!
                Class c3 = Person.class;//不会初始化静态属性
                //在一个JVM中,一种类,只会有一个类对象存在。所以以上三种方式取出来的类对象,都是一样的。
                //注: 准确的讲是一个ClassLoader下,一种类,只会有一个类对象存在。通常一个JVM下,只会有一个ClassLoader。
                System.out.println(c1==c2);//true
                System.out.println(c1.equals(c2));//true
                System.out.println(c1==c3);//true
                System.out.println(c1.equals(c3));//true
      }
    }

    (2)构造器的获取与利用构造器实例化对象:

    public class TestPerson {
    
        @SuppressWarnings({"rawtypes","unchecked"})
        public static void main(String[] args) {
            try {
                Class c1 = Class.forName("edu.java.reflection.Person");//包名.类名
                //获取造器数组
                Constructor[] con = c1.getConstructors();//获取所有公共的构造器
                for(Constructor s:con) {
                    System.out.println(s);
                }
                //获取空参构造器
                Constructor con = c1.getConstructor();
                //空参构造器实例化对象
                Object obj = con.newInstance();
                Person p = (Person)obj;//newInstance()返回的是Object,向下强转Person
                //有参构造器
                Class[] v = {String.class,int.class};
                Constructor con = c1.getConstructor(v);
                Object obj = con.newInstance("张三",20);
                Person p = (Person)obj;
                System.out.println(p);
                Constructor[] all = c1.getDeclaredConstructors();//获取所有构造器,包括私有的
                for(Constructor con:all) {
                    System.out.println(con);
                }
                Constructor con = c1.getDeclaredConstructor(String.class);//获取私有的有参构造器
                con.setAccessible(true);//取消变量权限检查,可以访问私有化变量
                Object obj = con.newInstance("李四");
                Person p = (Person)obj;
                System.out.println(p);
                //空参构造快速生成对象
                Object obj = c1.newInstance();
                Person p = (Person)obj;
      }
    }

    (3)获取字段值

    public class TestPerson {
    
        @SuppressWarnings({"rawtypes","unchecked"})
        public static void main(String[] args) {
            try {
                Class c1 = Class.forName("edu.java.reflection.Person");//包名.类名
                Field[] f = c1.getFields();//获取所有公共字段
                for(Field i:f) {
                    System.out.println(i);
                }
                Constructor con = c1.getConstructor(String.class,int.class);
                Object obj = con.newInstance("张三",20);
                Person p = (Person)obj;
                Field f = p.getClass().getField("name");//获取对象的指定字段值
                f.set(p, "李四");
                System.out.println(p);
                Field age = p.getClass().getDeclaredField("age");//获取私有变量
                age.setAccessible(true);
                age.set(p, 30);
                System.out.println(p);
            } catch(Exception e) {
                e.printStackTrace();
            }
            
        }
    
    }

    (4)通过类获取方法

    public class TestPerson {
    
        @SuppressWarnings({"rawtypes","unchecked"})
        public static void main(String[] args) {
            try {
                Class c1 = Class.forName("edu.java.reflection.Person");//包名.类名
                Constructor con = c1.getConstructor(String.class,int.class);
                Object obj = con.newInstance("张三",20);
                Person p = (Person)obj;
                Field f = p.getClass().getField("name");//获取对象的指定字段值
                f.set(p, "李四");
                System.out.println(p);
                Field age = p.getClass().getDeclaredField("age");//获取私有变量
                age.setAccessible(true);
                age.set(p, 30);
                System.out.println(p);*/
                //获取所有方法
                Method[] all = c1.getMethods();
                for(Method mm:all) {
                    System.out.println(mm);
                }
                Method m1 = c1.getMethod("eat");
                m1.invoke(p);
                Method m2 = c1.getDeclaredMethod("sleep",String.class,int.class,double.class);//获取私有带参方法
                m2.setAccessible(true);
                m2.invoke(p,p.name,30,90);
            } catch(Exception e) {
                e.printStackTrace();
            }
            
        }
    
    }

    2.泛型擦除

    JAVA的泛型是”假泛型“,不进class文件,所以利用反射,我们可以突破泛型限制添加数据

    public class TestPerson {
    
        @SuppressWarnings({"rawtypes","unchecked"})
        public static void main(String[] args) {
            try {
                //泛型擦除
                ArrayList<String> list = new ArrayList<String>();
                list.add("abc");
                Class c = list.getClass();
                Method method = c.getMethod("add", Object.class);
                method.invoke(list, 1);
                System.out.println(list);//数字1被成功添加,JAVA的泛型是”假泛型“,不进class文件
                System.out.println(list.get(0));
                System.out.println(list.get(1));//但是获取会报类型转换失败错误
            } catch(Exception e) {
                e.printStackTrace();
            }
            
        }
    
    }

    3.泛型应用

    public class Test {
         @SuppressWarnings({ "rawtypes", "unchecked" })//忽略多类型警告
        public static void main(String[] args) throws Exception {
            //从spring.txt中获取类名称和方法名称
            File sp = new File("e:/java/spring/spring.txt");
            Properties sc = new  Properties();
            sc.load(new FileInputStream(sp));
            String classname = (String)sc.get("class");
            //String methodname = (String)sc.get("method");
            String methodname = sc.getProperty("method");
            //根据类名称获取类对象
            Class cl = Class.forName(classname);
             //根据方法名称,获取方法对象
            Method m = cl.getMethod(methodname);
             //获取构造器
            Constructor c = cl.getConstructor();
            //根据构造器,实例化出对象
            Object service = c.newInstance();
            //调用对象的指定方法
            m.invoke(service);
            //如果要切换类及方法,只改变外部的txt文件内容即可,代码不用改
        }
    
    }

     利用这一思想,我们可以对之前用过的DButil包做一下改动:

    配置文件 DButil.properties

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://127.0.0.1:3306/Hero?characterEncoding=UTF-8
    user=root
    password=123456

    做改动:

    public class DButil {
        private DButil() {};
        public static Connection getConn() {
            try {
                Properties pro = new Properties();
                pro.load(new FileInputStream("properties/DButil.properties"));
                String driver = pro.getProperty("driver");
                String url = pro.getProperty("url");
                String user = pro.getProperty("user");
                String password = pro.getProperty("password");
                Class.forName(driver);
                Connection conn = DriverManager.getConnection(url, user, password);
                return conn;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("连接数据库失败!"+e);
            }
        }
        /**
         * 用来连接数据库
         * 返回Connection对象
         * */
        public static void close(Statement sta,Connection conn) {
            if(sta!=null) {
                try {
                    sta.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if(conn!=null) {
                try {
                    conn.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        /**
         * 用来关闭Statement Connection
         * 接收一个Statement对象、一个Connection对象
         * */
        public static void close(ResultSet rs,Statement sta,Connection conn) {
            if(rs!=null) {
                try {
                    rs.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            close(sta,conn);
        }
        /**
         * 用来关闭ResultSet Statement Connection
         * 接收一个ResultSet对象、一个Statement对象、一个Connection对象
         * */
    }
  • 相关阅读:
    iOS 8 UIAlertController 和 UIAlertAction
    iOS 利用异常 NSException 调试代码
    iOS 开发 atomic 与 nonatomic 区别
    iOS 9 HTTPS 的配置
    关于Frame加背景的那点事?
    java thread 线程锁同步,锁,通信
    java反射机制
    Java序列化与反序列化
    Java内存分配以及GC
    JavaBean入门笔记
  • 原文地址:https://www.cnblogs.com/whwjava/p/8966829.html
Copyright © 2020-2023  润新知