目录
1.类加载器(ClassLoader)
1.1.概述
1.2.类加载的时间
1.3.使用类加载器管理配置文件
2.反射
2.1.反射概述
反射依赖于一个东西:Class类。Class类是反射的基石!
2.1.1.Class类介绍
2.1.2.获取Class的三种方式
/*
* 演示:
获取Class对象的方式
* 方式1:类名.class
* 方式2:对象.getClass()
* 方式3:static Class forName(String className) 根据类的名称获取Class对象,注意此处的类名必须是全称
* 获取类的信息:
* String getSimpleName():获取类名全称(java.lang.String)
* String getName():获取类名简称(String)
*
* 注意:一个类,在内存中只会有1份字节码文件对象!
* 我们应该用哪一种?
* 如果是自己玩,就用前两种,这两种使用时,都需要先知道具体的数据的类型
* 如果是开发,一般用第三种。第三种比前两张扩展性更好
*/
public class ClassDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 方式1:类名.class
Class clazz1 = String.class;
System.out.println(clazz1.getSimpleName());// String
System.out.println(clazz1.getName());// java.lang.String
System.out.println("---------------------------");
// 方式2:对象.getClass();
Class clazz2 = "hello".getClass();
System.out.println(clazz2.getSimpleName());// String
System.out.println(clazz2.getName());// java.lang.String
System.out.println("---------------------------");
// 方式3:static Class forName(String className) 根据类的名称获取Class对象
// Class clazz3 = Class.forName("String");//类名必须是全称
Class clazz3 = Class.forName("java.lang.String");
System.out.println(clazz3.getSimpleName());
System.out.println(clazz3.getName());
System.out.println("---------------------------");
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz1 == clazz3);//true
}
}
2.1.3.预定义对象:
/*
* 演示:9种预定义对象
* 包含了8种基本数据类型,以及一个void
* 9种预定义对象,也被称为原始类型:
* 判断是否是原始类型:isPrimitive()
* 判断是否是数组:Class.isArray()
*
* 注意:任何一个包装类的静态成员变量:TYPE 都表示其对应基本类型的字节码对象
*/
public class ClassDemo02 {
public static void main(String[] args) {
Class int_clazz = int.class;
System.out.println(int_clazz);// int
System.out.println(char.class);// char
System.out.println(boolean.class);// boolean
System.out.println("------------------------");
Class integer_clazz = Integer.class;
System.out.println(int_clazz == integer_clazz);// false
System.out.println(int_clazz == Integer.TYPE);// true
System.out.println("------------------------");
Class void_clazz = void.class;
System.out.println(void_clazz);//void
System.out.println("------------------------");
System.out.println(int_clazz.isPrimitive());//true
System.out.println(void_clazz.isPrimitive());//true
System.out.println(integer_clazz.isPrimitive());//false
System.out.println("------------------------");
Class arr_clazz = int[].class;
System.out.println(arr_clazz);//class [I
System.out.println(arr_clazz.isPrimitive());//false
System.out.println(arr_clazz.isArray());//true
}
}
2.1.4.反射的概念
2.2.使用反射获取构造函数(Constructor)
/*
* 演示:反射获取构造函数
* Constructor[] getConstructors() 获取所有公共的构造函数
* Constructor[] getDeclaredConstructors() 获取所有构造函数
* Constructor getConstructor(Class ... parameterTypes) 根据参数列表获取某个公共的构造函数
* Constructor getDeclaredConstructor(Class ... parameterTypes) 根据参数列表获取某个任意的构造函数
* 获取构造函数有什么用?用来创建对象!
* Object newInstance(Object... initargs):创建对象,参数为相匹配的实际参数
*
* 对于私有的成员,必须开启暴力模式:
* setAccessible(true)
*/
public class ClassDemo03 {
public static void main(String[] args) throws Exception {
Class clazz = File.class;
//获取多个构造函数
//Constructor[] getConstructors() 获取所有公共的构造函数
// Constructor[] cs = clazz.getConstructors();
//Constructor[] getDeclaredConstructors() 获取所有构造函数
// Constructor[] cs = clazz.getDeclaredConstructors();
//遍历构造函数
// for( Constructor c : cs){
// System.out.println(c);
// }
//获取单个构造函数
//Constructor getConstructor(Class ... parameterTypes) 根据参数列表获取某个公共的构造函数
//需求:获取File(String pathname)
// Constructor c = clazz.getConstructor(String.class);
// System.out.println(c);
// Constructor getDeclaredConstructor(Class ... parameterTypes) 根据参数列表获取任意构造函数
// 需求:获取私有构造:File(String child, File parent)
Constructor c = clazz.getDeclaredConstructor(String.class,File.class);
// System.out.println(c);
// 设置暴力访问
c.setAccessible(true);
// Object newInstance(Object... initargs)
File f = (File) c.newInstance("柳岩.jpg",new File("D:\\test"));// java.lang.IllegalAccessException:
System.out.println(f.getAbsolutePath());
// Class类中的功能: newInstance() 使用类的空参构造创建对象
Class clazz2 = String.class;
String s = (String) clazz2.newInstance();
System.out.println(s.length());// 0
}
}
2.3.反射获取成员变量(Field)
/*
* 演示:反射获取成员变量
* Field[] getFields() 获取所有公共的成员变量
* Field[] getDeclaredFields() 获取所有的成员变量
* Field getField(String name) 根据变量名获取某个公共成员变量
* Field getDeclaredField(String name) 根据变量名获取某个任意成员变量
*
* 拿到成员有什么用?是用来获取对象中的数据
* Object get(Object obj) 返回指定对象上此 Field 表示的字段的值。
* void set(Object obj, Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值
*
* 注意:如果是静态成员,对象obj可以写null
*
* 获取成员变量的类型:
* Class getType() 返回该字段所声明的数据类型
*/
public class ClassDemo04 {
public static void main(String[] args) throws Exception {
Person p = new Person("柳岩", 21, "5216");
Class clazz = p.getClass();
// Field[] getFields() 获取所有公共的成员变量
// Field[] fs = clazz.getFields();
// Field[] getDeclaredFields() 获取所有的成员变量
// Field[] fs = clazz.getDeclaredFields();
// for(Field f : fs){
// System.out.println(f);
// }
// Field getField(String name) 根据变量名获取某个公共成员变量
Field f1 = clazz.getField("age");
// System.out.println(f1);// public int cn.itcast.demo02.Person.age
// Field getDeclaredField(String name) 根据变量名获取某个任意成员变量
Field f2 = clazz.getDeclaredField("addr");
// System.out.println(f2);// private java.lang.String cn.itcast.demo02.Person.addr
// Object get(Object obj) 返回指定对象上此 Field 表示的字段的值。
System.out.println(f1.get(p));// 21
// 设置暴力访问
f2.setAccessible(true);
System.out.println(f2.get(p));
// void set(Object obj, Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值
f2.set(p, "5416");
System.out.println(f2.get(p));
System.out.println("--------------------");
System.out.println(f1.getType());// int
System.out.println(f1.getType() == int.class);// true
System.out.println(f2.getType() == String.class);// true
}
}
2.4.反射获取成员方法
/*
* 演示:反射获取成员方法:
* Method[] getMethods() 获取所有公共的成员方法,包括继承自父类的方法。
* Method[] getDeclaredMethods() 获取自己声明的所有成员方法
* Method getMethod(String name, Class ... parameterTypes) 根据方法名称及参数列表获取某个公共的成员方法
* Method getDeclaredMethod(String name, Class ... parameterTypes) 根据方法名称及参数列表获取任意的成员方法
*
* 获取Method有什么用?当然是拿来调用的。执行Method
* String getName() 以 String 形式返回此 Method 对象表示的方法名称
* 执行一个Method:
* Object invoke(Object obj, Object... args) 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法
* obj : 要调用的指定对象
* args : 此Method所表示的方法的真实参数
* A:非静态的有参方法
* invoke时传递的参数必须和获取Method时传递的参数类型匹配
* B:静态方法
* 在执行invoke时,第一个参数obj可以传null
* C:无参方法
* 获取Method时,参数类型是可变参数,因此可以不写
* 执行invoke时,参数列表也是可变参数,因此也可以不写
*/
public class ClassDemo05 {
public static void main(String[] args) throws Exception {
Class clazz = String.class;
// Method[] getMethods() 获取所有公共的成员方法
// Method[] ms = clazz.getMethods();
// for( Method m : ms){
// System.out.println(m);
// }
// System.out.println("--------------------");
// System.out.println(ms.length);// 72
// Method[] getDeclaredMethods() 获取所有成员方法
// Method[] ms = clazz.getDeclaredMethods();
// for( Method m : ms){
// System.out.println(m);
// }
// System.out.println("--------------------");
// System.out.println(ms.length);// 73
// Method getMethod(String name, Class ... parameterTypes) 根据方法名称及参数列表获取某个公共的成员方法
// 获取一个方法:char charAt(int index)
Method m = clazz.getMethod("charAt", int.class);
// System.out.println(m);// public char java.lang.String.charAt(int)
// System.out.println(m.getName());//charAt
// 演示:非静态的、带返回值的、有参方法。
// 需求:执行charAt方法
// 方式1:非反射方式执行:
String str = "hello";
char c = str.charAt(2);
System.out.println(c);// l
// 方式2:反射执行
// Object invoke(Object obj, Object... args)
char c2 = (char) m.invoke(str, 2);
System.out.println(c2);// l
// 演示:静态,有参方法
// static String valueOf(double d)
Method m2 = clazz.getMethod("valueOf", double.class);
String s = (String) m2.invoke(null, 12.34);
System.out.println(s.length());// 5
// 演示:无参无返回值方法
// 获取show方法
Person p = new Person();
Class p_clazz = p.getClass();
Method m3 = p_clazz.getMethod("show");
m3.invoke(p);// show ..... run
}
}
2.5.应用举例: