1、类加载器
1.1类加载
当你需要使用某个类的时候,但是这个类还没有被加载到内存中,系统会通过类的加载,连接,初始化三个步骤对要加载的类进行初始化,这三个步骤也被统称为类加载或类的初始化
1.2类加载器
作用:负责将.class文件加载到内存中,并与之生成对应的java.lang.class对象
三种类加载器关系:Bootstrap class loader>Platform class loader>System class loader
public static void main(String[] args) {
//getSystemClassLoader();Returns the system class loader.
ClassLoader c=ClassLoader.getSystemClassLoader();
System.out.println(c);//AppClassLoader
//getPlatformClassLoader();Returns the platform class loader.
ClassLoader c1 = ClassLoader.getPlatformClassLoader();
System.out.println(c1);//PlatformClassLoader
// getParent();Returns the parent class loader for delegation.
ClassLoader c2 = c1.getParent();
System.out.println(c2);//null c2的类加载器是BootStrap。
// It is the virtual machine's built-in class loader, typically represented as null, and does not have a parent.
}
2、反射
什么是反射?
反射是可以获得任意一个类中的所有属性和方法,对于任意一个对象都能调用它的属性和方法。这种动态获取信息以及动态的获取类的属性和方法被称为Java的反射机制。
怎么反射?
对于要获取的字节码文件对象(.class)使用Class类中的方法,所以要获取每一个字节码文件的class对象。
怎么获取字节码文件对象?
有三种方法:1、直接.class获取该类的Class对象。
2、调用类的.getClass()方法获取Class对象
3、使用Class类中的静态方法forName(String className) 其中className是全限定名。
public static void main(String[] args) throws ClassNotFoundException {
/*
* 三种获取字节码文件对象
* */
//1、直接.class获取该类的Class对象。
Class<student> c1 = student.class;
System.out.println(c1);
//2、调用类的.getClass()方法获取Class对象
student s = new student();
Class<? extends student> c2 = s.getClass();
System.out.println(c2);
//3、使用Class类中的静态方法forName(String className) 其中className是全限定名。
Class<?> c3 = Class.forName("com.jackly.main.ch14.student");
System.out.println(c3);
}
从字节码文件获取构造方法的几个方法
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
/*
* 几个获取构造方法的方法
* */
Class<?> c = Class.forName("com.jackly.main.ch14.student");
//Constructor<?>[] getConstructors()返回一个数组,该数组包含Constructor反映此Class对象表示的类的所有公共构造函数的 对象。
// Constructor<?>[] cons = c.getConstructors();
//Constructor<?>[] getDeclaredConstructors()返回一个Constructor对象数组,反映由该Class对象表示的类声明的所有构造 函数。
// Constructor<?>[] cons = c.getDeclaredConstructors();
// for (Constructor con:cons){
// System.out.println(con);
// }
//Constructor<T> getConstructor(Class<?>... parameterTypes)返回一个Constructor对象,该对象反映此Class 对象表示的类的指定公共构造函数。
// Constructor<?> cons = c.getConstructor();
//Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
//返回一个Constructor对象,该对象反映此Class对象表示的类或接口的指定构造 函数。
// Constructor<?> cons = c.getDeclaredConstructor();
// System.out.println(cons);
}
反射练习 1:student s = new student(“张三”,20,“西安”); System.out.println(s); 转换为反射机制输出
/*
* student s = new student("张三",20,"西安");
System.out.println(s);
转换为反射机制
* */
//获取student类的字节码文件对象
Class<?> c = Class.forName("com.jackly.main.ch14.student");
//获取带参构造函数
Constructor<?> con = c.getConstructor(String.class, int.class, String.class);
//传入数据
Object obj = con.newInstance("张三", 20, "西安");
System.out.println(obj);
反射练习2:student s = new student(“张三”); System.out.println(s); 使用反射机制
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
/*
student s = new student("张三");
System.out.println(s);
使用反射机制
*/
Class<?> c = Class.forName("com.jackly.main.ch14.student");
Constructor<?> con = c.getDeclaredConstructor(String.class);
//私有成员变量不能直接被访问,但是可以通过暴力反射
//public void setAccessible(boolean flag):值为true的时候取消访问检查
con.setAccessible(true);
Object obj = con.newInstance("张三");
System.out.println(obj);
}
成员变量的反射4种方法:
1、Field[] getFields()
返回一个数组,该数组包含Field反映此Class对象表示的类或接口的所有可访问公共字段的对象。
2、Field getField(String name)
返回一个Field对象,该对象反映此Class 对象表示的类或接口的指定公共成员字段。
3、Field[] getDeclaredFields()
返回一个Field对象数组,反映由该Class对象表示的类或接口声明的所有字段 。
4、Field getDeclaredField(String name)
返回一个Field对象,该对象反映此Class 对象表示的类或接口的指定声明字段。
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
/*
* 获取类文件内的成员变量4种方法
* */
//获取字节码文件对象
Class<?> c = Class.forName("com.jackly.main.ch14.student");
//Field[] getFields()
//返回一个数组,该数组包含Field反映此Class对象表示的类或接口的所有可访问公共字段的对象。
// Field[] fields = c.getFields();
//Field[] getDeclaredFields()
//返回一个Field对象数组,反映由该Class对象表示的类或接口声明的所有字段 。
Field[] fields = c.getDeclaredFields();
for (Field field:fields){
System.out.println(field);}
System.out.println("--------");
//Field getField(String name)
//返回一个Field对象,该对象反映此Class 对象表示的类或接口的指定公共成员字段。
Field af = c.getField("address");
System.out.println(af);
//Field getDeclaredField(String name)
//返回一个Field对象,该对象反映此Class 对象表示的类或接口的指定声明字段。
Field nf = c.getDeclaredField("name");
System.out.println(nf);
//获取无参构造函数
Constructor<?> con = c.getDeclaredConstructor();
con.setAccessible(true);
Object obj = con.newInstance();
//AField提供有关类或接口的单个字段的信息和对其的动态访问。反射字段可以是类(静态)字段或实例字段。
//void set(Object obj, Object value)
//Field将指定对象参数上此对象表示的字段设置为指定的新值。
af.set(obj,"西安");
nf.setAccessible(true);//暴力反射
nf.set(obj,"李四");
System.out.println(obj);
}
反射类中的4种方法:
1、Method[] getMethods()
返回一个数组,该数组包含Method反映此 Class对象表示的类或接口的所有公共方法的对象,包括由类或接口声明的方法以及从超类和超接口继承的方法。(返回的不仅仅是自己定义的公共方法)
2、Method[] getDeclaredMethods()
返回一个数组,其中包含Method反映此 Class对象表示的类或接口的所有声明方法的对象,包括公共、受保护、默认(包)访问和私有方法,但不包括继承的方法。
3、Method getMethod(String name, Class<?>… parameterTypes)
返回一个Method对象,该对象反映此Class对象表示的类或接口的指定公共成员方法 。
4、Method getDeclaredMethod(String name, Class<?>… parameterTypes)
返回一个Method对象,该对象反映此Class对象表示的类或接口的指定声明方法 。
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
/*
* 获取成员变量中的方法
* */
Class<?> c = Class.forName("com.jackly.main.ch14.student");
//Method[] getMethods()
//返回一个数组,该数组包含Method反映此 Class对象表示的类或接口的所有公共方法的对象,包括由类或接口声明的方法以及从超类和超接口继承的方法。
// Method[] methods = c.getMethods();
//Method[] getDeclaredMethods()
//返回一个数组,其中包含Method反映此 Class对象表示的类或接口的所有声明方法的对象,包括公共、受保护、默认(包)访问和私有方法,但不包括继承的方法。
Method[] methods = c.getDeclaredMethods();
for (Method method:methods){
System.out.println(method);
}
System.out.println("------");
//Method getMethod(String name, Class<?>... parameterTypes)
//返回一个Method对象,该对象反映此Class对象表示的类或接口的指定公共成员方法 。
Constructor<?> cons = c.getDeclaredConstructor();
Method method1 = c.getMethod("method2", String.class);
Object obj = cons.newInstance();
//Object invoke(Object obj, Object... args)
//在Method 具有指定参数的指定对象上调用此对象表示的基础方法。
//Obj:返回类型
//obj:指定对象
//args:方法参数
//public void method1()
method1.invoke(obj,"李四");
System.out.println(obj);
//Method getDeclaredMethod(String name, Class<?>... parameterTypes)
//返回一个Method对象,该对象反映此Class对象表示的类或接口的指定声明方法 。
// Method m = c.getDeclaredMethod("function");
// Object obj = cons.newInstance();
// m.setAccessible(true);//暴力反射
// m.invoke(obj);
// System.out.println(obj);
}
反射练习1、越过泛型检查
* 题目:ArrayList 泛型集合添加字符串,如何实现?
* 思路:使用反射机制实现 获取
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
/*
* 反射练习1、越过泛型检查
* 题目:ArrayList<Integer> 泛型集合添加字符串,如何实现?
* 思路:使用反射机制实现 获取
* */
ArrayList<Integer> array=new ArrayList<Integer>();
array.add(10);
Class<? extends ArrayList> c = array.getClass();
Method m = c.getDeclaredMethod("add", Object.class);
m.invoke(array,"hello");
m.invoke(array,"world");
System.out.println(array);
}
反射练习2:运行配置文件指定内容
配置文件内容如下:
className=com.jackly.main.ch14.Student
methodName=study
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Properties prop = new Properties();
FileReader fr = new FileReader("javaSEStudy_01\\src\\com\\jackly\\main\\ch14\\class.txt");
prop.load(fr);
fr.close();
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
Class<?> c = Class.forName(className);
Constructor<?> cons = c.getDeclaredConstructor();
Object obj = cons.newInstance();
Method m = c.getMethod(methodName);
m.invoke(obj);
}
}
class Student{
public void study(){
System.out.println("好好学习天天向上");
}
}
class Teacher{
public void teach(){
System.out.println("要好好学习呀");
}
}
在写这段代码中遇到过一个问题:因为是在一个类里面写的Student和Teacher类,用的是默认修饰。在获取无参构造函数用的是getConstructor()获取的是公共的。报NoSuchMethodException异常,仔细看了代码才发现这个问题。