zoukankan      html  css  js  c++  java
  • JAVA类加载和反射介绍

    简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息.
    反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现的十分明显。

    当程序主动使用某个类时,若该类还没加载到内存中,系统会通过加载,链接,初始化3个操作对类进行初始化。
    类字面常量”,class”创建Class对象的引用时,不会自动地初始化该Class对象,准备工作包含3个步骤:
    1.加载:由类加载器执行,该步骤查找字节码,并从这些字节码中创建一个Class对象
    2.链接:在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必需的话,将解析这个类创建的对其他类的所有引用。
    3.初始化:如果该类有超类,则对其初始化,执行静态初始化器和静态初始化块

    类的初始化时机
    1.创建类的实例
    2.访问类或接口的静态变量(static final常量除外,static final变量可以)
    3.调用类的静态方法
    4.反射(Class.forName(packageName.className))
    5.初始化类的子类(子类初始化问题:满足主动调用,即访问子类中的静态变量、方法,否则仅父类初始化)
    6.java虚拟机启动时被标明为启动类的类
    注:加载顺序:启动类的static block最先加载
    (父类静态成员、静态代码块—>子类静态成员、静态代码块—>父类实例成员、代码块——>父类构造函数—>子类实例成员、代码块—>子类构造函数)

    我们需要明白在JAVA中任何class都要装载在虚拟机上才能运行,而forClass就是装载类用的,这是要和new不一样,要分清楚哦。
    A a = (A)Class.forName(“package.A”).newInstance();和 A a = new A;是等价的。
    记住一个概念,静态代码是和class绑定的,class装载成功就表示执行了你的静态代码,而且以后不会再走这套静态代码了
    Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类,也即是说JVM会执行该类的静态代码段。

    JAVA中获取Class对象有3种方式:
    1.Class.forName()
    2.Object.getClass()
    3.类字面常量 xx.class

    代码例子:

    package Reflect;
    class Demo{
        //other codes...
    }
     
    class hello{
        public static void main(String[] args) {
            Class<?> demo1=null;
            Class<?> demo2=null;
            Class<?> demo3=null;
            try{
                //一般尽量采用这种形式
                demo1=Class.forName("Reflect.Demo");
            }catch(Exception e){
                e.printStackTrace();
            }
            demo2=new Demo().getClass();
            demo3=Demo.class;
             
            System.out.println("类名称   "+demo1.getName());//Reflect.Demo
            System.out.println("类名称   "+demo2.getName());//Reflect.Demo
            System.out.println("类名称   "+demo3.getName());//Reflect.Demo        
        }
    }

    从Class中获取信息(可以查看Class的API文档了解):

    获取类的构造器
    首先介绍一下Constructor类,这个类用来封装反射得到的构造器,Class有四个方法来获得Constructor对象
    public Constructor<?>[] getConstructors() 返回类中所有的public构造器集合,默认构造器的下标为0
    public Constructor<T> getConstructor(Class<?>... parameterTypes) 返回指定public构造器,参数为构造器参数类型集合
    public Constructor<?>[] getDeclaredConstructors() 返回类中所有的构造器,包括私有
    public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回任意指定的构造器

    获取类的成员变量
    成员变量用Field类进行封装,主要的方法非常的类似:
    public Field getDeclaredField(String name) 获取任意指定名字的成员
    public Field[] getDeclaredFields() 获取所有的成员变量
    public Field getField(String name) 获取任意public成员变量
    public Field[] getFields() 获取所有的public成员变量

    获取类的方法
    public Method[] getMethods() 获取所有的共有方法的集合
    public Method getMethod(String name,Class<?>... parameterTypes) 获取指定公有方法 参数1:方法名 参数2:参数类型集合
    public Method[] getDeclaredMethods() 获取所有的方法
    public Method getDeclaredMethod(String name,Class<?>... parameterTypes) 获取任意指定方法

    常用的就这些,知道这些,其他的都好办……

    获取基本信息的例子:

    import java.lang.reflect.*;
    import java.lang.annotation.*;
    
    //使用2个注释修饰该类
    @SuppressWarnings(value="unchecked")
    @Deprecated
    public class ClassTest
    {
        //为该类定义一个私有的构造器
        private ClassTest(){
        }
        
        //定义一个有参数的构造器
        public ClassTest(String name){
            System.out.println("执行有参数的构造器");
        }
        
        //定义一个无参数的info方法
        public void info(){
            System.out.println("执行无参数的info方法");
        }
        
        //定义一个有参数的info方法
        public void info(String str){
            System.out.println("执行有参数的info方法"
                + ",其实str参数值:" + str);
        }
        
        //定义一个测试用的内部类
        class Inner{
        }
        
        public static void main(String[] args) throws Exception{
            //下面代码可以获取ClassTest对应的Class
            Class<ClassTest> clazz = ClassTest.class;
            
            //获取该Class对象所对应类的全部构造器
            Constructor[] ctors = clazz.getDeclaredConstructors();
            System.out.println("ClassTest的全部构造器如下:");
            for (Constructor c : ctors)
            {
                System.out.println(c);
                //private ClassTest()
                //public ClassTest(java.lang.String)
            }
            
            
            //获取该Class对象所对应类的全部public构造器
            Constructor[] publicCtors = clazz.getConstructors();
            System.out.println("ClassTest的全部public构造器如下:");
            for (Constructor c : publicCtors)
            {
                System.out.println(c);
                //public ClassTest(java.lang.String)
            }
            
            //获取该Class对象所对应类的全部public方法
            Method[] mtds = clazz.getMethods();
            System.out.println("ClassTest的全部public方法如下:");
            for (Method md : mtds)
            {
                System.out.println(md);
                //public static void ClassTest.main(java.lang.String[]) throws java.lang.Exception
                //public void ClassTest.info()
                //public void ClassTest.info(java.lang.String)
                //public final void java.lang.Object.wait() throws java.lang.InterruptedException
                //public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
                //public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
                //public native int java.lang.Object.hashCode()
                //public final native java.lang.Class java.lang.Object.getClass()
                //public boolean java.lang.Object.equals(java.lang.Object)
                //public java.lang.String java.lang.Object.toString()
                //public final native void java.lang.Object.notify()
                //public final native void java.lang.Object.notifyAll()
            }
            
            //获取该Class对象所对应类的指定方法
            System.out.println("ClassTest里带一个字符串参数的info方法为:"
                + clazz.getMethod("info" , String.class));
            //public void ClassTest.info(java.lang.String)
            
            //获取该Class对象所对应类的上的全部注释
            Annotation[] anns = clazz.getAnnotations();
            System.out.println("ClassTest的全部Annotattion如下:");
            for (Annotation an : anns)
            {
                System.out.println(an);
            }
            
            System.out.println("该Class元素上的@SuppressWarnings注释为:"
                + clazz.getAnnotation(SuppressWarnings.class));
            
            //获取该Class对象所对应类的全部内部类
            Class<?>[] inners = clazz.getDeclaredClasses();
            System.out.println("ClassTest的全部内部类如下:");
            for (Class c : inners)
            {
                System.out.println(c);
                //class ClassTest$Inner
            }
            
            //使用Class.forName方法加载ClassTest的Inner内部类
            Class inClazz = Class.forName("ClassTest$Inner");
            
            //通过getDeclaringClass()访问该类所在的外部类
            System.out.println("inClazz对应类的外部类为:" + inClazz.getDeclaringClass());
            //class ClassTest
            System.out.println("ClassTest的包为:" + clazz.getPackage());
            //null
            System.out.println("ClassTest的父类为:" + clazz.getSuperclass());
            //class java.lang.Object
        }
    }

    通过Class调用其他类中的构造函数 (也可以通过这种方式通过Class创建其他类的对象)

    package Reflect;
     
    import java.lang.reflect.Constructor;
     
    class Person{
         
        public Person() {
             
        }
        public Person(String name){
            this.name=name;
        }
        public Person(int age){
            this.age=age;
        }
        public Person(String name, int age) {
            this.age=age;
            this.name=name;
        }
        public String getName() {
            return name;
        }
        public int getAge() {
            return age;
        }
        @Override
        public String toString(){
            return "["+this.name+"  "+this.age+"]";
        }
        private String name;
        private int age;
    }
     
    class hello{
        public static void main(String[] args) {
            Class<?> demo=null;
            try{
                demo=Class.forName("Reflect.Person");
            }catch (Exception e) {
                e.printStackTrace();
            }
            Person per1=null;
            Person per2=null;
            Person per3=null;
            Person per4=null;
            //取得全部的构造函数
            Constructor<?> cons[]=demo.getConstructors();
            try{
                per1=(Person)cons[0].newInstance();
                per2=(Person)cons[1].newInstance("Rollen");
                per3=(Person)cons[2].newInstance(20);
                per4=(Person)cons[3].newInstance("Rollen",20);
            }catch(Exception e){
                e.printStackTrace();
            }
            System.out.println(per1);//[null  0]
            System.out.println(per2);//[Rollen  0]
            System.out.println(per3);//[null  20]
            System.out.println(per4);//[Rollen  20]
        }
    }
    综合例子:
    package Reflect;
     
    interface China{
        public static final String name="Rollen";
        public static int age=20;
        public void sayChina();
        public void sayHello(String name, int age);
    }
     
    class Person implements China{
        public Person() {
        }
        public Person(String sex){
            this.sex=sex;
        }
        public String getSex() {
            return sex;
        }
        public void setSex(String sex) {
            this.sex = sex;
        }
        @Override
        public void sayChina(){
            System.out.println("hello ,china");
        }
        @Override
        public void sayHello(String name, int age){
            System.out.println(name+"  "+age);
        }
        private String sex;
    }
     
    class hello{
        public static void main(String[] args) {
            Class<?> demo=null;
            try{
                demo=Class.forName("Reflect.Person");
            }catch (Exception e) {
                e.printStackTrace();
            }
            
            //保存所有的接口
            Class<?> intes[]=demo.getInterfaces();
            for (int i = 0; i < intes.length; i++) {
                System.out.println("实现的接口   "+intes[i].getName());
                // Reflect.China
            }
            
            //获得其他类中的全部构造函数
            Constructor<?>cons[]=demo.getConstructors();
            for (int i = 0; i < cons.length; i++) {
                System.out.println("构造方法:  "+cons[i]);
                //public Reflect.Person()
                /public Reflect.Person(java.lang.String)
            }
            
            for (int i = 0; i < cons.length; i++) {
                Class<?> p[]=cons[i].getParameterTypes();
                System.out.print("构造方法:  ");
                int mo=cons[i].getModifiers();
                System.out.print(Modifier.toString(mo)+" ");
                System.out.print(cons[i].getName());
                System.out.print("(");
                for(int j=0;j<p.length;++j){
                    System.out.print(p[j].getName()+" arg"+i);
                    if(j<p.length-1){
                        System.out.print(",");
                    }
                }
                System.out.println("){}");
            }
            //构造方法:  public Reflect.Person(){}
            //构造方法:  public Reflect.Person(java.lang.String arg1){}
            
            //通过反射调用其他类中的方法
            try{
                //调用Person类中的sayChina方法
                Method method=demo.getMethod("sayChina");
                method.invoke(demo.newInstance());//hello ,china
                //调用Person的sayHello方法
                method=demo.getMethod("sayHello", String.class,int.class);
                method.invoke(demo.newInstance(),"Rollen",20);//Rollen  20
                 
            }catch (Exception e) {
                e.printStackTrace();
            }
            
            
            System.out.println("===============本类属性========================");
            // 取得本类的全部属性
            Field[] field = demo.getDeclaredFields();
            for (int i = 0; i < field.length; i++) {
                // 权限修饰符
                int mo = field[i].getModifiers();
                String priv = Modifier.toString(mo);
                // 属性类型
                Class<?> type = field[i].getType();
                System.out.println(priv + " " + type.getName() + " "
                        + field[i].getName() + ";");
                //private java.lang.String sex;        
            }
            System.out.println("===============实现的接口或者父类的属性========================");
            // 取得实现的接口或者父类的属性
            Field[] filed1 = demo.getFields();
            for (int j = 0; j < filed1.length; j++) {
                // 权限修饰符
                int mo = filed1[j].getModifiers();
                String priv = Modifier.toString(mo);
                // 属性类型
                Class<?> type = filed1[j].getType();
                System.out.println(priv + " " + type.getName() + " "
                        + filed1[j].getName() + ";");
            }
            //public static final java.lang.String name;
            //public static final int age;
            
    
            Object obj = null;
            try{
             obj=demo.newInstance();
            }catch (Exception e) {
                e.printStackTrace();
            }
            
            
            
            //通过反射操作属性
            Field field = demo.getDeclaredField("sex");
            field.setAccessible(true);
            field.set(obj, "男");
            
            //通过反射取得并修改数组的信息:
            int[] temp={1,2,3,4,5};
            Class<?>demo=temp.getClass().getComponentType();
            System.out.println("数组类型: "+demo.getName());// int
            System.out.println("数组长度  "+Array.getLength(temp));//5
            System.out.println("数组的第一个元素: "+Array.get(temp, 0));//1
            Array.set(temp, 0, 100);
            System.out.println("修改之后数组第一个元素为: "+Array.get(temp, 0));//100
        }
    }

    将反射用于工厂模式(结合属性文件的工厂模式):

    首先创建一个fruit.properties的资源文件,内容为:
    apple=Reflect.Apple
    orange=Reflect.Orange

    主类代码:

    package Reflect;
     
    import java.io.*;
    import java.util.*;
     
    interface fruit{
        public abstract void eat();
    }
     
    class Apple implements fruit{
        public void eat(){
            System.out.println("Apple");
        }
    }
     
    class Orange implements fruit{
        public void eat(){
            System.out.println("Orange");
        }
    }
     
    //操作属性文件类
    class init{
        public static Properties getPro() throws FileNotFoundException, IOException{
            Properties pro=new Properties();
            File f=new File("fruit.properties");
            if(f.exists()){
                pro.load(new FileInputStream(f));
            }else{
                pro.setProperty("apple", "Reflect.Apple");
                pro.setProperty("orange", "Reflect.Orange");
                pro.store(new FileOutputStream(f), "FRUIT CLASS");
            }
            return pro;
        }
    }
     
    class Factory{
        public static fruit getInstance(String ClassName){
            fruit f=null;
            try{
                f=(fruit)Class.forName(ClassName).newInstance();
            }catch (Exception e) {
                e.printStackTrace();
            }
            return f;
        }
    }
    
    class hello{
        public static void main(String[] a) throws FileNotFoundException, IOException{
            Properties pro=init.getPro();
            fruit f=Factory.getInstance(pro.getProperty("apple"));
            if(f!=null){
                f.eat();//Apple
            }
        }
    }

    参考:
    参考sina博文<<forName和类字面常量.class>>
    参考<<疯狂JAVA编程>>第18章
    java反射详解 (各个例子写的还是挺不错的)
    http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html

  • 相关阅读:
    java的语法基础(二)
    MyBatis 的好处是什么?
    python中字符串的编码和解码
    Spring的简介和优点?
    相对于Statement,PreparedStatement的优点是什么?
    MyBatis 的好处是什么?
    .final finally finalize区别
    final类有什么用
    web广泛用到的技术:
    JDK,JRE,JVM三者的关系
  • 原文地址:https://www.cnblogs.com/lijunamneg/p/2980991.html
Copyright © 2011-2022 走看看