java反射学习总结

一、反射机制中主要掌握的类型。

以下是SUN提供的反射机制中的类,每个类都可以创建对象。

  • java.lang.Class;
  • java.lang.reflect.Constructor;
  • java.lang.reflect.Field;
  • java.lang.reflect.Method;
  • java.lang.reflect.Modifier;

例如

class User{

    private String name;//属性
    public User(){}//构造方法
    public void m1(){}//普通方法
}
  1. Class 代表例子中的这个类整体。
  2. Constructor 代表这个类整体中的构造方法。
  3. Field 代表这个类整体中的属性。
  4. Method 代表这个类整体中的普通方法。
  5. Modifier 代表这个类整体中的访问修饰符。

二、反射机制的作用

(1)完成反编译:.class–>.java
(2)通过反射机制访问java类的属性,普通方法,构造方法等。


三、获取Class类对象的三种方式

(1)例子

public class ReflectTest01{
    public static void main(String[] args) throws Exception{
    //第一种方式
    Class c1 = Class.forName("Employee"); 
    //c1引用保存内存地址指向堆中的对象,该对象代表的是Empolyee整个类。
    //forName(必须写类全名,类全名包括包名)
    }

    //第二种方式
    //java中每个类型都有class属性
    Class c2  = Employee.class;

    //第三种方式
    //java语言中任何一个java对象都有getClass方法
    Employee e = new Employee();
    Class c3 = e.getClass();//c3是运行时类(e的运行时类是Employee)

    //因为Employee这个类在JVM中只有一个所以c1,c2,c3的内存地址是相同的,指向堆中唯一的一个对象。
    System.out.println(c1 == c2);//ture
    System.out.println(c2 == c3);//ture

    //c7代表int类型
    Class c7 = int.class;
}


public class Employee{
    //属性
    private String name;
    //无参构造
    public Employee(){
    system.out.println("Employee的无参数构造方法执行");
    }
    //有参构造
    public Employee(String name){
    this.name = name;
    }
    //普通方法
    public void work(){
    system.out.println(name + "工作");
    }

}

public class ReflectTest02{

    public static void main(String [] args) throws Exception{

    //将A.class文件装载到JVM中的过程。
    //Class.forName("A");

    //不会执行静态语句块
    //Class c = A.class;
    }
}

class A{
    static{
         System.out.println("A.......");
    }

}

//获取Class类型的对象之后,可以创建该"类"的对象
public class ReflectTest03{

    public static void main(String [] args) throws Exception{
     Class c = Class.forName("Employee");

    //创建此Class对象所表示的类的一个新的实例
    Object o = c.newInstance();//c.newInstance()调用了Employee的无参数构造方法。
    System.out.println(o);//打印出Empolyee@c17164

    }

}

四、java语言中的可变长参数

public class Test01{
    //m1方法有一个int类型可变长参数
    public static void m1(int... a){
    //m1方法在调用的时候,传递的实参可以是0--N个。
    //int...表示类型 a表示局部变量
    System.out.println("Test");//打印出4个Tset
    }
    //如果有精确匹配的方法,则调用该方法。不会再去执行可变参数的那个方法。
    public static void m1(int i){
    System.out.println(i);//打印出来的为1,3,4为Test 第二个为1。
    }

    //可变长参数可以等同看做数组
    public static void m2(String... args){

        for(int i = 0;i < args.length;i++){
            System.out.println(args[i]);
        }
    }

    public static void m3(Class... args){
        for(int i = 0;i < args.length;i++){
        Class o = args[i];
        System.out.println(c.newInstance());
        }
    }
    //可变长参数只能出现一次,并且只能出现在所有参数的最后一位。
    //public static void m4(String... a,int i ){}这个是错误的
    //public static void m4(int i,String... a){}
    public static void main(String[] args) throws Exception{
        m1();
        m1(1);
        m1(1,2);
        m1(1,2,3,4);
        m2("运动","音乐","美食","旅游");
        m3(Employee.class);
    }

}

五、java.lang.reflect.Field;获取类中所有的属性

public class ReflectTest04{

    public static void main(String [] args) throws Exception{

    //获取整个类
     Class c = Class.forName("User");
    //获取类中的属性
    /*
    //获取所以的public修饰的属性
    Field[] fs = c.getFields();
    System.out.println(fs.length);  //输出1
    System.out.println(fs[0].getName());//输出age

    */

    //获取所有的属性
    Field[] fs = c.getDeclareFields();
    for(Field field:fs){
        //获取类中的修饰符
        int i = field.getModifiers();
        String str = Modifier.toString(i);
        System.out.println(str);

        //获取类中所有属性的类型
        Class type = field.getType();
        //System.out.println(type.getName());
        System.out.println(type.getSimpleName());

        //获取类中的属性的名字
        System.out.println(field.getName());
        }
    }

}


