• Java语言基础----常用API03(反射)


    java反射机制

    反射是java中的动态机制,它允许我们在程序运行期间再确定对象的实例化,方法的调用,
    属性的操作等。使得程序的灵活度大大提升,但是同时也带来了更多的资源开销和较低的
    运行效率。

    Class 类对象

    Class的每一个实例用于表示JVM中加载的一个类,并且每个被JVM加载的类都有且只有一个Class的实例。通过Class我们可以得知其表示的类的一切信息:类名,包名,有哪些构造器,方法属性等。

    获取一个类的类对象方式有:

    • 类名.class
      例如:Class cls = String.class;
      注:基本类型只能通过上述方式获取类对象
    • Class.forName(String className)
      使用Class的静态方法forName传入要加载的类的完全限定名(包名.类名)
      例如:Class cls = Class.forName("java.lang.String")
    • 类加载器ClassLoader形式
    1. public class ReflectDemo1 {
    2. public static void main(String[] args) throws ClassNotFoundException {
    3. // Class cls = String.class;//获取String的类对象
    4. Class cls = Class.forName("java.lang.String");
    5. //通过类对象获取其表示的String的相关信息
    6. String name = cls.getName();//java.lang.String
    7. name = cls.getSimpleName();//String
    8. //获取包名
    9. System.out.println(cls.getPackage().getName());//java.lang
    10. }
    11. }

    使用反射机制实例化对象

    1. public class ReflectDemo2 {
    2. public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
    3. //先获取要实例化对象的类所对应的类对象
    4. Class cls1 = Class.forName("reflect.Person");
    5. //类对象提供newInstance()必须有无参且公开的构造器可调用进行实例化
    6. Object o1 = cls.newInstance();
    7. System.out.println(o1);
    8. //1加载类对象
    9. Class cls2 = Class.forName("reflect.Person");
    10. //2获取对应的构造器 Person(String name,int age)
    11. // cls2.getConstructor();//不传参获取的为无参构造器
    12. Constructor c2 = cls2.getConstructor(String.class,int.class);
    13. //3通过构造器实例化对象 new Person("王五",22);
    14. Object o2 = c2.newInstance("王五",22);
    15. System.out.println(o2);
    16. }
    17. }

    使用反射机制调用含参,无参,私有,条件参数的方法们

    1. public class ReflectDemo4 {
    2. public static void main(String[] args) throws Exception {
    3. //得到类对象及实例化
    4. Class cls = Class.forName("reflect.Person");
    5. Object o = cls.newInstance();//Person o = new Person();
    6. //1)获取要调用的无参方法
    7. //仅传入方法名时,是获取该无参方法
    8. Method method = cls.getMethod("sayHello");//表示的Person的成员方法sayHello()
    9. method.invoke(o);//等同于o.sayHello(),调用o对象反射得到的对应方法
    10. //2)获取要调用的含参方法
    11. Method method = cls.getMethod("dosome",String.class);//dosome(String)
    12. method.invoke(o,"玩游戏");//p.dosome("玩游戏");
    13. Method method1 = cls.getMethod("dosome",String.class,int.class);
    14. method1.invoke(o,"看电视",5);
    15. //3)获取私有方法
    16. Method method = cls.getDeclaredMethod("secret");
    17. //强行打开访问权限
    18. method.setAccessible(true);
    19. method.invoke(o);
    20. //4)获取当前类对象所表示的类的所有公开方法(包含从超类继承的方法)
    21. Method[] methods1 = cls.getMethods();
    22. System.out.println(cls.getSimpleName()+":一共有"+methods1.length+"个公开方法");
    23. //5)获取当前类对象所表示的类自身定义的所有方法(含私有方法,不含从超类继承的方法)
    24. Method[] methods2 = cls.getDeclaredMethods();
    25. System.out.println(cls.getSimpleName()+":一共有"+methods2.length+"个本类方法");
    26. for(Method method : methods2){
    27. System.out.println(method.getName());
    28. //6)自动调用与当前类Test2在同一个包下所有类中 方法名含有s的无参公开方法
    29. //定位String类package描述的顶级目u录也是该类编译后存放包的顶级根目录
    30. String.class.getClassLoader().getResource(".").toURI();
    31. String.class.getResource(".").toURI();//定位String类编译后所在的目录(包)
    32. //定位Test2所在的目录(包)
    33. File dir = new File(
    34. Test2.class.getResource(".").toURI()
    35. );
    36. File[] subs = dir.listFiles(f->f.getName().endsWith(".class"));
    37. //遍历每一个class文件
    38. for(File sub : subs){
    39. String fileName = sub.getName();//获取文件名:例如Test2.class
    40. String className = fileName.substring(0,fileName.indexOf("."));
    41. Class cls = Class.forName(Test2.class.getPackage().getName()+"."+className);
    42. //实例化对象
    43. Object o = cls.newInstance();
    44. Method[] methods = cls.getDeclaredMethods();
    45. for(Method method : methods){
    46. if(method.getName().contains("s")&&
    47. method.getParameterCount()==0&&//int getParameterCount()可以获取其表示的方法的参数个数
    48. method.getModifiers()==Modifier.PUBLIC){
    49. System.out.println("自动调用"+className+"的方法:"+method.getName());
    50. method.invoke(o);
    51. }
    52. }
    53. }
    54. }
    55. }

    变长参数方法

    JDK5之后java推出了一个特性:变长参数

    编译器支持的操作,编译器在编译时,会将调用的方法改造成对应的参数方法
    变长参数只能是方法的最后一个参数且只能有一个变长参数实际是一个数组类型

    1. public class ArgsDemo {
    2. public static void main(String[] args) {
    3. doing(1,23,"one");
    4. doing(1,23,"one","two");
    5. doing(1,23,"one","two","three");
    6. doing(1,23,"one","two","three","four");
    7. //doing(1,23,new String[]{"one","two","three","four"});编译器在编译的时候相当于创建了数组
    8. }
    9. public static void doing(int age,long a,String... arg){
    10. System.out.println(arg.length);
    11. System.out.println(Arrays.toString(arg));
    12. }
    13. }

  • 相关阅读:
    天冷就要大口吃肉肉~python采集周边烤肉店数据【附代码】
    交通地理信息系统实习教程(二)
    阿里最新分享的《多线程核心技术第三版》神书就此霸榜GitHub,3天点击量已破百万
    c++ 泛型编程之类模板
    【TcaplusDB知识库】Tmonitor单机安装指引介绍(一)
    证照之星老版本升级XE最新版教程说明
    Vue3实战教程(快速入门)
    数据库读取数据源配置实现动态数据源
    SOFARegistry 源码|数据同步模块解析
    mybatis-plus-ext注解学习
  • 原文地址:https://blog.csdn.net/weixin_64742764/article/details/126063633