• 反射


    反射(reflect)机制的作用

      1.反编译:.class--->.java

      2.通过反射机制访问java类的属性,方法,构造方法等

    获取Class的三种方式

    package com.yuijam.reflect;
    
    public class Employee {
        
        private String name;
        
        public Employee(){
            
        }
        
        public Employee(String name){
            this.name = name;
        }
        
        public void m1(){
            
        }
        
    }
    package com.yuijam.reflect;
    
    public class ReflectTest01 {
    
        public static void main(String[] args) throws Exception{
            //第一种
            Class c1 = Class.forName("com.yuijam.reflect.Employee");
            //c1保存内存地址指向堆中的对象,该对象代表的是Employee整个类
            
            //第二种
            //Java中任何一个对象都有getClass方法
            Class c2 = Employee.class;
            
            //第三种
            //Java中每个类型都有class属性,注意这里说的是类型不是类,所以可以int.class
            Employee e = new Employee();
            Class c3 = e.getClass();
            
            //因为Employee这个类在JVM中只有一个,所以c1,c2,c3的内存地址是一样的,指向堆中的唯一一个对象
            System.out.println(c1==c2);
            System.out.println(c3 == c2);
        }
    
    }

    一个知识点

    package com.yuijam.reflect;
    
    public class ReflectTest02 {
    
        public static void main(String[] args) throws Exception{
            //将A.class文件装载到JVM的过程,会执行静态语句块,打印输出
            Class c1 = Class.forName("com.yuijam.reflect.A");
            
            //不会执行静态语句块
            Class c2 = A.class;
            
        }
    
    }
    
    class A{
        static{
            System.out.println("A----");
        }
    }

    通过Class类对象创建java对象

    package com.yuijam.reflect;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class ReflectTest03 {
    
        public static void main(String[] args) throws Exception{
            Class c = Class.forName("com.yuijam.reflect.Employee");
            
            //创建此Class对象所表示的类的一个新实例
            Object o = c.newInstance();//调用Employee的无参数构造方法
            //如果将Employee的无参数构造方法注释掉,会抛出异常
            System.out.println(o);
            
            Class d = Class.forName("java.util.Date");
            Object o1 = d.newInstance();
            if ( o1 instanceof Date){
                Date t = (Date)o1;
                System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(t));
            }
            
        }
    
    }

    Employee的无参数构造方法执行!
    com.yuijam.reflect.Employee@15db9742
    2016-10-23 21:41:20 754

    关于Java的可变长参数

    package Test;
    
    /**
     * Created by Arenas on 2016/10/24.
     */
    public class ReflectTest04 {
        //该方法在调用的时候传递的实参可以是0~N个
        public static void m1(int... i){
            System.out.println("test");
        }
        //如果有可以精确匹配的方法,则调用该方法,而不会调用可变长参数的那个方法
        public static void m1(int i){
            System.out.println(i);
        }
        //可变长参数可以等同看作数组
        public static void m2(String... s){
            for (String s1 : s) {
                System.out.println(s1);
            }
        }
        //可变长参数只能出现一次,并且只能出现在参数列表最后一个,下面这样是不行的
    //    public static void m3(int... i , String s){
    //
    //    }
        //这个是可以的
        public static void m3(int s , int... i){
    
        }
    
        public static void main(String[] args) {
            m1();
            m1(1);
            m1(1,2);
            m1(3,4,5);
    
            m2("kobe" , "kg" , "duncan" , "tracy");
        }
    
    }

    test
    1
    test
    test
    kobe
    kg
    duncan
    tracy

    Properties和IO的使用

    首先在D盘新建一个文件info.txt,内容为username=tracy

    package Test;
    
    import java.io.FileInputStream;
    import java.util.Properties;
    
    /**
     * Created by Arenas on 2016/10/24.
     */
    public class PropertiesIOTest {
    
        public static void main(String[] args) throws Exception{
            //创建输入流
            FileInputStream fis = new FileInputStream("D:/info.txt");
    
            //创建属性对象,和Map一样,只不过key和value只能是字符串类型
            Properties properties = new Properties();
            //将file流中的所有数据加载到属性对象中
            properties.load(fis);
    
            //关闭流
            fis.close();
            
            String v = properties.getProperty("username");
            System.out.println(v);
        }
    }

    输出:tracy

    info这样的文件通常称为配置文件,配置文件的作用是使程序更加灵活。像info这样一个具有特殊内容的配置文件,通常又称为属性文件。Java规范中要求属性文件以.properites结尾

    属性文件的要求:

      1.key和value之间可以使用“空格”,“冒号”,“等号”作为分隔符

      2.当“空格”,“冒号”,“等号”同时出现时,按最先出现的那个作为分隔符

    这里注意一个问题,在info文件中再加一条带中文的,如chinesename=麦迪

    输出一个乱码:ÂóµÏ

    这个时候进入cmd,输入如下:

    再将转换成的unicode码复制到info中替换中文麦迪,即可输出中文麦迪

    利用reflect、IO、properties创建Java对象

    在D盘新建文件ClassInfo.properites,内容为className=java.util.Date

    package Test;
    
    import java.io.FileReader;
    import java.util.Properties;
    
    /**
     * Created by Arenas on 2016/10/24.
     */
    public class ReflectTest05 {
    
        public static void main(String[] args)throws Exception{
            //创建属性对象
            Properties properties = new Properties();
            //创建流
            FileReader reader = new FileReader("D:/ClassInfo.properites");
            //加载
            properties.load(reader);
            //记得关闭流
            reader.close();
            //通过key获取value
            String className = properties.getProperty("className");
            //创建对象并打印出来
            Class c = Class.forName(className);
            System.out.println(c.newInstance());
        }
    }

    输出:Mon Oct 24 19:35:54 CST 2016

    反编译某个类的所有Field

    新建User

    package Test;
    
    /**
     * Created by Arenas on 2016/10/24.
     */
    public class User {
        private String name;
        private int age;
        protected String addr;
        boolean married;
    
        private User(){
    
        }
    
        public User(String name , int age){
            this.name = name;
            this.age = age;
        }
    
        public boolean login(String username , String password){
            return (username.equals("admin") && password.equals("123456"));
        }
    
        public void loginout(){
            System.out.println("login out");
        }
    }
    package Test;
    
    import java.io.FileReader;
    import java.lang.reflect.Field;
    import java.lang.reflect.Modifier;
    import java.util.Properties;
    
    /**
     * Created by Arenas on 2016/10/24.
     */
    public class ReflectTest06 {
    
        public static void main(String[] args) throws Exception{
            Properties properties = new Properties();
            FileReader reader = new FileReader("D:/ClassInfo.properties");
            properties.load(reader);
            reader.close();
            String className = properties.getProperty("className");
            Class c = Class.forName(className);
            Field[] fields = c.getDeclaredFields();
            for (Field field : fields){
                int i = field.getModifiers();
                System.out.println(Modifier.toString(i));
                Class type = field.getType();
                String str = field.getName();
                System.out.println(type.getName());
                System.out.println(str);
            }
        }
    }

    private
    java.lang.String
    name
    public
    int
    age
    protected
    java.lang.String
    addr

    boolean
    married

    反编译User类

    package Test;
    
    import java.io.FileReader;
    import java.lang.reflect.Field;
    import java.lang.reflect.Modifier;
    import java.util.Properties;
    
    /**
     * Created by Arenas on 2016/10/24.
     */
    public class ReflectTest06 {
    
        public static void main(String[] args) throws Exception{
            Properties properties = new Properties();
            FileReader reader = new FileReader("D:/ClassInfo.properties");
            properties.load(reader);
            reader.close();
            String className = properties.getProperty("className");
            Class c = Class.forName(className);
            Field[] fields = c.getDeclaredFields();
    
            StringBuilder builder = new StringBuilder();
            builder.append(Modifier.toString(c.getModifiers()));
            builder.append(" class ");
            builder.append(c.getSimpleName());
            builder.append("{
    ");
    
            for (Field field : fields){
                builder.append("	");
                builder.append(Modifier.toString(field.getModifiers()));
                builder.append(" ");
                builder.append(field.getType().getSimpleName());
                builder.append(" ");
                builder.append(field.getName());
                builder.append(";
    ");
            }
            builder.append("}");
            System.out.println(builder.toString());
        }
    }

    将User换成java.lang.String等也同样可以顺利打出

    获取某个指定的Field

    package Test;
    
    import java.lang.reflect.Field;
    
    /**
     * Created by Arenas on 2016/10/25.
     */
    public class ReflectTest07 {
        //获取某个指定的属性
        public static void main(String[] args) throws Exception{
            Class c = Class.forName("Test.User");
            //获取age属性,这里如果用getField只能获取public的属性,如果属性为private会抛出异常
            Field field = c.getDeclaredField("age");
            //使用反射机制可以打破封装属性,导致了Java对象的属性不安全
            //这里如果注释掉这条,对于private属性来说会抛出异常
            field.setAccessible(true);
            Object o = c.newInstance();
            //给o对象的age属性赋值110
            field.set(o , 110);
            System.out.println(field.get(o));
        }
    }

     获取所有方法

    package Test;
    
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    
    /**
     * Created by Arenas on 2016/10/25.
     */
    public class ReflectTest08 {
    
        public static void main(String[] args) throws Exception{
            Class c = Class.forName("Test.User");
            Method[] methods = c.getDeclaredMethods();
            for (Method method : methods){
                //获取返回值类型
                System.out.println(method.getReturnType().getSimpleName());
                System.out.println(Modifier.toString(method.getModifiers()));
                System.out.println(method.getName());
                //获得形参
                Class[] paras = method.getParameterTypes();
                for (Class para : paras){
                    System.out.println(para.getSimpleName());
                }
            }
        }
    
    }

    boolean
    public
    login
    String
    String
    void
    public
    loginout

    获取指定方法

    package Test;
    
    import java.lang.reflect.Method;
    
    /**
     * Created by Arenas on 2016/10/25.
     */
    public class ReflectTest09 {
    
        public static void main(String[] args)throws Exception{
            Class c = Class.forName("Test.User");
            //通过方法名和形参列表确定一个方法
            Method method = c.getDeclaredMethod("login" , String.class , String.class);
            Object o = c.newInstance();
            //调用o对象中的method方法,并传入两个参数,获取返回值returnValue
            Object returnValue = method.invoke(o , "admin" , "123456");
            System.out.println(returnValue);
        }
    }

    true

    获取所有构造方法

    package Test;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Modifier;
    
    /**
     * Created by Arenas on 2016/10/25.
     */
    public class ReflectTest10 {
    
        public static void main(String[] args) throws Exception{
            Class c = Class.forName("Test.User");
            Constructor[] constructors = c.getDeclaredConstructors();
            StringBuilder builder = new StringBuilder();
            for (Constructor constructor : constructors){
                String modifer = Modifier.toString(constructor.getModifiers());
                builder.append(modifer);
                builder.append(" ");
                String constructorName = constructor.getName();
                builder.append(constructorName);
           builder.append(" "); Class[] paras
    = constructor.getParameterTypes(); for (Class para : paras){ builder.append(para.getSimpleName()); builder.append(","); } builder.append(" "); } System.out.println(builder.toString()); } }

    private Test.User
    public Test.User String,int,

    同理可以根据参数类型来确定特定的构造方法

    通过getSuperclass()来获取父类,单继承,所以只有一个父类

    通过getInterfaces()获取接口,可以实现多个接口,所以返回一个Class数组

    反射的两个缺点

      1.性能问题

      用反射基本上属于一种解释操作,我们可以告诉JVM,我们希望做什么,并且他满足我们的要求。用字段和方法接入时,反射要远慢与直接代码。性能问题的程度取决于程序是如何使用反射的,如果他作为程序中很少涉及的部分,缓慢的性能将不会是一个问题。大量使用反射要慎重

      2.使用反射会模糊程序内部实际要发生的事情,程序员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术会带来维护问题。反射代码比直接代码更复杂。保守的使用反射,仅在他真正可以增加灵活性的地方使用。

      

  • 相关阅读:
    Binary Trees
    [POJ] String Matching
    Tree
    Maxmum subsequence sum problem
    poj 2104 划分树
    poj 2486 树形dp
    poj 1848 树形dp
    hdu 4578 线段树
    hdu 4585 set应用
    hdu 2412 树形DP
  • 原文地址:https://www.cnblogs.com/i-love-kobe/p/5991138.html
Copyright © 2020-2023  润新知