Class类是反射的基石,而java中各个java类也是属于同一类事物。而这类事物就是Class类
(平时定义类都是用class,注意这里小写和Class类的大写)
错误的赋值:Class cs=new Class();
正确的赋值:Class cs2=Date.class;
字节码:当一个类(二进制程序)被类加载器加载到内存中,会占用一部分内存空间,这部分空间的内容就叫做字节码;
不同的类字节码是不同的,所以在内存空间的内容是不同的,这一个个内存空间可分别用一个个对象来表示。
获取各个字节码对应的实例对象的三种方法:
(1)类名.class
(2)对象.getClass()
(3)Class.forName("类名"):返回字节码,java虚拟机还没有字节码,会用类加载器加载,把字节码缓存起来,该方法再返回该字节码
八个基本数据类型,分别对应八个Class对象,另外还有一个void.class
//获取各个字节码对应的实例对象三种方法
String string="反射";
Class cs1=String.class;
Class cs2=string.getClass();
Class cs3=Class.forName("java.lang.String");
//三个类型对应的字节码是同一份
System.out.println(cs1==cs2);//true
System.out.println(cs2==cs3);//true
//isPrimitive()判断是否是基本类型
System.out.println(cs1.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());//数组不是原始类型
System.out.println(int[].class.isArray());//true
反射概念理解
反射就是把Java类中的各种成分映射成相应的java类
例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示。就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。
Constructor类
Constructor类代表某一类的构造方法。获取构造方法:
1)得到这个类的所有构造方法:如得到上面示例中Person类的所有构造方法
Constructor[] cons = Class.forName(“cn.itheima.Person”).getConstructors();
2)获取某一个构造方法:
Constructor con=Person.class.getConstructor(StringBuffer.class);
利用构造方法创建对象:newInstance()
通常方式:String aString=new String(new StringBuffer("hello"));
反射方式:String aString=(String)constructor.newInstance(new StringBuffer("hello"));
注:1.反射导致程序性能下降。
2.注意强制类型转换,因为编译只是检查语法,并不执行,所以并不知道它是String类型的构造函数;
3.对于无参构造函数可以直接利用Class.newInstance()方法;
//反射
//constructor
String.class.getConstructors();
Constructor constructor=String.class.getConstructor(StringBuffer.class);
String aString=(String)constructor.newInstance(new StringBuffer("hello"));
System.out.println(aString);
Field类
Field代表成员变量;从以下具体例子了解Field类相关知识,ReflecPoint类如下所示:
package com.sf.day1;
public class ReflectPoint {
private double a;
public double b;
public String xString="best";
public String yString="bad";
public String zString="justsoso";
public ReflectPoint(double a, double b, String xString, String yString,
String zString) {
super();
this.a = a;
this.b = b;
this.xString = xString;
this.yString = yString;
this.zString = zString;
}
@Override
public String toString(){
return xString+" "+yString+""+zString;
}
}
注意下面代码中的afield和bfield知识类中的变量,而不是point里的变量,所以必须用Field类变量.get(对象)来获取对象中变量
//filed
ReflectPoint point=new ReflectPoint(3.0, 4.5,"best","bad","justsoso");
Field afield=point.getClass().getDeclaredField("a");//getDeclaredField获取该类中任意成员变量,包括私有
Field bfield=point.getClass().getField("b");
afield.setAccessible(true);//暴力反射,使得private类型的a可以被访问;
System.out.println(afield.get(point));//通过对象afield的get方法获得具体的某对象成员变量的值
System.out.println(bfield.get(point));
课堂练习:将对象中的所有String类型的成员变量对应的字符串内容中的字母b改成a
//filed练习
// Field xField=point.getClass().getField("xString");
// xField.get(point).toString().replace("b", "a");
// System.out.println(xField.get(point));
//练习
Field[] fields=point.getClass().getFields();
for(Field field:fields){
if(field.getType()==String.class)
{
String oldString=(String)field.get(point);
String newString=oldString.replace("b", "a");
field.set(point, newString);
}
}
System.out.println(point.toString());
Method类
Method代表成员方法获取Method对象:.getMethod(“方法名”,方法参数类型的字节码)
注:需要方法参数类型这个参数是由于方法重载的存在。
实现此方法所用方法:invoke(对象,参数)
注意:如果是实现某一静态方法,则不需要对象来调用,此时对象位置为null
//Method
Method method=string.getClass().getMethod("charAt", int.class);
System.out.println(method.invoke(string, 1));
//调用main
Method method2=Class.forName(args[0]).getMethod("main", String[].class);
method2.invoke(null, (Object)new String[]{"aaa","bbb","ccc"});
}
}
class TestMainMethod{
public static void main(String[] args) {
for(String arg:args){
System.out.println(arg);
}
注:实现main的调用要在Run configurations里设置Arguments为com.sf.day1.TestMainMethod;即是此处的args[0];
数组的反射
nt[]数组的名称为:[I
Array工具类用于完成对数组的反射操作:
Array.getLength(Object obj);//获取数组的长度
Array.get(Object obj,int x);//获取数组中的元素
Arrays.asList (List类型) 方法:直接展示改List中所有元素package com.sf.day1;
import java.lang.reflect.Array;
import java.util.Arrays;
public class ArrayRefl {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[]={1,2};
int b[]=new int[5];
int c[][]=new int[3][4];
String d[]=new String[]{"To","Be","No","1"};
System.out.println(a.getClass()==b.getClass());//true.注:用等号,没必要用equals
System.out.println(a.getClass().getName());// [I
System.out.println(c.getClass().getName());// [[I
System.out.println(c.getClass().getSuperclass().getName());//java.lang.Object
System.out.println(d.getClass().getSuperclass().getName());//java.lang.Object
Object obj1=a;
Object obj2=b;
Object obj3=c;
Object obj4=d;
//Object[] obj5=a; //定义错误,a中元素为int类型,注意基本数据类型不是Object
//Object[] obj5=b;
Object[] obj6=c; //可以,因为c中元素为一位数组,一维数组是Object
Object[] obj7=d;
System.out.println(a); // [I@1db9742
System.out.println(Arrays.asList(a));// [[I@1db9742]
System.out.println(d); //[Ljava.lang.String;@106d69c
System.out.println(Arrays.asList(d)); //[To, Be, No, 1]
printObj(a);
printObj(d);
printObj("hehe");
}
public static void printObj(Object obj) {
// TODO Auto-generated method stub
if(obj.getClass().isArray()){
for(int i=0;i<Array.getLength(obj);i++)
{
System.out.println(Array.get(obj, i)); //Array.get获取数组元素
}
}else {
System.out.println(obj);
}
}
}