Java容易搞错的知识点
一、关于Switch
代码:
Java代码
1 public class TestSwitch {
2 public static void main(String[] args) {
3 int i = 2;
4 switch (i) {
5 case 1:
6 System.out.println(1);
7 case 2:
8 System.out.println(2);
9 case 3:
10 System.out.println(3);
11 default:
12 System.out.println(4);
13 }
14 }
15 }
结果:
2
3
4
分析:
少了break;所以2以下的case和default都执行了一遍。
二、Equals和==运算符
代码:
Java代码
1 public static void test() {
2 String x = "hello";
3 String y = "world";
4 String z = new String("helloworld");
5 String a = "helloworld";
6 System.out.println("x+y equals z:" + (x + y).equals(z));
7 System.out.println("a == z:" + (a == z));
8 System.out.println("x == hello:" + (x == "hello"));
9 System.out.println("a == helloworld:" + (a == "hello" + "world"));
10 System.out.println("a == x+y:" + (a == (x + y)));
11 }
结果:
x+y equals z:true
a == z:false
x == hello:true
a == helloworld:true
a == x+y:false
分析:
1.String.equals()方法比较的是字符串的内容,所以(x + y).equals(z)为true.
2.“==”比较的是 String 实例的引用,很明显 a 和z 并不是同一个 String 实例,所以(a == z)为false.
3.根据常量池的知识,容易得知(x == "hello")和(a == "hello" + "world")都为true.
(常量池指的是在编译期被确定并被保存在已编译的.class 文件中的一些数据。它包含了
关于方法、类、接口等,当然还有字符串常量的信息。也就是所谓的持久代。)
4.那么(a == (x + y))为什么是false呢?这点暂点有点不大清楚。初步认为是x+y是引用相加,不能放入常量池。
三、Override覆盖
代码:
Java代码
1 public class Parent {
2
3 public static String say() {
4 return "parent static say";
5 }
6
7 public String say2() {
8 return "parent say";
9 }
10 }
11
12 public class Child extends Parent {
13 public static String say() {
14 return "child static say";
15 }
16
17 public String say2() {
18 return "child say";
19 }
20 }
21
22 public class OverrideTest {
23
24 public static void main(String[] args) {
25 Parent p = new Child();
26 System.out.println(p.say());
27 System.out.println(p.say2());
28
29 }
30
31 }
结果:
parent static say
child say
分析:
1.我们创建了一个Parent类的实例。变量 p 的数据类型为 Parent 类 但是它仍旧是 Child 类的一个实例。因为Child类覆盖了Parent类的方法say2(),所以p.say2()调用为子类的方法。
2.为什么p.say()却是调用父类Parent的方法呢?因为Java中规定“实例方法被覆盖,静态方法被隐藏”.
关于Override的一些规则:
用子类的静态方法隐藏父类中同样标识的实例方法是不合法的,编译器将会报错;
用子类的实例方法覆盖父类中同样标识的静态方法也是不合法的,编译器同样会报错;
带关键字 final的方法(静态和实例方法)都不能被覆盖;
实例方法能够被覆盖;
抽象方法必须在具体类中被覆盖。
我们知道,在JAVA中,子类可以继承父类,如果子类声明的方法与父类有重名的情况怎么办,大伙儿都知道要是重写,但是实际上这又分为两种情况,就是方法和变量在继承时的覆盖和隐藏问题,这些概念性的东西看似无聊,但是在面试或者是SCJP认证题中围绕这些是会经常碰到的,所以这里来讨论下
首先我们来看几个概念
隐藏 :child隐藏了parent的变量和方法,那么,child不能访问parent被隐藏的变量或者方法,但是,讲B转换成A中,可以访问A被隐藏的变量或者方法
覆盖 :child覆盖了parent的变量或者方法,那么,child不能访问parent被覆盖的变量或者方法,将child转换成parent后同样不能访问parent被覆盖的变量或者方法
首先看一下JAVA中方法和变量在继承时的覆盖和隐藏规则
1.父类的实例变量和静态变量能被子类的同名变量隐藏
2.父类的静态方法被子类的同名静态方法隐藏
3.父类的实例方法被子类的同名实例变量覆盖
还有几点需要注意的是
1.不能用子类的静态方法隐藏 父类中同样标示(也就是返回值 名字 参数都一样)的实例方法
2.不能用子类的实例方法覆盖 父类中同样标示的静态方法
3.这点儿请注意,就是变量只会被隐藏 不会被覆盖 ,无论他是实例变量还是静态变量,而且,子类的静态变量可以隐藏 父类的实例变量,子类的实例变量可以隐藏 父类的静态变量
Java代码
1 //父类
2 class Parent
3 {
4 public static String kind="javastudy.extendsstudy.parent";
5 public static int age=50;
6 public String name="Parent";
7
8 //静态方法,返回包名
9 public static String getKind()
10 {
11 System.out.println("parent的getKind()方法被调用了");
12 return kind;
13 }
14 //静态方法,返回年龄
15 public static int getAge()
16 {
17 System.out.println("Parent的getAge()方法被调用了");
18 return age;
19 }
20
21 //实例方法,返回姓名
22 public String getName()
23 {
24 System.out.println("Parent的getName()方法被调用了");
25 return this.name;
26 }
27 }
28 //子类
29 class Child extends Parent
30 {
31 public static String kind="javastudy.extendsstudy.child";
32 public int age=25;
33 public String name="child";
34
35 //隐藏父类静态方法
36 public static String getKind()
37 {
38 System.out.println("child的getkind()方法被调用了");
39 return kind;
40 }
41
42 //获取父类包名
43 public static String getParentKind()
44 {
45 return Parent.kind;
46 }
47
48 //覆盖父类实例方法
49 public String getName()
50 {
51 System.out.println("child的getName()被调用了");
52 return this.name;
53 }
54
55 //获取父类名称
56 public String getParentName()
57 {
58 return super.name;
59 }
60 /*
61 *错误,实例方法不能覆盖父类的静态方法
62 public int getAge()
63 {
64 return this.age;
65 }
66 */
67 }
68
69
70 class Test
71 {
72 public static void main(String[] args)
73 {
74 Child child=new Child();
75 System.out.printf("子类名称:%s,年龄:%d,包 名:%s%n",child.name,child.age,child.kind);
76 //输出:子类名称:child,年龄:25,包:javastudy.extendsstudy.child
77
78 //把child转换成parent对象
79 Parent parent=child;
80
81 System.out.printf("转换后的名称:%s,年龄:%d,包名:%s%n",parent.name,parent.age,parent.kind);
82 //输出:转换后的名称:Parent,年龄:50,包:javastudy.extendsstudy.parent
83
84 System.out.printf("子类访问父类被隐藏的实例变量name:%s%n",child.getParentName());
85 //输出:子类访问父类被隐藏的实例变量name:Parent
86
87 System.out.printf("子类访问父类被隐藏的静态变量kind:%s",child.getParentKind());
88 //输出:子类访问父类被隐藏的静态变量kind:javastudy.extendsstudy.parent
89
90 child.getName();
91 //输出:child的getName()被调用了
92
93 //**************注意看这个方法,返回的还是子类的getName
94 parent.getName();
95 //输出:child的getName()被调用了
96
97 child.getKind();
98 //输出:child的getkind()方法被调用了
99
100 parent.getKind();
101 //输出:parent的getKind()方法被调用了
102 }
103 }
//父类
class Parent
{
public static String kind="javastudy.extendsstudy.parent";
public static int age=50;
public String name="Parent";
//静态方法,返回包名
public static String getKind()
{
System.out.println("parent的getKind()方法被调用了");
return kind;
}
//静态方法,返回年龄
public static int getAge()
{
System.out.println("Parent的getAge()方法被调用了");
return age;
}
//实例方法,返回姓名
public String getName()
{
System.out.println("Parent的getName()方法被调用了");
return this.name;
}
}
//子类
class Child extends Parent
{
public static String kind="javastudy.extendsstudy.child";
public int age=25;
public String name="child";
//隐藏父类静态方法
public static String getKind()
{
System.out.println("child的getkind()方法被调用了");
return kind;
}
//获取父类包名
public static String getParentKind()
{
return Parent.kind;
}
//覆盖父类实例方法
public String getName()
{
System.out.println("child的getName()被调用了");
return this.name;
}
//获取父类名称
public String getParentName()
{
return super.name;
}
/*
*错误,实例方法不能覆盖父类的静态方法
public int getAge()
{
return this.age;
}
*/
}
class Test
{
public static void main(String[] args)
{
Child child=new Child();
System.out.printf("子类名称:%s,年龄:%d,包名:%s%n",child.name,child.age,child.kind);
//输出:子类名称:child,年龄:25,包:javastudy.extendsstudy.child
//把child转换成parent对象
Parent parent=child;
System.out.printf("转换后的名称:%s,年龄:%d,包名:%s%n",parent.name,parent.age,parent.kind);
//输出:转换后的名称:Parent,年龄:50,包:javastudy.extendsstudy.parent
System.out.printf("子类访问父类被隐藏的实例变量name:%s%n",child.getParentName());
//输出:子类访问父类被隐藏的实例变量name:Parent
System.out.printf("子类访问父类被隐藏的静态变量kind:%s",child.getParentKind());
//输出:子类访问父类被隐藏的静态变量kind:javastudy.extendsstudy.parent
child.getName();
//输出:child的getName()被调用了
//**************注意看这个方法,返回的还是子类的getName
parent.getName();
//输出:child的getName()被调用了
child.getKind();
//输出:child的getkind()方法被调用了
parent.getKind();
//输出:parent的getKind()方法被调用了
}
}
1.同名的实例方法被覆盖 ,同名的静态方法被隐藏 ,child类的getName实例方法覆盖 了parent的getName实例方法,chind的getKind方法隐藏 了parent类的getKind方法
2.隐藏 和覆盖 的区别在于,子类对象转换成父类对象后,能够访问父类被隐藏 的变量和方法,而不能访问父类被覆盖 的方法
3.如果需要访问父类被隐藏 的实例变量,加上super就好了,比如访问父类的name,写上super.name就好了
四、Java强类型
代码:
Java代码
1 public class Type {
2
3 public static void main(String[] args) {
4 double i = 5.0;
5 double j = 1 / 4 + 3 / 4 + i + 12 / 6.0 + 3 / 4 + 1 / 4;
6 System.out.println(j);
7 }
8
9 }
结果:
7.0
分析:
Java 是强类型的 strongly type,它支持8 种基本数据类型。通过对这些基本数据类型用法的严格检查 Java 编译器能够及时地在开发过程中捕捉到许多简单细微的错误。基本数据类型的转换可以隐性地发生,所以转换时会有精度损失。由于1/4和3/4发生隐性类型转换,精度损失,不会生成0.25和0.75,所以有分号的数都为0。
五、假构造函数
代码:
Java代码
1 public class Constructor {
2
3 private int a, b, c;
4
5 public void Constructor() {
6 a = 3;
7 b = 5;
8 c = a + b;
9 }
10
11 public void test() {
12 System.out.println("The value of c :" + c);
13 }
14
15 public static void main(String[] args) {
16 Constructor c = new Constructor();
17 c.test();
18 }
19 }
结果:
The value of c :0
分析:
public void Constructor()并不是一个真正的构造函数,而是一个方法。所以c的值为默认值0.
六、提前引用
代码:
Java代码
1 public class ForwardReference {
2
3 static int first = test();
4 static int second = 2;
5
6 static int test() {
7 return second;
8 }
9
10 public static void main(String[] args) {
11 System.out.println("first = " + first);
12 }
13
14 }
结果:
first = 0
分析:
由于在初始化second之前test方法就访问了它,那么方法得到的是second的默认值,即 0。 因此输出结果first= 0,而不是2。假如你使用方法调用来初始化静态变量,那么你必须保证 这些方法并不依赖于在它们之后声明的其它静态变量。静态变量以及静态初始化块是在类被加载进 JVM 时执行初始化操作的。Java 语言规范8.5节指出“静态初始化块和静态变量是按照其在代码中出现的顺序依次执行初始化操作的,而不能在类变量声明出现之前就引用它”。
七、对象引用
代码:
Java代码
1 public class TestRef {
2
3 public static void main(String[] args) {
4 StringBuffer a = new StringBuffer("a");
5 StringBuffer b = new StringBuffer("b");
6 append(a, b);
7 System.out.println(a.toString() + "," + b.toString());
8 b = a;
9 System.out.println(a.toString() + "," + b.toString());
10 }
11
12 public static void append(StringBuffer a, StringBuffer b) {
13 a.append(b);
14 b = a;
15 }
16 }
结果:
ab,b
ab,ab
分析:
大家来分析一下这题,我还没有完全理解。
我的分析,可能是错的,哈哈,算是抛砖引玉。
1.a.append(b);-->ab 。因为a是引用,所以调用a的方法,相当于直接调用jvm中的a,所做的append也相当于直接在对象上操作,生效。
2.append方法中第一次b=a,-->b。因为a,b都为main方法内局部变量,跨append方法作用域b对a的引用不生效。
3.main方法中第二次b=a,-->ab。因为在同一作用域方法中,b对a的引用生效,。
Java容易搞错的知识点的更多相关文章
- Java线程并发:知识点
Java线程并发:知识点 发布:一个对象是使它能够被当前范围之外的代码所引用: 常见形式:将对象的的引用存储到公共静态域:非私有方法中返回引用:发布内部类实例,包含引用. 逃逸:在对象尚未准备 ...
- 知名互联网公司校招 Java 开发岗面试知识点解析
天之道,损有余而补不足,是故虚胜实,不足胜有余. 本文作者在一年之内参加过多场面试,应聘岗位均为 Java 开发方向.在不断的面试中,分类总结了 Java 开发岗位面试中的一些知识点. 主要包括以下几 ...
- 记录这段时间java编程的小知识点
记录这段时间java编程的小知识点 eclipse项目导入中文乱码 eclipse左侧目录结构变动 eclipse代码段左右移动 按tal键,是整体右移. 按shift table 同时按,是整体左 ...
- Java面试之http知识点(必问)
Java面试之http知识点(必问) 版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/q ...
- 史上最全的Java高级技术点,全是Java高级进阶技术,几乎包含了Java后端的所有知识点
史上最全的Java高级技术点,全是Java高级进阶技术,几乎包含了Java后端的所有知识点 1
- Java工程师的必备知识点
最近参加了一次公司内部的调岗计划,打算加入一个更核心的部门.调岗计划有面试环节,为了不让自己搞砸,悉心准备了将近一个月,请教了百度和腾讯的有过面试官经验的大学同学,系统性的总结了Java工程师的核心知 ...
- 分享Java的9个知识点
关于java编程的知识,有人会问哪些是重要的知识点,不知道大家是否都知道呢? 现在兄弟连 小编给大家分享以下9点内容,仔细看咯! 1.多线程并发 多线程是Java中普遍认为比较难的一块.多线程用好了可 ...
- Java开发岗面试知识点解析
本文作者参加过多场面试,应聘岗位均为 Java 开发方向.在不断的面试中,分类总结了 Java 开发岗位面试中的一些知识点. 主要包括以下几个部分: Java 基础知识点 Java 常见集合 高并发编 ...
- Java集合类常见面试知识点总结
微信公众号[Java技术江湖]一位阿里Java工程师的技术小站 Java集合类学习总结 这篇总结是基于之前博客内容的一个整理和回顾. 这里先简单地总结一下,更多详细内容请参考我的专栏:深入浅出Java ...
随机推荐
- spring springmvc 展示图片,静态资源的处理
jsp中显示一张照片 <img alt="静态图片" src="static/目录.png"> 然后在springmvc的配置中加上 <!-- ...
- 使用netbeans 搭建maven工程 整合spring springmvc框架
使用netbeans7.4 自带的tomcat7.0 所以jdk选择7.xx 然后等待生成空的工程,会缺一些文件夹,和文件,后续需要的时候补齐 然后修改pom.xml添加引用,直接覆盖dependen ...
- Elasticsearch入门学习重点笔记
原文:Elasticsearch入门学习重点笔记 必记知识点 Elasticsearch可以接近实时的搜索和存储大量数据.Elasticsearch是一个近实时的搜索平台.这意味着当你导入一个文档并把 ...
- jedis与spring整合及简单的使用RedisTemplate操作
整理一下redis与spring的整合.以及使用redisTemplate.首先是要导入spring所需要的jar.当然还有 jedis-2.1.0.jar,commons-pool-1.5.4.ja ...
- xor
xor 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他语言1048576K 64bit IO Format: %lld 题目描述 Your are given n ...
- Codeforces 608E. Marbles
E. Marbles time limit per test 2 seconds memory limit per test 256 megabytes input standard input ou ...
- 基于pytest的接口测试
最近要开展接口测试,起初打算使用公司已有的Fitnesse测试工具来进行接口测试.过程中发现,构造接口字段数据.测试数据都比较困难,接口参数多的时候,用例量就会很多,关键执行速度还慢.所以放弃了. 找 ...
- 【二次元的CSS】—— 用 DIV + CSS3 画咸蛋超人(详解步骤)
[二次元的CSS]—— 用 DIV + CSS3 画咸蛋超人(详解步骤) 2016-05-17 HTML5cn 仅仅使用div作为身体的布局,用css3的各种transform和圆角属性来绘制各部位的 ...
- Redhad的开源Paas平台:OpenShift
参考redHat的官方文章翻译而来:https://openshift.redhat.com/community/wiki/architecture-overview OpenShift Origin ...
- 开源PaaS平台:Cloudify
Cloudify是gigaspaces公司推出的基于java的paas平台. refer to :http://timeson.iteye.com/blog/1699730