MyException - 我的异常网
当前位置:我的异常网» Java相关 » Class对象的创设与使用

Class对象的创设与使用

www.MyException.Cn  网友分享于:2013-09-19  浏览:0次
Class对象的创建与使用

类与Class对象


类是程序的一部分,每个类都有一个Class对象,即每当编写并且编译一个新类的时候就会产生一个Class对象。当程序创建第一个对类的静态成员的引用的时候,会将该类动态加载到JVM中,这个说明了类的构造起器也是一个静态方法,即使在构造器之前并没有使用static关键字。所以java程序在运行之前并没有被完全加载,各个类只在需要的时候才将该类的Class对象载入内存,该Class对象被用来创建这个类的所有对象。通过下面的代码可以证明以上内容:

class Demo1 {
    static int i;
    static {
        System.out.println("loading Demo1");
    }
}
class Demo2 {
    static {
        System.out.println("loading Demo2");
    }
}
class Demo3 {
    static {
        System.out.println("loading Demo3");
    }
}
class TestDemo {
    public static void main(String[] args) {
        int i = Demo1.i;
        try {
            Class.forName("Demo2");
        } catch (ClassNotFoundException e) {
            System.out.println("couldn't find Demo2");
        }
        new Demo3();
    }
    /* output
     * loading Demo1
     * loading Demo2
     * loading Demo3
     */
}

其中static{}是静态块,在类被加载的时候会执行,第一个输出是我们是用Demo1中的静态成员i而加载了Demo1类,而第二个输出我们调用了Class类的一个静态方法forName,参数是一个类的名称,返回的是该类名的类的Class对象,该方法还有一个作用就是若该类未被加载则加载它,最后使用了new关键字创建对象即调用了类的构造器,也对类进行了加载输出了第三行

Class对象的创建


若我们想要在运行的时候获取某个类的类型信息,就必须先获得该类的Class对象。得到Class对象的方法主要有三种

  • Class.forName:Class类的一个静态方法,传入类的全名
  • 对象.getClass:根类Object的方法,返回该对象的类的Class对象
  • 类名.class:这种方法又称为类字面常量,该方法不仅简单,而且更安全,因为可以在编译时就会受到检查
    class Demo1 {
        static final int i1 = 47;
        static final int i2 = (int)(Math.random() * 10000);
        static {
            System.out.println("loading Demo1");
        }
    }
    class TestDemo {
        public static void main(String[] args) {
            Class<Demo1> demo1Class = Demo1.class;
            System.out.println("after Demo1.class");
            int i = Demo1.i1;
            System.out.println("after Demo1.i1");
            i = Demo1.i2;
            System.out.println("after Demo1.i2");
        }
        /* output
         * after Demo1.class
         * after Demo1.i1
         * loading Demo1
         * after Demo1.i2
         */
    }

    从以上的代码中你会发现,通过使用类名.class的方法并没有对类进行加载,因为通过这种方法创建Class对象不会自动地初始化该Class对象。当我们使用某个类的时候实际上可以分为三个步骤:1)加载,这是由类加载器执行的,即通过查找到的字节码创建一个Class对象。2)链接,验证类中的字节码,为静态域分配存储空间,解析对其它类的引用。3)初始化,若该类有父类,则对其初始化,执行静态初始化器和静态块。从这三个步骤中看出只有对Class对象进行初始化才执行静态块。接着我们又调用了Demo1的i1也为执行静态块,因为被static final修饰的是一个编译期常量,当我们读取这个值的时候并不需要的类进行初始化,但并不是说访问的域被static final修饰时就不会对类进行初始化,从调用i2就可以看出,因为i2的值不是一个编译器的常量。

Class对象的使用


