——- android培训、java培训、期待与您交流! ———-
问题1: Class类是什么?有什么作用?
Class类是所有类的基类,是每一个类放在内存中的字节码。
通过Class类可以知道,每一个类中的所有组成部分。包括类中属性,该类的构造函数,该类所拥有的方法等内容。
问题2:如何获得一个类的Class类的字节码实例对象,三种方法(以Person类为例):
1)Class cls1 = Person.class
2)Class cls2 = person.getClass()
3)Class cls3 = Class.forName(“java.lang.String”)
forName加载有两种,一种是已经存在了,直接加载,另一种是不存在,先加载到虚拟机中在应用。
问题3:Class类有几种基本字节码?
基本字节码共九种,包括8种基本数据类型和Void.class,是否是基本自己码可以用isPrimitive()来判断。用isArray()判断是否是数组。
具体看下面代码实例:
class ReflectTest
{
public static void main(String args[])
{
String str = "abc";
Class cls1 = String.class;
Class cls2 = str.getClass();
Class cls3 = Class.forName("java.lang.String");
System.out.println("cls1==cls2");//true
System.out.println("cls1==cls2");//true
System.out.println("cls1.isPrimitive()");//false
System.out.println("int.class.isPrimitive()");//true
System.out.println("int.class==Integer.class");//false
System.out.println("int.class==Integer.Type");//true
System.out.println("int[].class.isPrimitive()");//false
System.out.println("int[].class.isArray()");//true
}
}
(一)利用反射得到构造方法,并实例化对象
1)正常情况:String str = new String(new StringBuffer(“abc”));
2)利用反射:Constructor con=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
String str = con.newInstance(new StringBuffer(“abc”));
3)String.class类中有一个方法newInstance()是获得无参构造。
示例1如下:
首先定义已知类:ReflectPoint
class ReflectPoint
{
private int x;//私有属性
public int y;//公共属性
public RefletctPoint(int x,int y)//含有两个整型参数的构造方法
{
super();
this.x = x;
this.y = y;
}
}
1)获取公共属性y
ReflectPoint rp = new ReflectPoint(3,5);//获得该类的实例对象
Field fiedlY = rp.getClass().getField("y");//通过该类的实例对象获得该类的公共属性y
System.out.println(fieldY.get(rp));//取得该类对应的此实例对象的公共属性y对应的值,结果为5。
2)私有属性获得方式
Field fieldX = rp.getClass().getDeclaredField("x");//通过该类的实例对象获得该类的私有属性x
fieldX.setAccessible(true);//设置该私有属性可以被访问。
System.out.println(fieldX.get(rp));//取得该类对应的此实例对象的私有属性x对应的值,结果为3。
示例2:
利用反射:将任意一个对象中的所有String 类型的成员变量所对应的字符内容中的‘b’改为 ‘a’。
首先定义已知类
class ReflectPoint
{
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "all";
public String toString()
{
return str1+"......"+str2+"......"+str3+"......";
}
}
封装一个函数进行改写操作
public static void changeStringValue(Object obj) throws Exception
{
Field[] fields = obj.getClass().getFields();
for(Field field:fields)
{
if(field.getType()==String.class)
{
String oldValue = (String)field.get(obj);
String newValue = oldValue.replace('b','a');
field.set(obj,newValue);
}
}
}
在主函数中调用并验证
{
ReflectPoint rp = new ReflectPoint();
changeStringValue(rp);
System.out.println(rp);
}
运行结果如下:
改写成功!
(三)利用反射:调用方法
以java.lang.String类为例,获取它的CharAt()方法
String str = "abc";
Method methodCharAt = String.class.getMethod("charAt",int.class);
System.out.println(methodCharAt.invoke(str1,1));//结果为b
此处invoke()为调用的意思,其中第一个参数为调用的对象,第二个为该方法的参数。如果是静态函数,则第一个参数为null,应书写如下:
System.out.println(methodCharAt.invoke(null,1));
示例3: 用反射提供一个程序,根据用户提供的类名,调用该类的main方法
首先写出已知类ReflectTest:
package com.test;
public class ReflectTest
{
public static void main(String args[])
{
for(String arg:args)
{
System.out.println(arg);
}
}
}
在另一个程序中调用:
public class ReflectDemo
{
public static void main(String args[])
{
String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);
mainMethod.invoke(null,(Object)new String[]{"123","345","234"});
mainMethod.invoke(null,new Object[]{new String[]{"123","345","234"}});
}
}
程序运行结果如下:
[“123”,”345”,”234”]
“123”
“345”
“234”
此处invoke()方法的第二参数,作为被调用方法的参数传入,其形式为Object数组形成,也可以为Object对象。
附带:分析一下数组与Object类的关系
看如下示例4:
public class ArrayObjectDemo
{
public static void main(String args[])
{
int[] a1 = new int[3];
int[] a2 = new int[4];
int[][] a3 = new int[2][3];
String[] a4 = new String[3];
System.out.println(a1.getClass()==a2.getClass());//true
System.out.println(a1.getClass()==a3.getClass());//false
System.out.println(a1.getClass()==a4.getClass());//false
System.out.println(a1.getClass.getName());//I
System.out.println(a1.getClass.getSuperclass().getName());//
System.out.println(a4.getClass.getSuperclass().getName());
Object obj1 = a1;
Object obj2 = a4;
Object[] obj3 = a3;
Object[] obj4 = a4;
Object[] obj5 = a1;//此处编译不通过。
System.out.println(a1);//
System.out.println(a4);//
System.out.println(Arrays.asList(a1));//
System.out.println(Arrays.asList(a4));//
}
}
备注:Arrays.asList()这个方法的作用是把数组转化为List集合。
综上例子可以发现:
1)具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
2)基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用。
3)非基本数据类型的一维数组既可以被当作Object类使用,也可以当作Object[]类型使用
利用反射机制和Array工具类完成对数组的操作:
示例5:打印数组。
封装打印数组的方法如下:
public void printObj(Object obj)
{
Class cla = obj.getClass();
if(cla.isArray())
{
int len = Array.getLength(obj);
for(int i=0;i<len;i++)
{
System.out.println(Array.get(obj,i));
}
}else
{
System.out.println(obj);
}
}
主方法调用并获得结果如下:
String[] a4 = new String[]{"a","b","c"};
printObj(a4);//结果为a,b,c
printObj("abdc");//结果为abcd
综上是说明Class类的基本作用;
作为反射机制,最大的作用在于:
实现框架功能
在许多框架中,在写框架时,还不知道要被调用的类名,所以,在程序中无法直接new某个类的实例对象,而要用反射方式来做。
用例子说明如下:
示例6:新建一个Properties类,新建config.properties文件。
className=java.util.HashSet
该主方法(模拟为框架代码)
public class ReflectTest3
{
public static void main(String args[])
{
InputStream is = new FileInputStream("config.properties");
Properties props = new Properties();
props.load(is);
is.close();
String className = props.getProperties("className");
Collection collections = Class.forName(className);
ReflectPoint pt1 = new ReflectPoint(3,3);
ReflectPoint pt2 = new ReflectPoint(5,5);
ReflectPoint pt3 = new ReflectPoint(3,3);
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);
System.out.println(collections.size()); //打印结果为2
}
}
定义被框架调用的类
class ReflectPoint
{
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "all";
public String toString()
{
return str1+"......"+str2+"......"+str3+"......";
}
}
以上内容是对反射内容的全部概括,但是也是最基本的内容,多做练习,加深理解。