Java——类谜题
1、令人混淆的构造器
代码如下格式:
public class Confusing {
private Confusing(Object o) {
System.out.println("Object");
}
private Confusing(double[] dArray) {
System.out.println("double array");
}
public static void main(String[] args) {
new Confusing(null);
}
}
分析:null这个参数,两个构造器都可以接受,会怀疑这段代码是否会通过编译,运行后发现可以通过编译并且打印出double array?Why?
正解:知识点——Java重载解析过程是以两个阶段运行的。第一个阶段,选取所有可以获得并且可以使用的方法或构造器。第二阶段,从上一阶段选取的方法或构造器中选取一个最精准的方法。精准的理解——能接受的参数类型越少越精准。例如:本例中的Object,他接收的范围太广了,至少能够把double数组和int数组接受了,所以他就不精准。但是,能接收double数组但不能接收其他数据对象类型例如int,所以就相对来说显得更精准,所以在第二个阶段,选取了相对精准的方法,所以才会有了double的输出。
2、静态方法的覆盖
代码:
class Dog {
public static void bark() {
System.out.print("woof ");
}
} class Basenji extends Dog {
public static void bark() { }
} public class Bark {
public static void main(String args[]) {
Dog woofer = new Dog();
Dog nipper = new Basenji();
woofer.bark();
nipper.bark();
}
}
先来说明一件事情:nipper编译期类型为Dog类型,运行期类型为Basenji类型。
分析:静态方法的调用是在编译期选好的,而这个调用当然就要看对象的编译期类型。本例子中,woofer和nipper具有相同的编译类型Dog,虽然nipper在运行期间类型为Basenji,所以他们两个都会打印出woof即打印结果为:woof woof。
静态方法的覆盖叫隐藏,一般方法的覆盖叫重载。重载能够得到动态分配的特性(其实就是看运行期的对象类型),隐藏不能得到这种特性(隐藏只能看编译期类型)。所以,如果将Dog和Basenji中的函数方法去掉static,变为重载,那么将会只打印一个woof。
3、instanceof和强制类型转换
三个程序的代码:
public class Type1 {
public static void main(String[] args) {
String s = null;
System.out.println(s instanceof String);
}
} public class Type2 {
public static void main(String[] args) {
System.out.println(new Type2() instanceof String);
}
} public class Type3 {
public static void main(String args[]) {
Type3 t3 = (Type3) new Object();
}
}
(1)instanceof左边对象运行期为null的时候返回false。
(2)instanceof在编译的时候,如果两边都是类(A instanceof B A、B都是类),则其中一个必须是另外一个的子类,否则就不能通过编译。很明显本例中的Type2和String没有子类关系,所以不能通过编译。
(3)先讨论下强制类型转换的知识:在Java中由于继承和向上转型,子类可以非常自然地转换成父类,但是父类转换成子类则需要强制转换。因为子类拥有比父类更多的属性、更强的功能,所以父类转换为子类需要强制。这种强制类型转换需要条件的。
父类能强制转换为子类:
Father father=new Son();//因为Java的继承和向上转型,子类可以很自然地转换为父类
但是请注意这个Son对象实例在内存中的本质还是Son类型的,只不过它的能力临时被消弱了而已,如果我们想变强怎么办?将其对象类型还原!
Son son=(Son)father; //这种强制类型转换时可以的。
其实father引用仍然是Father类型的,只不过是将它的能力加强了,将其加强后转交给son引用了,Son对象实例在son的变量的引用下,恢复真身,可以使用全部功能了。
父类不能强制转换为子类:当引用类型的真实身份(运行期的类型)是父类本身的类型时,强制类型转换就会产生错误。
Father father=new Father();
Son son=(Son)father;这个系统会抛出ClassCastException异常信息。
编译器在编译时只会检查类型之间是否存在继承关系,有则通过;而在运行时就会检查它的真实类型,是则通过,否则抛出ClassCastException异常。
所以在继承中,子类可以自动转型为父类,但是父类强制转换为子类时只有当引用类型真正的身份为子类时才会强制转换成功,否则失败。
4、Java类初始化顺序
JVM调用main函数时,会触发main函数所在类的初始化。首先,静态域被设置为缺省值(0),接下来按照静态域的出现顺序进行初始化。
我们大家都知道,对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序依次是(这里先假设没有继承) :
(静态变量、静态初始化块(他们两个初始化顺序是根据写的位置))>(变量、初始化块(他们两个初始化顺序是根据写的位置))>构造器。
如果有继承的话,是按照这个顺序先去加载父类。
父类--静态变量
父类--静态初始化块
子类--静态变量
子类--静态初始化块
父类--变量
父类--初始化块
父类--构造器
子类--变量
子类--初始化块
子类--构造器
5、Java实例初始化顺序
代码如下:
class Point {
protected final int x, y;
private final String name; // Cached at construction time
Point(int x, int y) {
this.x = x;
this.y = y;
name = makeName();
} protected String makeName() {
return "[" + x + "," + y + "]";
}
public final String toString() {
return name;
}
} public class ColorPoint extends Point {
private final String color;
ColorPoint(int x, int y, String color) {
super(x, y);
this.color = color;
}
protected String makeName() {
return super.makeName() + ":" + color;
}
public static void main(String[] args) {
System.out.println(new ColorPoint(4, 2, "purple"));
}
}
分析:打印出了[4,2]:null,并不是期望的[4,2]:purple。
总之,不要在构造器中调用可覆写的方法。在实例初始化中产生的循环将是致命的。该问题的解决方案就是惰性初始化,即当它第一次被使用时初始化,以此取代积极初始化,即当Point实例被创建时初始化,代码如下:
class Point {
protected final int x, y;
private String name; // Lazily initialized
Point(int x, int y) {
this.x = x;
this.y = y;
// name initialization removed
} protected String makeName() {
return "[" + x + "," + y + "]";
}
// Lazily computers and caches name on first use
public final synchronized String toString() {
if (name == null)
name = makeName();
return name;
}
}
6、这是一个奇怪的谜题
代码:
public class Creator {
public static void main(String[] args) {
for (int i = 0; i < 100; i++)
Creature creature = new Creature();
System.out.println(Creature.numCreated());
}
} class Creature {
private static long numCreated = 0;
public Creature() {
numCreated++;
}
public static long numCreated() {
return numCreated;
}
}
这样不能通过编译,因为,它违背了一个Java规范。Java语言规范不允许一个本地变量声明语句作为一条语句在for、while或do循环中重复执行[JLS 14.12-14]。一个本地变量声明作为一条语句只能直接出现在一个语句块中。(一个语句块是由一对花括号以及包含在这对花括展中的语句和声明构成的。)所以,如果将这个循环改为:
for(int i=0;i<100;i++){
Creature creature = new Creature();
}
加一个大括弧之后,他就能正常编译运行。
Java——类谜题的更多相关文章
- 如何用Java类配置Spring MVC(不通过web.xml和XML方式)
DispatcherServlet是Spring MVC的核心,按照传统方式, 需要把它配置到web.xml中. 我个人比较不喜欢XML配置方式, XML看起来太累, 冗长繁琐. 还好借助于Servl ...
- jvm系列(一):java类的加载机制
java类的加载机制 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装 ...
- java类与实例
最近在看设计模式,感觉自己对java的三大特性的理解不够清晰,搞不清楚抽象类.接口.泛型的用处和优缺点.设计模式学了一半,想着还是停下来脑补一下java的基础,就从java对象开始吧. 一.java对 ...
- oracle调用JAVA类的方法
导入jar包 在oracle中导入需要的jar包,我们把编辑好的java类打成jar包,直接在oarcle里面写简单的调用就可以了, 1.操作系统需要拥有支持loadjava命令的jdk. 2.加 ...
- Java 类的实例变量初始化的过程 静态块、非静态块、构造函数的加载顺序
先看一道Java面试题: public class Baset { private String baseName = "base"; // 构造方法 public Baset() ...
- hibernate中java类的成员变量类型如何映射到SQL中的数据类型变化
hibernate映射文件??.hbm.xml配置映射元素详解--Hibernate映射类型 在从Hibernate的java的成员类型映射到SQL中的数据类型,其内映射方式它满足,SQL可以自己调制 ...
- kettle系列-[KettleUtil]kettle插件,类似kettle的自定义java类控件
该kettle插件功能类似kettle现有的定义java类插件,自定java类插件主要是支持在kettle中直接编写java代码实现自定特殊功能,而本控件主要是将自定义代码转移到jar包,就是说自定义 ...
- Myeclipse中导入项目后java类中汉字注释出现乱码问题(已解决)
今天重装系统,安装了新的Myeclipse后,导入之前的项目后,,出现了乱码问题.乱码问题主要是java类中的注释,而jsp页面中汉字却完好如初: 右键项目,查看项目的编码格式,UTF-8,把java ...
- Java类初始化
Java类初始化 成员变量的初始化和构造器 如果类的成员变量在定义时没有进行显示的初始化赋值,Java会给每个成员变量一个默认值 对于 char.short.byte.int.long.float. ...
随机推荐
- Oracle用户密码过期和用户被锁解决方法【转】
[原因/触发因素] 确定是由于Oracle11g中默认在default概要文件中设置了“PASSWORD_LIFE_TIME=180天”所导致. [影响和风险] 影响 密码过期后,业务进程连接数据库异 ...
- 二分 Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) D
http://codeforces.com/contest/722/problem/D 题目大意:给你一个没有重复元素的Y集合,再给你一个没有重复元素X集合,X集合有如下操作 ①挑选某个元素*2 ②某 ...
- oracle数据库字符集的修改
本文摘自:http://blog.csdn.net/nsj820/article/details/65711051.改客户端字符集:通过WINDOWS的运行菜单运行Regedit,修改注册表 Star ...
- SDWebImage的总结
SDWebImage 1> 图片文件缓存的时间有多长:1周 _maxCacheAge = kDefaultCacheMaxCacheAge 2> SDWebImage 的内存缓存是用什么实 ...
- Spring Boot 系列教程11-html页面解析-jsoup
需求 需要对一个页面进行数据抓取,并导出doc文档 html解析器 jsoup 可直接解析某个URL地址.HTML文本内容.它提供了一套非常省力的API,可通过DOM,CSS以及类似于JQuery的操 ...
- PHP全选择删除功能
<script type="text/javascript" language="javascript"> function selectBox(s ...
- 编译使用tinyxml
环境: win7 32位旗舰版,VS2010,tinyxml_2_6_2版本 1.下载tinyxml,并解压到tinyxml文件夹下 2.生成动态链接库 原生的Tinyxml只支持静态库(没有在.h文 ...
- Integer比较值的时候小心使用
package integerdemo; public class IntegerDemo { public static void main(String[] args) { //-128--127 ...
- IDAPython: importing “site” failed
问题:IDA启动时,弹出IDAPython: importing “site” failed对话框. 解决办法:环境变量添加PYTHONHOME,值为python安装路径,比如:C:\Python27
- AI 人工智能 探索 (七)
我简单画了一幅图,来讲下 ai 中的设计模式.图形中的这些人物,我想大家都能看的明白. 当 盗贼出现,人们发现了他们,就 呼叫 主类,然后主类再 通知 下面对应的管理局,然后管理局再 分配人手过去 ...