- 浏览: 118029 次
- 性别:
- 来自: 北京
最新评论
-
supertangcugu:
senninha 写道然鹅。。jdk1.8已经把这货移到了he ...
小例子:如何说明String常量池的位置 -
senninha:
然鹅。。jdk1.8已经把这货移到了heap区?只有把-Xmx ...
小例子:如何说明String常量池的位置 -
onada1108:
还有你是基于jdk那个版本
小例子:如何说明String常量池的位置 -
onada1108:
我想问下,你这个方法跑啦多长时间
小例子:如何说明String常量池的位置 -
hu_xuefeng:
hsbljyy 写道看来真的有很多谬误啊!当变量在-128~1 ...
从“关于Java堆与栈的思考”一帖看错误信息的传播
关于java的构造方法有几个简单的问题:
1.构造方法有返回值吗?
没有。构造方法没有任何返回类型,也不允许是void。比如:
public class Test {
//这不是构造函数!
public void Test() {
System.out.println("void Test()");
}
public static void main(String[] args) {
Test test = new Test();
test.Test();
}
}
这里我们定义了一个返回类型为void的Test()方法,有了返回类型void,它就不是构造方法了。
Test test = new Test();
有人用上面的表达式来说明构造方法返回对象引用,这是明显错误的。new关键字有两个作用。一是分配内存,
创建对象。二是调用构造方法,完成对象的初始化工作。完成这两步之后,才算创建了一个完整的Java对象。我们
可以用Test test = new Test();的反编译代码来说明这个问题:
0: new #5; //class Test
3: dup
4: invokespecial #6; //Method "":()V
7: astore_1
原表达式被编译成四条bytecode指令。
new指令负责根据参数分配内存并创建Test对象,然后将新创建对象的引用置于栈顶。
dup指令复制栈顶的内容,记住,此时栈最顶端的两个单元都是新创建对象的引用。
接着是调用初始化方法,该方法是由构造方法编译而来,栈顶的引用作为此方法的参数消耗了。通过调用初始化方法完成
对象的创建过程。这里注意一下初始化方法Method "":()V,它是void类型的。
最后的astore_1指令将栈顶的对象引用赋给局部变量(前面说了,dup之后栈顶两个引用,一个给初始化方法吃掉了,一个留给astore_1操作用),也就是执行赋值操作。
因此,得到的引用是new指令的结果,不是构造方法的返回值。
有一点需要注意:new指令创建对象,同时使对象的各个字段得到其默认值,比如整数为0,浮点数为0.0,引用为null,boolean为false等。也就是说在构造方法执行之前,各个字段都有默认值了。这一点我们在第三条继续说明。
通过上面说明,我们明确了构造方法的职能(初始化new指令创建的对象,得到一个状态合法的对象,完成对象的
创建过程)。任何类都有构造方法,但是new指令只能创建非抽象类的对象。理解了这一点,也就不要再问"抽象类也有构造方法,为什么不能创建对象"之类的问题了。
2.构造方法是静态的?
错误。
这是《Thinking In Java》中的一个观点。书里有一段:
Even though it doesn't explicitly use the static keyword, the constructor is actually a static method. So the first time an object of type Dog is created, or the first time a static method or static field of class Dog is accessed, the Java interpreter must locate Dog.class, which it does by searching through the classpath.
《java编程思想》中文第四版96页:
总结一下对象的创建过程,假设有个名为Dog的类:
1.即使没有显示地使用static关键字,构造器实际上也是静态方法。因此,当首次创建类型为Dog的对象时(构造器可以看成
是静态方法),或者Dog类的静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。
这里我并没有看明白作者为什么说构造器实际上是静态方法。但是我们知道,静态方法是不能使用this的。因此,"构造器实际上也是静态方法"这点很好否定。看下面例子:
public class Test {
public Test() {
this.test2();
}
public static void test(){
this.test2();
}
public static void test2(){
}
}
test方法编译错误,因为静态方法中不能使用非静态的this,而构造方法使用this是没有问题的。
如果有C++经验的话,可以类比一下。C++里的new操作符有两个作用,调用operator new()来分配内存,然后调用构造函数来完成初始化。
而这里的operator new()是隐式静态的。参考《C++程序设计语言(特别版)》中文版的374页:
比如这个例子:
class Employee{ //... public: //.... void* operator new(size_t); void operator delete(void* ,size_t); }
成员operator new()和operator delete()默认为static成员,因为它们没有this指针,也不会修改任何对象。它们将提供一些存储,供构造函数去初始化,而后由析构函数去清理。
类比可知,静态的是负责分配内存的工具,而不是构造函数。 不知道《Thinking In Java》的作者是不是把这点弄混了?
3.父类的构造方法中调用被子类重写的方法有多态现象。
这句话很绕,直接看例子:
class Father{
private int i = 5;
public Father() {
System.out.println("Father's i is " + this.i);
test();
}
public void test(){
System.out.println(this.i);
}
}
class Son extends Father{
private int i = 55;
public Son() {
System.out.println("Son's i is " + this.i);
}
@Override
public void test() {
System.out.println(this.i);
}
}
public class Test {
public static void main(String[] args) {
new Son();
}
}
结果是:
Father's i is 5
0
Son's i is 55
结合第一点,构造方法调用之前,首先是new指令创建了一个对象,并将各个成员初始化为其默认值。下面看构造方法的调用过程。
子类构造方法会调用父类构造方法,父类构造方法首先打印Father's i is 5。然后调用test()方法,注意,我们创建的是Son类的对象,所以test()方法调用的是Son类定义的test()方法,也就是说发生了多态。我们再去看Son类中test方法的实现,就是简单的输出this.i,为什么是0呢,别忘了我们还没有执行子类的构造方法啊,所以此时子类的i还是new指令初始化得到的0。好,test()方法执行完了,总算回到子类构造方法继续执行,先把i赋值为55,下面的输出语句Son's i is 55也就不难理解了。
在构造方法中调用方法要特别注意这种多态现象。
这种现象和c++里的现象是不同的。在C++中,如果在父类的构造函数中调用虚方法的话,调用的是父类定义的版本,不会发生多态现象。但一个有趣的现象是,C++的经典书籍和Java的经典书籍竟然都建议不要在构造方法里面调用多态方法,因为现象并不是你期待的!这就奇怪了,难道C++程序员和Java程序员天生就有相反的期待吗?
评论
《java编程思想》中文第四版96页:
总结一下对象的创建过程,假设有个名为Dog的类:
1.即使没有显示地使用static关键字,构造器实际上也是静态方法。因此,当首次创建类型为Dog的对象时(构造器可以看成
是静态方法),或者Dog类的静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。
这里我并没有看明白作者为什么说构造器实际上是静态方法。但是我们知道,静态方法是不能使用this的。因此,"构造器实际上也是静态方法"这点很好否定。
我的理解是,静态方法是不需要通过类的实例来调用的,而是类被加载后放在栈中的,是属于“类方法”。非静态方法是要通过类的实例才调用的,是属于“对象方法”。从这个角度来讲,构造方法可以认为是静态的,因为在调用构造方法时必定是还未实例化的,而实例化后就不能再调用构造方法了。这样理解不知道对不对
我做了个测试程序:
public static void main(String[] args) { try{ Class c = Class.forName("mypackage.SK"); Constructor[] cc = c.getConstructors(); Method[] m = c.getMethods(); int b = cc[0].getModifiers(); System.out.println(b); System.out.println(Integer.toHexString(b)); System.out.println("final:" + Modifier.isFinal(b)); System.out.println("public:" + Modifier.isPublic(b)); System.out.println("abstract:" + Modifier.isAbstract(b)); System.out.println("native:" + Modifier.isNative(b)); System.out.println("protected:" + Modifier.isProtected(b)); System.out.println("Static:" + Modifier.isStatic(b)); catch(ClassNotFoundException cl) { System.out.println("ClassNotFound"); } catch(SecurityException se) { System.out.println("SecurityException"); } }
而SK:
public class SK { public SK(){ } }
结果是static:false
《java编程思想》中文第四版96页:
总结一下对象的创建过程,假设有个名为Dog的类:
1.即使没有显示地使用static关键字,构造器实际上也是静态方法。因此,当首次创建类型为Dog的对象时(构造器可以看成
是静态方法),或者Dog类的静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。
这里我并没有看明白作者为什么说构造器实际上是静态方法。但是我们知道,静态方法是不能使用this的。因此,"构造器实际上也是静态方法"这点很好否定。
我的理解是,静态方法是不需要通过类的实例来调用的,而是类被加载后放在栈中的,是属于“类方法”。非静态方法是要通过类的实例才调用的,是属于“对象方法”。从这个角度来讲,构造方法可以认为是静态的,因为在调用构造方法时必定是还未实例化的,而实例化后就不能再调用构造方法了。这样理解不知道对不对
class Father {
private int i = 5;
private static int j= 6;
public Father() {
System.out.println("Father's i is " + this.i);
test();
}
public void test() {
System.out.println("father i :"+this.i);
System.out.println("father j :"+j);
}
}
class Son extends Father {
private static int i = 55;
public Son() {
System.out.println("Son's i is " + i);
}
@Override
public void test() {
super.test();
System.out.println("son i :"+i);
}
}
public class Test {
public static void main(String[] args) {
new Son();
}
}
发表评论
-
接口类型引用为何能调用Object类的方法
2009-09-20 19:15 3443首先看这段代码 ... -
小例子:如何说明String常量池的位置
2009-09-20 00:44 14430以前批过《关于Java堆与栈的思考》这个帖子,具体内容 ... -
无聊:为啥可以使用空引用调用static方法或者访问static field
2009-09-10 00:52 2009先看代码: public class ... -
无聊:谁说private方法自动是final的?兼评《Java编程思想》中的几个问题
2009-09-03 10:07 7184首先声明,本文无任何实际价值,只是讨论一些 ... -
从“关于Java堆与栈的思考”一帖看错误信息的传播
2009-08-05 05:03 10015我对转贴的信息一直有敌意,原因如下:首先,除了 ... -
谜题解析
2009-07-30 12:35 2844题目接http://zangxt.iteye.com/blog ... -
几个谜题,深入的了解java
2009-07-29 18:10 5997在2009年的JavaOne大会上,Joshua Bloch和 ... -
java中匿名内部类的构造方法调用
2008-07-28 19:14 12055与人讨论匿名内部类的构造方法问题,自己 ... -
static方法与覆盖
2008-08-01 17:50 1331The Java Programming Langu ... -
局部内部类 与 final变量
2008-09-12 23:39 1247局部内部类可以访问定义该类的作用字段中的所有变量,包 ... -
java 1.6 表达式计算方法
2008-10-11 12:42 1097import javax.script.Script ... -
看一下enum的原理
2008-10-29 13:22 2504java5增加了enum,其实对enum的处理很简 ... -
一个静态初始化的问题
2008-10-31 21:59 1176问题代码: public class Test1{ ... -
读Java Puzzlers笔记: 表达式问题
2008-11-02 11:27 1162一.奇数性判断一个数是否为奇数,方法: publ ... -
i++ ,++i,i=i++的问题
2008-11-05 20:16 1229很经典的无聊问题之一。 int i=0;i=i+ ... -
instanceof的使用
2008-11-06 20:47 1404总结:Java Puzzlers一书中的谜题50 看 ... -
Java的好书
2008-11-14 21:59 2273学Java也算有一段时间了,记录一下看过或者还需要 ... -
HashMap小测试
2008-11-25 18:48 1142测试HashMap代码: ... -
jvm对boolean类型的处理
2008-11-25 19:16 2051JVM对boolean类型的支持比较有意思,java虚拟 ... -
一.准备工作
2008-12-03 12:48 1126首先下载openjdk的源文件包,地址http: ...
相关推荐
### Java构造方法详解 #### 一、构造方法基础概念 构造方法是Java中一种特殊的方法,主要用于初始化新创建的对象。每个类至少有一个构造方法。如果程序员没有显式地定义构造方法,Java编译器会自动为类添加一个无...
### Java 错误处理:java.lang.OutOfMemoryError: Java heap space 在Java应用程序开发过程中,经常遇到的一个问题就是内存溢出错误,特别是在处理大量数据或长时间运行的应用时。其中,“java.lang....
### Java.lang.OutOfMemoryError: Java Heap Space 解决方法详解 在Java开发与运维中,`java.lang.OutOfMemoryError: Java heap space`是一个常见的错误信息,它表明JVM(Java虚拟机)的堆内存已经耗尽,无法再分配...
《精通Hibernate:Java对象持久化详解》是一本深入解析Hibernate技术的专著,它主要针对Java开发者,旨在帮助他们理解和掌握Java对象持久化的精髓。Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了...
JAVA构造方法详解 JAVA构造方法是一个特殊的方法,它用于初始化类的对象。构造方法的作用是对类进行初始化,如果你没有定义任何构造方法的形式,编译器会为你提供一个不带任何参数的构造函数,那么你产生类的对象时...
### Java零基础-构造方法详解 #### 内容概要 本文旨在深入解析Java语言中的构造方法这一核心概念。构造方法是对象初始化的关键步骤,在Java编程中占据着至关重要的地位。通过对构造方法的学习,读者不仅能理解其...
读书笔记:针对 java高并发编程详解 多线程与架构设计 的学习项目
本文将深入解析`Android view构造方法第3个参数详解 demo`,并提供相关的实践示例。 首先,我们来看一下View类的主要构造方法: ```java public View(Context context) { this(context, null); } public View...
资源名称:Java应用开发详解视频教程(22集)资源目录:【】第00章:JAVA课堂序章【】第01章:JAVA概述及开发环境搭建【】第02章:简单Java程序【】第03章:Java基础程序设计【】第04章:数组与方法【】第05章:面向...
《Java2编程详解(Special Edition Using Java)》是一本针对Java初学者和爱好者精心编写的教程,旨在提供全面且深入的Java编程知识。本书详细介绍了Java语言的核心概念、语法和应用,是学习Java 2平台的理想资源。...
精通 Hibern一本ate:Java 对象持久化技术详解(第2版)是
1. **基础语法**:Java的基础始于它的语法,包括变量、数据类型、运算符、流程控制语句(如if-else、for、while)以及方法的定义与调用。书中会深入讲解这些基础知识,帮助读者构建扎实的编程基础。 2. **面向对象...
Java中的构造方法this、super的用法详解 Java中的构造方法是指与类同名、没有返回值的方法。在Java中,构造方法的作用有两点:一是通过构造方法建立一个对象;二是通过构造方法可以快速的赋初值。构造方法的定义是...
- **动态代理**:Java的`java.lang.reflect.Proxy`类可以基于反射创建动态代理,实现接口的动态实现。 - **单元测试**:单元测试框架如JUnit利用反射来执行注解的方法。 - **插件化**:反射支持在运行时加载和...
继承的父类为:java.lang.Object ``` ##### 案例7:获得其他类中的全部构造函数 通过`Class`对象的`getConstructors()`方法可以获得一个类的所有公共构造函数。 ```java Constructor[] constructors = clazz....