反射
java反射:在程序运行过程中,可以对任意一个类型进行任意的操作。例如:加载任意类型、调用类型的任意方法、获取任意的成员变量、构造方法,可以创建该类型的对象。
对于任意一个对象,都能调用这个对象的任意一个方法【不知道要使用什么类型】
如果要获取一个类型的各种内容,首先要获取这个类的字节码对象
解剖这个类型,获取类中的成员,需要使用Class类型中定义的方法
这种【动态】获取信息以及【动态】访问成员的这种方式,称为:反射
//获取字节码对象的三个方法
//想要获得和操纵类中的属性和方法就要先获得类的字节码对象
//对象名+ .getClass()
Sky s1 = new Sky();
Class<? extends Sky> class1 = s1.getClass();
//类名+ .class
Class class2 = Sky.class;
//Class.forName("全类名") (包名.类名)
Class class3 = Class.forName("zG_review_practice.Sky");
// 全类名可以通过控制台输入,网络获取,通过文件读取
System.out.println(class1); //获取的是全类名
// Class类型的实例表示正在运行的java应用程序的类或者接口
反射常用方法
//常用方法
Sky sky = class1.newInstance(); //使用该方法新建对象 新建后可以使用对应方法
Class<? extends Sky> class4 = sky.getClass(); //获取构造方法
Constructor constructor = class4.getConstructor(String.class, int.class, double.class);
Sky sky2 = (Sky)constructor.newInstance("Ocean Bule", 5555, 12.1);
//getConstructor 按获取的类的构造方法中的类型写顺序,要一致,新建时转为当前类的类型
//私有成员无法访问
Field field = class2.getField("area"); //获取对应类中的成员变量 参数填变量名
field.set(sky, "5345.667"); //传入对象和要设置的值
暴力反射
通过Class类中:
getDeclaredXxx方法:可以获取类中的所有声明的成员(属性、方法、内部类),私有的成员也可以获取到。
修改该对象的访问权限:
成员变量、构造方法还是成员方法,都是AccessibleObject类型的子类,就具有判断是否可以访问,和设置是否可以访问的方法
isAccessible():判断当前对象是否可以访问
setAccessible(boolean flag):设定当前对象是否可以访问
一旦设定当前对象可以访问,私有的成员也可以被访问,被修改
// 案例
Class class5 = Sky.class;
Field field2 = class5.getDeclaredField("area");
System.out.println(field2.isAccessible()); //判断是否可以访问 可不写
field.setAccessible(true); //修改权限 true为可以修改,false不能修改
field2.set(sky2, "5649.999"); //修改完成
//获取方法并运行
Sky sky3 = new Sky();
Class class6 = Sky.class;
Method method = class6.getMethod("setColor", String.class);
//运行 //写入方法的名字和参数类型 没有参数可以不写或者写null
method.invoke(sky2, "Ocean"); //写入要调用的对象 和传入的参数 若没有参数则同上处理
method.getReturnType(); //返回返回值类型
泛型擦除
一般情况下如果规定了数据的泛型,不符合泛型的数据是不允许加入到存储数据的容器中的
但通过泛型擦除可以做到跳过编译步骤
List<Integer> list = new ArrayList<Integer>();
list.add(3452);
// list.add("fse"); //一般情况下是不能写入的 编译不通过
Class<? extends List> class7 = list.getClass();
Method method2 = class7.getMethod("add", Object.class);
method2.invoke(list, "fse");
method2.invoke(list, '%');
System.out.println(list); //会写入上面的值 跳过了编译阶段 类也可以传入
}
以上案例中使用的测试类
class Sky{
private String color;
private int height;
private double area;
public Sky() {
super();
// TODO Auto-generated constructor stub
}
public Sky(String color, int height, double area) {
super();
this.color = color;
this.height = height;
this.area = area;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public double getArea() {
return area;
}
public void setArea(double area) {
this.area = area;
}
@Override
public String toString() {
return "Sky [color=" + color + ", height=" + height + ", area=" + area + "]";
}
}