Java基础二十四:类加载器,反射获取构造方法、成员变量、成员方法及相关案例练习

发布于:2023-01-16 ⋅ 阅读:(520) ⋅ 点赞:(0)

反射

1、类加载基础知识

1cb9ce0b799840019d385782d598cb3d.png 

14e9d83f3a65425292c374c3aa61c2d9.png 

2、类加载器

ebd0dfc2f329491bb34403ff9848911b.png3e18805b9a40492a8d9b31cd8bba4d61.png  

//类加载器基础知识

public class ClassLoaderDemo1 {
   public static void main(String[] args) {
       //获取委派的系统类加载器
       ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
       System.out.println(systemClassLoader);//结果:AppClassLoader

       //获取AppClassLoader父类加载器
       ClassLoader parent = systemClassLoader.getParent();
       System.out.println(parent);//结果:ExtClassLoader

       //获取ExtClassLoader父类加载器
       ClassLoader parent1 = parent.getParent();
       System.out.println(parent1);//结果:null,它是虚拟机的内置加载器,通常表示null
   }
}

3、反射概述

2ef5bb00180d4f62b19ca8c33b743258.png4d1c13bc67ea46fa97f44b32862c909a.png  

4、获取Class类的对象

73a6c755e22f44f4bbd02b22d1e3d163.png 

//获取Class类的对象
public class ClassLoaderDemo2 {
   public static void main(String[] args) throws ClassNotFoundException{
       //第一种方式:使用Class类的属性获取该类的Class对象

//这种方式最便捷,适合测试代码
       Class<Student> c1 = Student.class;
       System.out.println(c1);

       Class<Student> c2 = Student.class;
       System.out.println(c1==c2);
       System.out.println("------------");
       //第二种方式:调用对象的getClass()方法,返回该对象所属类对应的Class对象
       Student stu = new Student();
       Class<? extends Student> c3 = stu.getClass();
       System.out.println(c1==c3);
       System.out.println("------------");
       //第三种方式:使用Class类中的静态方法forName(String className)

//这个方式可以把路径配置到一个文件里面,灵活性更高
       Class<?> c4 = Class.forName("ClassLoader.Student");
       System.out.println(c1==c4);
   }
}

5、反射获取构造方法并使用

47654b7020b24640b8214fc9476912c8.png 

//反射获取构造方法并使用
public class ClassLoaderDemo3 {
   public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException,
           IllegalAccessException, InvocationTargetException, InstantiationException {
       //获取Class对象
       Class<?> c = Class.forName("ClassLoader.Student");

       /*获取公共方法:Constructor<?>[] getConstructors()
       获取私有、默认方法:Constructor<?>[] getDeclaredConstructors()
        */
       //Constructor<?>[] cons = c.getConstructors();//获取Class类中的所有公共方法用这个
       Constructor<?>[] cons = c.getDeclaredConstructors();//获取Class类中的所有私有方法、默认方法没用这个

       for(Constructor con:cons){
           System.out.println(con);
       }
       System.out.println("----------------");
       //获取Class类中的单个方法getConstructor(Class<?>...parameterType)
       //getDeclaredConstructor(Class<?>...parameterType)
       //参数表示的意思是:需要获取的构造方法的参数个数和数据类型对应的字节码文件对象
       Constructor<?> con = c.getConstructor();//获取无参构造方法
       Object obj = con.newInstance();//Constructor中创建对象的方法
       System.out.println(obj);//结果:Student{name='null', age=0, address='null'}
   }
}

6、反射获取构造方法并使用的练习

/*练习一:反射获取构造方法并使用的练习
* Student s = new Student("林小小",30,"西安");
* System.out.println(s);
* 练习二:Student s = new Student("林大小");
* System.out.println(s);
* */
public class ClassLoaderDemo4 {
   public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, ​   InvocationTargetException, InstantiationException {
       //获取Class对象
       Class<?> c = Class.forName("ClassLoader.Student");
       //基本数据类型也可以通过.class获取到对应的Class类型
       Constructor<?> con = c.getConstructor(String.class, int.class, String.class);//公共方法
       //能Class类的成员变量赋值
       Object obj = con.newInstance("林小小", 30, "西安");
       System.out.println(obj);
       System.out.println("--------------");
       Constructor<?> con1 = c.getDeclaredConstructor(String.class);//私有方法
       //暴力反射:setAccessible(boolean flag);值为true就取消访问检查,否则会抛异常
       con1.setAccessible(true);
       Object obj1 = con1.newInstance("林大小");
       System.out.println(obj1);
   }
}

7、反射获取成员变量并使用

f4b06e26f8164b34ba61b05d69ab945b.png 

//反射获取成员变量并使用
public class ClassLoaderDemo5 {
   public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
       //获取Class对象
       Class<?> c = Class.forName("ClassLoader.Student");
       //Field[] fields = c.getFields();//获取公共成员变量
       Field[] fields = c.getDeclaredFields();//获取所有成员变量
       for (Field field: fields) {
           System.out.println(field);
       }
       System.out.println("--------");
       Field addressField = c.getField("address");//获取单个的,公共的成员变量
       //获取无参构造方法,创建对象
       Constructor<?> con = c.getConstructor();
       Object obj = con.newInstance();
       addressField.set(obj,"深圳");//给obj的成员变量addressField赋值为深圳
       System.out.println(obj);
       //获取单个的,非公共的成员变量
       ........
   }
}

