`
donlianli
  • 浏览: 340482 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
Group-logo
Elasticsearch...
浏览量:218592
社区版块
存档分类
最新评论

重新认识不可变对象String

阅读更多

    我们在最初学习时,在Java中,String被列为复合性数据类型,但现在来看,其实他真正的是一个不可变类,而与之属于一类的还有Integer,Long,Double,Float,Boolean等对象。所有这些类都有一个共同的特性,就是不可变性。一旦这个类被初始化,他的状态不再变化。这些类都被设计成final类型的,这些类只有一个构造方法。一旦被构造出来,就再也无法修改其内部状态。

   这些作为原始数据类型的封装类,可以直接参与一些集合类的运算,比如,可以直接在一个String的list里面,将某个string给remove掉,可以将两个list做差集等等,总之,这些基本的不可构建类,对于一些集合操作jdk都已经帮我们封装好。但是我们自己定义的类,却不能拿起做差集和随便remove。

比如下面的代码,可以正确运行:

 

public class App {
	public static void main(String[] args) {
		List<String> list = new ArrayList<String>();
		list.add("abcdefg");
		list.add("higklmn");
		System.out.println("before remove:"+list.size());
		list.remove("higklmn");
		System.out.println("after remove:"+list.size());
	}
}

 我举上面的例子是说明,这些不可变类,通常已经重写了默认的equals方法及hashcode方法,例子可能不太恰当,但这估计是JDK中唯一一类重写了equals和hashcode的类。但是下面的代码,却不能正常运行:

 

 

public class App {
	public static void main(String[] args) {
		List<AObject> list = new ArrayList<AObject>();
		list.add(new AObject(1,2));
		list.add(new AObject(3,4));
		System.out.println("before remove:"+list.size());
		list.remove(new AObject(3,4));
		System.out.println("after remove:"+list.size());
	}
	static class AObject{
		private int a;
		private int b;
		public AObject(int a,int b){
			this.a = a;
			this.b = b;
		}
	}
}

 这就是我们在写Java的时候,不能使用两个Object的==或者equals来判断对象是否相同的原因。

 

同时,通过以上的用法,可以看出,String和int等基本数据类型相差比较的,相反,String是一个类,是一种特殊的类。

 

线程安全

不可变类除了具有以上特性外,最重要的莫过于线程安全了。Java并发编程实战中告诉我们,除非使用同步,否则尽可能的使用不可变对象。因为不可变对象即使不使用同步技术也不会出现线程安全的问题。根据我个人的理解,使用不可变对象时,Java总能保证对象在初始化完毕后,才将对象发布出去,这样就不会出现失效数据,不会出现对象处于一种不安全的发布装。

 

如果我们也要用到jdk的集合类,我们可能也要写一些不可变类,但有一个原则,就是对象一旦创建,不能在修改其状态或者方法的值。如何创建不可变类,这里有一遍文章比较好,大家可以参考:Java的可变类与不可变类

 
对这类话题感兴趣?欢迎发送邮件至donlianli@126.com
关于我:邯郸人,擅长Java,Javascript,Extjs,oracle sql。
更多我之前的文章,可以访问 我的空间

 

2
6
分享到:
评论
10 楼 andyLee520 2013-07-12  
donlianli 写道
lijinhaiangel 写道
你举的例子就不对吧:list.remove(new AObject(3,4));这段代码相当于remove的一个新生成的对象,如果是这样的就OK啊: AObject aObject= new AObject(3,4); list.add(aObject);  list.remove(aObject);


	public static void main(String[] args) {
		List<Long> list = new ArrayList<Long>();
		list.add(new Long(1));
		list.add(new Long(3));
		System.out.println(list.size());;
		list.remove(new Long(3));
		System.out.println(list.size());;
	}


这段代码怎么解释?



因为这段代码使用的是 new Long 而源代码中Long是重写了equals方法的。
9 楼 andyLee520 2013-07-12  
详细请参见ArrayList源代码,remove(Object o) 方法,你就会明白为什么第二种remove会报错了。
总体来讲,楼主总结的很好!
8 楼 yixiandave 2013-07-11  
static class AObject{ 
        private int a; 
        private int b; 
        public AObject(int a,int b){ 
            this.a = a; 
            this.b = b; 
        } 
    }
这种对象无法被remove掉只因为你没有重写equals方法
你自己去查看ArrayList源码就会发现,remove方法实际上就是遍历数据,执行equals匹配成功的移除,和是否原数据封装类无关
7 楼 菜鸟java 2013-07-10  
学习了!楼主写的很好
6 楼 donlianli 2013-07-09  
mike.liu 写道
mike.liu 写道
donlianli 写道
lijinhaiangel 写道
你举的例子就不对吧:list.remove(new AObject(3,4));这段代码相当于remove的一个新生成的对象,如果是这样的就OK啊: AObject aObject= new AObject(3,4); list.add(aObject);  list.remove(aObject);


	public static void main(String[] args) {
		List<Long> list = new ArrayList<Long>();
		list.add(new Long(1));
		list.add(new Long(3));
		System.out.println(list.size());;
		list.remove(new Long(3));
		System.out.println(list.size());;
	}


这段代码怎么解释?


list.remove(Object obj)方法,是调用的obj.equals()进行判断。Long类型重载了equals()方法,因此虽然是两个不同的Long对象,只要值相同,则equals()返回true。AObject没有重载equals()方法,因此其默认实现是判断两个对象是否为同一个,即使用的==进行判断。


你只要正确地重载了AObject的equals()方法,则你的第二段代码也可以运行正确。
你举的例子,与final类完全无关。


你分析的很对,jdk对String,Long等不可变类都重写了这些方法,我的意思就是说明这些。我举得例子主要是说明Jdk自带的集合类对这些基础不可变对象可以进行一些基本的支持,比如像删除这样的操作,并不是说对final类的支持。要写自己定义的不可变类,需要把hashcode和equals等方法都重写的。
5 楼 mike.liu 2013-07-09  
mike.liu 写道
donlianli 写道
lijinhaiangel 写道
你举的例子就不对吧:list.remove(new AObject(3,4));这段代码相当于remove的一个新生成的对象,如果是这样的就OK啊: AObject aObject= new AObject(3,4); list.add(aObject);  list.remove(aObject);


	public static void main(String[] args) {
		List<Long> list = new ArrayList<Long>();
		list.add(new Long(1));
		list.add(new Long(3));
		System.out.println(list.size());;
		list.remove(new Long(3));
		System.out.println(list.size());;
	}


这段代码怎么解释?


list.remove(Object obj)方法,是调用的obj.equals()进行判断。Long类型重载了equals()方法,因此虽然是两个不同的Long对象,只要值相同,则equals()返回true。AObject没有重载equals()方法,因此其默认实现是判断两个对象是否为同一个,即使用的==进行判断。


你只要正确地重载了AObject的equals()方法,则你的第二段代码也可以运行正确。
你举的例子,与final类完全无关。
4 楼 mike.liu 2013-07-09  
donlianli 写道
lijinhaiangel 写道
你举的例子就不对吧:list.remove(new AObject(3,4));这段代码相当于remove的一个新生成的对象,如果是这样的就OK啊: AObject aObject= new AObject(3,4); list.add(aObject);  list.remove(aObject);


	public static void main(String[] args) {
		List<Long> list = new ArrayList<Long>();
		list.add(new Long(1));
		list.add(new Long(3));
		System.out.println(list.size());;
		list.remove(new Long(3));
		System.out.println(list.size());;
	}


这段代码怎么解释?


list.remove(Object obj)方法,是调用的obj.equals()进行判断。Long类型重载了equals()方法,因此虽然是两个不同的Long对象,只要值相同,则equals()返回true。AObject没有重载equals()方法,因此其默认实现是判断两个对象是否为同一个,即使用的==进行判断。
3 楼 donlianli 2013-07-09  
lijinhaiangel 写道
你举的例子就不对吧:list.remove(new AObject(3,4));这段代码相当于remove的一个新生成的对象,如果是这样的就OK啊: AObject aObject= new AObject(3,4); list.add(aObject);  list.remove(aObject);


	public static void main(String[] args) {
		List<Long> list = new ArrayList<Long>();
		list.add(new Long(1));
		list.add(new Long(3));
		System.out.println(list.size());;
		list.remove(new Long(3));
		System.out.println(list.size());;
	}


这段代码怎么解释?
2 楼 de6566088 2013-07-09  
AObject 需要重新定义hashcode才能判定出AObject传入相同的参数值时,其关系是否相等。
1 楼 lijinhaiangel 2013-07-09  
你举的例子就不对吧:list.remove(new AObject(3,4));这段代码相当于remove的一个新生成的对象,如果是这样的就OK啊: AObject aObject= new AObject(3,4); list.add(aObject);  list.remove(aObject);

相关推荐

    java自制string类例程

    在Java编程语言中,String类是一个非常基础且重要的部分,它是不可变的,也就是说一旦创建了一个String对象,就不能更改它的内容。然而,许多初学者在学习过程中可能会尝试自己创建一个类似的字符串类,以便更好地...

    Javascript实例-String对象-唐诗三百首

    JavaScript是Web开发中不可或缺的一部分,尤其对于前端开发者来说,它提供了丰富的功能来处理文本数据,如字符串。在本实例中,“Javascript实例-String对象-唐诗三百首”着重讲解了如何利用JavaScript的String...

    重新认识JavaScript

    - **跨平台发展**:除了在浏览器环境中广泛应用外,JavaScript还被集成到诸如Adobe Acrobat、Photoshop等桌面应用中,甚至在服务器端(如Node.js)、移动应用开发(如React Native)等领域都有着不可替代的地位。...

    Web前端开发技术-认识JavaScript的对象.pptx

    JavaScript是Web前端开发中至关重要的语言,特别是在处理用户交互和数据操作方面。对象是JavaScript的...在实际开发中,还会涉及到对象的原型链、继承、封装等高级特性,这些都是深入理解JavaScript不可或缺的部分。

    Java面向对象基础源代码教程

    面向对象编程(Object-Oriented Programming,OOP)是Java的核心理念,它允许开发者通过模拟真实世界中的对象和概念来组织代码,使得程序更加模块化、可维护和可扩展。在"Java面向对象基础源代码教程"中,我们将深入...

    JSP九大内置对象

    ### JSP九大内置对象详解 #### 一、概述 ...JSP内置对象是JSP环境中预定义的一系列对象,它们在JSP页面中可以直接使用而...在实际项目开发中,根据具体需求合理利用这些内置对象能够有效地提高程序的可维护性和可读性。

    c#中string的特性介绍及注意事项小结

    在这个例子中,`MachHello`方法中的`hello`赋值并不会改变原始`hello`变量,因为`string`对象是不可变的。因此,即使在方法内部改变了`hello`,原始的`hello`仍然保持不变,这是由于字符串的副本被创建并用于新值。 ...

    快学Scala课后习题答案

    例如,`val x = 5` 创建了一个不可变变量,而`def add(a: Int, b: Int): Int = a + b` 定义了一个接受两个整数并返回它们之和的函数。 2. **类型系统**:Scala有强大的静态类型系统,类型推断使得编程更为便捷。...

    Android知识体系梳理(4)-Java基础篇-Object方法分析,String的深度解析,String Pool分析,与StringBuilder、StringBuffer的对比

    String是Java中最常用的类之一,它表示不可变的字符序列。String对象存在于Java的字符串常量池(String Pool)中,这个池是为了优化性能,避免多次创建相同的字符串对象。当创建一个新的String实例时,如果常量池中...

    认识Java的Class类.doc

    1. **Class类对象的创建**:在Java中,我们不能直接创建Class对象,因为它的构造函数是private的。当我们加载一个类时,Java虚拟机(JVM)会自动创建对应的Class对象。类的加载可以通过以下几种方式: - 类的实例化...

    学习笔记java\CoreJava笔记\CoreJava_day05

    在Java中,String是一个不可变的对象,这意味着一旦创建,其内容就不能改变。笔记列举了四种可能的String对象状态: 1. 空(默认值),没有被初始化。 2. 有指针,但指向一个空字符串 ""。 3. 未初始化,仅声明但未...

    C#面向对象程序设计及实践教程PPT第二章.pptx

    - **常量**:其值在程序运行期间不可变。 - **声明格式**:`const 数据类型 常量名 = 数值表达式;` - 示例:`const float RATE = 0.035;` - **注意事项**: - 常量必须初始化且不能修改。 - 常量值只能是常量或...

    认识C#中的委托和事件

    通过以上介绍可以看出,委托和事件是.NET Framework中不可或缺的概念。掌握它们不仅可以帮助我们更好地理解和编写高质量的C#代码,还能让我们在实际项目开发中更加得心应手。希望本文能为初学者提供一定的帮助,让...

    JavaScript中的全局对象介绍

    在JavaScript编程中,全局对象是一个非常重要的概念,它为JavaScript程序提供了一个可供访问的全局命名空间。全局对象包含了一些基本的属性和方法,使得开发者可以在任何地方方便地访问这些资源。本文将详细介绍...

    关于Java栈与堆的思考

    字符串在Java中是不可变的(immutable),这意味着一旦一个字符串对象被创建,它的值就不能被改变。这有助于提高程序的安全性和效率。 #### 四、结论与建议 通过上述分析,我们可以得出以下结论和建议: - **结论...

    Java应届生面试题1.doc

    String 是不可变的,StringBuffer 和 StringBuilder 是可变的,后两个类都可以进行字符串的修改和追加操作。 二、 JSP 7. forward 和 redirect 的区别(4 分) Forward 和 redirect 都可以实现页面跳转,但是 ...

    面向对象课程设计c#

    然而,在实际操作过程中,许多国内企业在客户信息管理方面遇到了不少挑战,例如缺乏对客户信息价值的认识、信息管理分散不集中、信息应用效率低等问题。 本次课程设计的目标是设计并实现一个面向对象的客户信息管理...

    认识PHP的基本语法

    变量与常量是编程中的基础概念,变量存储可变的数据,而常量存储不可变的数据。常量一旦定义,其值不能被改变,通常使用define函数定义。 运算符用于执行算术、比较、逻辑等操作。PHP支持算术运算符(如+、-、*、/...

    Java学习笔记

    面向对象的主要优势在于提高了代码的可重用性和模块化程度,使得大型软件系统的开发和维护变得更加高效。 #### 对象与类的概念 - **对象**:对象是现实世界中的实体在计算机中的抽象表示。每一个对象都有自己的...

Global site tag (gtag.js) - Google Analytics