• Java基础之反射总结


    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

    Java是一门面向对象语言,万物皆对象。对象是由类new出来的。例如我们有一个Dog类:

    public class Dog{ }

    创建一个Dog对象:Dog dog = new Dog();这个dog就是一个对象。

    既然万物皆对象,那么Dog这个类是什么类的对象呢?答案就是Class类的对象。在Java中所有类都是Class类的对象。官方叫做类的ClassType:类类型。

    类类型的获取有三种方式:

    Class c1 = Dog.class;

    Class c2 = dog.getClass();

    Class c3 = Class.forName("Dog");

    通过类的类类型,可以创建类的实例对象: Dog dog = Dog.class.newInstance();

    Class的常用操作:

    package com.shtel.test.reflection;
    import java.lang.reflect.Array;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
     
    //Class 测试
    public class ClassTest {
     
        //定义私有构造器
        @SuppressWarnings("unused")
        private ClassTest() {
             
        }
         
        //定义一个有参构造器
        public ClassTest(String name) {
            this.name=name;
            System.out.println("执行有参构造器");
        }
         
        //定义两个私有属性,一个公共属性
        private String name = "rose";
        private Number age;
        public String getName() {
            return name;
        }
     
        public void setName(String name) {
            this.name = name;
        }
     
        public Number getAge() {
            return age;
        }
     
        public void setAge(Number age) {
            this.age = age;
        }
        public String hobby;
         
        //定义一个无参的info方法
        public void info() {
            System.out.println("执行无参的info方法");
        }
         
        //定义一个有参的info方法
        public void info(String str) {
            System.out.println("执行有参的info方法;参数="+str);
        }
         
        //定义一个私有方法
        private void pri() {
            System.out.println("执行私有方法");
        }
         
        //定义测试内部类
        class Inner{}
         
        public static void main(String[] args) throws Exception {
             
            //获取ClassTest的类类型
            Class<ClassTest> clazz = ClassTest.class;
             
            //获取ClassTest的全部构造器
            Constructor[] decConstructors = clazz.getDeclaredConstructors();
            System.out.println("ClassTest全部构造器:");
            for(Constructor ctr : decConstructors) {
                System.out.println(ctr);
            }
             
            //获取ClassTest的全部public构造器
            Constructor[] constructors = clazz.getConstructors();
            System.out.println("ClassTest全部public构造器:");
            for(Constructor ctr : constructors) {
                System.out.println(ctr);
            }
             
            //获取ClassTest全部public方法
            Method[] methods = clazz.getMethods();
            System.out.println("ClassTest全部public方法:");
            for(Method mth : methods) {
                System.out.println(mth);
            }
             
            //获取指定放方法
            System.out.println("获取指定方法:"+clazz.getMethod("info", String.class));
             
            //获取ClassTest全部内部类
            Class<?>[] inners = clazz.getDeclaredClasses();
            System.out.println("ClassTest全部内部类:");
            for(Class<?> inner : inners) {
                System.out.println(inner);
            }
             
            //获取ClassTest全部public属性
            Field[] fileds = clazz.getFields();
            System.out.println("ClassTest全部public属性:");
            for(Field f : fileds) {
                System.out.println(f);
            }      
             
            //获取ClassTest全部public属性
            Field[] decFileds = clazz.getDeclaredFields();
            System.out.println("ClassTest全部属性:");
            for(Field f : decFileds) {
                System.out.println(f);
            }
             
            //通过Class创建对象
            ClassTest ct = clazz.newInstance();
            //指定构造器创建实例对象
            ClassTest ct1 = clazz.getConstructor(String.class).newInstance("lucy");
            System.out.println(ct.name);
            System.out.println(ct1.name);
             
            //通过Class调用方法
            Method info = clazz.getMethod("info", String.class);
            info.invoke(ct1, "hello");
            //通过Class调用私有方法
            Method pri = clazz.getDeclaredMethod("pri");
            //取消访问权限检查
            pri.setAccessible(true);
            pri.invoke(ct);
             
            //动态创建数组(java.lang.reflect包下还提供一个Array类,用来动态的创建数组操作数组)
            Object arr = Array.newInstance(String.class, 10);
            Array.set(arr, 0, "零");
            Array.set(arr, 1, "一");
            System.out.println(Array.get(arr, 0) +"
    "+ Array.get(arr, 1));
        }
    }
    类的静态加载和动态加载:
    
    编译时刻加载类称为静态加载,运行时刻加载类称为动态加载,使用new方法新建实例即为静态加载类,在编译时候就要加载全部类。
    
    例子:
    
    
    public class CreateDog(){   
        public static void main(String[] args) {
            //参数传入金毛,就创建金毛,调用对应bark方法
            if(args[0].equals("JinMao")) {  
                new JinMao().bark();
            }
            //参数传入哈士奇,就创建哈士奇,调用对应bark方法
            if(args[0].equals("HaShiQi")) { 
                new HaShiQi().bark();
            }
         }
    }
    //金毛类
    public class JinMao(){
        public void brak(){
            System.out.println("JinMao !");
        }
    }

    当我们编译CreateDog类的时候会报错,找不到HaShiQi这个类,因为这个类还没有写。这就是静态加载,要在编译时刻加载所有用到的类。假如某个项目有100个功能,每个功能都有一个类。那就必须这个一百个类都正常存在,那么这个程序才能使用。但是我们往往使用的就是其中一个功能,由于其他类的缺少,这个功能也不能使用。这就是静态加载的弊端。

    为了解决这个问题,我们可以使用动态加载,将上面的例子修改如下:

    public interface Dog {
             void bark();
    }
    public Class JinMao implements Dog(){
        public void bark(){
            System.out.println("JinMao !");
        }
    }
    public class CreateDog(){   
        public static void main(String[] args) {
            try{
            Dog dog = (Dog)Class.forName(args[0]).newInstance();
            dog.bark();
            } catch(Exception e){
                e.printStackTrace();
            }
         }
    }

    这是再来编译程序就不会出错。当我们传入参数是JinMao的时候,就会调用JinMao.bark()方法。当我门传入参数是HaShiQi的时候会报ClassNotFoundException(因为没写HaShiQi类)。倘若我只想听金毛的叫声,这个程序是可以的,不会因为没有哈士奇而不能听金毛的叫声。这就解决了静态加载的弊端。

    通过类类型可以获取这个类的所有的方法和属性:

    public static void getClassMethodMessage(Object obj){
        Class<? extends Object> c = obj.getClass();
        Method[] methods = c.getMethods();
        for(int i=0;i<methods.length;i++){
            //获取类里的方法名称
            System.out.print(methods[i].getName()+"(");
            //获取方法的参数数组
            Class<?>[] paramType = methods[i].getParameterTypes();
        for(Class<?> c1 : paramType){
            System.out.print(c1.getName()+",");
        }
        System.out.print(")");
        System.out.println();
        }
    }
    public static void getClassFiledMessage(Object obj){
            Class<? extends Object> c = obj.getClass();
            //获取类属性
            Field[] fileds = c.getFields();
            for(Field f:fileds){
                System.out.println(f.getName());
            }
        }

    通过反射调用方法:

    public class ReflectTest {
        public static void main(String[] args) {
        try {
                Class<Dog> c = Dog.class;
                Dog dog = (Dog)c.newInstance();
                Method eat = c.getMethod("eat",String.class);
                eat.invoke(dog,"大骨头");
            }  catch (Exception e) {
                e.printStackTrace();
                }
            }
    }
    public class Dog {
        private String DogName;
        public String getDogName() {
            return DogName;
        }
        public void setDogName(String dogName) {
            DogName = dogName;
        }
        public void brak(){
            System.out.println("狗叫了");
        }
        public void eat(String food){
            System.out.println("我正在吃"+food);
        }
    }
  • 相关阅读:
    C#获取本地IP地址
    C#中将字符串转换成数值
    JavaScript实现基于对象的双端队列
    Java网络编程
    JavaScript实现基于对象的队列
    JavaScript实现基于对象的栈
    JavaScript实现基于数组的栈
    发送短信按钮倒计时案例
    JavaScript动态显示时间
    html
  • 原文地址:https://www.cnblogs.com/jnba/p/10518540.html
Copyright © 2020-2023  润新知