Java学习的第四周
一 String类:
在自定义类中对toString()方法的重写, 打印输出时对toString()方法的调用问题
举例:
```java
public class ToStringTest{
static int i = 1;
public static void main(String args[]){
System.out.println("love " + new ToStringTest());
// I love java
ToStringTest a = new ToStringTest();
a.i++;
System.out.println("me " + a.i);//me 2
}
public String toString(){
System.out.print("I ");//I
return "java ";
}
}
// 运行结果: I love java me 2
------
> **原因:**
>
> 当执行代码的时候,首先加载静态变量,然后执行main方法,由于main方法内部第一行代码为输出语句,里面new了此类对象,当执行此行代码时会先创建了本类的对象,由于此类重写了toString方法,会先执行toString方法的打印输出,然后返回“java ”,再执行main方法第一行打印输出。在Java中“System.out.println(类对象名);”实际输出的是该对象的toString()方法返回的字符串,即括号中的内容等价于类对象名.toString(),toString方法的好处是在碰到println方法的时候会被自动调用,不用显示的写出来。
### **1.String类中的equals方法与object类中的equals方法的不同点:**
答:String类中的equals方法是用来判断两个对象的内容是否相同,而Object 类中的equals方法是用来判断两个对象是否是同一个对象,所谓同一个对象指的是内存中的同一块存储空间。
### **2.String作为形参与StringBuffer作为形参的区别:**
答: String为常量, 特殊的引用类型, 当String作为形参的时候, 不会影响到实际参数
StringBuffer作为形参, 会影响到实际参数.
**举例:**
```java
public Static void main
3.String类的常用方法:
String的判断功能:
public boolean equals(Object anObject) // 判断字符串内容与指定的对象中的内容是否一致!
public boolean equalsIgnoreCase(String anotherString) // 忽略大小写比较 (前两个使用较多)
public boolean contains(String s) // 判断是否包含指定的字符串 (是否包含指定的内容:开发中使用居多)
public boolean startsWith(String prefix) // 判断当前字符串是否在这里插入代码片以指定的内容开头
public boolean endsWith(String suffix) // 判断当前字符串是否指定的内容结尾
public boolean isEmpty() // 判断字符串内容是否为空: 如果为空,返回true
String 的获取功能:
* public char charAt(int index):获取指定索引处的字符
* public int indexOf(String str):获取指定字符串在大字符串中第一次出现是索引
* public static String valueOf(int i) : 将int类型转换成字符串
* valueOf():万能方法,可以将任意的类型转换字符串
* public String concat(String str):字符串拼接
* public int length():获取字符串的长度
* public String[] split(String regex):字符串的分割功能:
* // 按照指定的字符串格式将字符串分割成字符串数组
* // 举例: String s = "JavaEE-Python-Hadoop-Golang-R" ;
* // 以"-"字符串将s拆分字符串数组在这里插入代码片
* String[] strArray = str.split("-") ;
String的转换功能:
* public byte[] getBytes() :以平台的默认编码集将字符串数据转换成字节数组
* public char[] toCharArray() (使用居多):将字符串转换成字符数组
* public String toLowerCase() :将字符串数据转换成小写
* public String toUpperCase(): 将字符串数据转换成大写
* //将任意类型转换成字符串
* public static String valueOf(int a)
* public static String valueOf(char ch)
String的分割功能:
public String substring(int beginIndex)//从指定位置处开始默认截取到末尾
* public String substring(int beginIndex, int endIndex)
* //从指定位置处开始截取到指定位置结束(包前不包后)
* //后面这个位置是:endIndex-1处
String的替换功能以及按照字典顺序比较:
public String replace(char target,Char replacement):
* //参数1:以前的字符
* //参数2:新的字符去替换以前的字符
* public String replace(String oldStr,String newStr):去替换字符串
*
* //去除字符串两端空格:trim()
* //按照字典顺序比较:
* public int compareTo(String anotherString):
* //使用当前字符串内容和指定的anotherString按照字典顺序比较!
字符串常量和变量的区别:
-
字符串变量相加:先开空间(产生地址值),在相加,还需要判断当前相加后的结果在常量池中是否存在
-
字符串常量相加:先相加,然后在常量池中找是否存在该常量,如果存在,直接返回地址值;如果不存在再开空间
举例:
public static void main(String[] args) {
String s1 = "hello" ;
String s2 = "world" ;
String s3 = "helloworld" ;
//s1:开空间"hello"的空间值 s2:开空间 "world"
System.out.println((s1 +s2) == s3); //false
//比较字符串内容是否相同
System.out.println((s1+s2).equals(s3));///true
System.out.println("--------------------------");
System.out.println(s3 == "hello"+"world");//true
System.out.println(s3.equals("hello"+"world"));//true
4.compareTo(String anotherString) 如何按照字段顺序比较
源码分析:
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
结论: 当两个字符串第一个字符不相同时, 返回 两字符的差值 (第一个字符对应的ASCII表值的差值) 当参数为一个子字符串时, 从第一个开始是相同的字符, 返回两字符长度的差值,即转换成char数组后长度相减.
二 字符串常量池
字符串创建的两种方式:
1.字面值的方式创建字符串
String s1 = "abx";
String s2 = "abx";
System.out.println(s1==s2); // true
采用字面值的方式创建字符串, JVM首先会去字符串池中寻找, "abx"这个对象, 如果不存在则在常量池中创建"abx"这个对象, 然后将这个对象的地址值返回给对象的引用s1; 存在的情况, 不会创建任何对象, 直接将"abx"对象的地址值返回赋给s2. 因为s1和s2指向同一个字符串常量池的"abx"对象, 所以结果为true.
2.使用new关键字创建字符串**
String s1 = new String("qwer");
String s2 = new String("qwer");
System.out.println(s1==s2); // false
当使用new 关键字创建字符串时, JVM首先会去字符串常量池中查找是否有"qwer"这个字符串, 如果有则不在字符串常量池中创建"qwer"这个对象, 直接在堆中创建这个"qwer"字符串对象;
当字符串常量池中没有时, 首先会在字符串常量池中创建"qwer"这个字符串对象, 然后会在堆中创建一个"qwer"字符串对象, 然后将堆中这个字符串对象的地址返回赋给s3引用,s3指向了堆中创建的这个"xyz"字符串对象。s4则指向了堆中创建的另一个"xyz"字符串对象。s3 、s4是两个指向不同对象的引用,结果为false。
三 StringBuffer(字符串缓冲区)
1.特点:
StringBuffer:是一个线程安全的可变的字符序列! 提供了字符串缓冲区(里面存储的内容都是字符串数据)在单线程程中,StringBulider去替代StringBuffer(具有相互兼容的API), JVM自动的优化,在单线程程序中,底层转换为StringBuiler类进行运算.(单线程中不考虑安全问题,只考虑效率问题)
2.常用功能:
StringBuffer的构造方法
* public StringBuffer():无参构造,默认缓冲区大小,初始容量16个字符 (默认缓冲区大小足够!)
* public StringBuffer(int capacity):指定固定大小的初始容量,构造一个字符串缓冲区
* public StringBuffer(String str):构造一个缓冲区大小,容量大小等于字符串长度+初始容量16
StringBuffer的获取功能
* public int capacity():获取字符串缓冲区的容量大小!
* public int length():获取字符串缓冲区中的字符串长度!
StringBuffer的添加功能(重点)
* append(boolean /int/String....)
* //追加到末尾(末尾追加),可以追加任何数据类型,返回值是它本身
*
* public StringBuffer insert(int offset,String str):
* //在指定位置处添加指定的字符串(在指定位置处的前面插入数据)
StringBuffer的删除功能
* //删除指定索引处的字符,返回缓冲区本身 (推荐)
* public StringBuffer deleteCharAt(int index)
*
* //删除从指定位置开始到指定位置结束的字符(包前不包后)end-1处
*
* public StringBuffer delete(int start, int end)
StringBuffer的替换/反转功能
* //从指定位置开始到指定位置结束(end-1处)位置的字符使用新的str字符串替换掉
* public StringBuffer replace(int start ,int end, String str)
*
*
* (重点)
* public StringBuffer reverse() :将字符串缓冲区的字符串进行反转
*
String和StringBuffer两个类型转换
1.String--->StringBuffer的转换
a)StringBuffer(String str)
b)StringBuffer()+append(String str)
2.StringBuffer-->String的转换
a)String(StringBuffer buffer)
b)StringBuffer的功能: public String toString()
StringBuffer截取功能等
* public String substring(int start):从指定位置默认截取到末尾
* public String substring(int start,int end) //从指定位置截取到指定位置(end-1)处结束
Integer类:
Integer类型是int类型的包装类类型.
int ---> String
Intger类中:
* public static String valueOf(int value)
* public static Integer valueOf(int i) ---> Intger类名的 int intValue()
* String---->int (开发中使用居多!)
* Integer类中:
* public static int pareseInt(String str)
四 集合
举例:
System.out.println(((Student)it.next()).getName()+”---”+((Student)it.next()).getAge()); // 错误
注意事项:迭代器在使用的时候,有人为了方便,如下使用就会有问题
System.out.println(((Student)it.next()).getName()+”—”+((Student)it.next()).getAge());
因为集合只能存对象,默认的是Object类的对象, 上级不能调用下级, 必须进行强制类型转换. 多态的强制类型转换方式.
1.集合的五种遍历方式:
1) 使用普通for循环遍历
for(int i = 0; i < list.size(); i++){
System.out.println(list.get(i)+" ");
}
2) 使用Iterator迭代器进行遍历
ArrayList<String> list = new ArrayList<String>();
Iterator it = list.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
3)使用ListIterator列表迭代器进行集合的遍历
ArrayList<String> list = new ArrayList<String>();
ListIterator it = list.listIterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
4)使用增强for循环进行遍历
for(String s : list){
System.out.println(s);
}
5)使用toArray()方法将集合转化为数组进行遍历
ArrayList<String> list = new ArrayList<String>();
String[] arr = list.toArray();
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
2.List集合下ArrayList, LinkedList, Vector三种集合的特点:
ArrayList:
底层数据结构是一个数组, 查询快, 增删慢,具有扩容性
线程不安全, 不同步, 执行效率高!
LinkedList:
底层数据结构是链接列表, 查询慢, 增删快
线程不安全, 不同步, 执行效率高!
Vector:
底层数据结构是对象数组, 查询快, 增删慢
线程安全, 同步, 执行效率低
3.Set集合下的HashSet和TreeSet集合的特点:
HashSet:
底层是一种哈希表(数组+链表/红黑树), 基于HashMap实现的,默认构造函数是构建一个初始容量为16,
负载因子为0.75 的HashMap。 保证元素不重复, 元素唯一, 存储和取出的顺序不一致 (无序性)
add(Object obj)—>依赖于HashMap(K,V)集合的put(K,V)—>最终依赖于hashCode()和equals()方法
如果是自定义的类中重写hashCode() 和equals() 方法, 就可以将重复的元素去掉.
LinkedHashSet:
底层数据结构是链表和哈希表组成, 元素唯一, 但是有序.
TreeSet:
基于HashMap的一种红黑树结构(Red- Block- Tree), 其实就是一个二叉树结构
构造方法:
1) 无参构造 public TreeSet() --> 自然顺序排序
2) 有参构造 选择器排序
**注意:**TreeSet<Student自定义类型>,如果自定义类型,要进行自然排序,这个自定义类型必须实现Comparable接口.
TreeSet中的add方法的源码:
interface Colletion{
}
interface Map<K,V>{
}
interface NavigableMap<K,V> extends Map<K,V>{
}
class TreeMap<K,V> implements NavigableMap<K,V>{
public V put(K key, V value) { //key=20,18,13,22,17,19,18,24
Entry<K,V> t = root; //键值对对象 声明变量t this.root(this:TreeMap集合对象)
if (t == null) { //如果键值对对象为空
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null); //创建一个新的键值对对象
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent; //声明父节点(键值对)
// split comparator and comparable paths
//选择器排序
//TreeSet() {}
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
//自然排序
//key=20,18,13,22,17,19,18,24
if (key == null) //判断的元素内容是否空
throw new NullPointerException(); //肯定会抛出空指针异常
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key; //Object key (Student)
do {
parent = t; //将第一个节点作为父节点(根节点) 20
cmp = k.compareTo(t.key); //后面进来的元素根节点进行比较
if (cmp < 0)
t = t.left; //存储根节点的左边
else if (cmp > 0)//否则大了,根节点的右边
t = t.right;
else
return t.setValue(value); //相等,将以前的元素进行存储
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
}
interface Set extends Collection{
}
class TreeSet implements Set{
private transient NavigableMap<E,Object> m;
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
}
Map集合:
HashMap<K,V>:
底层数据结构哈希表, 元素存取的顺序不能保持一致. 键必须唯一, 不重复, 需要重写键的hashCode()方法, equals()方法.
LinkedHashMap<K,V>:
存取的数据结构为哈希结构+链表结构. 通过链表结构可以保证元素的存取顺序一致: 通过哈希表结构可以保证键的唯一,不重复, 需要重写键的hashCode() 和equals() 方法.
注意: Map 接口中的集合都有两个泛型常量<K,V>, 在使用时, 需为两个泛型赋予数据类型. 两个泛型的数据类型可以相同, 也可以不同.
Map中常用的方法:
public V put(K key, V value)
: 把指定的键与指定的值添加到Map集合中。public V remove(Object key)
: 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。public V get(Object key)
根据指定的键,在Map集合中获取对应的值。boolean containsKey(Object key)
判断集合中是否包含指定的键。public Set<K> keySet()
: 获取Map集合中所有的键,存储到Set集合中。public Set<Map.Entry<K,V>> entrySet()
: 获取到Map集合中所有的键值对对象的集合(Set集合)。
注意: 使用put()方法时, 若指定的键(key)在集合中没有, 则没有该键对应的值, 返回null, 并把指定的键值添加到集合中.
若指定的键(key)在集合中存在, 则返回值为集合中键对应的值(该值为替换前的值), 并把指定键所对应的值, 替换成指定的新值.
Map集合遍历键找值方式:
第一种方式:
1.通过元素中的键获取对应的值
步骤:
1.使用keySet()方法, 获取Map集合中所有的键, 由于键是唯一的不重复, 所以返回一个set集合存储所有的键.
2.遍历set集合, 得到每一键.
3.根据键, 通过get(K key) 获取值
举例:
package map_02;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
public class MapArrayListTest {
public static void main(String[] args) {
HashMap<String, ArrayList<Student>> hm = new HashMap<String,ArrayList<Student>>();
ArrayList<Student> list1 = new ArrayList<Student>();
list1.add(new Student("张三",22));
list1.add(new Student("张四",23));
list1.add(new Student("张五",24));
ArrayList<Student> list2 = new ArrayList<Student>();
list2.add(new Student("李四",22));
list2.add(new Student("李五",23));
list2.add(new Student("李六",24));
ArrayList<Student> list3 = new ArrayList<Student>();
list3.add(new Student("王一",22));
list3.add(new Student("王二",23));
list3.add(new Student("王三",24));
ArrayList<Student> list4 = new ArrayList<Student>();
list4.add(new Student("赵一",22));
list4.add(new Student("赵二",23));
list4.add(new Student("赵三",24));
hm.put("001", list1);
hm.put("002", list2);
hm.put("003", list3);
hm.put("004", list4);
Set<String> set = hm.keySet();
for (String str : set) {
ArrayList<Student> al = hm.get(str);
for (Student s : al) {
System.out.println(str+"---"+s.getName()+"---"+s.getAge());
}
}
}
}
2.通过Entry键值对对象
key和value在Map集合中是一种一一对印的关系, 这种关系为Entry, Entry将键值对封装成了键值对对象.
获取entry对象的方法: public Set<Map.Entry<K,V>> entry Set(): 获取Map集合中所有的键值对对象的集合(Set集合)
获取键和值的方法: Entry对象中
pubic K getKey() : 获取Entry对象中的键
public V getValue() : 获取Entry对象中的值
举例(伪代码):
// 获取 所有的 entry对象 entrySet
Set<Entry<String,String>> entrySet = map.entrySet();
// 遍历得到每一个entry对象
for (Entry<String, String> entry : entrySet) {
// 解析
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"的CP是:"+value);
}
Collections(集合工具类):
常用功能:
java.utils.Collections
是集合工具类,用来对集合进行操作。部分方法如下:
public static <T> boolean addAll(Collection<T> c, T... elements)
:往集合中添加一些元素。public static void shuffle(List<?> list)
:打乱集合顺序。public static <T> void sort(List<T> list)
:将集合中元素按照默认规则排序。public static <T> void sort(List<T> list,Comparator<? super T> )
:将集合中元素按照指定规则排序。
Comparable与Comparator的区别
Comparable:强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法。只能在类中实现compareTo()一次,不能经常修改类的代码实现自己想要的排序。实现此接口的对象列表(和数组)可以通过Collections.sort(和Arrays.sort)进行自动排序,对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。
Comparator: 强行对某个对象进行整体排序。可以将Comparator 传递给sort方法(如Collections.sort或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用Comparator来控制某些数据结构(如有序set或有序映射)的顺序,或者为那些没有自然顺序的对象collection提供排序。
举例:
package tree_map_01;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeMap;
public class TreeMapTest {
public static void main(String[] args) {
TreeMap<Student, String> tm = new TreeMap<Student,String>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// 年龄升序
int result = o1.getAge() - o2.getAge();
// 年龄相同,姓名不同排序
result = (result==0)? (o1.getName().compareTo(o2.getName())) : result;
return result;
}
});
Student s1 = new Student("zhangsan",20);
Student s2 = new Student("zhangsan",21);
Student s3 = new Student("lisi",21);
Student s4 = new Student("lisi",22);
Student s5 = new Student("wangwu",23);
Student s6 = new Student("wangwu",24);
Student s7 = new Student("maliu",25);
Student s8 = new Student("maliu",26);
Student s9 = new Student("zhangsan",20);
tm.put(s1, "001");
tm.put(s2, "002");
tm.put(s3, "003");
tm.put(s4, "004");
tm.put(s5, "005");
tm.put(s6, "006");
tm.put(s7, "007");
tm.put(s8, "008");
tm.put(s9, "009");
Set<Student> set = tm.keySet();
for (Student s : set) {
String str = tm.get(s);
System.out.println(s.getName()+"---"+s.getAge()+"---"+str);
}
}
}
Collection和Map集合的区别
Collections: 是一个单列集合, 只能存储一种数据类型
Set集合中的HashSet和TreeSet的add方法都和HashMap, TreeMap的put方法有关.
Map集合是一个双列S集合, 能够存储两种数据类型, (键和值是一种键值对的存在)
包括HashMap<K,V>, TreeMap<K,V>.