0 0

不用构造方法也能创建对象?3

package go.test.com;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;
public class TestClass implements Serializable{
	private static final long serialVersionUID = 0L;
	public TestClass() throws Exception {
		throw new Exception("哎呀妈呀,异常啦!!!!");
	}

	public static void main(String[] args) throws Exception {
		byte[] head = { -84, -19, 0, 5, 115, 114, 0 };
		byte[] ass = { 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 120, 112 };
		String name = TestClass.class.getName();
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		baos.write(head);
		baos.write(name.length());
		baos.write(name.getBytes());
		baos.write(ass);
		baos.flush();
		baos.close();
		ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
		TestClass o = (TestClass) ois.readObject();
		ois.close();
		System.out.println("创建对象: " + o);
	}
}


别着急执行,先看看.你觉得能够正常执行吗?


对象创建的几种方法:
1.使用new关键字
2.使用clone方法
3.反射机制
4.反序列化
以上四种都可以产生java对象
1,3都会明确的显式的调用构造函数
2是在内存上对已有对象的影印 所以不会调用构造函数
4是从文件中还原类的对象 也不会调用构造函数

上述代码就是反序列化的结果

反序列化具体机制.还望能有高人详细指点.

--------------------------------------------------------------------
RednaxelaFX 写道
嗯顺带推荐Effective Java, Second Edition的第74条
引用
balabala.....

求原理. 实际上是创建了一个隐式构造函数对么?
昨天看了一小会儿源码.理解上还是模模糊糊.
问题补充
rocketball 写道
我愚见,应该是序列化的原因。你前面22代码写入的内容跟你实例化一个对象后的内容看看是不是一样的
我比较了下ttt.txt中内容跟你内容是一样的

是反序列化.感觉找到了点可以Geek的东西

问题补充
joknm 写道
Class.forName 算不算得到一个新对象的方法?

Class.forName应该会调用构造方法吧. 对于上面的对象 应该会抛出异常的....
问题补充
RednaxelaFX 写道
嗯顺带推荐Effective Java, Second Edition的第74条
引用
balabala.....


logicgate 写道
serializable对象的反序列化是不会调用constructor的,如果想控制序列化方式,可以在class中提供readObject()和writeObject()方法。


求原理. 实际上是创建了一个隐式构造函数对么?
昨天看了一小会儿源码.理解上还是模模糊糊.
问题补充
seele 写道
序列化里的信息包含 className.
反序列化 根据className进行强制转型

强制转型 怎么转的?
我感觉应该是先生成基类的对象.然后在此基础上构建子类. 但是怎么转型很疑惑

问题补充:可恶的管理员!!!! 跟本没看我的帖子什么内容. 瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!瞎转帖!!!!

问题补充:此帖不是问答贴.. 系管理员瞎转帖所谓. 问题关闭. 博客重发

问题补充:-----------------------------------------------------------
2010年12月23日 10:09

9个答案 按时间排序 按投票排序

0 0

其实蛮好理解的吧。

先从与技术无关的角度来看,一个object在被序列之前必定处于某个非初始状态,而构造函数使一块内存(object)处于初始状态,所以如果反序列化的时候调用[显式]构造函数必定会使一个已有状态的对象处于初始状态,这明显是不合逻辑的。

其次,上面提到了[显式]构造函数,看过oop 对象模型的都知道,构造函数其实由两部份组成:

第一部份是编译器帮你拼凑的,比如对virtual table的绑定,对象常量的初始值等等,这些值是跟对象的状态无关的,所以一般来说序列化的时候这些状态不会持久化到外部文件里,而造成空间浪费,但相应的反序列化的时候因为这些东西没有持久化,所以还是需要调用某些东西来还原这些常状态。

第二部份就是真正的我们写代码时可见的构造函数内容了。

而我认为,第一部份的构造内容,还是需要调用的,而这部份内容就叫隐式内容了。 (当然也和具体实现有关,我没看源码)

2010年12月23日 10:09
0 0

序列化里的信息包含 className.
反序列化 根据className进行强制转型

2010年12月23日 10:09
0 0

自己构造序列化后的数据,然后再反序列化回来,哈,这个思路高!

