------- android培训、java培训、期待与您交流! ----------
1.1 Class类
什么是Class类?
java用类用于描述一类事物的共性,该事物有什么属性。
但是属性的具体的值是由对象确定的。那么java中的类也是一类事物,它都有成员变量,方法,构造器,这类事物就是用Class类描述的。
Class的实例是什么呢?是java类?其实java类从硬盘中加载进内存时,就会形成一个字节码文件,之后再用这个字节码去复制对象,所以这个字节码里有这个类的所有的信息。
Class类的实例就是这个字节码。
Class类的三种实例化方法:
1. 由类对象创建;
2 由类创建;
3由Class类的静态方法创建;
Class cls1 = String.class;
Class cls2 = Class.forName("java.lang.String");
Class cls3 = new String().getClass();
注意:每个类的字节码在java虚拟机里都是唯一的,调用时java虚拟机会查看这个字节码是否已经加载,如果已经加载它就返回已经存在的字节码,如没有加载它才会用java的类加载器加载字节码缓存在虚拟机,然后把它返回。
Class有9 个预定义对象:8个基本数据类型和一个void的类型。
public static void main(String[] args) throws Exception{
Class cls1 = String.class;
Class cls2 = Class.forName("java.lang.String");
Class cls3 = new String().getClass();
System.out.println(cls1 == cls2);
System.out.println(cls3 == cls2);
System.out.println(int.class == Integer.class);
System.out.println(int[].class.isArray());
System.out.println(cls1.isPrimitive());
System.out.println(int.class.isPrimitive());
Class cl = void.class;
输出结果:
true
true
false
true
false
true
Class类中方法摘要:
|--static Class> forName(String className ) 使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 Class 对象。
|-- A getAnnotation(Class annotationClass) 如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。注释也是一个类!
|--Annotation[] getAnnotations() 返回此元素上存在的所有注释。
|--Class>[] getClasses() 返回一个包含某些 Class 对象的数组,这些对象表示属于此 Class 对象所表示的类的成员的所有公共类和接口。
|--ClassLoader getClassLoader() 返回该类的类加载器。
|--Constructor
|-- Constructor>[] getConstructor(Class>... parameterTypes) 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
|-- ConstructorConstructor
对象,该对象反映此 Class
对象所表示的类或接口的指定构造方法。
|-- Constructor>[] getDeclaredConstructors() 返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。
|-- Method getMethod(String name, Class>... parameterTypes) 返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
|-- Method[] getMethods() 返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口
|-- String getName() 以 String 的形式返回此 Class 对象所表示的实体。
|-- Class super T> getSuperclass() 返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。
|-- boolean isArray() 判定此 Class 对象是否表示一个数组类。
|-- boolean isPrimitive() 判定指定的 Class 对象是否表示一个基本类型。
|--T newInstance() 创建此 Class 对象所表示的类的一个新实例。
1.2 反射
反射是吧java类中个各个成分映射成相应的java类。一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示。
一个java类的组成成分:
成员变量---->Field,
方法--------->Method,
构造器------->Constructor.
等信息都被包装秤一个类。
2 Constructor类:
Constructor类代表某一个类中的构造方法。
//String str = new String(StringBuffer("axdsf"));用反射实现创建一个这样的实例对象;
Constructor constructor = String.class.getConstructor(StringBuffer.class);
String str = (String)constructor.newInstance(new StringBuffer("axdsf"));
System.out.println(str.charAt(2));
输出:d
|--T newInstance(Object... initargs) 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
|-- String getName() 以字符串形式返回此构造方法的名称。
|-- Class>[] getParameterTypes() 按照声明顺序返回一组 Class 对象,这些对象表示此 Constructor 对象所表示构造方法的形参类型。
|-- T newInstance(Object... initargs) 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
3 Field 类: 代表某个类中的成员变量
public class ReflectPoint {
private int x;
public int y;
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "access";
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
@Override
public String toString(){
return str1 + ":" + str2 +":"+ str3;
}
}
ReflectPoint pt = new ReflectPoint(3,5);
Field fieldY = pt.getClass().getField("y");
//此时的fieldY是类上的变量而不是对象上的,所以要关联对象;
System.out.println(fieldY.get(pt));
Field fieldX = pt.getClass().getDeclaredField("x");
fieldX.setAccessible(true);
//此时的fieldY是类上的变量而不是对象上的,所以要关联对象;
// System.out.println(fieldX.get(pt));
//这样有些复杂 所以在Class类有一个newInstance()方法使用无参构造器构造实例;
5
3
Field类中的方法摘要:
|--Object get(Object obj) 返回指定对象上此 Field 表示的字段的值。
|--setAccessible public void setAccessible(boolean flag) 将此对象的 accessible 标志设置为指示的布尔值。这是Field从其父类AccessibleObject继承过来的方法。
|--void set(Object obj, Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
|-- Class> getType() 返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。
如果要把ReflectPoint类中的String变量中的‘a’ 改为‘b’:
public static void main(String[] args) throws Exception{
changeStringValue(pt);
System.out.println(pt);
输出结果:bbll:bbsketbbll:bccess
4 Method类 代表某一个类的成员方法:
普通的方法调用时用对象或者类比如:
str.charAt(1); //普通调用方法;
用反射的方法:
Method method = Class.forName("java.lang.String").getMethod("charAt", int.class); //参数为方法名(String类型),参数的类型(Class类型);
System.out.println(method.invoke(str, 1)); //调用的对象(str),以及实际传入的参数(1);
// method.invoke(null, 2);//静态方法调用 不需要对象,所以是null;
|-- Object invoke(Object obj, Object... args) 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
在jdk1.4中方法为 Object invoke(Object obj, Object[] args)
|-- String getName() 以 String 形式返回此 Method 对象表示的方法名称 “
|-- int getModifiers() 以整数形式返回此 Method 对象所表示方法的 Java 语言修饰符。
一个小练习:用反射执行传入的类的main方法(类名作为参数传入)。
平时知道类名我们可以直接调用TestArguments.main(new String[]{"11","22","33","44"});
class TestArguments{
public static void main(String[] args){
for(String arg : args)
System.out.println(arg);
}
}
String startingClassName = args[0];
Method mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);
// mainMethod.invoke(null,new String[]{"11","22","33","44"}); //IllegalArgument
// mainMethod.invoke(null, new Object[]{new String[]{"11","22","33","44"}}); //可以用
mainMethod.invoke(null, (Object)new String[]{"11","22","33"});
输出:
11
22
33
调用时把TestArgument类名作为参数传入下面代码的主函数。此时运用第一个invoke会出现IllegalArgument异常,这是因为java把String[]数组拆包了,不是作为一个数组整体传入,我们有两种解决方法:
1 新建一个Object[]数组,里面的元素时String[]数组;
2 强制String[]数组转换为Object。
5 数组的反射:
//数组的反射
int[] a1 = new int[]{1,2,3};
Object aobj1 = a1; //数组是object的之类
Object aobj2 = a4;
// Object[] aobj3 = a1; //int 不是object
Object[] aobj4 = a4;
Object[] aobj5 = a3;
printObject(a4);
private static void printObject (Object obj){
Class clas = obj.getClass();
if(clas.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);
}
true
int[]
[[I
String[]
Object
[I@70dea4e
[Ljava.lang.String;@5c647e05
[[I@70dea4e]
[as, ssss, sadada]
as
ssss
sadada