Java的final关键字与String的内部比较方法

最近抽了点时间温故,一些零零散散的问题还是整理了起来。我决定把一些曾经坑过自己的问题写成博客文章,给学弟学妹们一个警示吧。

今天的故事从一个例子开始:

@Test
	public void testFinal()
	{
		String s1="happyBKsOffer";
		String s2="happyBKs";
		final String s3="happyBKs";//s3.replace("h", "H");
		String s4=s2+"Offer";
		String s5=s3+"Offer";
		if (s1 == s4) {
			System.out.println("s1==s4");
		} else {
			System.out.println("s1!=s4");
		}
		if (s1 == s5) {
			System.out.println("s1==s5");
		} else {
			System.out.println("s1!=s5");
		}

		if (s1.equals(s4)) {
			System.out.println("s1 equals s4");
		} else {
			System.out.println("s1 not equals s4");
		}
		if (s1.equals(s5)) {
			System.out.println("s1 equals s5");
		} else {
			System.out.println("s1 not equals s5");
		}

	}

如果你看到这个代码觉得莫名其妙并且伴随着一点心虚,觉得不都是一样的嘛,那么恭喜你,看完了今天的例子,你就不用再往坑里跳了。如果你一眼就看出了其中的坑,那么也恭喜你,可以在我博客下方评论处BB了,“这也算个问题,太基础了”。(本文出自:http://my.oschina.net/happyBKs/blog/493904,请自行表明出处)

实际的运行结果如下:

s1!=s4
s1==s5
s1 equals s4
s1 equals s5

有没有一点出乎您的意料呢?

那么这到底是怎么了,s4和s5都是"happBKs"与"Offer"的凭借,为什么再==和equals下的结果不相同呢?

我们先说说==和equals方法的区别。这两种判断两个值是否相等的方式其实存在本质的不同。==在判定基本数据类型时,没有什么不同,就是判断连个基本数据类型的值是否相等;在判定对象数据类型时,会根据对象的类中覆盖的equals方法来判定对象是否相等(如果没有重新实现类的equals方法,运行时会判定两个对象的地址是否指向同一个对象)。

这时候,也许纯洁无邪的孩子们会说:“我明白了,如果是int类型,那么equals和==没什么区别,Integer类型则不是”。这时候,就会有人在旁边阴笑,心里想:“拆箱和装箱都不懂,呵呵。。。结果肯定都一样”

我给个例子:

@Test
	public void testInt()
	{
		int a=1,b=1;
		if (a == b) {
			System.out.println("a==b");
		} else {
			System.out.println("a!=b");
		}

//		if (a.equals(b)) {
//			System.out.println("a equals b");
//		} else {
//			System.out.println("a not equals b");
//		}

		Integer c=new Integer(1),d=new Integer(1);
		if (c == d) {
			System.out.println("c==d");
		} else {
			System.out.println("c!=d");
		}

		if (c.equals(d)) {
			System.out.println("c equals d");
		} else {
			System.out.println("c not equals d");
		}

		Integer e=1,f=1;
		if (e == f) {
			System.out.println("e==f");
		} else {
			System.out.println("e!=f");
		}

		if (e.equals(f)) {
			System.out.println("e equals f");
		} else {
			System.out.println("e not equals f");
		}
	}

那么结果会怎么样呢?

a==b
c!=d
c equals d
1
e==f
e equals f

是的,笑别人单纯的人眼睛没有瞎,真的结果就如同小朋友们料想的那么单纯。好了,别捶胸顿足故作恍然大悟了,单纯的结果后面有着不单纯的原因。

首先int的==比较没有什么可多说的。为什么Integer类型的c和d,e和f在equals时会有两种不同的记过呢?这是因为java编译器的优化机制造就的:c和d各自初始化了一个对象类型,所以在==比较时,他们指的不是一个对象,所以==比较是不同的,而Integer的equals方法已经重写,比较的是两者实际的整型数值,所以是相等的。e和f的确用到了装箱的拆箱,但是java编译器在编译时做了优化,将两个常量1装箱后优化为一个对象,这样e和f指向同一个Integer对象了,所以在==时是相同的。

回到我们刚才的实例中。s2和s3虽然都是"happyBKs",但是s2是final类型,s3是一般的类型。在java编译器编译时,同样会对常量数值做一些优化,编译器会将s4=s2+"Offer"进行优化,因为s2是常量、"Offer"也是常量,所以,s4会在编译后直接被转换成s4="happyBKsOffer",而s1的初始化赋值也是常量"happyBKsOffer",所以编译器会再次将它们优化为一个String对象,s1和s4指向同一个String对象,所以两者在==是相同的。而s5=s3+"Offer",s3不是final的,所以必须在运行时计算,这样s5只有在运行时候才能生成一个对象,肯定与s1的那个不是同一个String对象,所以s1与s5在==比较时肯定是不同的。

明白了吧。也许你还是很揪心,我们这里只给出一个建议吧:那就是,尽量养成用equals的好习惯!

好最后,我们队final 本身再做个总结:final可以修饰类、方法和变量。

修饰类

当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。

  在使用final修饰类的时候,要注意谨慎选择,除非这个类真的在以后不会用来继承或者出于安全的考虑,尽量不要将类设计为final类。

修饰方法

  使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java版本中,不需要使用final方法进行这些优化了。

  因此,如果只有在想明确禁止 该方法在子类中被覆盖的情况下才将方法设置为final的。

  注:类的private方法会隐式地被指定为final方法。

修饰变量

  修饰变量是final用得最多的地方,也是本文接下来要重点阐述的内容。首先了解一下final变量的基本语法:

  对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

String类型我们也做一个补充总结:

String不是基本类型,而是对象类型,并且,其内部哟一个final的char数组,因此String的方法中不提供修改String中内容字符的方法。即便是subString、replace等看似修改了String的方法,其实只是返回了一个新的String对象,而原数组没有变化。这样做的目的有性能的、线程安全诸多方面的考虑,以后我会专门开一个文章讲这个。

时间: 2024-10-05 23:26:46

Java的final关键字与String的内部比较方法的相关文章

聊聊Java的final关键字

Java的final关键字在日常工作中经常会用到,比如定义常量的时候.如果是C++程序员出身的话,可能会类比C++语言中的define或者const关键字,但其实它们在语义上差距还是挺大的. 在Java中,final可以用来修饰类.方法和变量(包括成员变量和局部变量).我们先来简单介绍一下final关键字的这几个用法. 一.final修饰类 常见的一个例子就是String类.当用final修饰一个类时,表明这个类不能被继承,并且final类中的所有成员方法都会被隐式地指定为final方法,但成员

Java之final关键字解析

Java之final关键字解析 final关键字可以修饰不同的内容,这些内容仅包括一个变量,一个方法或者一个类,以下是final修饰这些内容的作用: final变量:表示该变量为常量,即只能初始化一次 final方法:表示该方法不能被重写 final类:表示该类不可以被继承 final变量 当一个变量被final关键字修饰时,意味着它的值不可以被修改了,也就是说,这个变量表示一个常量.这也意味着final变量必须被初始化.如果一个final变量表示的是一个对象的引用,那么该变量就不能重新表示另一

关于Java中final关键字的用法总结

用于数据 永不改变的编译时常量,必须是基本类型,static final常量定义时必须赋值 一个运行时被初始化却又不希望被改变的值 空白final,确保使用前必须被初始化,但有更大的灵活性 final参数,用于对象引用,对象不可改变,用于基本类型,值不可以改变 用于方法 防止方法的行为被改变,不可覆盖 private方法默认为final的 曾经使用final方法可以提高效率,现已不提倡 用于类 表示该类不可以被继承 final类方法默认指定为final的 关于Java中final关键字的用法总结

Java基础001:final关键字、String字符串的相加问题

1.final关键字的作用 1.1.final修饰的类:不能被其他类继承:1.2.final修饰的方法:不能被子类重写1.3.final修饰的变量:分两种情况,引用变量.基本类型变量,如下: final修饰的引用变量:一旦给其赋值,就不能被再次赋值 final String s = "32"; //引用变量 s = "1"; /** 报错:The final local variable s cannot be assigned. It must be blank

Java之final关键字

1.final类 final类不能被继承,因此final类的成员方法没有机会被覆盖,默认都是final的.在设计类时若不需要有子类,类的实现细节不允许改变,并且确信不会再被扩展,那么就设计为final类. 2.final方法 如果类的某个方法不允许子类覆盖,则可以把该方法声明为final方法.使用final方法的原因有二: 第一.把方法锁定,防止任何继承类修改它的意义和实现. 第二.高效.编译器在遇到调用final方法时候会转入内嵌机制,大大提高执行效率. 3.final变量(常量) final

Java 1.7.0_06中String类内部实现的一些变化【转】

原文链接: java-performance 翻译: ImportNew.com- 夏千林译文链接: http://www.importnew.com/7656.html ChangeLog: 2013年11月19日,更新了Java8版本中的变化. 013年11月28日,更新了Java 7u40版本中的变化.(感谢Sunny Chan以及他的同事提示我关注新版本的JDK) 共享一个基础char[]  原先的String类中有4个非静态变量: char[] value用于存储字符串. int of

java 对 final 关键字 深度理解

基础理解 : 1.修饰类 当用final去修饰一个类的时候,表示这个类不能被继承.处于安全,在JDK中,被设计为final类的有String.System等,这些类不能被继承 .注意:被修饰的类的成员可以是final修饰,可可以不是 . 2.修饰方法 : 方法不能被子类重写.常用在类设计时不希望被子类重写而修饰. 3.修饰方法参数 : 被修饰 的参数变量,不能在方法体内再次被赋值.这个好像是站在调用者的角度考虑的哈,就好像有个大佬拿了把菜刀给我,叫我去看人 ,大佬说,你一定要用这把菜刀去砍,不要

java中final关键字的作用

1.被final关键字修饰的类不能被继承 final class Father{ } public class Son extends Father { } //Son不能继承Father类 2.final 修饰的方法不能被重写 3.final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改 (1)对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改:如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象. 上面的一段代码中,对变量i和引用

关于java中final关键字与线程安全性

在Java5中,final关键字是非常重要而事实上却经常被忽视其作为同步的作用.本质上讲,final能够做出如下保证:当你创建一个对象时,使用final关键字能够使得另一个线程不会访问到处于"部分创建"的对象,否则是会可能发生的.这是 因为,当用作对象的一个属性时,final有着如下的语义: 当构造函数结束时,final类型的值是被保证其他线程访问该对象时,它们的值是可见的 为什么是必须的 使用final是所谓的安全发布(safe publication)的一种方式,这里,发布(pub