浅谈 Java 中的 Class 类
最近一段时间,对于 java 的反射比较感兴趣,于是打算通过深入学习来更好的了解反射的实现机制。于是开始查阅有关反射的博文,但是在学习的过程中,发现 Class
类始终伴随着反射出现。因为多少接触过 Class
类,所以有关反射的代码还是能看懂的,不会影响我学习反射的知识,本就可以直接略过。
但是仔细一想,学习是一个主动的过程,要积极的去解决每一个小的问题,争取在求知过程中不留存疑惑,否则到最后会发现因为这些小问题的存在,使得自己的理解始终停在“知其然,不知所以然”的层面。既然接触到了 Class
类,就应该顺带消化了,这样的才能学到更多的东西。
后续我会和大家分享我在学习反射时的一些心得,在此之前,先分享一下我学习 Class
类的一些体会哈。此次分享没有太多高深的知识,但是还是觉得只要您认真的看完本文,多少会有收获的,哪怕是巩固一下也不错,嘿嘿 : )
面向对象
我们都知道,java 是一门面向对象的语言。在面向对象的世界里,万事万物皆对象,除了静态成员(因为静态成员属于某个类,而不是对象)和普通数据类型。
在面向对象的语言中,我们擅长将现实世界中的一个实际存在的事物抽象并封装成一个类,并在类中添加相应的成员变量(属性)和方法,然后我们就可以创建该类的对象,该对象持有属于自己的成员变量和方法。
既然万事万物皆对象,那么我们的类是不是对象呢?是的,我们写的每一个类都是对象,是 java.lang.Class 类的对象。也就是说,每一个类既有自己的对象,同时也是 Class
类的对象。那么,该如何表示 Class
类的对象呢,让我们接着往下看,以进一步了解 Class
类。
java.lang.Class 类
初识 Class 类
很遗憾直到现在我才认识到 Class 的意义,不敢说这次接触就彻底弄懂了 Class
类,但至少目前所理解的内容可以帮助我更好的分析其他问题了。
都说学习技术最好的方法就是查看源码和官方 API ,那么这次我也这么来,虽然我技术一般,但是格调还是要跟上的!我发现了一篇比较好的从源码角度分析 Class
类的博客,在这里推荐给大家,感兴趣的可以跟着这篇文章把 Class
类的源码过一遍,一定会有收获的。当然,您现在不看也没关系,因为推荐的博客中只有一点是我接下来要强调的,我会在后面给大家概括出来。点我跳转
先来看看 Class
类的构造方法(有删减):
/** Private constructor. * Only the Java Virtual Machine* creates Class objects.*/private Class(ClassLoader loader) {classLoader = loader;}
根据注释可知,Class 类的构造方法是私有的,只有 Java 虚拟机可以创建该类的对象,因此我们无法在代码中显式地声明一个 Class 对象。这就是我要强调的内容,其对于后面内容的理解十分重要。
Class 类与其他类的关系
由类或类对象得到 Class 类的对象
自定义一个类 MyClass,并声明该类的对象:
class MyClass{}MyClass mClass1 = new MyClass();
在上面说过,Class
类的构造方法是私有的,只有 java 虚拟机可以调用该方法创建该类的对象。也就是说我们无法像定义普通类对象一样,通过 new 直接创建 Class
类的对象。
但是,我们依然可以通过其他方式得到 Class 类的对象
通过类的静态成员表示。每个类都有一个隐含的静态成员class,表示如下:
Class c1 = MyClass.class;
通过类对象的
getClass()
方法。由1不难理解,既然存在静态变量,那么通过对象的 getter 方法,就可以获取静态成员class:Class c2 = mClass1.getClass();
通过
Class
类的静态方法forName()
方法获取Class
的对象。区别于通过 new 创建对象(编译时静态加载),在开发时如果我们需要动态加载我们的功能模块,该方法可以帮助我们实现在程序运行时类的动态加载。try {//注意,forName()需要传入类的全路径//如果当前类与参数类在同一包下即可省略包名mClass = Class.forName("custom.OtherClass");} catch (ClassNotFoundException e) {e.printStackTrace();}
如果我们的程序中没有 OtherClass 这个类,使用 Class.forName() 动态加载时,在程序编译时刻是不会报错的,只有在运行时刻检测到没有该类才会出错。
类的动态加载和静态加载是 Java 中一个重要的知识点,但因为我们开发时通常都使用 IDE, 其帮助我们自动实现了程序的编译和运行,使得我们常常忽略了程序的编译时和运行时状态。说着说着,我发现这块我有必要再写一篇博客记录一下,今天就先不讨论了。
由 Class 类的对象得到类的对象
我们可以通过类或类对象得到 Class
类的对象,反过来,我们也可以由 Class
类的对象得到类的对象:
MyClass mClass2 = (MyClass)c2.newInstance();
需要提醒您的是:c2.newInstance()
需要调用 MyClass
类的无参构造方法!如果 MyClass
类中存在显示的有参构造方法,会覆盖默认的无参构造方法,同时又没有显示的声明无参构造方法,那么执行这段代码时会直接导致程序Crash掉。下面为大家演示一下:
示例代码,请看注释:
/*** Created by Mr Rui on 2016/5/1.*/
public class TestDemo {public static void main(String args[]){//得到 Class 对象 mClassClass mClass = MyClass.class;try {// 由 mClass 实例化 MyClass 的对象,// 需要调用 MyClass 的无参构造方法MyClass mMyClass = (MyClass) mClass.newInstance();} catch (Exception e) {e.printStackTrace();}}
}class MyClass{//有参构造方法,会覆盖默认的无参构造方法public MyClass(String s){}
}
程序异常:
java.lang.InstantiationException: MyClassat java.lang.Class.newInstance(Class.java:427)at TestDemo.main(TestDemo.java:12)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:497)at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.NoSuchMethodException: MyClass.<init>()at java.lang.Class.getConstructor0(Class.java:3082)at java.lang.Class.newInstance(Class.java:412)... 6 more
解决办法就是在 MyClass 中的显示的添加一个 无参构造方法,就不再提供示例了。
针对这一点,相信有许多人在使用第三方框架或者开源库时,遇到过因为在类中添加了带参数的构造方法而导致程序出错的情况!针对这个,我的理解是:有些框架是基于反射实现的,它根据我们传入的类对象,使用其 newInstance()
方法获取 Class
对象,进而进行后续的反射操作(不在本文的讨论范围)。可是因为我们无意覆盖了默认的无参构造方法,导致程序无法正常获取 Class
对象,所以就出错了。说到这儿,您应该能理解其中缘由了吧!
这次分享的内容比较少,归结起来就是如何获取 Class
类的对象,以及如何由 Class 对象得到类对象。至于如何使用 Class 对象进行反射操作,如何实现程序运行时动态加载类,在后面的分享中会继续向大家介绍的。
我将所理解知识梳理并整理出来,一方面供大家参考交流,另一方面因为我也处在学习的阶段,希望能得到更多人的指导。如果文中有任何错误或遗漏的地方,还望您给予指正,我会积极完善!
Java 反射基础(上)
扫描下方二维码,关注我的公众号,及时获取最新文章推送!
浅谈 Java 中的 Class 类相关推荐
- 浅谈Java中的BigInteger类
在Java中,由于CPU原生提供的整型数据最大范围是64位的long型整数 那么如果我们在使用的时候数据超过了long型整数的范围该怎么办,这个时候,我们就需要用到Java中的一个类:java.mat ...
- java 中的单元测试_浅谈Java 中的单元测试
单元测试编写 Junit 单元测试框架 对于Java语言而言,其单元测试框架,有Junit和TestNG这两种, 下面是一个典型的JUnit测试类的结构 package com.example.dem ...
- 浅谈Java中的Set、List、Map的区别
就学习经验,浅谈Java中的Set,List,Map的区别,对JAVA的集合的理解是想对于数组: 数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型),JAVA集合可以存储和操 ...
- java中修饰常量的事_浅谈java中的声明常量为什么要用static修饰
今天定义一个类常量,想着也只有这个类可以用到,就没用static关键字修饰.结果sonar代码检查提示: Rename this field "PERSON_TYPE_USER" ...
- 浅谈JAVA中如何利用socket进行网络编程(二)
转自:http://developer.51cto.com/art/201106/268386.htm Socket是网络上运行的两个程序间双向通讯的一端,它既可以接受请求,也可以发送请求,利用它可以 ...
- file相对路径java_浅谈java 中文件的读取File、以及相对路径的问题
一.对于java项目中文件的读取 1.使用system 或是 系统的properties对象 ①直接是使用 string relativelypath=system.getproperty(" ...
- java中的强制类型转换注意事项_浅谈Java中强制类型转换的问题
为了更好的理解我们先看下面的例子: package com.yonyou.test; import java.util.ArrayList; import java.util.Iterator; im ...
- 浅谈Java中的栈和堆
人们常说堆栈堆栈,堆和栈是内存中两处不一样的地方,什么样的数据存在栈,又是什么样的数据存在堆中? 这里浅谈Java中的栈和堆 首先,将结论写在前面,后面再用例子加以验证. Java的栈中存储以下类型数 ...
- java布尔类型比较器_浅谈Java中几种常见的比较器的实现方法
在java中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题. 通常对象之间的比较可以从两个方面去看: 第一个方面:对象的地址是否一样,也就是是否引用自同一个对象.这种方式可以直接使用& ...
最新文章
- Win32汇编数据对齐相关的伪指令(ALIGN、EVEN、ORG)
- 我用nagios-check_http check Checker
- FastDFS配置nginx插件访问图片
- PMCAFF|百度客户端产品:高效开发客户端产品的正确姿势
- C语言中如何使用宏连接多个字符串(#和##的用法)
- python短时傅里叶变换_短时傅里叶变换的python实现
- python字符串_python的字符串怎么拼接
- Day4:html和css
- Android三种左右滑动效果 手势识别(转)
- L2-001 城市间紧急救援 (25 point(s))
- zookeeper启动失败解决方法
- 【支付】银行卡收单业务
- 搜狗输入法 linux 卸载,ubuntu彻底卸载搜狗拼音输入法
- Vue 事件绑定与解绑
- c语言计算利息答案是0.0,ACCP北大青鸟4.0 程序逻辑和C语言实现课本后的习题和上机题目,怎么做?...
- Warshall沃舍尔算法
- 浅谈无线路由器自动掉线解决办法
- android listview网络图片,Android ListView从网络获取图片及文字显示
- 单片机定时器计数原理
- 珞石(ROKAE)机械手简单的编程