Java学习的第四周

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>.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值