- 浏览: 228811 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
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 15911、在进行字符串逆转时可以采用StringBuffer对象 ... -
ztf实习开发总结
2012-07-25 20:34 1364weblogic workshop的问题 1、流程管理系统是 ... -
Java中this关键字的几种用法
2012-05-11 18:38 931http://blog.csdn.net/anmei2010/ ... -
java中this的用法
2012-05-09 23:11 0http://blog.csdn.net/anmei2010/ ... -
java核心技术总结八--多线程
2012-05-03 23:32 10641、多线程程序在较低的层次上扩展了多任务的概念: 一个程序同时 ... -
堆和栈的区别
2012-04-11 23:46 717一、预备知识—程序的 ... -
native关键字
2012-04-11 12:53 954java native关键字 一. ... -
什么是重构
2012-04-11 12:50 867重构 ( Refactoring ... -
ConcurrentHashMap 高并发性的实现机制
2012-04-07 23:59 5173简介 ConcurrentHashMap 是 util.co ... -
String和stringbuffer和stringbuilder的区别
2012-03-19 17:13 1013String 字符串常量 StringBuffer 字符串 ... -
java核心技术总结七--异常、日志、断言和调试
2012-03-03 23:09 1673第十一章 1、异常的分类: Th ... -
java核心技术总结六
2012-02-22 21:15 977第10章 1、用命令打jar包: ... -
java核心技术总结五
2012-01-03 15:46 977第六章 1、接口 (1)、接口中可以包含多个方法,还可以定 ... -
java核心技术总结四
2011-12-30 21:55 2735第五章总结: 1、java用关键字extends代替 ... -
ftp文件的上传与下载
2011-12-30 17:11 997http://www.cnblogs.com/chen1987 ... -
java核心技术总结三
2011-12-30 09:49 1012第四章:对象和类 1、在类之间,最常见的关系有: ... -
java表达式类型转换
2011-12-16 17:11 1180今天无意中看到我之前做的一个关于java面试题的小测试 ,发现 ... -
Double型数值保留2位小数
2011-12-14 10:32 18011//保留2位小数 public static doubl ... -
java核心技术总结二
2011-12-09 22:44 1077第二章; 1、netBeans是sun公司的集成开 ... -
java核心技术总结一
2011-12-09 22:19 1357看过书后好久不看就会遗忘,所以现在就将正在看的java核心技术 ...
相关推荐
java 静态_非静态 字段_方法_代码块 子类父类构造_初始化顺序! 三个class 让你清清楚楚 第一个class java代码如下: package initialOrder; class Parent { // 静态变量 public static String p_StaticField...
大家在去参加面试的时候,经常会遇到这样的考题:给你两个类的代码,它们之间是继承的关系,每个类里只有构造器方法和一些变量,构造器里可能还有一段代码对变量值进行了某种运算,另外还有一些将变量值输出到控制台...
所有代码块是从上往下顺序执行的,所以代码块里面使用到的变量如果在块下面初始化会有问题 执行构造方法中内容。 所以看见的空构造方法,只能说第三部没有需要执行的内容。 下面举例子 public class TestClass { ...
未创建此类对象)的静态对象时,所有的静态变量也要按它们在类中的顺序初始化。 2、 继承时,对象的初始化过程 (1) 主类的超类由高到低按顺序初始化静态成员,无论静态成员是否为private。 (2) 主类静态成员的...
未创建此类对象)的静态对象时,所有的静态变量也要按它们在类中的顺序初始化。 2、继承时,对象的初始化过程 (1) 主类的超类由高到低按顺序初始化静态成员,无论静态成员是否为private。 (2) 主类静态...
类的初始化 成员初始化 构造器初始化初始化顺序 数组初始化 对象的销毁 对象作用域 this 和 super 访问控制权限继承 多态组合代理 向上转型static final 接口和抽象类接口 抽象类异常 认 识 Exception 什么是 ...
我们大家都知道,对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序依次是(静态变量、静态初始化块)>(变量、初始化块)>构造器。我们也可以通过下面的测试代码来验证这一点:
生成对象的最后一步是执行构造方法,进行初始化。由于对构造方法可以进行重写 ,所以通过给出不同个数或类型的参数会分别调用不同的构造方法。 例子:以类 Rectangle 为例,我们生成类 Rectangle 的对象: Rectangle p1...
errorInit.java 演示变量初始化错误的程序 integerExample.java 演示各种整型变量的使用 isPrime.java 判断素数 leapYearByIf.java 用if语句判断闰年 leapYearByLogical.java 用逻辑表达式判断闰年 lowToUpper...
6.2.1 在类中给每个变量一个初始值 147 6.2.2 定义自己的引用 147 6.2.3 使用点操作符的技巧 148 6.2.4 类的数组 149 6.3 小结:Java其实是个类和对象的世界 152 6.4 习题 153 第7章 Java中的方法——给汽车...
5.3.2 成员变量的初始化和内存中的运行机制 128 5.3.3 局部变量的初始化和内存中的运行机制 130 5.3.4 变量的使用规则 130 5.4 隐藏和封装 132 5.4.1 理解封装 132 5.4.2 使用访问控制符 132 5.4.3 package和...
6.2.1 在类中给每个变量一个初始值 147 6.2.2 定义自己的引用 147 6.2.3 使用点操作符的技巧 148 6.2.4 类的数组 149 6.3 小结:Java其实是个类和对象的世界 152 6.4 习题 153 第7章 Java中的方法——给汽车...
3.5.2 变量赋值和初始化 3.5.3 常量 3.6 类型转化 3.6.1 数值类型之间的转换 3.6.2 强制类型转换 3.7 运算符 3.7.1 算术运算符 3.7.2 关系运算符 3.7.3 逻辑运算符 3.7.4 位运算符 3.7.5 自动递增和递减 ...
派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。 3.封装: 封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即...
3.18 Java类的基本运行顺序 53 3.19 Java包装类、拆箱和装箱详解 54 3.20 包装类的应用 54 3.20.1.1 1) 实现 int 和 Integer 的相互转换 54 3.20.1.2 2) 将字符串转换为整数 55 3.20.1.3 3) 将整数转换为字符串 55 ...
初始化:在准备阶段已经赋过一个系统要求的初始值,而在初始化阶段则通过程序制定的主管计划去初始化变量和其他资源,从另一个角度理解就是 执行类构造器的()方法 .()方法是由编译器自动收集类中的所有变量的复制动作和...
"类的初始化过程 当创建一个对象时,对象的各个变量根据其类型被设置为相应的默认初始值,然后调用构造方法,而每次调用构造方法都是要执行三个阶段: 1.调用超类的构造方法; 2.由初始化语句对给变量进行初始化...
静态初始化块(经常用来初始化类,加载类信息时执行!) 67 package 68 JDK中的主要包 68 import 68 eclipse的使用 69 继承(extend, inheritance) 70 为什么需要继承?继承的作用? 70 继承介绍 70 如何实现继承? ...