反射
反射的基石 Class类,java是面向对象的,任何一个对象都属于某个类。运行xx.java文件会产生一些扩展名为??.class的文件。这些??.class文件是Class类的实例对象。
xx.class文件是xx类的字节码文件。这些文件是二进制编码,用于jvm加载调用。
什么是字节码,当jvm用到xx类是,首先jvm会把xx.class类,加载进内存。每一个java程序至少有一个字节码文件。
获取Class对象的几种方法:
TYPE.class; 用类名直接获取class文件,Class cls1 = Integer.class;
Var.getClass(); 用实例变量名获取class文件, Class cls2 = new String().getClass();
Class.forName(String ClassName); 通过文件名来获取class文件, Class cls3 = Class.forName("Object.lang.String");注意异常。
九个预定义的Class实例对象
有九种预定义的 Class 对象,表示八个基本类型和 void。这些类对象由 Java 虚拟机创建,与其表示的基本类型同名,即 boolean、byte、char、short、int、long、float 和 double。
如何判断是否是基本类型用isPrimitive()来判断。
数组类型不是基本数据类型,System.out.println(int[].class.isPrimitive())打印出false。
获取class的基本信息
反射就是把java中的各种成分映射成相应的java类。一个类的组成部分:成员变量、方法、构造方法、包、注解等信息。这些信息可以通过getField(String name),,getFields(),getMthod(Stringname,Class<?>...parameterTypes),getConstructor(Class<?>... parameterTypes),getConstructors()等等来获取各种类的信息。具体可以查阅API文档,不再赘述。
构造方法的反射应用
怎么获取类的构造函数,可以获取被private修饰的构造方法,并且创建对象。举例说明:
public class Test {
public static void main(String[] args) throws Exception {
//得到String的所有构造方法
Constructor[] con = String.class.getConstructors();
//获取 String(StringBuffer buffer)构造方法
Constructor sb = String.class.getConstructor(StringBuffer.class);
//获取String(char[] value, int offset, int count) 构造方法
Constructor cii = String.class.getConstructor(char[].class,int.class,int.class);
//获取实例对象
String str1 = (String) sb.newInstance( new StringBuffer("abcde"));
System.out.println(str1);
str1 = (String) cii.newInstance("abcde".toCharArray(),0,"abcde".length());
System.out.println(str1);
//该方法返回的实例是空惨构造方法返回实例对象
str1 = String.class.newInstance();
System.out.println(str1);
}
}
可以通过使用泛型的方法去掉强制转换,加粗字段部分语句改成如下:
Constructor<String> cii = String.class.getConstructor(char[].class,int.class,int.class);
String str1 = sb.newInstance( new StringBuffer("abcde"));
颠覆我们的思维的时刻来临了。单利设计模式,在一般情况下只创建一个对象。但是通过反射我们可以调用类中被private修饰的构造函数,使其创建多个实例。如下代码所示:
class Single {
private static Single instance;
private Single(){}
public static Single getInstance(){
if(instance==null)
instance = new Single();
return instance;
}
}
public class Test {
public static void main(String[] args) throws Exception {
//获取被private修饰要使用getDeclaredConstructor()
Constructor con = Single.class.getDeclaredConstructor(null);
//设置访问的权限
con.setAccessible(true);
System.out.println(con.newInstance(null));
System.out.println(con.newInstance(null));
System.out.println(con.newInstance(null));
}
}
成员变量的反射应用
反射可以获取类的所有Field,Field可以被任何修饰符修饰。举例说明:
public class Point {
public int x ;
private int y;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
Point(){}
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
public class Test {
public static void main(String[] args) throws Exception {
Point p = new Point(4,2);
Field fieldX = p.getClass().getField("x");
System.out.println("p原始的x值 = "+fieldX.get(p));
fieldX.set(p, 5);
System.out.println("p修改后的x值 = "+p.getX());
Field fieldY = p.getClass().getDeclaredField("y");
fieldY.setAccessible(true);
System.out.println("p原始的y值 = "+fieldY.get(p));
fieldY.set(p, 6);
System.out.println("p原始的y值 = "+p.getY());
}
}
高级应用:
要求定一个Reflect类,定义String,int,char成员变量若干个,把String类型的字母a替换成b,int类型全部替换成0,char类型替换成@。
class Refect{
public String str1 = "aaaaaa";
public String str2 = "ababab";
public int a = 345;
public int b = 246;
public char c = 'A';
public char d = 'B';
public String getStr1() {
return str1;
}
public void setStr1(String str1) {
this.str1 = str1;
}
@Override
public String toString() {
return "Refect [a=" + a + ", b=" + b + ", c=" + c + ", d=" + d+ ", str1=" + str1 + ", str2=" + str2 + "]";
}
}
public class Test {
public static void main(String[] args) throws Exception {
Refect r = new Refect();
r.toString();
System.out.println(r.getStr1());
change(r);
System.out.println(r.getStr1());
r.toString();
}
private static void change(Object o) throws Exception {
// TODO Auto-generated method stub
Field[] fields = o.getClass().getFields();
for(Field tmp:fields){
if(tmp.getType()==int.class){
tmp.set(o, 0);
}else if(tmp.getType()==String.class){
String str = (String) tmp.get(o);
System.out.println(str);
tmp.set(o, str.replace('a', 'b'));
}else if(tmp.getType()==char.class){
tmp.set(o, '@');
}
}
}
}
运行结果:
aaaaaa
aaaaaa
ababab
bbbbbb
成员方法的反射应用:
public class Test {
public static void main(String[] args) throws Exception {
String str = "abc";
//获取charAt方法
Method methodCharAt = String.class.getMethod("charAt", int.class);
//执行charAt方法
System.out.println(methodCharAt.invoke(str, 0));
//获取hashCode方法
Method methodHashCode = String.class.getMethod("hashCode", null);
//执行hansCode方法
System.out.println(methodHashCode.invoke(str, null));
System.out.println(str.hashCode());
}
}
如果调用类的静态方法,invoke的第一参数为null;
接受数组类型的举例:
public class Test {
public static void main(String[] args) throws Exception {
Method methodMain = thod.class.getMethod("main", String[].class);
String[] a = {"itcast","itheima","lsh","Yes"};
methodMain.invoke(new thod(),(Object)a);
methodMain.invoke(new thod(), new Object[]{ new String[]{"itcast","itheima","lsh","Yes"}});
}
}
class thod{
public void main(String[] args){
for(String s:args){
System.out.println(s);
}
}
}
数组与Object的关系:
基本数据类型的一位数组只能转换成一个Object对象,不能转换成Object数组对象。
能够转换成Object数组的对象必须是泛型对象的数组,就是引用类型的数组才能转换成Object数组对象。
Java 1.5之前不支持泛型,所有的对象直接强制转换成Object对象,java1.5之后支持泛型,可以把泛型数组转换成Object数组,为了兼容java1.5之前版本,导致基本数据类型的数组不能转换成Object 数组。举例说明:
public class Test {
public static void main(String[] args) throws Exception {
int[] a = { 1, 3, 3, 3 };
char[] b = { '2', 'a', 'b' };
int[][] c = new int[3][4];
String[] str = { "a", "b", "c" };
//正确 int数组可以强制转换成Object对象
Object A = a;
// 下面一句话错误 int数组不能转换成Object数组
// Object[] A1 = a;
// 下面这句话错误 和上面的错误一致
// Object[] B = b;
//这句话正确 二维数组 可以理解成一个一维数组,每个数组元素是一个一维数组
Object[] C = c;
//String 不是基本数据类型
Object[] Str = str;
}
}
数组的反射应用:
数组的应用主要是改,查操作。用isArray()判断是否是数组类型的量。
用反射来操作数组要使用Array,数组工具。
public class Test {
public static void main(String[] args) throws Exception {
int[] a = { 1, 3, 3, 3 };
char[] b = { '2', 'a', 'b' };
String[] str = { "a", "b", "c" };
print(a);
print(b);
print(str);
}
public static void print(Object obj){
//isArray() 判断是否为数组类型
if(obj.getClass().isArray()){
//Array.getLength(obj) 获取数组的长度
for(int i=0;i<Array.getLength(obj);i++){
//Array.get(obj,i) 获取索引为i的元素值
System.out.println(Array.get(obj, i));
//可以更改数组元素的值必须保证value的类型和数组元素的类型一致
//Array.set(obj, i, value);
}
}else{
System.out.println(obj);
}
}
}
如何获取数组类型中元素的类型,可以通过下面的方法来获取Array.get(obj,i).getClass().getName()
------- android培训、 java培训、期待与您交流! ----------