8、反射获取成员变量的练习

//通过反射给成员变量赋值小练习
public class ClassLoaderDemo6 {
   public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, 
           IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
       Class<?> c = Class.forName("ClassLoader.Student");
       Constructor<?> con = c.getConstructor();
       Object obj = con.newInstance();

      //ield nameField = c.getField("name");//获取公共方法
       Field nameField = c.getDeclaredField("name");//获取私有方法
       nameField.setAccessible(true);//暴力反射
       nameField.set(obj,"林小小");
       System.out.println(obj);

       Field ageField = c.getDeclaredField("age");
       ageField.setAccessible(true);
       ageField.set(obj,30);
       System.out.println(obj);

       Field addressField = c.getDeclaredField("address");
       addressField.setAccessible(true);
       addressField.set(obj,"深圳");
       System.out.println(obj);
   }
}

9、反射获取成员方法并使用

34662475472e42d990bbb5752c333d55.png 

//反射获取成员方法并使用
public class ClassLoaderDemo7 {
   public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
       //第一步
       Class<?> c = Class.forName("ClassLoader.Student");
       //Method[] methods = c.getMethods();//获取公共方法,返回对象方法的数组。包含继承的父类方法
       Method[] methods = c.getDeclaredMethods();//获取私有方法,只有本类的私有方法
       for(Method method: methods){
           System.out.println(method);
       }
       System.out.println("---------------");
       //第二步
       Method m = c.getMethod("method1");//获取单个成员方法
       //获取无参构造方法,创建对象
       Constructor<?> con = c.getConstructor();
       Object obj = con.newInstance();
       /*Object  invoke(Object obj,Object...args )在具有指定参数的指定对象上调用此方法表示的基础方法
       Object:是返回值类型
       obj: 是调用方法的对象
       Object...args: 是方法需要的参数
       * */
       //第三步:其实就是调用obj对象的成员方法m,实际就是调用的成员方法method1
       m.invoke(obj);//调用了Student类中的method1方法,无参
       
       //getConstructor()与之对应的还有c.getDeclaredMethod("");
   }
}

10、反射获取成员方法并使用小练习

//反射获取成员方法并使用小练习
/*Student  = new Student();
 s.method1();
 s.method2("林小小");
 String ss = s.method3("林大小",32);
 System.out.println(ss);
 s.function();
*/
public class ClassLoaderDemo8 {
   public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
       Class<?> c = Class.forName("ClassLoader.Student");//获取Class对象
       Constructor<?> con = c.getConstructor();//通过无参构造方法创建一个对象
       Object obj = con.newInstance();

       Method m1 = c.getMethod("method1");//通过对象获取method1方法,无参
       m1.invoke(obj);

       Method m2 = c.getMethod("method2", String.class);//通过对象获取method2方法,有参
       m2.invoke(obj,"林小小");

       Method m3 = c.getMethod("method3", String.class, int.class);//通过对象获取method2方法,有参,有返回值
       Object ob = m3.invoke(obj, "林大小", 32);
       System.out.println(ob);

       Method m4 = c.getDeclaredMethod("function");//通过对象获取调用function()私有方法,无参,无返回值
       m4.setAccessible(true);//暴利反射,针对私有方法
       m4.invoke(obj);
   }
}

11、反射练习之越过泛型检查

注:1、通过反射可以反问类的私有成员

   2、通过反射也可以给指定数据类型集合中添加其它类型数据

//反射练习2: ArrayList<Integer>集合,在集合中香港一个String类型的字符串数据
//反射可以越过检查,获取原始参数类型,原始的方法参数类型Object就可以存储任意类型的数据
public class ClassLoaderDemo9 {
   public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
       ArrayList<Integer> array = new ArrayList<>();
       array.add(10);
       array.add(20);

       Class<? extends ArrayList> c = array.getClass();//首先要获取该集合的Class对象
       Method m = c.getMethod("add", Object.class);//类型是Object类型,并没有指定是Integer类型
       m.setAccessible(true);//暴利反射
       m.invoke(array,"林小小");//往集合中添加String类型的字符串
       m.invoke(array,"林大小");
       m.invoke(array,"林小");

       System.out.println(array);
       
   }
}

12、 反射练习之运行配置文件指定内容

//通过配置文件,运行类中的方法
public class ClassLoaderDemo10 {
   public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { /*配置文件运行类中的方法,解决问题是主方法中如果需要来回切换调用不同类的方法问题
       Student s = new Student();
       s.study();
       Teacher t = new Teacher();
       t.teach();*/
//创建一个txt文件,文件中配置有一个className= 类名,methodName= 方法名字
Properties p = new Properties();//第一步:加载数据
       FileReader fr = new FileReader("F:\\test\\class.txt");//获取配置文件地址
       p.load(fr);//拿到配置文件中的数据
       fr.close();

//第二步:根据对应的键,获取对应的值

String className = p.getProperty("className");
String methodNmae =p.getProperty("methodName");

//通过反射来使用
Class<?> c = Class.forName(className);//这一步获取的是ClassLoader.Student
       Constructor<?> con = c.getConstructor();
       Object obj = con.newInstance();//创建对象
       Method m = c.getMethod(methodNmae);//这一步拿的是study
       m.setAccessible(true);//暴力反射
       m.invoke(obj);
   }
}86b63052239f49f7babb53ff557f91d3.png 

 


网站公告

今日签到

点亮在社区的每一天
去签到