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形式
public class ReflectDemo1 {
    public static void main(String[] args) throws ClassNotFoundException {
       
//        Class cls = String.class;//获取String的类对象

        Class cls = Class.forName("java.lang.String");
        //通过类对象获取其表示的String的相关信息
        String name = cls.getName();//java.lang.String
        name = cls.getSimpleName();//String
        
        //获取包名
        System.out.println(cls.getPackage().getName());//java.lang
    }
}

使用反射机制实例化对象

public class ReflectDemo2 {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {

        //先获取要实例化对象的类所对应的类对象
        Class cls1 = Class.forName("reflect.Person");
        //类对象提供newInstance()必须有无参且公开的构造器可调用进行实例化
        Object o1 = cls.newInstance();
        System.out.println(o1);

        //1加载类对象
        Class cls2 = Class.forName("reflect.Person");
        //2获取对应的构造器  Person(String name,int age)
//        cls2.getConstructor();//不传参获取的为无参构造器
        Constructor c2 = cls2.getConstructor(String.class,int.class);
        //3通过构造器实例化对象 new Person("王五",22);
        Object o2 = c2.newInstance("王五",22);
        System.out.println(o2);
    }
}

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

public class ReflectDemo4 {
    public static void main(String[] args) throws Exception {

        //得到类对象及实例化
        Class cls = Class.forName("reflect.Person");
        Object o = cls.newInstance();//Person o = new Person();
        //1)获取要调用的无参方法
        //仅传入方法名时,是获取该无参方法
        Method method = cls.getMethod("sayHello");//表示的Person的成员方法sayHello()
        method.invoke(o);//等同于o.sayHello(),调用o对象反射得到的对应方法

        //2)获取要调用的含参方法
        Method method = cls.getMethod("dosome",String.class);//dosome(String)
        method.invoke(o,"玩游戏");//p.dosome("玩游戏");

        Method method1 = cls.getMethod("dosome",String.class,int.class);
        method1.invoke(o,"看电视",5);

        //3)获取私有方法
        Method method = cls.getDeclaredMethod("secret");
        //强行打开访问权限
        method.setAccessible(true);
        method.invoke(o);

        //4)获取当前类对象所表示的类的所有公开方法(包含从超类继承的方法)
        Method[] methods1 = cls.getMethods();
        System.out.println(cls.getSimpleName()+":一共有"+methods1.length+"个公开方法");

        //5)获取当前类对象所表示的类自身定义的所有方法(含私有方法,不含从超类继承的方法)
        Method[] methods2 = cls.getDeclaredMethods();
        System.out.println(cls.getSimpleName()+":一共有"+methods2.length+"个本类方法");
        for(Method method : methods2){
            System.out.println(method.getName());

        //6)自动调用与当前类Test2在同一个包下所有类中 方法名含有s的无参公开方法

        //定位String类package描述的顶级目u录也是该类编译后存放包的顶级根目录
        String.class.getClassLoader().getResource(".").toURI();
        String.class.getResource(".").toURI();//定位String类编译后所在的目录(包)

        //定位Test2所在的目录(包)
        File dir = new File(
            Test2.class.getResource(".").toURI()
        );
        File[] subs = dir.listFiles(f->f.getName().endsWith(".class"));
        //遍历每一个class文件
        for(File sub : subs){
            String fileName = sub.getName();//获取文件名:例如Test2.class
            String className = fileName.substring(0,fileName.indexOf("."));
            Class cls = Class.forName(Test2.class.getPackage().getName()+"."+className);
            //实例化对象
            Object o = cls.newInstance();
            Method[] methods = cls.getDeclaredMethods();
            for(Method method : methods){
                if(method.getName().contains("s")&&
                   method.getParameterCount()==0&&//int getParameterCount()可以获取其表示的方法的参数个数
                   method.getModifiers()==Modifier.PUBLIC){
                    System.out.println("自动调用"+className+"的方法:"+method.getName());
                    method.invoke(o);
                }
            }
        }
    }
}

变长参数方法

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

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

public class ArgsDemo {
    public static void main(String[] args) {
        doing(1,23,"one");
        doing(1,23,"one","two");
        doing(1,23,"one","two","three");
        doing(1,23,"one","two","three","four");
        //doing(1,23,new String[]{"one","two","three","four"});编译器在编译的时候相当于创建了数组
    }

    public static void doing(int age,long a,String... arg){
        System.out.println(arg.length);
        System.out.println(Arrays.toString(arg));
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值