2010年12月23日 10:09
0 0

Class.forName 算不算得到一个新对象的方法?

2010年12月23日 10:09
0 0

serializable对象的反序列化是不会调用constructor的,如果想控制序列化方式,可以在class中提供readObject()和writeObject()方法。

2010年12月23日 10:09
0 0

RednaxelaFX 写道
嗯顺带推荐Effective Java, Second Edition的第74条
引用
A second cost of implementing Serializable is that it increases the likelihood
of bugs and security holes.
Normally, objects are created using constructors;
serialization is an extralinguistic mechanism for creating objects. Whether
you accept the default behavior or override it, deserialization is a “hidden constructor”
with all of the same issues as other constructors.
Because there is no
explicit constructor associated with deserialization, it is easy to forget that you
must ensure that it guarantees all of the invariants established by the constructors
and that it does not allow an attacker to gain access to the internals of the object
under construction. Relying on the default deserialization mechanism can easily
leave objects open to invariant corruption and illegal access (Item 76).


英文琢磨了半天,好不容易给看明白了。

2010年12月23日 10:09
0 0

aaa,不会吧

2010年12月23日 10:09
0 0

嗯顺带推荐Effective Java, Second Edition的第74条

引用
A second cost of implementing Serializable is that it increases the likelihood
of bugs and security holes.
Normally, objects are created using constructors;
serialization is an extralinguistic mechanism for creating objects. Whether
you accept the default behavior or override it, deserialization is a “hidden constructor”
with all of the same issues as other constructors.
Because there is no
explicit constructor associated with deserialization, it is easy to forget that you
must ensure that it guarantees all of the invariants established by the constructors
and that it does not allow an attacker to gain access to the internals of the object
under construction. Relying on the default deserialization mechanism can easily
leave objects open to invariant corruption and illegal access (Item 76).

2010年12月23日 10:09
0 0

我愚见,应该是序列化的原因。你前面22代码写入的内容跟你实例化一个对象后的内容看看是不是一样的
我比较了下ttt.txt中内容跟你内容是一样的

package go.test.com;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class TestClass implements Serializable{
	private static final long serialVersionUID = 0L;
	public TestClass() throws Exception {
		System.out.println("哎呀妈呀,异常啦!!!!");
	}
	public static void main(String[] args) throws Exception {
		byte[] head = { -84, -19, 0, 5, 115, 114, 0 };
		byte[] ass = { 0, 0,0, 0, 0, 0, 0, 0, 2, 0, 0, 120, 112};
		String name = TestClass.class.getName();
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		baos.write(head);
		baos.write(name.length());
		baos.write(name.getBytes());
		baos.write(ass);
		baos.flush();
		baos.close();
		ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
		TestClass o = (TestClass) ois.readObject();
		ois.close();
		System.out.println("创建对象: " + o);
		FileOutputStream fs=new FileOutputStream("E:\\ttt.txt");
		ObjectOutputStream oo=new ObjectOutputStream(fs);
		oo.writeObject(new TestClass());
		oo.close();
		FileInputStream fis = new FileInputStream("E:\\ttt.txt");  
        ObjectInputStream oooo = new ObjectInputStream(fis);  
        TestClass t= (TestClass) oooo.readObject();
        oooo.close();
		System.out.println("创建对象: " + t);
		System.out.println(name);
	}
}


2010年12月23日 10:09

