学习java也有两年了,对一些基础还是理解的不够深,上网一搜很的确有不少这样的文章。下面就整理下以免以后忘记了。(理解:java 构造方法不等于创建对象而是初始化对象,new 关键字分配内存和创建对象)如理解有误的话,还请指点!
一、这个文章理解的还是比较有趣的。(转)
http://zangxt.iteye.com/blog/472238
http://shukuiyan.iteye.com/blog/1007808
关于java的构造方法有几个简单的问题:
1.构造方法有返回值吗?
没有。构造方法没有任何返回类型,也不允许是void。比如:
Java代码
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的。因此,"构造器实际上也是静态方法"这点很好否定。看下面例子:
Java代码
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++程序设计语言(特别版)》中文版的
比如这个例子:
Cpp代码
class Employee{
//...
public:
//....
void* operator new(size_t);
void operator delete(void* ,size_t);
}
成员operator new()和operator delete()默认为static成员,因为它们没有this指针,也不会修改任何对象。它们将提供一些存储,供构造函数去初始化,而后由析构函数去清理。
类比可知,静态的是负责分配内存的工具,而不是构造函数。 不知道《Thinking In Java》的作者是不是把这点弄混了?
3.父类的构造方法中调用被子类重写的方法有多态现象。
这句话很绕,直接看例子:
Java代码
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 中的 new 关键字和 newInstance() 方法都是用于创建对象的,但是它们之间有着本质的区别。理解这两者的区别对于 Java 编程尤其重要。 首先,new 关键字是 Java 的一个保留字,用于创建一个新的对象。例如,`A ...
Java 中 newInstance() 方法和 new 关键字的区别 Java 中的对象创建方式有多种,newInstance() 方法和 new 关键字是其中两种常用的方式。但是,它们之间有着本质的区别。本文将详细介绍 newInstance() 方法和 new ...
### newInstance()方法与new关键字的区别 在Java编程语言中,创建对象是十分常见的操作,而`newInstance()`方法和`new`关键字则是实现这一目的的两种主要方式。它们之间的区别不仅在于一个是方法调用,另一个是语言...
总结,Java构造方法在创建和初始化对象时起着至关重要的作用。通过理解并熟练运用构造方法,开发者可以更好地设计和实现类,提高代码的可读性和维护性。在实践中,要灵活运用构造方法的重载、`this`关键字以及与继承...
### Java构造方法详解 #### 一、构造方法基础概念 构造方法是Java中一种特殊的方法,主要用于初始化新创建的对象。每个类至少有一个构造...通过本文的详细阐述,希望读者能够对Java构造方法有更深入的理解和掌握。
Java构造方法解析 在Java编程语言中,构造方法是一个特殊的方法,它的主要任务是初始化一个新创建的对象。构造方法与类名相同,并且没有返回类型,即使是void也不行。了解和熟练使用构造方法是Java程序员的基本技能...
下面详细解析Java构造方法的特性和使用方法。 构造方法的特性: 1. 方法名与类名相同:构造方法的名字必须与类名完全相同,这是Java语法规定的一部分,便于编译器识别并自动调用构造方法。 2. 构造方法无返回类型:...
本文将深入探讨如何在Java中使用Socket关键字进行通信,以及它与相关工具的结合使用。 一、Socket基础知识 Socket,也被称为套接字,是网络编程中的一个抽象概念,它代表了两台计算机之间的连接点。在TCP/IP协议族...
“深入理解Java构造器机理” 在 Java 编程语言中,构造器是一种特殊的方法,用于初始化对象的创建。它是 Java 类中最重要的一个概念。下面将深入讨论构造器的机理、执行顺序、作用及与其他概念的区别。 一、构造器...
- 创建对象通常通过使用`new`关键字和类的构造方法来完成。 - 例如: ```java Car myCar = new Car(); ``` 3. **访问成员**: - 一旦创建了对象,就可以使用`.`操作符来访问其成员变量和方法。 - 例如: ``...
在类的构造方法中,`this`关键字可以用来调用同一类中的其他重载构造方法,以便于代码的复用和简化。这个特性使得开发者能够更高效地管理对象的初始化过程。 首先,我们要理解构造方法的作用。构造方法是Java类中...
总结来说,`this`关键字在Java程序中用于明确地引用当前对象的实例变量或方法,帮助我们区分局部变量和实例变量。而Java的内存分配机制则确保了对象和其实例变量在堆内存中的正确存储和管理。理解`this`的关键字用法...
此外,文章还探讨了final关键字在构造方法、类、方法以及变量等方面的具体应用,并提出了一些重要的规则与注意事项。 #### 了解final关键字 **final** 关键字是Java语言中用来修饰变量、方法和类的关键字之一,它...
new关键字通常和类的构造函数配合使用。构造函数是一种特殊的方法,它在创建对象时被调用,用于初始化对象的状态。例如: ```java String str = new String(); ``` 这段代码通过调用String类的构造函数来创建一个空...
Java关键字是编程的基础,它们是Java语言预定义的标识符,具有特殊含义并被Java编译器识别。在Java中,一共有51个关键字(包括保留字),但描述中提到的是48个,可能是因为某些关键字在特定上下文不常用或者被归类到...
在Java编程语言中,构造方法是用于初始化新创建对象的特殊方法。它们的名字与类名相同,不返回任何类型,并且通常与new关键字一起使用。构造方法的重载(Overloading)是面向对象编程的一个重要特性,允许我们在同一...
Java中的`new`关键字是创建和初始化对象的关键操作,它在编程中扮演着至关重要的角色。当我们使用`new`关键字时,实际上是执行了以下几个步骤: 1. 分配内存:Java虚拟机(JVM)在堆内存中为新对象分配所需的空间。...
`break` 是 Java 中用于控制流程的关键字,常用于循环语句(如 `for` 和 `while`)和 `switch` 语句中。在循环中使用 `break` 可以立即退出当前循环;在 `switch` 语句中,`break` 用于防止代码执行到下一个 `case` ...
- 用于引用超类的关键字,可以调用超类的构造函数或方法。 43. **switch** - 控制流程关键字,用于基于不同情况执行不同的代码块。 44. **synchronized** - 用于同步代码块或方法的关键字,确保线程安全。 ...