栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

反射、类对象和类加载器

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

反射、类对象和类加载器

反射代码实现 通过反射创建对象

用Class.forNamw通过类名获取字节码文件(Class类型的对象代表某一个类的字节码文件),然后通过newInstance创建对象,代替new创建对象。Class.forname()方法最早我们在使用jdbc驱动开发JSP程序的时候经常用,是不是很熟悉。

//目标类,没有实现set,get方法
public class Target {
    public String name;
    private int age;//私有属性
    public void doSome(){
        System.out.println("doSome");
    }
}
//测试类
public class Test66 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class targetClass=Class.forName("demo.Target");//完整包名
        Target target= (Target) targetClass.newInstance();//调用无参构造方法构造的对象
        target.doSome();
}

结果:

可以看到不使用Target target = new Target(); 也可以实现对象创建。这样的好处是,让程序更加灵活,在不改变Java代码的情况下,可以通过读属性文件创建对象,做到不同对象的实例化(比如只需要修改properties文件中的value),其实就是遵循了OCP(开闭原则:对扩展开发,对修改关闭。)

反射机制的其他重要方法

getDeclaredField获取属性、getDeclaredMethod获取方法、invoke进行方法调用

注意:牢记这几个方法,在日常开发中,一看到这几个方法就想到是反射,那么学习反射的目的就达到了(阅读Spring源码等)

//测试类
public class Test66 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
        Class targetClass=Class.forName("demo.Target");//完整包名
        Target target= (Target) targetClass.newInstance();//调用无参构造方法构造的对象
        //反射机制获取类的公共属性
        Field nameFiled = targetClass.getDeclaredField("name");
        nameFiled.set(target,"反射");//给target对象的no属性赋值,语法有点诡异
        String name = (String) nameFiled.get(target);//获取属性值
        System.out.println("target对象的name属性的值为:"+name);
        //反射机制获取累的私有属性
        Field ageFiled = targetClass.getDeclaredField("age");
        //age是Target类的私有属性,不能直接访问。
        ageFiled.setAccessible(true);//打破封装,这也是反射机制的缺点,危险
        ageFiled.set(target,18);
        int age = (int) ageFiled.get(target);
        System.out.println("target对象的age属性的值为:"+age);
        //getDeclaredMethod获取类的方法
        Method doSome = targetClass.getDeclaredMethod("doSome");
        doSome.invoke(target);//获取到方法后再用invoke调用
}

对java类的私有属性和封装的理解,请参考Java类的私有属性和封装的理解_source code August的博客-CSDN博客

类对象

类对象(Class类型的对象代表某一个类的字节码文件)

类对象的三种不同获取方式:

public class Test2222 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class targetClass=Class.forName("demo.Target");//通过类名获取类对象
        Class targetClass1 = Target.class;
        Class targetClass2 = new Target().getClass();
        System.out.println(targetClass==targetClass1);//true
        System.out.println(targetClass==targetClass2);//true
    }
}

补充:

Class.forname()方法的执行会导致:类加载,而JVM加载类时会执行静态代码块,所以如果只希望一个类的静态代码块执行,其他代码不执行,就可以用Class.forname()方法。实例代码如下:

//目标类
public class Target {
    public String name;
    private int age;
    public static void doOther(){
        System.out.println("静态方法");
    }
    public static int itemCapacity=8; //声明的时候 初始化
    static{
        //静态代码块中的属性
        itemCapacity = 6;//静态初始化块 初始化
        System.out.println("静态代码块执行");
    }
}
//测试类

public class Test2222 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class targetClass=Class.forName("demo.Target");//通过类名获取类对象
//      System.out.println(Target.itemCapacity);//观察静态代码块执行后属性的值
}

运行结果:

所以只执行Class.forname()方法,静态代码块会执行。同时补充一点,实例化对象是在类加载之后的,所以如果你执行了new,那么类加载一定做了,如果类有静态代码块,那也一定执行了。还需注意,我们在属性itemCapacity定义的时候赋值为8了,但是在类加载之后(静态代码块执行之后),结果是6,不信可以试一试。

类加载器ClassLoader

ClassLoader是专门负责加载类的命令/工具,代码在开始执行之前,会将所需要的类全部加载到JVM中。(简单理解)

类加载器的作用有类加载和类缓存,.java文件在经过编译之后会变成.class字节码文件,类加载器将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。这是类加载的作用。但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间,不过JVM垃圾回收机制(gc)可以回收这些Class对象,这是类缓存的作用。(复杂理解,来自网络)

JDK中有三个类加载器:启动类加载器,扩展类加载器,应用类加载器

假设有一段代码:String s="abc";

通过类加载器加载,看到以上代码,类加载器会找String.class文件,找到就加载

首先,通过”启动类加载器“专门加载:C:Program FilesJavajdk1.8jrelibrt.jar

注意rt.jar中都是JDK最核心的类库

如果通过”启动类加载器“找不到的时候,会通过”扩展类加载器“加载,专门加载:C:Program FilesJavajdk1.8jrelibext.jar

如果通过“扩展类加载器”加载不到的时候,会通过“应用类加载器”加载,专门加载classpath中的类。

双亲委派机制

为了面试了解一下吧。双亲委派机制就是优先加载前两个类加载器,防止黑客植入后门程序,比如自己写个String,自己写的是在应用加载器加载,有双亲委派机制,就会调用启动类加载器优先加载JDK自己的String。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/343686.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号