------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
反射
Class 类:反射的基石
反射就是将java类中的各种成分映射成相应的java类。
java程序中的各个java类,可以描述为同一类事物,用Class类来表示。
换句话说:Class类是全部java类的抽象,无论是JDK中的,还是自定义的类。
void,数组,java基本数据类型也都表示为Class对象。
特性:
Class类没有公共构造方法,Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的。
1. Class cls1 = 类名.class;
2. Class cls2 = 对象引用(或对象).getClass();
3. Class cls3 = Class.forName(“类名称”);
常用方法:
1. Object.getClass():返回此Object的运行时类。
2. isPrimitive():判定指定的Class对象,是否指定一个基本数据类型。
3. Class.forName(String className)
返回 字符串指定的类或接口相关连的Class对象。
返回字节码文件(.class文件)两种方式:
1. 已加载过得类,放在java虚拟机中。
2. 没有加载过,类加载器加载到虚拟机中。
得到各个 字节码 对应的 实例对象(Class类型)。
1. 类名.class (如:System.class)
2. 对象.getClass() (如:new Data().getClass)
3. Class.forName(“类名”) (如:Class.forName(“java.lang.Thread”) )
forNmae(“类名”),将实例化该类
getConstructor()
Constructor strConst = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
获得具体的构造方法时,要传递类型
Constructor类
String str = (String)strConst.newInstance(new StringBuffer("abc"));
调用获得的方法来构造对象时,要用到相同类型的实例对象。
getField()
1. 非private成员
① 通过反射访问成员变量时,通过Class类的getField(“成员变量名称”)方法,得到Field对象。
② 再将被访问的对象,传递给Field对象,即可得到该值了。
2. private成员
① 使用Class类的getDeclaredField(),该方法可以返回全部声明过的字段。
② 使用Field类的父类AccessibleObject的setAccessible(boolean flag)方法将私有变量设置成为可访问的变量。
public static void myGetField() throws Exception {
// 1. 使用反射得到单个变量的构造方法的对象,这是传递的变量为构造函数的类型
Constructor fieConst = ReflectField.class.getConstructor(int.class,int.class);
// 2. 使用此构造方法类的对象,实例化类,传递给类型对应的对象
ReflectField rf = (ReflectField)fieConst.newInstance(4,5);
// 3. 传递要查询的字段名,返回
Field fieldA = ReflectField.class.getField("x");
// 4. 传递对象,字段对象根据获得其相应的值,说明该类访问另一个对象。
System.out.println(fieldA.get(rf));
// y字段为private,需要使用Field的getDeclaredField,返回所有声明过的对象。
Field fieldY = ReflectField.class.getDeclaredField("y");
// 私有成员变量,需要暴力反射,设置为可以访问
fieldY.setAccessible(true);
System.out.println(fieldY.get(rf));
getMethod()
public Method getMethod(String name, Class<T>... parameterTypes )
name : 方法名
parameter Types : 参数列表
Method类
invoke()方法:
public Object invoke(Object obj , Object...arg / Object[]...args)
参数:
1. obj : 从这个对象中调用底层方法。
① 如果底层方法是静态的,则可以忽略obj参数,该参数可以为null。
② 如果底层方法是静态,并且尚未初始化声明此方法的类,则会将其初始化
2. args : 参数列表。 * 如果底层方法所需的形参个数为0,则所提供的args长度,可以为0或null。
public static void myGetMethod() throws Exception {
String str = "123";
Method charAtMethod = String.class.getMethod("charAt", int.class);
System.out.println(charAtMethod.invoke(str,1));
System.out.println(charAtMethod.invoke(str, new Object[]{2}));
}
对接收数组方式的成员方法反射
在A类的main方法中,调用B类的main方法,并且传递字符串参数给B的main方法:
注意:
1. 需要给A的main的参数列表args[0]复制,B类的名称。
2. main方法是static的,则可以忽略该对象参数,而只传递null。
public class GetXxx {
public static void main(String[] args) throws Exception {
//myGetConstructor();
//myGetMethod();
/**
* 1. 因为在GetXxx类运行时,其main方法的参数传递了TestArguments的完整类名,
* 所以,就能够根据ClassName来获得该类的字节码,从而可以得到该类的全部内容。
* **/
String mainArgument = args[0];
// 2.根据args[0]就可以获得TestArguments类的字节码文件,从而得到main方法。
Method mainMethod = Class.forName(mainArgument).getMethod("main", String[].class);
// 3. main()方法是静态的,静态的则不用传递对象,传递null即可。
mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
}
}
class TestArguments {
public static void main(String[] args) {
for(String arg : args) {
System.out.println(arg);
}
}
}
数组:
Class类:
每个数组属于被映射为Class对象的一个类,所有具有相同类型及维度的数组 都共享该Class类。
getName():
public String getName()
以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
1. 当类对象表示一个数组类型:
① 其名字为:
表示该数组嵌套的一个或多个”[”字符加元素类型名。
2. 当类对象表示一个非数组类型的引用类型:
3. 当类对象表示一个基本数据类型或void:
① 返回该类的二进制名称
getSuperclass()
public Class<? super T> getSuperclass()
返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。
System.out.println(a1.getClass().getSuperclass().getName());
System.out.println(s1.getClass().getSuperclass().getName());
System.out.println(a1.getClass().getSuperclass().getName() == s1.getClass().getSuperclass().getName());
结果:
java.lang.Object
java.lang.Object
true
Arrays类
asList方法
public static <T> List<T> asList(T... a)
说明:JDK1.4asList方法,其参数支持Object[]数组。所以传递的是Object数组,则其可以直接解析,非Object的参数,则返回其对应的getName()方法返回的数组的名称。
int[][] a4 = new int[][]{{1,2,3,4}};
String[] s2 = new String[]{"a","b","c"};
System.out.println(Arrays.asList(a4));
System.out.println(Arrays.asList(s2));
结果为:
[[I@dc8569]
[a, b, c]
需求:
使用反射,遍历类的数组。
Class类 --> isArray()
boolean isArray() |
Array类 --> getLength(Object obj)
Array类 --> get(Object array, int index)
public static void main(String[] args) {
// testArray();
int[][] a = new int[][]{{1,2,3,4}};
int[] a1 = new int[]{11,22,33,44};
int i = 2;
String[] s = new String[]{"a","b","c"};
Object[] objs = {a,a1,i,s};
for(Object obj : objs) {
printArray(obj);
}
}
public static void printArray(Object objs) {
// 1. Class类的isArray()方法,判断该对象是否为数组
if(objs.getClass().isArray()) {
// 2. Array类的static getLength(Object obj)方法,获得该数组对象的长度。
for(int i = 0; i < Array.getLength(objs) ; i++) {
// 3. Array类的static get(Object obj , int index)方法,得到数组对应索引上的值。
System.out.println(Array.get(objs, i));
}
} else {
System.out.println(objs);
}
}
框架
框架的思想
框架就是开发商改好的毛坯房,自己写的类就像后来根据门框大小,木桶标准等等自己安装的家具门窗。自己写的类是为框架服务的。
与工具类的区别
工具类是为自己写的类服务的,而自己写的类是为框架服务的。
代码:
config.properties
className=java.util.HashSet
package com.lxh.reflect;
import java.util.*;
import java.io.*;
public class ReflectFrame {
public static void main(String[] args) throws Exception {
InputStream in = new FileInputStream("C:\\Users\\fox\\Workspaces\\MyEclipse 8.5\\reflect\\src\\com\\lxh\\reflect\\config.properties");
Properties prop = new Properties();
prop.load(in);
String className = prop.getProperty("className");
/**
* 反射
* 先写好这个类,只需要在开始运行这个类之前,其他类已经写好了就可以。
* */
Collection collections = (Collection)Class.forName(className).newInstance();
// 创建几个圆点的对象,其中rf1和rf3的值相同。
ReflectField rf1 = new ReflectField(1,1);
ReflectField rf2 = new ReflectField(2,2);
ReflectField rf3 = new ReflectField(1,1);
collections.add(rf1);
collections.add(rf2);
collections.add(rf3);
collections.add(rf1);
// rf1.x = 5;
// collections.remove(rf3);
System.out.println(collections.size());
}
}