相关推荐

    9.java学习第九章——对象的创建和使用+构造方法+方法重载——作业的形式:创建对象在JVM中的存储状态(内存图).pdf

    - 构造方法的名字必须与类名相同,没有返回值类型(即使是void也不行)。 #### 2. 构造方法的使用 - 默认构造方法:如果没有显式定义任何构造方法,Java编译器将自动提供一个默认构造方法。 - 显式构造方法:可以...

    构造方法JAVA构造方法

    如同其他方法一样,构造方法也可以被重载。这意味着一个类可以有多个构造器,每个具有不同的参数列表。这提供了更大的灵活性,使得可以根据不同需求创建对象。 ```java public class MyClass { private int ...

    类和对象、构造方法总结

    现在我们可以用这个构造方法创建带有初始名字的学生对象: ```java Student student3 = new Student("王五"); student3.id = 24680; student3.study("物理"); ``` `TestMain.java`和`Language.java`文件可能包含...

    类与对象、构造方法

    ●类的定义 ●对象的定义 ●类与对象 ●对象定义类的示例 ●实例变量 ●实例方法 ●实例成员的访问 ●对象的创建 ●构造方法 ●构造方法的特点 ●实例成员访问形式

    实验三:Java类与对象

    `Monkey`类中有默认构造方法和带参数的构造方法,后者允许我们在创建对象时立即设置属性值。 接着,我们学习了如何创建和使用对象。在Java中,通过`new`关键字和类的构造方法来创建对象。实验中,我们创建了两个`...

    子类对象构建调用父类的构造方法

    程序中描述了子类对象构建调用父类的构造方法,以及类变量和实例变量创建的不同过程

    java构造方法

    无参构造方法用于简单的初始化,而有参构造方法允许在创建对象时传递参数,这样可以在对象创建时设定更复杂的初始状态。 #### 四、构造方法的调用 构造方法在使用`new`关键字创建对象时被自动调用。此外,在一个类...

    java中带有不同构造方法的程序内存分析

    不过,如果构造方法创建了大量的临时对象或者资源,开发者需要确保在构造完成后及时释放这些资源,以避免内存泄漏。 总的来说,Java中带有不同构造方法的程序内存分析涉及构造方法的选择、内存的分配(包括栈和堆)...

    java 构造方法的资源

    构造方法的主要任务是在创建对象时设置对象的初始状态,为对象成员变量赋值。当一个类被实例化时,Java会自动调用该类的构造方法来完成初始化工作。 二、构造方法的声明 构造方法的声明格式如下: ```java public ...

    PHP的类、对象、构造方法。

    我们可以利用构造方法来初始化对象的属性,如下所示: ```php class Person { public $name; private $age; public function __construct($name, $age) { $this->name = $name; $this->age = $age; } } $p ...

    Java构造方法.pdf

    构造方法没有返回类型,也不能定义为void,在方法名前面不声明方法类型。构造方法的主要作用是完成对象的初始化工作,它能够把定义对象时的参数传给对象的域。 构造方法的语法格式 构造方法的语法格式如下所示: `...

    第04章 面向对象(上) 06 构造方法

    在Java中,构造方法是一个特殊的方法,它在创建对象时被自动调用,用于初始化新创建的对象的状态。本章节我们将深入探讨Java中的构造方法及其重要性。 首先,构造方法的命名必须与类名完全相同,不包含任何返回类型...

    Java构造方法解析.pdf

    // 使用无参构造方法创建对象 Student s1 = new Student(); // 使用带参构造方法创建对象 Student s2 = new Student("张三", 21); } } ``` 在上述代码中,Student类定义了两个构造方法,一个是无参的默认构造...

    Java 构造方法

    例如,如果类名为`Person`,那么它的构造方法也应该叫做`Person`。 2. **无返回类型**:构造方法不同于普通方法,它没有返回类型,即使`void`也不写。 3. **访问修饰符**:构造方法可以有各种访问修饰符,如`public`...

    MLDN魔乐JAVA_05构造方法、匿名对象.rar

    在Java编程语言中,构造方法和匿名对象是两个非常重要的概念,它们对于理解和创建对象起着关键作用。本文将深入探讨这两个主题,并结合实例进行详细解释。 首先,我们来看构造方法。构造方法是一种特殊的方法,它与...

    c#面向对象静态类、构造方法、静态方法介绍.zip

    接着,构造方法(Constructor)是C#类中的特殊方法,用于在创建对象时初始化其成员。构造方法与类名相同,没有返回类型。每个类可以有一个默认构造函数(无参数的构造器),也可以根据需求定义带参数的构造函数。...

    java四种创建对象的方式

    克隆方法创建对象是指利用对象自身的clone方法创建一个与原来对象内容相同的对象。这种方式不会调用原对象的构造方法。为了让一个类支持克隆操作,该类需要实现Cloneable接口。实现Cloneable接口的clone方法需要抛出...

Global site tag (gtag.js) - Google Analytics