<a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流!
String类字符串是一个特殊的对象。它一旦初始化就不可以被改变。
String str = "a"; 这个只是一个引用,内存中如果有“a"的话,str就指向它;如果没有,才创建它;
如果你以后还用到"a"这个字符串的话并且是这样用:
String str1 = "a"; String str2 = "a"; 这3个变量都共享一个字符串"a"。
而String str = new String("a")是根据"a"这个String对象再次构造一个String对象,将新构造出来的String对象的引用赋给str。
String类部分方法
lchar charAt(int index)
lint length()
lchar[] toCharArray();
lint indexOf(String str);
lboolean endsWith(String str);
lString[] split(String reg);
lString substring(int index);
lString(char[] arr);
String使用非常方便,因此一般涉及字符串时都用该类进行字符串处理。至于String类的类在机制,则极少去探究。直到读到下面这个例子。
class X |
按照我的理解,类X,类Y,类Z中的三个常量字符串属于不同的对象,用 == 操作符比较,那么结果必然是false,输出应该为:
false |
但实际上输出确是:
true |
使我大惑不解。因此,找了许多资料来看(尤其是C++和Java比较编程,里面解释比较详细),终于逐渐明白了原因。
== 只有在两个比较对象指向同一对象时,其值才为true。X.strX==Y.strY 与 X.strX==Z.strZ 测试结果都为true,说明这三个常量指向的都是同一个对象。
在Java中,String是字符串常量。由相同序列的字符组成的两个字符串属于同一对象,位于内存中的同一个位置。每个字符串常量只有一个String对象来表示。即使这个字符串常量出现在一个程序的不同位置甚至一个程序的不同程序包中。也就是说,X.strX与Y.strY由于都是同一字符序列,因此指向的肯定是同一对象。
Z.strZ也是如此。"hell"+"o",两个常量字符串相加后,创建了一个新的字符串常量(这个工作是编译期间完成的),它与X.strX,Y.strY有相同的字符序列,因此指向同一对象。
虽然一个常量表达式将两个字符串常量链接在一起的结果在编译器已完成,但是,
String s1="hel"; |
这段代码中,s3只能在运行期间创建。这三条语句所创建的"hello"字符串作为String对象存储在内存中的一个独立位置。
Java提供一个机制,通过String类定义的intern()方法把一个运行时创建的字符串加到字符串常量池(如果它还没有入池)。如果上面的三条代码改为:
|
Java将把s1+s2所返回的字符串对象中的字符序列与已经存储在字符串常量池中的字符串进行比较。如果找到一个匹配,intern()就返回这个字符串的引用。如果没有找到匹配,s1+s2所返回的字符串将被加入到字符串常量池中,并返回这个字符串常量的引用。
就解释了为什么X.strX==(s1+s2)返回false,而X.strX==(s1+s2).intern()返回true。(s1+s2).intern()指向strX,strY,StrX指向的字符串常量"hello"。
StringBuffer,字符串的组成原理就是通过该类实现的。StringBuffer可以对字符串内容进行增删。StringBuffer是一个容器。很多方法与String相同。StingBuffer是可变长度的
StringBuffer特有方法
StringBuffer append(int x);
StringBuffer delete(int start, int end );
StringBuffer insert(int index,String str);
StringBuffer reverse();
JDK1.5出现一个StringBuilder,区别是StringBuffer是同步的,StringBuilder是非同步的
基本数据类型对象包装类。将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据。常用的操作之一:用于基本数据类型与字符串之间的转换。例:Integer的parseInt方法,intValue方法。
基本数据类型对象包装类新特性。JDK1.5以后,简化了定义方式。Integer x = new Integer(4);可以直接写成Integer x = 4;//自动装箱。x = x + 5;//自动拆箱。通过intValue方法。
需要注意:在使用时,Integer x = null;上面的代码就会出现NullPointerException
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。数组中可以存储基本数据类型,集合只能存储对象。
集合类的特点
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
集合框架中的常用接口
Collection接口有两个子接口:List(列表),Set(集)。List:可存放重复元素,元素存取是有序的。Set:不可以存放重复元素,元素存取是无序的。List接口中常用类。Vector:线程安全,但速度慢,已被ArrayList替代。ArrayList:线程不安全,查询速度快。LinkedList:链表结构,增删速度快。
取出List集合中元素的方式:get(int index):通过脚标获取元素。iterator():通过迭代方法获取迭代器对象。迭代是取出集合中元素的一种方式。因为Collection中有iterator方法,所以每一个子类集合对象都具备迭代器。
用法:
Iterator iter = l.iterator();
while(iter.hasNext())
{
System.out.println(iter.next());
}
迭代注意事项
迭代器在Collcection接口中是通用的,它替代了Vector类中的Enumeration(枚举)。迭代器的next方法是自动向下取元素,要避免出现NoSuchElementException。迭代器的next方法返回值类型是Object,所以要记得类型转换。面向对象的语言中,所有的类都直接或者间接的继承了Object。方法的返回值类型为Object,返回出来后依然可以用强行转换成datatable,这样做那是因为不能确定你的方法可能返回那种类型,具体的说就是比如方法可能返回出一个String,或者Integer,或者是一个实体对象,但是任何类型都可看做是Object,这是Java面向对象语言的特性。
Set接口中常用的类HashSet:线程不安全,存取速度快。
当HashSet中放入了两个对象后,默认他们的hashCode都是不一样的,因此不需要调用equals方法就能确定这两个对象不是同一个,但是如果这两个对象的值是一样的,这种判断结果就不符合要求了,因此需要重写hashcode方法,将两个对象的hashcode值设为相同,这样就可以进入equals判断阶段,equals方法是继承自object类的,比较的是对象的地址值,所以判断的结果也必定不同,这又不符合要求了,因此也需要重写equals方法。经过改写以上两个方法,可以完成两个对象的比较,只要两个对象的内容(值)相同,就判断为同一个对象,不得重复存储。
TreeSet:线程虽然不安全,但是可以对Set集合中的元素进行排序。通过compareTo或者compare 方法中的来保证元素的唯一性。元素是以二叉树的形式存放的。
HashSet:通过equals方法和hashCode 方法来保证元素的唯一性。
泛型是JDK1.5以后出现的机制。泛型提高了程序的安全性,运行期遇到的问题转移到了编译期,省去了类型强转的麻烦。泛型类的出现优化了程序设计
Map与Collection在集合框架中属并列存在,Map存储的是键值对,存储元素使用put方法,Collection使用add方法。Map集合没有直接取出元素的方法,要想取出元素,必须先转成Set集合,再通过迭代获取元素。Map集合中键要保证唯一性
Hashtable:线程安全,速度慢,不允许存放<null键,null值>,已被HashMap替代。HashMap:线程不安全,速度快,允许存放<null 键,null值>。TreeMap:对键进行排序,排序原理与TreeSet 相同。
集合框架中的工具类。Collections可以对集合进行查找,取出集合中的最大值,最小值等;
Arrays可以将数组转成List集合,对数组进行排序和二分查找。
新增for语句Collection在JDK1.5后出现的父接口Iterable就是提供了这个for语句。
格式:
for(数据类型变量名: 数组或集合)
{
执行语句;
}
简化了对数组,集合的遍历
函数的另一种表现形式
返回值类型 函数名(参数类型… 形式参数)
{
执行语句;
}
其实接收的是一个数组,可以指定实际参数的个数。