您的位置:首页 > 其它

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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: