首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > J2SE开发 >

Java对象创造过程

2011-12-15 
Java对象创建过程Java对象被创建有两种方式:第一种是通过new XX()第二种是Class.forName(XX).newInstan

Java对象创建过程
Java对象被创建有两种方式:第一种是通过new XX();第二种是Class.forName("XX").newInstance().我现在对这个流程的认识有些混乱.
  要生成一个类的对象,必须有两样东西被加载到内存,一种是Class对象;另一种是类,然后类对象才会被创建.由于Java是动态加载(类的静态成员被引用,类才会别加载),所以类加载的时候相对于上面的两种方式分别是在:第一种:new XX(),因为构造器方法也是静态方法,这种方式会调用构造器方法,所以此时类会被加载;第二种:Class.forName()首先会检查类有无被加载,没有则加载类.至此,两种方式的类都被加载.
  我的疑问是Class对象是何时被加载的,是和类一样吗?(我现在知道的关于Class对象的知识就是它是在.java文件被创建,被编译后产生了和类名字一样的.class文件.)是在类被加载之前还是之后,还有Class对象是怎么和类配合生成类对象的...希望大家能多多发表自己的见解.

[解决办法]
怎么说的有点乱七八糟的啊,加载类就是加载Class对象。

new XX();
Class.forName("XX").newInstance();
这两种效果一样,加载方式也一样,毫无区别,newInstance()实际上也是调用默认构造器方法的。
只是在用的场合不一样,前面一种用的很普遍。后面一种一般都是结合工厂模式应用的比较多。
[解决办法]
这两种方式效果是一样的,但是稍微有以下两点小区别:
区别1:Class.forName的方式能实现动态地载和创建Class 对象,而NEW指定生成某个类的对象
例:String str = 你定义的字符串
Class t = Class.forName(str); 
t.newInstance();
区别2:JAVA的工厂模式中常使用Class.forName方式创建对象

[解决办法]
class Test{
}
还有一种方式,
Class<?> i=Test.class ;
i.newInstance();
不同之处:LZ列举上面2种都会伴随类的初始化,而这种不会伴随类的初始化。

[解决办法]
加载class二进制文件,生成该类对应的Class对象。
[解决办法]
ClassLoader读取class文件内容得到一个byte[],
然后就可以调用defineClass来在ClassLoader中生成Class
[解决办法]
http://java.sun.com/docs/books/jvms/second_edition/html/ConstantPool.doc.html
[解决办法]

探讨
加载类就是加载Class对象,这句话是对的吗?这个话是一楼的大哥说的.我只是求证下

[解决办法]
关键是 static initialization
class A {
//
static {
System.out.println("haha");
}
}
这个东西类似常量的初始化。

第一种调用方法,VM 启动的时候,会去找所有被 import 了的类,如果找到了,这段代码就会被调用。也就是一启动就会调用。
第二种方法,如果你一直没有 import 这个类,vm 一直等到 Class.forName("XX").newInstance() 才会调。如果 static initialization 里面写了很多代码,又不想在不需要的时候调用它们,就只有第二种方法来。
[解决办法]
编译:类名.java -> 类名.class
运行:类装载器 ->字节码验证器->....->通过JIT等生成存储在内存中的可执行代码...
首先是类装载器根据 类名.class 在文件中找到相应的 类名.class,然后加载该 类名.class,及将类名.class文件转化为java虚拟机中的类字节码。
Class.forName("XX") 返回值是一个Class类的实例对象,该Class对象封装了 XX.class的字节码数据,也就是生成存储在内存中的可执行代码。//Class类的作用
Class.forName("XX").newInstance() 返回的是XX.class类 中XX的一个实例对象。
举个例子:
public class classObjectTest{
public static void main(String args[])throws ClassNotFoundException{
Class c;
classObjectTest cot=new classObjectTest();
c=Class.forName("classObjectTest");//相当于c=cot.getClass();
System.out.println(cot);
System.out.println(c);
System.out.println(c.getName());

}
}
结果:D:\>java classObjectTest
classObjectTest@de6ced
class classObjectTest
classObjectTest
也不知道对不对,有点晕了
[解决办法]
说明一下加载的过程:
public class LoaderTest{
public static void main(String args[])throws ClassNotFoundException{
Class c;
LoaderTest lt=new LoaderTest();
c=Class.forName("LoaderTest");
System.out.println(c);
System.out.println(c.getName());
System.out.println(c.getClassLoader());
System.out.println(c.getClassLoader().getParent());
System.out.println(c.getClassLoader().getParent().getParent());


 }
}
class LoaderTest
LoaderTest
sun.misc.Launcher$AppClassLoader@19821f
sun.misc.Launcher$ExtClassLoader@addbf1
null
首先对于编译后的LoaderTest.class,必须要知道哪个加载器来加载,(下面是一种委托模式,及子类加载器都先调用父类加载器加载)首先调用AppClassLoader来加载,但AppClassLoader会让他继承的父类加载器ExtClassLoader加载LoaderTest.class,ExtClassLoader没有父类加载器(返回值为null),将LoaderTest.class转交给虚拟内核中的Bootstrap,由于Bootstrap只能加载java核心包中的类,所以告诉ExtClassLoader自己不能加载,ExtClassLoader是用来加载%JAVA_HOME%/jre/lib/ext/中的jar包中类,自己也不能加载LoaderTest.class,于是就告诉AppClassLoader自己不能加载该LoaderTest.class。由于AppClassLoader可以加载应用程序的启动态,可以加载该LoaderTest.class,
然后就像上面说的那样,加载时生成了一个个Class类的实例对象,该Class对象封装了 LoaderTest.class的字节码数据,也就是生成存储在内存中的可执行代码。我们可以通过Class.forName("LoaderTest").getName()获得这个Class对象的名称,通过Class.forName("LoaderTest").newInstance()来获得 LoaderTest这个类的对象。

[解决办法]
类加载器为程序的执行加载所需要的全部类。类加载器将局部文件系统的类名空间与来自网络源的类名空间相分离,以增加安全性。由于局部类总是首先加载,因而可限制任何“特洛依木马”的应用。
当全部类被加载后,可执行文件的记忆体格式被确定。这时,特定的内存地址被分配给符号引用并创建检索表格。由于记忆体格式在运行时出现,因而Java技术解释器增加了保护以防止对限制代码区的非法进入。

网上找了些资料,有用的话就好了。。。


[解决办法]
java虚拟机使用每个类的第一件事就是将该类的字节码撞进来。类装载器负责根据一个类的名称来定位和生成类的字节码数据后返回给java虚拟机。如,UTF-8编码形式的.class 文件,装进java虚拟机后要被转换成Unicode 编码,装载类本身也是一个java类,当一个类被夹在后,java虚拟机将其编译成可执行代码存储在内存中,并将索引信息存储在一个HashTable中,索引关键字就是这个类的完整名称。在java虚拟机需要用到某个类时,首先通过hashtable查找相应的信息,如果该可执行代码已经存在,java虚拟机就直接从内存中调用该可执行代码,否则调用类装载器加载。
[解决办法]
在调用Class.forName("")时,类会被初始化,调用newInstance()产生类的实例
使用new时,JVM同样先初始化类,然后再产生实例

Class.forName("")是动态加载,并且被加载的类有一定的限制,它必须有一个默认的,有访问权限的无参构造器,否则会抛出异常(可以编译)
而new则相对必较灵活,它不需要默认的无参构造器,没有访问权限的话将无法编译
[解决办法]

探讨
LZ概念上有点混乱.

A.java--编译器--->A.class--ClassLoader(当第一次A a = new A();或者Class.forName("A")时加载)-->
java.lang.Class类型的对象(暂且命名aCls).

1)A.java编译后就可以抛弃了,jvm使用的是A.class.把A.java删除后,A.class可以正常使用,就证明了这点.
2)当第一次生成一个类的对象时,会有一个合适的ClassLoader去把A.class文件读取并加载入内存.
3)接着jvm生成一个描述该类的java.lang.Class类型的对象,可以通过 Class aCls = a.getClass();获得getClass()方法继承自java.lang.Object类.一个类无论被实例多少次,都只会有一个该类的Class类型的对象,就是第一次加载时产生的.

最后,我们所说的A类,不是指A.java或者A.class也不是aCls,而是指一种类型,A类型.前两者是文件,后者是对象.简单的说,鸟类就是鸟类,我也说不明白了,看来只可意会,不可言传啊.哈哈.


热点排行
Bad Request.