黑马程序员--反射知识点总结,黑马程序员--知识点
黑马程序员--反射知识点总结,黑马程序员--知识点
——- android培训、java培训、期待与您交流! ———-
认识Class类
之前学习的java处理的基本机制,是先把java源文件通过java编译器编译后生成字节码文件(.class),然后通过ClassLoader机制将这些字节码文件加载到内存中,最后生成相应的实例并执行。
Class类与java反射
通过java的反射机制,可以访问程序中已经加载进内存的java对象的描述,可以访问、检测和修改描述java对象本身的信息。
Class和class的区别
1)class:Java中的类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由此类的实例对象确定,不同的实例对象有不同的属性值。
2)Class:指的是Java程序中的各个Java类是属于同一类事物,都是Java程序的类,这些类称为Class。例如人对应的是Person类,Java类对应的就是Class。
3)属性:类名,类的访问属性,类所属包名,字段名称列表,方法名称列表等。
获取字节码的三种方式
方式一:
Object类的getClass()方法,判断两个对象是否是同一个字节码文件,对象.getClass()
方式二:
静态属性class,锁对象。类名.class是一种固定写法。源程序一看到就知道是字节码
方式三:
Class类中静态方法forName(),读取配置文件Class.forName()
public static void main(String[] args) throws ClassNotFoundException {
Class clazz = Peason.class;//静态属性class,锁对象 获取字节码方式一
Class clazz2 = Class.forName("TestDemo.Peason");//Class类中静态方法forName(),读取配置文件 获取字节码方式二
Peason z = new Peason();
Class clazz3 = z.getClass();//Object类的getClass()方法,判断两个对象是否是同一个字节码文件 获取字节码方式三
System.out.println(clazz==clazz2);
System.out.println(clazz2==clazz3);
}
反射中的各种类:
一、Constructor类
1、概述:Constructor代表某个类的构造方法
2、获取构造方法:
1)如何得到摸个类的所有构造方法:如得到String类的所有构造方法
Constructor[] cons = Class.forName(“java.lang.String”).getConstructors();
2)获取某一个构造方法:
Constructor con =String.class.getConstructor(StringBuffer.class);①
3、创建实例对象:
1)通常方式:String str = new String(new StringBuffer (”abc”));
2)反射方式:String str = (String)con.newInstance(new StringBuffer(“abc”));②
调用获得的方法时要用到上面相同类型的实例对象,即两个StringBuffer()要对应相等。
NewInstance():构造出一个实例对象,每调用一次就构造一个对象。
注意:上面的两个地方①②都要用到StringBuffer,这必须是一致的。
第①个是指定要带StringBuffer参数类型的构造方法,即所需使用的是含StringBuffer类型的构造方法。
第②个是用这个构造方法创建对象,要传入的参数类型是StringBuffer。
4、Class.newInstance():创建一个对象,不带参数的构造方法。
//new String(new StringBuffer("abc"));
Constructor constructor1 =
String.class.getConstructor(StringBuffer.class);
String str2 =
(String)constructor1.newInstance(new StringBuffer("abc"));
System.out.println(str2);
//Class.newInstrance创建不带参数的构造方法
String str3 =
(String)Class.forName("java.lang.String").newInstance();
System.out.println("str3:"+str3);
二、Field类
1、概述:Field类代表成员变量(字段)的反射。
public class ReflectPoint {
private int x;
public int y;
public String toString(){
return str1+";" + str2 + ";" + str3;
}
}
public class FieldTest(){
ReflectPoint pt1 = new ReflectPoint(3,5);
//fieldX和fieldY并不是对象身上的变量,而是类上的
//要用它去取某个对象上的对应的值,传入什么对象,就取相应对象的值。
Field fieldY = pt1.getClass().getField("y");
System.out.println(fieldY.get(pt1));
//获取私有的成员变量
Field fieldX = pt1.getClass().getDeclaredField("x");
fieldX.setAccessible(true);
System.out.println(fieldX.get(pt1));
}
2、获取成员变量:
如上例子所示:
1)获取公有的成员变量:
getField(String name)和get(变量)
2)获取私有的成员变量:暴力反射
getDeclared(String name)
setAccessible(boolean b),将b设为true即可
get(变量)
//替换字符
private static void changeStringValue(Object obj) throws Exception {
Field[] fields = obj.getClass().getFields();
for(Field field : fields){
//此处需要用==比较,因为是同一份字节码对象
if(field.getType() == String.class){
String oldValue = (String)field.get(obj);
String newValue = oldValue.replace('b','a');
field.set(obj, newValue);
}
}
}
三、Method类
1、概述:Method类代表某个类中的一个成员方法。
调用某个对象身上的方法,要先得到方法,再针对某个对象调用。
2、专家模式:谁调用这个数据,就是谁在调用它的专家。
如人关门:
调用者:是门调用管的动作,对象是门,因为门知道如何执行关的动作,通过门轴之类的细节实现。
指挥者:是人在指挥门做关的动作,只是给门发出了关的信号,让门执行。
总结:变量使用方法,是方法本身知道如何实现执行的过程,也就是“方法对象”调用方法,才执行了方法的每个细节的。
3、获取某个类中的某个方法:(如String str = ”abc”)
1)通常方式:str.charAt(1)
2)反射方式:
Method charAtMethod=
Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);
charAtMethod.invoke(str,1);
说明:如果传递给Method对象的invoke()方法的第一个参数为null,说明Method对象对应的是一个静态方法
4、用反射方式执行某个main方法:
首先要明确为何要用反射:在写源程序时,并不知道使用者传入的类名是什么,但是虽然传入的类名不知道,而知道的是这个类中的方法有main这个方法,所以可以通过反射的方式,通过使用者传入的类名(可定义字符串型变量作为传入类名的入口,通过这个变量代表类名),内部通过传入的类名获取其main方法,然后执行相应的内容。
//Method类演示
private static void methodTest(String [] args) throws Exception {
String str1 = "abc";
//一般方法:
System.out.println(str1.charAt(1));
//反射方法 :
Method methodCharAt =
Class.forName("java.lang.String").getMethod("charAt",int.class);
System.out.println(methodCharAt.invoke(str1,1));
//用反射方式执行某个main方法
//一般方式:
Test.main(new String[]{"aaa","bbb","ccc"});
System.out.println("-------");
//反射方式:
String startingClassName = args[0];
Method methodMain =
Class.forName(startingClassName).getMethod("main",String[].class);
//方案一:强制转换为超类Object,不用拆包
methodMain.invoke(null,(Object)new String[]{"aaa","bbb","ccc"});
//方案二:将数组打包,编译器拆包后就是一个String[]类型的整体
methodMain.invoke(null,new Object[]{new String[]{"aaa","bbb","ccc"}});
}
//定义一个测试类
class Test{
public static void main(String [] args){
for(String arg : args){
System.out.println(arg);
}
}
}
四、数组的反射
1、数组字节码的名字:有[和数组对应类型的缩写,如int[]数组的名称为:[I
2、基本数据类型的一维数组不能转换为Object数组,如:
int[] a = new int[3];Object[] obj= a;这样是不成立的。
3、如何得到某个数组中的某个元素的类型:
例:int a = newint[3];Object[] obj= new Object[]{”ABC”,1};
无法得到某个数组的具体类型,只能得到其中某个元素的类型,如
Obj[0].getClass().getName()得到的是java.lang.String
若通过b.getClass().getName(),结果是:[Ljava.lang.Object;
public static void main(String[] args) {
int[] a1 = new int[]{1,2,3,4};
String[] a2 = new String[]{"a","b","c"};
printObject(a1);
printObject(a2);
printObject("abc");
}
private static void printObject(Object obj){
Class clazz = obj.getClass();//获取对象的字节码
if(clazz.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);//如果不是数组就直接打印
}
}
}
反射通过泛型检查
ArrayList的一个对象,在这个集合中添加一个字符串数据,如何实现呢?
public static void main(String[] args) throws Exception {
ArrayList<Integer> list = new ArrayList<>();
list.add(111);
list.add(222);
Class<?> clazz = Class.forName("java.util.ArrayList");//获取集合的字节码对象
Method m = clazz.getMethod("add", Object.class);//通过字节码获取方法
Object s = m.invoke(list,"abc"); //调用方法
System.out.println(s); //打印方法的返回值
System.out.println(list);
通过反射写一个通用的设置某个对象的某个属性为指定的值
public static void setProperty(Object obj, String propertyName, Object value) throws Exception{
Class<?> clazz = obj.getClass();//获取字节码对象
Field f = clazz.getDeclaredField(propertyName);//暴力获取给字段的名字
f.setAccessible(true); //去除权限
f.set(obj, value); //修改属性
public static void main(String[] args) throws Exception {
Student s = new Student(); //创建对象
Test3.setProperty(s, "name", "王小乖");//调用方法
Test3.setProperty(s, "age", 21);
System.out.println(s);
}
}
class Student{
private String name;//将属性私有。并且不给提供访问方法
private int age;
public String toString(){
return name +","+age;
}
}
动态代理
动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理
代理:本来应该自己做的事情,请了别人来做,被请的人就是代理对象。
public static void main(String[] args) {
UserImp ui = new UserImp();
ui.add();
ui.delete();
System.out.println("-----------------------");
MyInvocationHandler m = new MyInvocationHandler(ui);
User u = (User) Proxy.newProxyInstance(ui.getClass().getClassLoader(), ui.getClass().getInterfaces(), m);
u.add();
u.delete();
public interface User {
public void add();
public void delete();
}
public class UserImp implements User {
@Override
public void add() {
//System.out.println("权限校验");//通过输出类模拟
System.out.println("添加功能");
//System.out.println("日志记录");//<span >通过输出类模拟</span>
}
@Override
public void delete() {
//System.out.println("权限校验");
System.out.println("删除功能");
//System.out.println("日志记录");
}
相关文章
- 暂无相关文章
用户点评