反射:
通过java语言的反射机制可以操作字节码文件。
在java.lang.reflect.*;的包下。
反射机制重要的类:
java.lang.Class; //代表整个字节码文件
java.lang.reflect.Method; //代表字节码中的方法字节码
java.lang.reflect.Constructor; //代表字节码中的构造方法字节码
java.lang.Field; //代表字节码中的属性字节码。类中的成员变量,包括静态变量、实例变量。
java.lang.Class:
获取java.lang.Class的方式:
1.用Class.forName()来获取:1.静态方法。2.方法的参数是一个字符串。3.字符串需要是一个完整类名。4.完整类名带有包名。
2.用getClass()方法来获取:任何一个对象都有getClass()方法。返回当前对象方法区的字节码文件。
3.用class属性来获取:java语言中任何一种类型,包括基本数据类型,都有class属性。
- 可以通过获得当前的Class文件(c),使用c.newInstance()来创建对象。通过反射机制创建对象。此时,只需要修改
配置文件中的信息,就可以实现创建不同对象的功能。 - 使用Class.forName(“完整类名”); 会导致类加载,这样可以只执行这个类的静态代码块。
java.lang.Field:
通过 类名.getFields() 可以得到field数组,数组中是类中所有public修饰的属性。
通过得到的field.getName(),方法可以得到属性名。
类名.getDeclaredFields(),可以获得类中所有属性。
field.getType(),可以得到当前属性的类型,返回一个class,可以通过field.getType().getName()获得类型名字。
getModifiers(),class中的方法,可以返回此类或接口的修饰符,返回的是int类型,
可以通过Modifiers中的toString(int mod) 方法,将返回的int类型数据转换为对应的修饰符。
使用反射机制去访问一个对象的属性:
Class studentClass = Class.forName("reflesh.student");
Object obj = studentClass.newInstance();//obj是student对象,底层调用无参构造方法。
//获取名字为no的属性
Field noField = studentClass.getField("no");
//给obj对象的no属性赋值222.
noField.set(obj,222);
//读取obj对象的no属性的值。
noField.get(obj);
注意:以上访问只能访问public类型的,private类型的需要用Field类中的方法**setAccessible(true)**来打破封装,才可以获取。
java.lang.reflect.Method:
通过 类名.getDeclaredMethods() 返回一个Methods数组,数组中存放对象的所有方法。
Method.getName();//返回方法的名字
Method.getModifiers();//返回修饰符列表,返回的是数值
Method.toString();//通常将Method.getModifiers()返回的数值传进去,返回修饰符列表。
Method.getReturnType();//可以获得方法的返回值类型。可配合.getSimpleName()使用。
Method.getParameterTypes();//可以获得参数类型数组,通过getSimpleName()方法可以看到属性。
使用反射机制去调用一个对象的方法(重点):
例如:
public static void main(String[] args) throws Exception {
Class student = Class.forName("reflesh.student");//获取类
Object obj = student.newInstance();//用类来new对象
Method method = student.getDeclaredMethod("login",String.class,String.class);//获取对象的方法
Object result = method.invoke(obj,"admin","123");//将方法和这个对象绑定,传参。
}
反射机制让代码具有通用性,可变化的内容写到配置文件中。修改配置文件可以创建不同的对象和方法,java代码不需要修改。
java.lang.reflect.Constructor:
通过类名.getDeclaredConstructors();获得一个Constructor数组,里面存放对象的所有构造方法。
通过constructor.getModifiers();获得构造方法的修饰符
通过constructors.getParameterTypes();可以获得当前构造方法的参数类型数组
用反射调构造方法:
无参数构造方法:
Class student = Class.forName("reflesh.student");
Object obj = student.newInstance();
有参数构造方法:
Class student = Class.forName("reflesh.student");
Constructor con = student.getDeclaredConstructor(String.class,String.class);
con.newInstance("sun","6225");
路径问题:
解决通常情况下,代码交换位置出现的路径问题,前提条件:文件必须在类路径(在src下的都是类路径)下。
String path = Thread.currentThread().getContextClassLoader().getResource("test.properties").getPath();
Thread.currentThread() | 当前线程对象。 |
getContextClassLoader | 线程对象的方法,可以获得当前线程的类加载器对象。 |
getResource() | 获得资源,类加载器的方法,当前线程的类加载器默认从根路径下加载资源。 |
也可以在类加载器中使用getResourceAsStream()方法得到流。
例如:
InputStream reader = Thread.currentThread().getContextClassLoader().getResourceAsStream("test.properties");
资源绑定器:
使用这种方式时,配置属性文件必须放在类路径下。并且只能绑定xx.properties文件。
在写路径的时候,路径后面的扩展名不能写。
ResourceBundle bundle = ResourceBundle.getBundle("test");
String className = bundle.getString("ClassName");
类加载器:
专门负责加载类的命令/工具。ClassLoader
JDK自带的3个类加载器:
1.启动类加载器:
代码在开始执行前,会将所需要的类全部加载到JVM中。首先通过启动类加载器加载.class文件,专门加载核心类库(rt.jar)。
2.扩展类加载器:
如果通过启动类加载器加载不到时,会通过扩展类加载器加载。扩展类加载器专门加载ext目录中的文件。
3.应用类加载器:
如果扩展类加载器也没有找到,会通过应用类加载器加载,应用类加载器专门加载classpath中的jar包。
双亲委派机制:
为了保证类加载的安全,优先从启动类加载器中加载(父),再从扩展类加载器中加载(母),如果都加载不到
才会考虑从应用类加载器中加载。
可变长度参数:
在方法的参数中,类型的后面加…可以实现。
例如:public static void add(int… args)
可以将可变长度参数当作一个数组来看。
例如:
public static void main(String[] args) {
reflesh3.printString("abc","efg","ghj");//这里也可以直接传一个数组
}
public static void printString(String...args){
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
}
注意:可变长参数只能有1个,且必须在参数列表的最后。
如何获得一个类的父类:
通过getSuperclass()来获取父类。
例如:
public static void main(String[] args) throws Exception{
Class stringClass = Class.forName("java.lang.String");
Class superClass = stringClass.getSuperclass();
System.out.println(superClass.getSimpleName());
}
如何获得一个类的所有接口:
通过getInterfaces()方法来获得一个数组,数组中存放对象的所有接口。
例如:
public static void main(String[] args) throws Exception{
Class stringClass = Class.forName("java.lang.String");
Class[] interfaces = stringClass.getInterfaces();
for(Class in : interfaces){
System.out.println(in.getSimpleName());
}
}