1、Class类
(1)概念:Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。Class类代表JAVA类,它的各个实例对象对应各个类在内存中的字节码,如Person类的字节码,一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容也是不同的,这一个个的空间可分别用一个个的对象来表示,这些对象显然具有相同的类型,Class类型。
(2)Class
类的实例表示正在运行的Java 应用程序中的类和接口,如何获取Class类实例对象:
-通过类名.class,如Class c=System.class
-通过对象的getClass()方法,格式:对象.getClass(),如Class c =newPerson().getClass
-通过Class类的forName方法,格式:Class.forName(“类名”),这里的类名需要是所需类的完全限定名,如Class c=Class.forName(“java.util.String”)
示例:
public classRefDemo
{
public static void main(String[]args)throws Exception
{
//创建一个字符串
String str="abc";
//获取Class类的实例对象
Class c1=str.getClass();
Class c2=String.class;
Class c3=Class.forName("java.lang.String");
//验证三个Class实例是否指向一个字节码
System.out.println(c1==c2);
System.out.println(c1==c3);
}
}
程序运行结果为true,说明c1,c2,c3是同一个对象实例。
(3)Java中有九个预定义的Class类实例对象,即基本的Java 类型(boolean
、byte
、char
、short
、int
、long
、float
和double
)和关键字void
也表示为 Class
对象。
(4)booleanisPrimitive()
isPrimitive是Class类的一个方法,可以用来判定一个指定的Class对象是否表示一个基本类型。当且仅当该类表示一个基本类型时,才返回 true。
(5)每个数组属于被映射为Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该Class
对象。如int[].class表示一个int类型数组的Class对象。
(6)booleanisArray()
Class类的isArray方法用来如果此对象表示一个数组类,则返回 true
;否则返回 false
判定此Class
对象是否表示一个数组类。
(7)所有在源程序中出现的类型都有各自的Class实例对象。
2、反射
(1)概念:反射就是把JAVA类中的各种成分映射成相应的JAVA类,例如一个JAVA类中用一个Class类的对象来表示,一个类中的组成部分,成员变量、方法、构造方法和包等信息也用一个个的JAVA类来表示,表示JAVA类的Class类显然要提供一系列的方法来获取其中的变量、方法、构造方法、修饰符和包等信息,这些信息就是用相应类的实例对象来表示,即Field,Method,Contructor,Package等。
(2)一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象。
3、Constructor类
(1)概念:Constructor类代表某个类中的构造方法。
(2)Class类的getConstructor方法,该方法可以获取某个类中的构造方法。
(3)获取某个类中的构造方法:
-得到某个类的所有构造方法:Constructor[]constructor=Class.forName(类名).getConstructors()
-得到某个类的一个构造方法:Constructorconstructor=Class.forName(类名).getConstructor(参数类型.class)
-定义某个类的实例对象可以用Constructor类的newInstance()方法
示例:
importjava.lang.reflect.*;
public class RefDemo2
{
publicstatic void main(String[] args)throws Exception
{
//获取String类的所有构造函数
Constructor[]con1=String.class.getConstructors();
//获取String类的带StringBuffer类型参数的构造函数
Constructorcon2=String.class.getConstructor(StringBuffer.class);
//调用Constructor的newInstance方法创建String类对象
Stringstr=(String)con2.newInstance(new StringBuffer("abc"));
//打印字符串
System.out.println(str);
}
}
4、Field类
(1)Field类代表某个类中的一个成员变量,得到的Field类对象对应的是类上面的成员变量,而不是对应到对象上面的成员变量。
(2)Class类中的获取某个类中的成员变量的方法
-FieldgetField(String name): 返回一个Field
对象,它反映此Class
对象所表示的类或接口的指定公共成员字段。
-Field[] getFields():返回一个包含某些 Field
对象的数组,这些对象反映此 Class
对象所表示的类或接口的所有可访问公共字段。
-FieldgetDeclaredField(String name):返回一个Field
对象,该对象反映此Class
对象所表示的类或接口的指定已声明字段。
-Field[]getDeclaredFields():返回Field
对象的一个数组,这些对象反映此Class
对象所表示的类或接口所声明的所有字段。
(3)获取某个类的成员变量:
-得到某个类中的某个公有成员变量的Field类:Fieldfield=对象名.getClass().getField("成员变量")
-得到某个类中的某个私有成员变量的Field类:Field field=对象名.getClass().getDeclaredField("成员变量")
-通过Field类对象去访问某个类的成员变量:field.get(类对象名),若是访问私有成员变量,需先调用field.setAccessible(true)方法
示例:
importjava.lang.reflect.*;
public classRefDemo3
{
public static void main(String[]args)throws Exception
{
Demo d=new Demo(3,4);
//获取Demo类中的私有成员x
FieldfieldX=d.getClass().getDeclaredField("x");
//获取Demo类中的公有成员y
FieldfieldY=d.getClass().getField("y");
//将私有成员变量x设置为可访问
fieldX.setAccessible(true);
//通过Field的get方法获取Demo对象的成员变量的值
System.out.println(fieldX.get(d));
System.out.println(fieldY.get(d));
}
}
class Demo
{
private int x;
public int y;
Demo(int x,int y)
{
this.x=x;
this.y=y;
}
}
(4)练习:将一个对象的所有String类型的成员变量的所对应的字符串内容中的‘b’改为‘a’。
importjava.lang.reflect.*;
public class RefDemo4
{
public static void main(String[]args)throws Exception
{
Demo d=new Demo();
//打印改变前的d对象
System.out.println(d);
//调用方法
changeStringValue(d);
//打印改变后的对象
System.out.println(d);
}
public static voidchangeStringValue(Object obj)throws Exception
{
//获取对象的所有成员变量
Field[]field=obj.getClass().getFields();
//遍历对象的成员变量
for(Field f:field)
{
//判断成员变量是否为String类型
if(f.getType()==String.class)
{
//获取成员变量所对应的值
StringoldValue=(String)f.get(obj);
//修改成员变量所对应的值
StringnewValue=oldValue.replace('b','a');
//修改对象中成员变量所对应的值
f.set(obj,newValue);
}
}
}
}
class Demo
{
public String str1="ball";
public Stringstr2="basketball";
public String toString()
{
returnstr1+"..."+str2;
}
}
5、Mthod类
(1)Method类代表某个类中的一个成员方法。
(2)Class类中获取某个类中成员方法的方法:
-MethodgetMethod(String name,Class<?>…parameterType):返回一个 Method
对象,它反映此Class
对象所表示的类或接口的指定公共成员方法。
-Method[] getMethod(): 返回一个包含某些 Method
对象的数组,这些对象反映此 Class
对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共member 方法。
-MethodgetDeclaredMethod(String name,Class<?>…parameterType): 返回一个 Method
对象,该对象反映此Class
对象所表示的类或接口的指定已声明方法。
-Method[]getDeclaredMethods(): 返回Method
对象的一个数组,这些对象反映此Class
对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
(3)获取某个类中的方法
-得到某个类中的某个方法:Methodmethod=类名.class.getMethod("方法名",参数类型.class)
(4)调用某个类中的某个方法
-调用某个类中的某个方法,通过Method类的invoke()方法:method.invoke(类对象名,方法参数列表),若方法在类中为静态方法,则类对象名为null
示例:
importjava.lang.reflect.*;
public classRefDemo5
{
publicstatic void main(String[] args)throws Exception
{
Stringstr="abcd";
//获取String中带int型参数的CharAt方法
MethodmethodCharAt=str.getClass().getMethod("charAt",int.class);
//调用String中带int型参数的CharAt方法
charch=(char)methodCharAt.invoke(str,1);
System.out.println(ch);
}
}
6、数组的反射
(1)具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
(2)代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。即数组类型的父类是Object。基本类型的一维数组的Class实例对象可以被当做Object类型使用,不能被当作Object[]类型使用,非基本类型的一维数组,即可以当作Object类型使用,以可以当作Object[]类型使用。
(3)Array类:Array类用于完成对数组的反射操作。
(4)数组的反射应用:获取数组中的元素。
示例:
importjava.lang.reflect.*;
public classRefDemo6
{
public static void main(String[] args)
{
//创建一个字符串数组
String[] str=newString[]{"a","b","c"};
//将数组类型赋给Object
Object obj=str;
//获取该数组Class实例对象
Class c=obj.getClass();
//获取数组的元素个数
int len=Array.getLength(obj);
//获取数组中的元素
for(int i=0;i<len;i++)
System.out.println(Array.get(obj,i));
}
}
7、反射的作用
(1)反射的主要就是实现框架功能。
(2)框架与工具类的区别:工具类被用户的类调用,而框架则是调用用户提供的类。
(3)在写框架时,可能用户的类还没有,所以就无法知道要调用的类名,所以在程序中就无法直接new某个类的实例对象,此时就要用反射方式来做。
示例:
importjava.util.*;
importjava.io.*;
public class RefDemo7
{
public static void main(String[]args)throws Exception
{
//获取配置文件中配置的集合类型,配置文件中配置有//className=java.util.ArrayList键值对
InputStream is=newFileInputStream("config.properties");
Properties prop=newProperties();
prop.load(is);
is.close();
//获取配置文件中键className对应的值,即类名java.util.ArrayList
StringclassName=prop.getProperty("className");
//用反射的方式建立ArrayList的实例对象
Collectioncoll=(Collection)Class.forName(className).newInstance();
Demo d1=new Demo(3,3);
Demo d2=new Demo(4,4);
Demo d3=new Demo(5,5);
//将Demo对象存入集合中
coll.add(d1);
coll.add(d2);
coll.add(d3);
//打印集合中的元素
System.out.println(coll);
}
}
class Demo
{
public int x;
public int y;
public Demo(int x,int y)
{
this.x=x;
this.y=y;
}
public int hashCode()
{
return 31*(31+x)+y;
}
public String toString()
{
return x+"..."+y;
}
}