Class对象中提供了大量的方法来让我们获取类中的属性与方法,而且我们也可以通过Class对象来创建类的实例与修改属性值和执行方法,以下为Class对象中比较常用的方法:

  • getFields:获取public修饰的所有属性,返回一个Field数组(包括父类的)
  • getDeclaredFields:获取所有属性,返回一个Field数组
  • getField:传入一个参数(属性名),获取单个属性,返回一个Field对象,只能获取public修饰的
  • getDeclaredField:传入一个参数(属性名),获取单个属性,返回一个Field对象
    public class Demo {
        public int field1;
        private String field2;
        public void method1(Integer arg0) {
            System.out.println("执行method1");
        }
        private String method1() { return null;}
    }
    class TestDemo {
        public static void main(String[] args) throws Exception {
            Class<Demo> demoClass = Demo.class;
            Field[] fields1 = demoClass.getFields();
            Field[] fields2 = demoClass.getDeclaredFields();
            System.out.println(Arrays.toString(fields1));
            System.out.println(Arrays.toString(fields2));
            Field field1 = demoClass.getField("field1");
            // Field field2 = demoClass.getField("field2"); // 运行时抛异常
            Field field3 = demoClass.getDeclaredField("field2");
            System.out.println(field1);
            System.out.println(field3);
        }
        /* output
         * [public int Demo.field1]
         * [public int Demo.field1, private java.lang.String Demo.field2]
         * public int Demo.field1
         * private java.lang.String Demo.field2
         */
    }
  • getMethods:获取所有的public修饰的方法,包括父类的,返回Method数组
  • getDeclaredMethods:获取所有的返回,不包括父类,返回Method数组
  • getMethod:传入一个参数(方法名),返回一个Method对象,只能获取到public修饰的
  • getDeclared:传入一个参数(方法名),返回一个Method对象
    class TestDemo {
        public static void main(String[] args) throws Exception {
            Class<Demo> demoClass = Demo.class; //上段代码的Demo类
            Method[] methods1 = demoClass.getMethods();
            Method[] methods2 = demoClass.getDeclaredMethods();
            System.out.println(Arrays.toString(methods1));
            System.out.println(Arrays.toString(methods2));
            Method method1 = demoClass.getMethod("method1", new Class[]{Integer.class});
    //        Method method2 = demoClass.getMethod("method2");
            Method method3 = demoClass.getDeclaredMethod("method2");
            System.out.println(method1);
            System.out.println(method3);
        }
        /**
         * [public void Demo.method1(java.lang.Integer), public final void java.lang.Object.wait() throws java.lang.InterruptedException,...
         * [public void Demo.method1(java.lang.Integer), private java.lang.String Demo.method2()]
         * public void Demo.method1(java.lang.Integer)
         * private java.lang.String Demo.method2()
         */
    }
  • newInstance:创建该类型的一个实例
    class TestDemo {
        public static void main(String[] args) throws Exception {
            Class<Demo> demoClass = Demo.class;
            Demo demo = demoClass.newInstance();
            Field field2 = demoClass.getDeclaredField("field2");
            field2.setAccessible(true);
            field2.set(demo, "setField2");
            System.out.println(field2.get(demo));
            Method method1 = demoClass.getMethod("method1", Integer.class);
            method1.invoke(demo, new Object[]{11});
        }
        /**
         * setField2
         * 执行method1
         */
    }

    以上代码中可以看出创建类的一个实例并不只能通过new关键字来创建,而且上述还使用了Field对象的方法,可以获取一个实例中的属性值。而且你会发现通过Field对象的方法甚至可以改变一个实例的私有的属性值。若想改变私有属性值必须调用setAccessible方法并传入true(默认为false)。后面又使用了Method对象的方法,可以执行实例的方法,传入参数分别为实例与方法的参数数组,若调用Method的setAccessible方法并传入true,可以执行实例的私有方法。到这你可能会想有没有什么办法可以阻止我们通过反射(即Field和Method方法)调用那些私有的属性,可以试着将该属性值放在一个私有内部类中或则放在匿名类中,最后将会发现这都不法阻止反射的调用。但我们可以通过将一个属性用final来修饰,即使可以执行修改操作但并不会真正的改变属性值。

 

文章评论

总结2014中国互联网十大段子
总结2014中国互联网十大段子
编程语言是女人
编程语言是女人
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
如何成为一名黑客
如何成为一名黑客
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
漫画:程序员的工作
漫画:程序员的工作
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
那些争议最大的编程观点
那些争议最大的编程观点
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
程序员和编码员之间的区别
程序员和编码员之间的区别
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
程序员的鄙视链
程序员的鄙视链
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
每天工作4小时的程序员
每天工作4小时的程序员
我的丈夫是个程序员
我的丈夫是个程序员
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
旅行,写作,编程
旅行,写作,编程
中美印日四国程序员比较
中美印日四国程序员比较
程序员都该阅读的书
程序员都该阅读的书
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
老程序员的下场
老程序员的下场
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
一个程序员的时间管理
一个程序员的时间管理
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
10个调试和排错的小建议
10个调试和排错的小建议
Java程序员必看电影
Java程序员必看电影
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
 程序员的样子
程序员的样子
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
我是如何打败拖延症的
我是如何打败拖延症的
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
代码女神横空出世
代码女神横空出世
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有