- 浏览: 233752 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
wcl694216530:
[url][img][img][url][flash=200, ...
oracle的语法start with和connect by nocycle -
gyhbody:
你这个是不是SWC加载错误啊?
flex乱码问题 -
gyhbody:
那 通过什么来查看SWC文件
flex乱码问题 -
liushp1:
[img] [/img]
jsp中redirect和forward的区别 -
little_fei754:
我的输出是120 120。求大神解释。
java表达式类型转换
看下面的代码先不要运行而尝试给出输出:
class A {
public A() {
init();
}
public void init() {
}
}
public class B extends A {
int i;
int s = 0;
public void init() {
i = 100;
s = 100;
}
public void println() {
System.out.println(i);
System.out.println(s);
}
public static void main(String[] arg) {
new B().println();
}
}
它的输出是什么呢?为什么不输出 100 100,而输出 100 0呢?
可以用下面的代码来尝试解释:
class A {
public A() {
System.out.println("enter A()");
init();
System.out.println("exit A()");
}
public void init() {
System.out.println("enter A.init");
System.out.println("exit A.init");
}
}
public class B extends A {
public B() {
System.out.println("enter B()");
System.out.println("exit B()");
}
int i;
int s = inits();
public static int inits() {
System.out.println("enter B.inits");
System.out.println("exit B.inits");
return 0;
}
public void init() {
System.out.println("enter B.init");
i = 100;
s = 100;
System.out.println("exit B.init");
}
public void println() {
System.out.println("enter B.println");
System.out.println(i);
System.out.println(s);
System.out.println("exit B.println");
}
public static void main(String[] arg) {
new B().println();
}
}
上面的代码输出如下:
enter A()
enter B.init
exit B.init
exit A()
enter B.inits
exit B.inits
enter B()
exit B()
enter B.println
100
0
exit B.println
由此可以看出大致执行顺序如下:
main的new B()
->class B的public B()的第一行(首先调用基类构造函数,隐含的super()调用),第二行还没执行又
->class A的public A()第一行,第二行init()去调用class B的init()而不是class A的init()所以
这里i=100,s=100(运行时多态性),public A()完了之后
->public B()的第一行,下面先执行实例变量的初始化。(此处在下面继续讨论)
下来是s=inits()结果s=0,i没变还是100,最后才执行public B()的两条输出,到这里new B()才算完,
下面就是B的println()。
关于i和s在类初始化方面的赋值方面的问题,请继续看下面的例子:
class Base {
Base() {
System.out.println("Base() before print()");
print();
System.out.println("Base() after print()");
}
public void print() {
System.out.println("Base.print()");
}
}
class Derived extends Base {
int value = 100;
Derived() {
System.out.println("Derived() With " + value);
}
public void print() {
System.out.println("Derived.print() with " + value);
}
}
public class Main {
public static void main(String[] args) {
new Derived();
}
}
如果变量有定义初始化值,如value=100,则先赋初始值,然后运行构造函数,那么在这个程
序的任何位置value都应该是100,但事实却非如此,输出结果如下:
Base() before print()
Derived.print() with 0 <---------这里是0而不是100
Base() after print()
Derived() With 100
会不会比较容易让人迷惑?
总结一下吧,顺序当然是很容易就推出,没什么好讨论的。
实际上例子只是说明,
int i; != int i = 0;
一般的初学者都会认为两者是相同的。
但是实际上不但是在顺序上不一样,而且javac对两者的编译是完全不一样。
前者只是申明一个变量,在初始化对象变量(这里指int i = 0;)的时候并不会编译成初始化指令。
而这些初始化对象变量的指令,会在本类构造函数里面的第一条指令(注意不是构造函数之前)
之前执行,而在此之前可能已经执行了父类的构造函数。
所以我们不难推出最开始那个例子的结果为什么一个是100,一个是0。
还有要注意的是构造函数实际上并没有分配空间(尽管我们通常都会认为)。
对于一般的对象生成(用new关键字,其他情况要另外分析)。
javac会把它编译成new #number 这个指令,#number指向的是类在常数池的索引。
这个new指令就是分配对象空间,并根据类里面所声明的变量进行空间分配,
并把他们赋值成初始化的值(就是大家都知道的,int(0),objct(null))。
举个简单的例子。对于一般的语句:比如说new A();
实际上执行顺序如下:
new #A的索引
//然后是下面大括号的指令,它们都是A的构造函数(这里的构造函数并不等同于我们代码
里面的public A() {.. },实际上是大于,然后
根据里面的代码生成A的构造函数字节代码段。)
{
执行父类构造函数字节代码段
本类对象变量的初始化指令(比如int i = 10;这些指令是在编译时确定的)
然后下面的指令就是public A() {...}里面代码的指令
{
...
...
}
}
实际上,假如你只是在类申明了int i;而在以后的代码都不引用它的话,
javac是不会把它编译到class里面的。这也许是javac的优化结果。
class A {
public A() {
init();
}
public void init() {
}
}
public class B extends A {
int i;
int s = 0;
public void init() {
i = 100;
s = 100;
}
public void println() {
System.out.println(i);
System.out.println(s);
}
public static void main(String[] arg) {
new B().println();
}
}
它的输出是什么呢?为什么不输出 100 100,而输出 100 0呢?
可以用下面的代码来尝试解释:
class A {
public A() {
System.out.println("enter A()");
init();
System.out.println("exit A()");
}
public void init() {
System.out.println("enter A.init");
System.out.println("exit A.init");
}
}
public class B extends A {
public B() {
System.out.println("enter B()");
System.out.println("exit B()");
}
int i;
int s = inits();
public static int inits() {
System.out.println("enter B.inits");
System.out.println("exit B.inits");
return 0;
}
public void init() {
System.out.println("enter B.init");
i = 100;
s = 100;
System.out.println("exit B.init");
}
public void println() {
System.out.println("enter B.println");
System.out.println(i);
System.out.println(s);
System.out.println("exit B.println");
}
public static void main(String[] arg) {
new B().println();
}
}
上面的代码输出如下:
enter A()
enter B.init
exit B.init
exit A()
enter B.inits
exit B.inits
enter B()
exit B()
enter B.println
100
0
exit B.println
由此可以看出大致执行顺序如下:
main的new B()
->class B的public B()的第一行(首先调用基类构造函数,隐含的super()调用),第二行还没执行又
->class A的public A()第一行,第二行init()去调用class B的init()而不是class A的init()所以
这里i=100,s=100(运行时多态性),public A()完了之后
->public B()的第一行,下面先执行实例变量的初始化。(此处在下面继续讨论)
下来是s=inits()结果s=0,i没变还是100,最后才执行public B()的两条输出,到这里new B()才算完,
下面就是B的println()。
关于i和s在类初始化方面的赋值方面的问题,请继续看下面的例子:
class Base {
Base() {
System.out.println("Base() before print()");
print();
System.out.println("Base() after print()");
}
public void print() {
System.out.println("Base.print()");
}
}
class Derived extends Base {
int value = 100;
Derived() {
System.out.println("Derived() With " + value);
}
public void print() {
System.out.println("Derived.print() with " + value);
}
}
public class Main {
public static void main(String[] args) {
new Derived();
}
}
如果变量有定义初始化值,如value=100,则先赋初始值,然后运行构造函数,那么在这个程
序的任何位置value都应该是100,但事实却非如此,输出结果如下:
Base() before print()
Derived.print() with 0 <---------这里是0而不是100
Base() after print()
Derived() With 100
会不会比较容易让人迷惑?
总结一下吧,顺序当然是很容易就推出,没什么好讨论的。
实际上例子只是说明,
int i; != int i = 0;
一般的初学者都会认为两者是相同的。
但是实际上不但是在顺序上不一样,而且javac对两者的编译是完全不一样。
前者只是申明一个变量,在初始化对象变量(这里指int i = 0;)的时候并不会编译成初始化指令。
而这些初始化对象变量的指令,会在本类构造函数里面的第一条指令(注意不是构造函数之前)
之前执行,而在此之前可能已经执行了父类的构造函数。
所以我们不难推出最开始那个例子的结果为什么一个是100,一个是0。
还有要注意的是构造函数实际上并没有分配空间(尽管我们通常都会认为)。
对于一般的对象生成(用new关键字,其他情况要另外分析)。
javac会把它编译成new #number 这个指令,#number指向的是类在常数池的索引。
这个new指令就是分配对象空间,并根据类里面所声明的变量进行空间分配,
并把他们赋值成初始化的值(就是大家都知道的,int(0),objct(null))。
举个简单的例子。对于一般的语句:比如说new A();
实际上执行顺序如下:
new #A的索引
//然后是下面大括号的指令,它们都是A的构造函数(这里的构造函数并不等同于我们代码
里面的public A() {.. },实际上是大于,然后
根据里面的代码生成A的构造函数字节代码段。)
{
执行父类构造函数字节代码段
本类对象变量的初始化指令(比如int i = 10;这些指令是在编译时确定的)
然后下面的指令就是public A() {...}里面代码的指令
{
...
...
}
}
实际上,假如你只是在类申明了int i;而在以后的代码都不引用它的话,
javac是不会把它编译到class里面的。这也许是javac的优化结果。
上面的总结下来就是如下
- 如果父类有静态成员赋值或者静态初始化块,执行静态成员赋值和静态初始化块
- 如果类有静态成员赋值或者静态初始化块,执行静态成员赋值和静态初始化块
- 将类的成员赋予初值(原始类型的成员的值为规定值,例如int型为0,float型为0.0f,boolean型为false;对象类型的初始值为null)
- 如果构造方法中存在this()调用(可以是其它带参数的this()调用)则执行之,执行完毕后进入第7步继续执行,如果没有this调用则进行下一步。(这个有可能存在递归调用其它的构造方法)
- 执行显式的super()调用(可以是其它带参数的super()调用)或者隐式的super()调用(缺省构造方法),此步骤又进入一个父类的构造过程并一直上推至Object对象的构造。
- 执行类申明中的成员赋值和初始化块。
- 执行构造方法中的其它语句。
发表评论
-
java基础总结1
2013-03-02 21:31 16701、在进行字符串逆转时可以采用StringBuffer对象 ... -
ztf实习开发总结
2012-07-25 20:34 1396weblogic workshop的问题 1、流程管理系统是 ... -
Java中this关键字的几种用法
2012-05-11 18:38 987http://blog.csdn.net/anmei2010/ ... -
java中this的用法
2012-05-09 23:11 0http://blog.csdn.net/anmei2010/ ... -
java核心技术总结八--多线程
2012-05-03 23:32 11251、多线程程序在较低的层次上扩展了多任务的概念: 一个程序同时 ... -
堆和栈的区别
2012-04-11 23:46 810一、预备知识—程序的 ... -
native关键字
2012-04-11 12:53 1034java native关键字 一. ... -
什么是重构
2012-04-11 12:50 942重构 ( Refactoring ... -
ConcurrentHashMap 高并发性的实现机制
2012-04-07 23:59 5216简介 ConcurrentHashMap 是 util.co ... -
String和stringbuffer和stringbuilder的区别
2012-03-19 17:13 1065String 字符串常量 StringBuffer 字符串 ... -
java核心技术总结七--异常、日志、断言和调试
2012-03-03 23:09 1717第十一章 1、异常的分类: Th ... -
java核心技术总结六
2012-02-22 21:15 1002第10章 1、用命令打jar包: ... -
java核心技术总结五
2012-01-03 15:46 1009第六章 1、接口 (1)、接口中可以包含多个方法,还可以定 ... -
java核心技术总结四
2011-12-30 21:55 2816第五章总结: 1、java用关键字extends代替 ... -
ftp文件的上传与下载
2011-12-30 17:11 1049http://www.cnblogs.com/chen1987 ... -
java核心技术总结三
2011-12-30 09:49 1046第四章:对象和类 1、在类之间,最常见的关系有: ... -
java表达式类型转换
2011-12-16 17:11 1229今天无意中看到我之前做的一个关于java面试题的小测试 ,发现 ... -
Double型数值保留2位小数
2011-12-14 10:32 18058//保留2位小数 public static doubl ... -
java核心技术总结二
2011-12-09 22:44 1116第二章; 1、netBeans是sun公司的集成开 ... -
java核心技术总结一
2011-12-09 22:19 1407看过书后好久不看就会遗忘,所以现在就将正在看的java核心技术 ...
相关推荐
总之,深入理解Java的ClassLoader机制和类变量初始化顺序是提升Java编程技能的重要步骤。通过学习这些知识点,开发者可以更好地优化代码、设计更健壮的系统,并解决与类加载和初始化相关的复杂问题。
总之,Java类继承初始化顺序涉及到静态和非静态初始化块、构造器的调用以及方法的覆盖。理解这些概念对于编写健壮的、易于维护的Java代码至关重要。在实际编程中,应合理利用继承特性,同时注意避免不必要的复杂性和...
### Java中类的初始化顺序详解 #### 一、概述 在Java编程语言中,类的初始化是一个非常重要的概念。类的初始化涉及到多个方面,包括静态成员变量、实例成员变量、静态初始化块、实例初始化块以及构造函数等。本文...
总之,Java代码的初始化顺序是类加载的必然过程,涉及到静态和实例初始化块、构造函数、成员变量初始化以及继承关系的影响。这个demo是学习和理解这些概念的重要工具,通过实际操作可以加深对Java内存管理和对象生命...
java 静态_非静态 字段_方法_代码块 子类父类构造_初始化顺序! 三个class 让你清清楚楚 第一个class java代码如下: package initialOrder; class Parent { // 静态变量 public static String p_StaticField...
- 实例初始化块({}):然后执行类中的实例初始化块,这些代码会为实例变量赋值或执行其他初始化任务。 - 构造器主体:最后,执行当前类的构造器主体,完成对象的具体初始化。 4. **多线程下的初始化**: - 当多...
在Java编程语言中,初始化块是程序执行时用于初始化对象或类的重要机制。这里我们将深入探讨两种类型的初始化块:静态初始化块(Static Initializer Block)和对象初始化块(Instance Initializer Block)。这两种...
了解和熟练使用构造方法是Java面向对象编程的基础,下面将详细阐述Java构造方法的相关知识点。 一、构造方法的作用 构造方法的主要任务是在创建对象时设置对象的初始状态,为对象成员变量赋值。当一个类被实例化时...
### Java 类中静态域、块,非静态域、块,构造函数的初始化顺序 #### 一、概述 在 Java 编程语言中,类的初始化顺序对于理解程序的行为至关重要。特别是当涉及到静态域(静态变量)、非静态域(实例变量)、静态块...
对于构造方法执行顺序,要能够分析和解释复杂的继承结构中对象初始化的过程。这些都是衡量开发者对Java面向对象特性理解程度的重要指标。 总之,掌握这些Java基础知识不仅可以帮助你在面试中脱颖而出,也能使你在...
4. **子类非静态成员初始化**:接着是子类的非静态成员变量初始化。 5. **基类构造函数调用**:通过`super()`调用基类的构造函数。 6. **子类构造函数调用**:最后执行子类自身的构造函数。 ### 初始化过程详解 ##...
如果类中存在多个构造代码块或成员变量初始化,它们将按照在代码中出现的顺序依次执行。 #### 三、构造方法的执行 构造方法用于初始化类的实例,它们在创建对象时被调用。构造方法的执行顺序遵循以下规则: - ...
这意味着如果一个类中有多个成员变量,它们的初始化顺序将按照代码中声明的顺序进行。 #### 八、总结 构造方法是Java编程语言中一个重要的概念,它对于对象的初始化至关重要。理解构造方法的工作原理、如何正确...
字节码揭示了类的内部操作,包括方法调用、变量初始化等。 总的来说,Java类的构造方式是一个涉及内存分配、初始化、继承和多态的重要主题。理解和掌握这一过程对于编写高效、可靠的Java代码至关重要。通过实例和...
在上面的示例代码中,我们可以看到,类变量和实例变量的初始化顺序是按照定义的顺序进行的。同时,我们还可以看到,静态变量的初始化顺序是按照定义的顺序,并且只在第一次访问时初始化。 在 Java 中,static ...
3. **初始化块与成员变量初始化的顺序**:如果静态成员变量定义与静态初始化块同时存在,则先执行静态成员变量的初始化;同理,对于非静态成员变量也是如此。 掌握这些原则可以帮助开发者更准确地控制类的初始化...
首先,Java 解释器会执行类中的静态变量初始化和静态初始化块。这些静态元素的初始化只会在类加载时执行一次,并且按照它们在源代码中的顺序进行。在给定的例子中,我们看到 `parent` 类和 `child` 类都有静态变量...
Java类的初始化顺序是编程中一个非常重要的概念,它涉及到对象的创建过程和成员变量的初始化。当一个Java类被实例化或者其静态成员被访问时,类的初始化过程就开始了。以下详细解释了Java类的初始化顺序: 1. **...
在 JAVA 中,类的初始化顺序可以分为四个阶段:静态变量、静态初始化块、变量、初始化块和构造器。其中,静态变量和静态初始化块的初始化顺序是最高的,接着是变量和初始化块,最后是构造器。 在了解类的初始化顺序...