public class User{
    //Filed
    private String id;
    public int age;
    protected String addr;
    boolean sex;

}

六、java.lang.reflect.Field;获取类中指定的属性

public class ReflectTest05{

    public static void main(String [] args) throws Exception{
        //以前的方式
        /*
        User u = new User();
        u.age = 12;//set
        System.out.println(u.age);\
        */


        //获取类
        Class c = Class.forName("User");
        //获取类中指定的属性。属性根据名字来区分
        //获取id属性
        Field idF = c.getDeclaredField("id");

        //获取到某个特定的属性可以用来set,get
        Object o = c.newInstance();

        //打破封装
        idF.setAccessible(true);//使用反射机制可以打破封装性,导致java对象的属性不安全。

        //给o对象的id属性赋值“110”
        idF.set(o,"110");//set

        //get
        System.out.println(idF.get(o));

    }

}

public class User{
    //Filed
    private String id;
    public int age;
    protected String addr;
    boolean sex;

}

七、java.lang.reflect.Method; 获取类中所有的方法

public class CustomerService{

    //登录
    public boolean login(String name,String pwd){

    if("admin".equals(name) && "123".equals(pwd)){

        return ture;
    }
    return false;

    }
    //退出
    public void logout(){
        System.out.println("系统安全退出!");

    }
}

public class ReflectTest06{

    public static void main(String [] args) throws Exception{
        //获取类
        Class c = Class.forName("CustomerService");
        //获取类中所有的方法
        Method[] ms = c.getDeclaredMethods();
        for(Method m:ms){

            //获取修饰符
            System.out.println(Modifier.toString(m.getModifiers()));

            //获取方法的返回值类型
            Class returnType = m.getReturnType();
            System.out.println.(returnType.getSimpleName());

            //获取方法名
            System.out.println(m.getName());

            //获取方法中的形式参数列表
            Class[] parameterTypes = m.getparameterTypes();
            for(Class parameterType:parameterTypes){
            System.out.println(parameterType.getSimpleName());
            }
        } 
    }
}

八、获取获取某个特定的方法,通过反射机制执行

//以前:
//CustomerService cs = new CustomerService();
//boolean isSuccess = cs.login("admin","123");
//通过反射机制
public class ReflectTest07{

    public static void main(String [] args) throws Exception{

        //获取类
        Class c = Class.forName("CustomerService");

        //获取某个特定的方法
        //通过:方法名+形参列表
        Method m = c.getDeclareMethod("login",String.class,String class);

        //通过反射机制执行login方法
        Object o = c.newInstance();

        //调用o对象的m方法,传递"admin""123"参数,方法的执行结果是retValue
        Object retValue = m.invoke(o,"admin","123");
        System.out.println(retValue);//true 
        Object retValue = m.invoke(o,"admin","456");
        System.out.println(retValue);//false    
    }
}
//获取构造方法
public class ReflectTest08{
    public static void main(String[] args) throws Exception{

    //获取类
    Class c = Class.forName("java.lang.String");

    //获取所有的构造
    Constructor[] cs = c.getDeclaredConstructors();
    for(Constructor con:cs){
        //获取修饰符
        System.out.println(Modifier.toString(con.getModifiers()));

        //获取构造方法名
        System.out.println(c.getName());

        //构造方法的形式参数列表
        Class[] parameterTypes = con.getParameterTypes();
        for(Class parameterType:parameterTypes){
                System.out.println(parameterType.getSimpleName());
            }
        }
    }
}

//获取某个类中特定的构造方法,然后创建对象。
public class ReflectTest09{

    public static void main(String[] args) throws Exception{

    //获取类
    Class c = Class.forName("Customer")
    //获取特定的构造方法
    Constructor con = c.getDeclaredConstructor(String.class,int.class)
    //创建对象
    Object o = con.newInstance("张三",25);
    System.out.println(o);
    }

}

class Customer{
    String name;
    int age;
    Customer(String name,int age){
        this.name = name;
        this.age = age;
    }
    public String toString(){
        return "Customer["+name+","+age+"]";
    }

}

九、关于类获取父类和父接口

public class ReflectTest10{
    //通过反射机制获取String类的父类和父接口
    public static void main(String[] args) throws Exception{

        Class c = Class.forName("java.lang.String");
        //获取父类
        Class superClass = c.getSuperclass();
        //打印父类的名字
        System.out.println(superClass.getName());
        //获取父接口
        Class[] ins = c.getInterfaces();

        for(Class in:ins){
            System.out.println(in.getName());
        }
    }
}

十、反射机制的缺点

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

2、使用反射会模糊程序内部实际要发生的事情。程序人员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术会带来维护问题。反射代码比相应的直接代码更复杂。解决这些问题的最佳方案是保守地使用反射————仅在它可以真正增加灵活性的地方————记录其在目标类中的使用。

猜你喜欢

转载自blog.csdn.net/qq_41112517/article/details/80297543