前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java- Class.forName() 和 Xxx.class

Java- Class.forName() 和 Xxx.class

作者头像
桑鱼
发布2020-03-18 15:14:07
5800
发布2020-03-18 15:14:07
举报

每个类都有一个Class对象。就是说,每当编写并且编译了一个新类,就会产生一个Class对象,被保存在一个同名的.class文件中。c

所有的类都是在第一次使用时,动态加载到JVM中的。比如使用new操作符创建类的新对象(构造器是默认类的静态方法)。

一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。

class Candy{
    static {
        System.out.println("Loading Candy");
    }
}

class Gum{
    static {
        System.out.println("Loading Gum");
    }
}

class Cookie{
    static {
        System.out.println("Loading Cookie");
    }
}

public class SweetShop {
    public static void main(String[] args) {
        System.out.println("inside main");
        new Candy();
        System.out.println("After creating Candy");
        try {
            Class.forName("com.sangyu.test.test21.Gum");
        } catch (ClassNotFoundException e) {
            System.out.println("Could not find Gum");
        }

        System.out.println("After Class.forName(\"Gum\")");
        new Cookie();
        System.out.println("After creating Cookie");
    }
}

上面例子中,每个类Candy、Gum、Cookie,都有一个static子句,该子句在类第一次被加载时执行。这时会有相应的信息打印出来,告诉我们这个类什么时候被加载了。

Class.forName("Gum") 这个方法是Class类的静态方法,需要用一个包含目标类的文本名(注意拼写和大小写)的String作为输入参数,返回的是Class对象的引用。这个方法还有一个其他的作用:如果类Gum没有被加载的情况,调用这个方法时就会被加载。在加载过程中,Gum的static子句被执行

package com.sangyu.test.test21;

interface HasBatteries{}
interface Waterproof{}
interface Shoots{}

class Toy{
    Toy(){}
    Toy(int i){}
}

class FancyToy extends Toy implements HasBatteries,Waterproof,Shoots{
    FancyToy(){
        super(1);
    }
}
public class ToyTest {
    static void printInfo(Class cc){
        System.out.println("Class name: " + cc.getName() + " is interface? [" + cc.isInterface() + "]");
        System.out.println("Simple name: " + cc.getSimpleName());
        System.out.println("Canonical name: " + cc.getCanonicalName());
        System.out.println("------------------------------------------------");
    }

    public static void main(String[] args) {
        Class c = null;
        try{
            c = Class.forName("com.sangyu.test.test21.FancyToy"); //
        } catch (ClassNotFoundException e) {
            System.out.println("Can't find FancyToy");
        }
        printInfo(c);
        for(Class face : c.getInterfaces()){
            printInfo(face);
        }
        Class up = c.getSuperclass();
        Object obj = null;
        try {
            obj = up.newInstance();
        } catch (IllegalAccessException e) {
            System.out.println("Can't instantiate");
        } catch (InstantiationException e) {
            System.out.println("Can't access");
        }
        printInfo(obj.getClass());
    }
}

FancyToy 继承Toy并实现HasBatteries,Waterproof,Shoots接口,main()方法中创建了Class的引用,并将其指向了FancyToy。printInfo()方法中getName()获得全限定的类名,isInterface()判断是否为接口,getSimpleName()获得不含包名的类名,getCanonicalName()获得全限定的类名。main()方法中其他的方法比如getInterfaces()返回Class中所包含的接口,getSuperclass()获得基类,newInstance() 创建实例。在上面例子中,getSuperclass()获得的class引用指向了up,在创建实例时,Object的引用指向的是Toy对象。另外,使用newInstance() 来创建的类,必须带有默认的构造器

Java还提供了另一种方法来生成对Class对象的引用,对上述程序可以这么写:FancyToy.class; 这样做不仅要简单,而且更安全,因为它在编译时就会受到检查(因此不需要置于try语句块中),并且根除了对forName()方法的调用,所以也更高效。

当使用.class来创建对Class对象的引用时,不会自动地初始化该Class对象。

class Initable{
    static final int staticFinal = 47;
    static final int staticFinal2 = ClassInitialization.rand.nextInt(1000);
    static {
        System.out.println("Initializing Initable");
    }
}

class Initable2{
    static int staticNonFinal = 147;
    static {
        System.out.println("Initializing Initable2");
    }
}

class Initable3{
    static int staticNonFinal = 74;
    static {
        System.out.println("Initializing Initable3");
    }
}
public class ClassInitialization {
    public static Random rand = new Random(47);

    public static void main(String[] args) throws ClassNotFoundException {
        Class initable = Initable.class;
        System.out.println("After creating Initable ref");

        System.out.println(Initable.staticFinal);
        System.out.println(Initable.staticFinal2);
        System.out.println(Initable2.staticNonFinal);

        Class initable3 = Class.forName("com.sangyu.test.test21.Initable3");
        System.out.println("After creating Initable3 ref");
        System.out.println(Initable3.staticNonFinal);
    }
}

在上述例子中,Initable引用的创建不会引发初始化,Class.forName("Initable3") 立即进行了初始化。static final 修饰的值是编译器常量,Initable类没有初始化就可以访问,但staticFinal2并非编译器常量,所以在访问时强制进行类的初始化。Initable2.staticNonFinal 是一个static域不会final的,在对它访问时,要先进行链接(为这个域分配存储空间)和初始化(初始化该存储空间)。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档