您的位置:首页 > 编程语言 > Java开发

Java容易搞错的知识点

2014-03-09 10:12 357 查看
一、关于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的引用生效,。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: