Class类---反射学习笔记(一)
2015-09-02 18:25
501 查看
Class类介绍:
在面向对象的世界里,万事万物皆对象。注意:Java中,有两种不是面向对象的:
(1)基本数据类型
(2)静态的成员
但是基本类型都有其对应的包装类,包装类是面向对象的。
类是对象,类是java.lang.Class类的实例对象。
package com.test.ClassTest; /** * Class类的说明和用法 * 2015年9月1日 上午10:17:54 * @author 张耀晖 * */ public class ClassTest { public static void main(String[] args) { //Foo的实例对象如何表示 Foo foo1 = new Foo(); //Foo这个类,也是一个实例对象,Class类的实例对象,如何表示呢? //任何一个类都是Class类的实例对象,这个实例对象有三种表示方式 //第一种表示方式---》实际在告诉我们任何一个类都有一个隐含的静态成员变量class Class c1 = Foo.class; //第二种表示方式(已经知道该类的对象通过getClass方法) Class c2 = foo1.getClass(); /*官网说法: * c1,c2表示了Foo类的类类型(class type) * foo1是Foo类的实例对象 * 万事万物皆对象 * 类也是对象,是Class类的实例对象 * 这个对象我们称为该类的类类型 */ //不管c1或者c2都代表了Foo类的类类型,一个类只可能是Class类的一个实例对象 System.out.println(c1==c2); //第三种表示方式 Class c3 = null; try { c3 = Class.forName("com.test.ClassTest.Foo"); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println(c2==c3); //我们完全可以通过类的类类型创建该类的对象实例--》通过c1或者c2或者c3创建Foo的实例 try { Foo foo2 = (Foo)c1.newInstance();//前提:Foo类需要有无参数的构造方法 foo2.print(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } class Foo{ void print(){ System.out.println("hello"); } }
运行结果:
程序分析:
(1)三种得到某个类的类类型的方法:
类名.class;
类的实例对象.getClass();
Class.forName(“类的全称”);
(2)通过类的的类类型创建类的实例对象:
类的类类型.newInstance();
注意:使用该方法的前提是这个类需要有无参的构造方法,因为newInstance()方法调用默认的构造方法(无参的构造方法)初始化新创建的对象,如果这个类没有默认的构造方法,就会抛出异常。
动态加载类与静态加载类
Class.forName(“类的全称”)不仅表示了类的类类型,还代表了动态加载类。
java代码在跑起来需要,编译,运行的过程。我们经常使用的IDE(如Eclipse)只是将编译与运行过程帮我们做了,并不是不需要经过编译和运行的过程。
编译:命令为javac
运行:命令为java
(1)静态加载类:编译时加载的类
(2)动态加载类:运行时加载的类
class Office{ public static void main(String[] args) { //new 创建对象 是动态加载类,在编译的时刻就需要加载所有的可能使用到的类 if ("Word".equals(args[0])) { Word w = new Word(); w.start(); } if ("Excel".equals(args[0])) { Excel e = new Excel(); e.start(); } } }
上边的这段代码跑的时候,会在编译的时候报错。
class Word{ public static void start(){ System.out.println("Word..start..."); } }
然后添加Word类之后的编译结果:
为什么会出现上边的结果呢?
原因:
new(创建对象)是静态加载类,在编译的时候就需要加载所有可能使用到的类。
但是这种静态加载类也会造成一种问题:
我想现在用哪个就加载哪个,不用就不加载怎么办呢?
比如:我现在想用Word这个类(Word类已经有了)中的start()方法,不需要用Excel这个类中的东西,怎么才能正确的运行这段代码呢?
答案:通过动态加载类来解决。
下面就是使用动态加载类解决上边的问题的代码:
class OfficeBetter{ public static void main(String[] args) { try{ //动态加载类,在运行时刻加载 Class c = Class.forName(args[0]); //通过类类型,创建该类的对象 OfficeAble oa = (OfficeAble)c.newInstance(); oa.start(); }catch(Exception e){ e.printStackTrace(); } } }
interface OfficeAble { public void start(); }
class Word implements OfficeAble{ public void start(){ System.out.println("Word..start..."); } }
运行结果:
从这个程序中可以发现,虽然没有创建Excel.java类,但是在使用“Class c = Class.forName(args[0]);”可以实现动态加载类。
动态加载类是在运行的时候加载的,编译的时候不会出现错误。在运行的时候才会报错。
同时在使用这种方法可以动态的扩展程序,比如当我们发布了一款游戏的时候,过一段时间我们需要增加一个游戏角色的时候,就不需要重新编译之前的程序,可以单独的写好这个角色的代码,然后实现之前角色代码实现的接口,动态的扩展游戏的内容。
再比如说上边的代码,如果我想现在添加Excel.java类的代码进去,就这个样直接编译Excel.java类然后,运行OfficeBetter Excel就可以了。
class Excel implements OfficeAble { public void start() { System.out.println("excel...start..."); } }
添加Excel类后运行结果:
基本数据类型,void关键字都存在类类型。
package com.test.ClassTest; public class ClassDemo { public static void main(String[] args) { Class c1 = int.class; Class c2 = Integer.class; Class c3 = String.class; Class c4 = void.class; System.out.println(c1.getName()); System.out.println(c2.getName()); System.out.println(c3.getName()); System.out.println(c4.getName()); } }
结果:
代码分析:
上边的代码结果反映出:
一个Class对象实际上表示的是一个类型,而这个类型未必一定是一种类。
例如,int不是类,但是int.class是一个Class类型的对象。
Class类的基本API操作
下面这段代码是检查类的结构的工具类package com.test.ClassMethodTest; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * 获取类信息 2015年9月1日 下午5:46:14 * * @author 张耀晖 * */ public class ClassUtil { /** * 打印类的成员函数的信息 * * @param obj该对象所属类的信息 */ public static void printClassMethodMessage(Object obj) { // 要获取类的信息,首先要获取类的类类型 Class c = obj.getClass();// 传递的是哪个子类的对象(比如Object代表的是String类型的),c就是该子类的类类型 // 获取类的名称 System.out.println("类的名称是:" + c.getName()); /* * 获得所有的方法Method类,方法对象一个成员方法就是一个Method对象 * getMethods()方法获取的是所有的public函数,包括父类继承而来的 * getDeclaredMethods()方法获取的是所有该类自己声明的方法,不问访问权限 */ Method[] m = c.getMethods();// 或者是getDeclaredMethods() for (int i = 0; i < m.length; i++) { // 得到方法的返回值类型的类类型 Class returnType = m[i].getReturnType(); System.out.print(returnType.getName() + " "); // 得到方法的名称 System.out.print(m[i].getName() + "("); // 获取参数类型--》得到的是参数列表的类型的类类型 Class[] paramTypes = m[i].getParameterTypes(); for (Class class1 : paramTypes) { System.out.print(class1.getName() + ","); } System.out.println(")"); } } /** * 打印类的成员变量的信息 * @param obj该对象所属类的信息 */ public static void printClassFieldMessage(Object obj) { /* * 成员变量也是对象 java.lang.reflect.Field Field类封装了关于成员变量的操作 * getFileds()方法获取的是所有的public的成员变量的信息 * getDeclaredFields()方法获取的是该类自己声明的成员变量的信息 */ Class c = obj.getClass(); // Field[] fs = c.getFields(); Field[] fs = c.getDeclaredFields(); for (Field field : fs) { // 得到成员变量的类型的类类型 Class fieldType = field.getType(); String typeName = fieldType.getName(); // 得到成员变量的名称 String fieldName = field.getName(); System.out.println(typeName + " " + fieldName); } } /** * 打印对象的构造函数的信息 * @param obj */ public static void printConMessage(Object obj){ Class c = obj.getClass(); /* * 构造函数也是对象 * java.lang.Constructor中封装了构造函数的信息 * getConstructors()获取所有的public的构造函数 * getDeclaredConstructors()得到自己声明的构造函数,不管权限(因为构造函数都是自己声明的,所以就是说得到所有的构造函数) */ // Constructor[] cs = c.getConstructors(); Constructor[] cs = c.getDeclaredConstructors(); for (Constructor constructor : cs) { System.out.print(constructor.getName()+"("); //获取构造函数的参数列表 Class[] paramTypes = constructor.getParameterTypes(); for (Class class1 : paramTypes) { System.out.print(class1.getName()+","); } System.out.println(")"); } } }
测试类:
package com.test.ClassMethodTest; public class ClassDemo1 { public static void main(String[] args) { String s = "hello"; ClassUtil.printClassMethodMessage(s); System.out.println("============================="); ClassUtil.printClassFieldMessage(s); System.out.println("============================="); ClassUtil.printConMessage(s); } }
运行结果:
类的名称是:java.lang.String boolean equals(java.lang.Object,) java.lang.String toString() int hashCode() int compareTo(java.lang.String,) int compareTo(java.lang.Object,) int indexOf(java.lang.String,int,) int indexOf(java.lang.String,) int indexOf(int,int,) int indexOf(int,) java.lang.String valueOf(int,) java.lang.String valueOf(long,) java.lang.String valueOf(float,) java.lang.String valueOf(boolean,) java.lang.String valueOf([C,) java.lang.String valueOf([C,int,int,) java.lang.String valueOf(java.lang.Object,) java.lang.String valueOf(char,) java.lang.String valueOf(double,) char charAt(int,) int codePointAt(int,) int codePointBefore(int,) int codePointCount(int,int,) int compareToIgnoreCase(java.lang.String,) java.lang.String concat(java.lang.String,) boolean contains(java.lang.CharSequence,) boolean contentEquals(java.lang.CharSequence,) boolean contentEquals(java.lang.StringBuffer,) java.lang.String copyValueOf([C,) java.lang.String copyValueOf([C,int,int,) boolean endsWith(java.lang.String,) boolean equalsIgnoreCase(java.lang.String,) java.lang.String format(java.util.Locale,java.lang.String,[Ljava.lang.Object;,) java.lang.String format(java.lang.String,[Ljava.lang.Object;,) void getBytes(int,int,[B,int,) [B getBytes(java.nio.charset.Charset,) [B getBytes(java.lang.String,) [B getBytes() void getChars(int,int,[C,int,) java.lang.String intern() boolean isEmpty() java.lang.String join(java.lang.CharSequence,[Ljava.lang.CharSequence;,) java.lang.String join(java.lang.CharSequence,java.lang.Iterable,) int lastIndexOf(int,) int lastIndexOf(java.lang.String,) int lastIndexOf(java.lang.String,int,) int lastIndexOf(int,int,) int length() boolean matches(java.lang.String,) int offsetByCodePoints(int,int,) boolean regionMatches(int,java.lang.String,int,int,) boolean regionMatches(boolean,int,java.lang.String,int,int,) java.lang.String replace(char,char,) java.lang.String replace(java.lang.CharSequence,java.lang.CharSequence,) java.lang.String replaceAll(java.lang.String,java.lang.String,) java.lang.String replaceFirst(java.lang.String,java.lang.String,) [Ljava.lang.String; split(java.lang.String,) [Ljava.lang.String; split(java.lang.String,int,) boolean startsWith(java.lang.String,int,) boolean startsWith(java.lang.String,) java.lang.CharSequence subSequence(int,int,) java.lang.String substring(int,) java.lang.String substring(int,int,) [C toCharArray() java.lang.String toLowerCase(java.util.Locale,) java.lang.String toLowerCase() java.lang.String toUpperCase() java.lang.String toUpperCase(java.util.Locale,) java.lang.String trim() void wait() void wait(long,int,) void wait(long,) java.lang.Class getClass() void notify() void notifyAll() java.util.stream.IntStream chars() java.util.stream.IntStream codePoints() ============================= [C value int hash long serialVersionUID [Ljava.io.ObjectStreamField; serialPersistentFields java.util.Comparator CASE_INSENSITIVE_ORDER ============================= java.lang.String([B,int,int,) java.lang.String([B,java.nio.charset.Charset,) java.lang.String([B,java.lang.String,) java.lang.String([B,int,int,java.nio.charset.Charset,) java.lang.String([B,int,int,java.lang.String,) java.lang.String([C,boolean,) java.lang.String(java.lang.StringBuilder,) java.lang.String(java.lang.StringBuffer,) java.lang.String([B,) java.lang.String([I,int,int,) java.lang.String() java.lang.String([C,) java.lang.String(java.lang.String,) java.lang.String([C,int,int,) java.lang.String([B,int,) java.lang.String([B,int,int,int,)
对比String类的源码发现结果是正确的。
分析上面的代码:
(1)查看任意对象所属类的所有的成员变量,方法,构造方法的名称和类型的步骤:
获得对应的Class对象
通过Class对象调用getDeclaredFields(),getDeclaredMethods(),getDeclaredConstructors()
通过Field,Method,Constructor对象调用getName()和getType(),getName()和getParameterTypes(),getName()和getParameterTypes()
(2)在java.lang.reflect包中有三个类Field,Method,Constructor分别用于描述类的成员变量,方法,构造器。
(3)Class类中的getFields(),getMethods(),getConstructors()方法将分别返回类提供的public的成员变量,方法,构造器数组,其中包括超类的公有成员。
Class类的getDeclareFields(),getDeclareMethods(),getDeclareConstructors()方法将分别返回类中声明的全部成员变量,方法,构造器,其中包括私有和受保护成员,但是不包括超类(所继承的类)的成员。
Class类还有很多方法可以查看Class类的API。
相关文章推荐
- 游标使用
- Class类---反射学习笔记(一)
- 多队列网卡
- 版本更新时Activity作为对话框形式弹出进度条
- nginx之nginx部署
- Windows与Ubuntu之间共享文件
- 搭建Spring + SpringMVC + Mybatis框架之一(创建项目)
- C++模板元编程 - 1 基本数据类型和运算
- 断舍离——有时间的话
- Ionic之搭建开发环境,并创建工程
- Android学习笔记.IDE使用eclipse还是studio
- Python Tkinter Checkbutton的使用
- Javascript变量和值之间的比较
- 快速排序
- Linux权限管理之ACL权限
- STM32F4使用硬件SPI驱动ADS8322
- Java基础-----基础小结
- 【转】 定义模板和服务
- 协变(Covariance)与逆变(Contravariance)
- 操作系统重装后一系列软件重装