Java笔记-反射

反射:

通过java语言的反射机制可以操作字节码文件。
在java.lang.reflect.*;的包下。

反射机制重要的类:

java.lang.Class; //代表整个字节码文件
java.lang.reflect.Method; //代表字节码中的方法字节码
java.lang.reflect.Constructor; //代表字节码中的构造方法字节码
java.lang.Field; //代表字节码中的属性字节码。类中的成员变量,包括静态变量、实例变量。

java.lang.Class:

获取java.lang.Class的方式:
1.用Class.forName()来获取:1.静态方法。2.方法的参数是一个字符串。3.字符串需要是一个完整类名。4.完整类名带有包名。
2.用getClass()方法来获取:任何一个对象都有getClass()方法。返回当前对象方法区的字节码文件。
3.用class属性来获取:java语言中任何一种类型,包括基本数据类型,都有class属性。

  • 可以通过获得当前的Class文件(c),使用c.newInstance()来创建对象。通过反射机制创建对象。此时,只需要修改
    配置文件中的信息,就可以实现创建不同对象的功能。
  • 使用Class.forName(“完整类名”); 会导致类加载,这样可以只执行这个类的静态代码块。

java.lang.Field:

通过 类名.getFields() 可以得到field数组,数组中是类中所有public修饰的属性。
通过得到的field.getName(),方法可以得到属性名。
类名.getDeclaredFields(),可以获得类中所有属性。
field.getType(),可以得到当前属性的类型,返回一个class,可以通过field.getType().getName()获得类型名字。
getModifiers(),class中的方法,可以返回此类或接口的修饰符,返回的是int类型,
可以通过Modifiers中的toString(int mod) 方法,将返回的int类型数据转换为对应的修饰符。

使用反射机制去访问一个对象的属性:

Class studentClass = Class.forName("reflesh.student");
        Object obj = studentClass.newInstance();//obj是student对象,底层调用无参构造方法。

        //获取名字为no的属性
        Field noField = studentClass.getField("no");

        //给obj对象的no属性赋值222.
        noField.set(obj,222);

//读取obj对象的no属性的值。
        noField.get(obj);

注意:以上访问只能访问public类型的,private类型的需要用Field类中的方法**setAccessible(true)**来打破封装,才可以获取。

java.lang.reflect.Method:

通过 类名.getDeclaredMethods() 返回一个Methods数组,数组中存放对象的所有方法。
Method.getName();//返回方法的名字
Method.getModifiers();//返回修饰符列表,返回的是数值
Method.toString();//通常将Method.getModifiers()返回的数值传进去,返回修饰符列表。
Method.getReturnType();//可以获得方法的返回值类型。可配合.getSimpleName()使用。
Method.getParameterTypes();//可以获得参数类型数组,通过getSimpleName()方法可以看到属性。

使用反射机制去调用一个对象的方法(重点):

例如:

public static void main(String[] args) throws Exception {
        Class student = Class.forName("reflesh.student");//获取类
        Object obj = student.newInstance();//用类来new对象
        Method method = student.getDeclaredMethod("login",String.class,String.class);//获取对象的方法
        Object result = method.invoke(obj,"admin","123");//将方法和这个对象绑定,传参。
    }

反射机制让代码具有通用性,可变化的内容写到配置文件中。修改配置文件可以创建不同的对象和方法,java代码不需要修改。

java.lang.reflect.Constructor:

通过类名.getDeclaredConstructors();获得一个Constructor数组,里面存放对象的所有构造方法。
通过constructor.getModifiers();获得构造方法的修饰符
通过constructors.getParameterTypes();可以获得当前构造方法的参数类型数组

用反射调构造方法:

无参数构造方法:

Class student = Class.forName("reflesh.student");
        Object obj = student.newInstance();

有参数构造方法:

Class student = Class.forName("reflesh.student");
Constructor con = student.getDeclaredConstructor(String.class,String.class);
con.newInstance("sun","6225");

路径问题:

解决通常情况下,代码交换位置出现的路径问题,前提条件:文件必须在类路径(在src下的都是类路径)下。

String path = Thread.currentThread().getContextClassLoader().getResource("test.properties").getPath();
Thread.currentThread()当前线程对象。
getContextClassLoader线程对象的方法,可以获得当前线程的类加载器对象。
getResource()获得资源,类加载器的方法,当前线程的类加载器默认从根路径下加载资源。

也可以在类加载器中使用getResourceAsStream()方法得到流。
例如:

InputStream reader =  Thread.currentThread().getContextClassLoader().getResourceAsStream("test.properties");

资源绑定器:

使用这种方式时,配置属性文件必须放在类路径下。并且只能绑定xx.properties文件。
在写路径的时候,路径后面的扩展名不能写。

ResourceBundle bundle = ResourceBundle.getBundle("test");
        String className = bundle.getString("ClassName");

类加载器:

专门负责加载类的命令/工具。ClassLoader
JDK自带的3个类加载器:
1.启动类加载器:
代码在开始执行前,会将所需要的类全部加载到JVM中。首先通过启动类加载器加载.class文件,专门加载核心类库(rt.jar)。
2.扩展类加载器:
如果通过启动类加载器加载不到时,会通过扩展类加载器加载。扩展类加载器专门加载ext目录中的文件。
3.应用类加载器:
如果扩展类加载器也没有找到,会通过应用类加载器加载,应用类加载器专门加载classpath中的jar包。

双亲委派机制:

为了保证类加载的安全,优先从启动类加载器中加载(父),再从扩展类加载器中加载(母),如果都加载不到
才会考虑从应用类加载器中加载。

可变长度参数:

在方法的参数中,类型的后面加…可以实现。
例如:public static void add(int… args)
可以将可变长度参数当作一个数组来看。
例如:

public static void main(String[] args) {
        reflesh3.printString("abc","efg","ghj");//这里也可以直接传一个数组
    }
    public static void printString(String...args){
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
    }

注意:可变长参数只能有1个,且必须在参数列表的最后。

如何获得一个类的父类:

通过getSuperclass()来获取父类。
例如:

public static void main(String[] args) throws Exception{
        Class stringClass = Class.forName("java.lang.String");
        Class superClass = stringClass.getSuperclass();
        System.out.println(superClass.getSimpleName());
    }

如何获得一个类的所有接口:

通过getInterfaces()方法来获得一个数组,数组中存放对象的所有接口。
例如:

 public static void main(String[] args) throws Exception{
        Class stringClass = Class.forName("java.lang.String");
        Class[] interfaces = stringClass.getInterfaces();
        for(Class in : interfaces){
            System.out.println(in.getSimpleName());
        }  
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值