• Java Class对象详解


    要怎样在java里来使用一个类,首先必须先把类的.class字节码文件加载进来,然后再进行连接对该类里的域分配内存,最后再调用构造器,如果该类有基类的话,会先去调用基类的构造器,总的来说,分为以下三个步骤。

    1.根据环境变量找到并加载.class文件
    2.为该类的非编译时常量分配内存
    3.调用该类的构造器

    java里的所有类都有一个Class对象,通过这个Class对象我们能够获取此类的各种信息。
    当某个字节码文件被JVM加载的时候,Class对象就被创建。
    Class类没有构造方法,是内部的一个defineClass方法来创建此对象的,此对象与被加载的字节码文件的类的类型相对应。

    其实在java里包括基本数据类型(int short long byte float double boolean char),也包括了void

            System.out.println(int.class.getName());
    		System.out.println(char.class.getName());
    		System.out.println(short.class.getName());
    		System.out.println(long.class.getName());
    		System.out.println(byte.class.getName());
    		System.out.println(float.class.getName());
    		System.out.println(double.class.getName());
    		System.out.println(boolean.class.getName());
    		System.out.println(void.class.getName());
    

    都有与之对应的class对象,同类型的类型也共享一个class对象。也包括了数组,所有同类型同维度的数组也共享一个class对象。

    public class Main {
    	public static void main(String[] args) {
    		System.out.println(char[].class.getName());//[C
    		System.out.println(char[][].class.getName());//[[C
    	}
    }
    

    class的forName方法

    同时class里有一个static的方法forName,可以让我们显示的来把一个类的.class文件加载至JVM虚拟机。

    static Class< ? > forName(String className)

    public class Main {
    	public static void main(String[] args) throws Exception{
    		Class a = Class.forName("A");
    	}
    }
    
    class A{
    	void print(){
    		System.out.println("hello world");
    	}
    }
    

    该方法返回的是一个Class对象,这个Class对象也可以添加泛型。
    这样的话我们就获得一个与A类型对应的Class对象。
    但是这时编译器会强制的让我们抛出或者捕获这个异常,所以我们需要将它捕获或者抛出。

    接下来我们还能重载一个A类的private的构造器(注:默认的构造器是隐式的static,我们重载之后就不再是static),但是我们仍然能获取它的class对象,因为调用构造器是在最后一步,而我们这里只是加载.class文件。

    public class Main {
    	public static void main(String[] args) throws ClassNotFoundException {
    		Class a = Class.forName("A");
    	}
    }
    
    
    class A{
    	private A(){
    		
    	}
    	void print(){
    		System.out.println("hello world");
    	}
    }
    
    

    这段代码是毫无错误的

    但是直到现在我们都还不能通过Class.forName来操作一个类,因为它只是简单的加载而已,但是没关系Class类还有一个newInstance方法,这个方法能帮助我们创建一个class类的实例,我们只需显示的转换一下类型即可操作A类.

    public class Main {
    	public static void main(String[] args) throws Exception {
    		A a = (A)Class.forName("A").newInstance();
    		a.print();
    	}
    }
    
    
    class A{
    	
    	void print(){
    		System.out.println("hello world");
    	}
    }
    

    这时,其实我们得到的就是一个A类型的实例了。

    但是如果我们这时把A的构造方法声明为private呢?

    public class Main {
    	public static void main(String[] args) throws Exception {
    		A a = (A)Class.forName("A").newInstance();
    		a.print();
    	}
    }
    
    
    class A{
    	private A(){
    		
    	}
    	void print(){
    		System.out.println("hello world");
    	}
    }
    

    编译器是仍然不会报错的,但是如果我们执行这段代码就会发现会抛出一个异常,因为这是在运行时加载的,所以编译器是无法察觉的。这也是相当危险的,所以一般情况下我们都会遵守用new来创建对象。

    既然class是运行时对象,那么对于final static 声明的域也是毫无作用的了,这么说的原因是用final static声明的域是不需要动态的来分配内存的,因为它是一个编译时常量。

    到现在我们大概明白了class的含义和运用,那它和.class有什么联系呢。
    其实每个类也有一个.class的常量,我们称为类字面常量,这个常量能够返回该类的class对象,也能通过newIstance创建实例来操作。

    运用类字面常量的好处就在于不用去抛出或者捕获异常,所犯的错误在编译时就能查找出来。

    public class Main {
    	public static void main(String[] args) throws Exception {
    		A a = (A)A.class.newInstance();
    		a.print();
    	}
    }
    
    
    class A{
    	void print(){
    		System.out.println("hello world");
    	}
    }
    

    封装类的TYPE

    这里以boolean类型来说明这个问题

    System.out.println(boolean.class == Boolean.TYPE);//true
    

    所以我们得出基本类型的.class 和 封装类的TYPE是等价的。

  • 相关阅读:
    ES 入门记录之 match和term查询的区别
    ElasticSearch 学习记录之Text keyword 两种基本类型区别
    ES 记录之如何创建一个索引映射,以及一些设置
    娱乐至死 读书笔记
    ES 入门之一 安装ElasticSearcha
    王二的经济学故事 读书笔记
    redis特性 存储 API 集群 等
    Linux 卸载 openjdk
    Linux 下面解压.tar.gz 和.gz文件解压的方式
    本地连接 vmware服务器
  • 原文地址:https://www.cnblogs.com/haodawang/p/5967204.html
Copyright © 2020-2023  润新知