Day07-常用对象API


title: Day07-常用对象API
date: 2020-06-10 15:49:21
author:子陌


String类

所属包:java.lang.String

  • 字符串是一个特殊的对象
  • 所属包:java.lang.System
  • String str = "abc";String str1 = new String("abc");有什么区别
package zimo.demo;
public class StringDemo{
    
    
    public static void main(String[] args){
    
    
        /*
         *	String类的特点:
         *	字符串对象一旦被初始化就不会被改变
         *
         * 	字符串缓冲区中没有就建立,字符串缓冲区中有就直接用,可以共享
         */

        String s = "abc";		 			 // 创建一个字符串对象,在常量池中创建了"abc"并赋值给s
        String s1 = "abc";					 // 和s是同一个对象
        s = "nba";							// “abc”和“nba”是不同对象
        
        String s2 = new String("abc");		  // 在堆内存中创建,创建了两个对象,一个new 一个字符串对象在堆内存中 

        System.out.println(s == s1); 		// true
        System.out.println(s == s2); 		// false
        System.out.pritnln(s.equals(s1));	// true String中equals进行复写
    }
}

String构造器

package zimo.demo1;
public class StringConstructorDemo{
    
    
    public static void main(String[] args){
    
    
        stringConstructorDemo();
        stringConstructorDemo1();
    }
    
    public static void stringConstructorDemo(){
    
    
        String s = new String(); // 等价String s = "";   不等价 String s = null;
        byte[] arr = {
    
    65,98,67,68};
        String s1 = new String(arr);
        System.out.println(s1);		// AbCD
    }
    public static void stringConstructorDemo1(){
    
    
        char[] arr = {
    
    'z','i','m','o'};
        String s1 = new String(arr);
        String s2 = new String(arr,1,3);
        System.out.println(s1);		// zimo
        System.out.println(s2);		// imo
    }
}

功能分类

  1. 获取:
    • int length()获取字符串中字符的个数(长度) 数组长度是属性,字符串是方法
    • char charAt(int index)根据位置获取字符
    • int indexOf(int ch)根据字符获取在字符串中d的第一次出现的位置
    • int indexOf(int ch, int fromIndex)从指定位置进行ch的查找第一次出现的位置
    • int indexOf(String ch) int indexOf(String ch, int fromIndex)查找字符串的第一次出现的位置
    • int lastindexOf(int ch)..........同理从后往前查找
    • String substring(int beginIndex) String substring(int beginIndex, int endIndex)获取一部分字符串,也叫子串
  2. 转换:
    • String[] split(String regex)将字符串的切割,通过(正则表达式)规则切割(字符串 — > 字符数组)
    • char[] toCharArray()将字符串变成字符数组
    • byte[] getBytes()将字符串变成字节数组
    • String toUpperCase() String toLowerCase将字符串中的字母转成大小写
    • String replace(char oldCh, char newCh)将字符串中的内容进行替换
    • String trim()将字符串头尾的空格去掉
    • String concat(string str)将字符串进行连接
  3. 判断:
    • boolean equals(Object obj)两个字符串内容是否相同
    • boolean equalsIgnoreCase(String str)忽略大小写,比较字符串内容
    • boolean contains(String str)比较字符串中是否包含
    • boolean startsWith(string str) boolean endsWith(String str)字符串是否以指定字符串开头/结尾
  4. 比较:
    • int compareTo(String str)比较字符串大小(ascii码表顺序/字典顺序)

intern()方法:判断字符串池中是否存在,如果存在返回引用,如果不存在,在字符串池中建立一个新的对象

StringBuffer类

所属包:java.lang.StringBuffer

字符串缓冲区,用于存储数据的容器,最终转成字符串输出

  • 字符串的组成原理就是通过该类实现的
  • StringBuffer可以对字符串内容进行增删
  • StringBuffer是一个容器
  • 很多方法与String相同
  • StringBuffer是可变长度的
  1. 添加操作StringBuffer append(T t)

  2. 插入操作StringBuffer insert(int offset, T t)

  3. 删除操作StringBuffer delete(int start, int end)包含头不包含尾

  4. 查找操作StringBuffer charAt(int index)

    查找操作StringBuffer indexOf(String str)

    查找操作StringBuffer lastIndexOf(String str)

  5. 修改操作StringBuffer replace(int start, int end, String str)

    修改操作void charAt(int index, char ch)

  6. 设置长度void setLength(int newLength)

  7. 反转操作StringBuffer reverse()

StringBuilder类

所属包:java.lang.StringBuilder

兼容于StringBuffer 1.5后才出来的,用于单线程使用的等价类,由于它的执行不同步,所以速度更快(验证锁)

不同点:

  • StringBuffer是线程同步的。通常用于多线程
  • StringBuilder是线程不同步的。通常用于单线程,提高效率

JDK的升级:

  • 简化书写
  • 提高效率
  • 增加安全

基本数据类型对象包装类

  • 将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据
  • 常用操作之一:用于基本数据类型与字符串之间的转换

byte : Byte short : Short int : Integer long : Long

float : Float double : Double char : Character boolean : Boolean

class IntegerDemo{
    
    
    public static void main(String[] args){
    
    
        // String转int
        Integer x = new Integer("123")x;
        Integer xx = new Integer(123); 		// x != xx    x.equals(b): true
        int x1 = x.intValue();
        int x2 = Integer.parseInt("123");
        
        // 十进制转其他进制
        Integer.toBinaryString(60);
        Integer.toOctalString(60);
        Integer.toHexString(60);
        Integer.toString(60,3);		// 三进制
        // 其他进制转十进制
        Integer.parseInt("3c",16);	// 十六转十 
    }
}

1.5版本后进行新特性的升级

class IntegerDemo{
    
    
    public static void main(String[] args){
    
    
        // 新特性:自动装箱  简化书写
        Integer x = 4;
        x = x + 5;		// x = new Integer(x.intValue() + 6);  x.intValue()自动拆箱
        
        // 注意:当自动拆箱时遇到对象null时,会抛出异常
        x = null;
        x = x + 10;		// err:NullPointException
        
        //jdk 1.5后,自动装箱,如果装箱是一个字节,那么数据会被共享,不会开辟新空间
        Integer a = 127;
        Integer b = 127; 
        Integer a1 = 128;
        Integer b1 = 128; 
        boolean flag = (a == b);		// true
        flag = (a1 == b1);			    // false
    }
}

集合类

所属包:java.util

集合只用于存储对象,集合长度是可变的,集合可以存储不同类型,不能存储基本数据类型(数组是存储变量,长度固定,存储类型相同,存储基本数据类型)

集合因为内部的数据结构不同,有多种具体容器。不断向上抽取形成了集合框架

集合框架

框架的顶层Collection接口

Collection常见方法:

  • 添加:boolean add(Object obj) boolean addAll(Collection<?> c)添加元素

  • 删除:boolean remove(Object obj) boolean remove(Collection<?> c) 删除元素

  • 清空:boolean clear()清空集合

  • 查找:boolean contains(Object obj) boolean containsAll(Collection<?> c)是否包含内容

  • 判空:boolean isEmpty()判断是否为空

  • 长度:int size()获取长度

  • 迭代:Iterator iterator()获取内容 Iterator接口就是对所有Collection容器进行元素取出的公共接口

  • 其他:boolean retainAll(Collection c)取交集

    其他:Object[] toArray()将集合装成数组

集合框架的构成及分析

集合框架

  • Collection

– List:有序(存入和取出的顺序一致),元素都有索引(角标),元素可以重复。

–Set:元素不能重复,无序。

List接口特有常见方法

有一个共性特点就是都可以操作角标,list集合的元素,数据可以重复

  • 添加元素:

    void add(int index, E element)

    void add(int index, Collection c)

  • 删除元素:

    E remove(int index)

  • 修改元素:

    E set(int index, E element)

  • 获取元素:

    E get(int index)

    int indexOf(E element)

    int lastIndexOf(E element)

    List subList(int fromIndex, int toIndex)

class ListDemo{
    
    
    public static void main(String[] args){
    
    
        List list = new ArrayList();
        show(list);
    }
    
    public static void show(List list){
    
    
        // 添加元素
        list.add("abc1");
        list.add("abc2");
        list.add("abc3");
        
        // 插入元素
        list.add(1, "add9");			// abc1 abc9 abc2 abc3
        
        // 删除元素
        System.out.println("remove:" + list.remove(2));		// abc1 abc9 abc3
        
        // 修改元素
        System.out.println("set:" + list.set(1,"abc8"));	// abc1 abc8 abc3
        
        // 获取元素
        System.out.println("get:" + list.get(1,"abc8"));	// abc8
        System.out.println("subList:" + list.subList(1,2));	// abc8
    }
}

list集合是可以完成列表的增删改查

// 迭代器使用
{
    
    
    List list = new ArrayList();
    // 添加元素
    list.add("abc1");
    list.add("abc2");
    list.add("abc3");
    
    // 添加元素:err 并发操作异常
    {
    
    
        Iterator it = list.iterator();
        while(it.hasNext()){
    
    
            Object obj = it.next();		// java.util.ConcurrentModificationException
                                      // 在迭代过程中,不要使用集合对象操作元素,容易出现异常,可以使用Iterator子类接口实现
            if(obj.equals("abc2")){
    
    
                list.add("abc9");
            }
        }
    }
    --------------------------------------------------------------------------------------------------------
    // 通过子类迭代器接口:只有list集合具备该迭代功能
    {
    
    
        ListIterator it = list.ListIterator();	// 获取列表迭代器对象
        while(it.hasNext()){
    
    
            Object obj = it.next();	
            if(obj.equals("abc2")){
    
    
                it.add("abc9");
            }
        }
        
        while(it.hasPrevious()){
    
    
            System.out.println(it.previous());
        }
    }
    
}
  • List:

    可变数组原理:创建一个新数组,将原来的拷贝到新数组中

    – Vector:内部是数组数据结构,它是同步的,可增长的对象数组,可以通过整数索引访问

    ​ 增删,查询都很慢(1.0出现,1.2收编到集合框架)(自动扩容:100%的增长)

    – ArrayList:内部是数组数据结构,它是不同步的,大小可变数组,替代了Vector,

    ​ 查询速度快(如果是多线程,要么加锁,要么其他方式实现,vector摒弃了)(自动扩容:50%增长)

    – LinkedList:内部是链表结构,不同步的

    ​ 增删元素效率快

一般list集合除了vector是同步的,其他的都是不同步的,出于效率考虑

  • LinkedList:

    添加元素:

    • addFirst() addLast()
    • offerFirst() offerLast()(1.6)

    获取但不移除:

    • getFirst() getLast():链表为空,抛出异常NoSuchElementException,链表为空
    • peekFirst() peekLast():链表为空返回null,不抛出异常(1.6)

    获取并移除:

    • removeFirst() removeLast():链表为空,抛出异常NoSuchElementException,链表为空
    • poolFirst() poolLast():链表为空返回null,不抛出异常(1.6)
/**
 *	请使用LinkedList来模拟一个堆栈或者队列数据结构
 *	堆栈:先进后出		FILO	First In Last Out
 *	队列:先进先出		FIFO	First In First Out
 */
// 描述容器:提供对象完成两种结构

// 队列
class MyQueue{
    
    
    private LinkedList link;
    public MyQueue(){
    
    
        link = new LinkedList();
    }
    /**
    * 	队列添加元素功能
    */
    public void myAdd(Object obj){
    
    
        link.addLast(obj);
    }
    
    /**
    * 	队列获取一个元素
    */
    public Object myGet(Object obj){
    
    
        return link.removeFirst();
    }
    
    /**
    * 	队列获取一个元素
    */
    public Object myIsEmpty(Object obj){
    
    
        return link.isEmpty();
    }
}

// 堆栈
class MyStackHeap{
    
    
    private LinkedList link;
    public MyStackHeap(){
    
    
        link = new LinkedList();
    }
    /**
    * 	堆栈添加元素功能
    */
    public void myAdd(Object obj){
    
    
        link.addLast(obj);
    }
    
    /**
    * 	堆栈获取一个元素
    */
    public Object myGet(Object obj){
    
    
        return link.removeLast();
    }
     
    /**
    * 	堆栈获取一个元素
    */
    public Object myIsEmpty(Object obj){
    
    
        return link.isEmpty();
    }
}

public class LinkedTest{
    
    
    public static void main(String[] args){
    
    
        
    }
}

Set接口集合

接口:public interface Set<E> extends Collection<E>

元素不可以重复,是无序的,与Collection方法一致

  • HashSet(哈希表):内部数据结构是哈希表,是不同步的
    • LinkedHashSet:哈希表和链表实现,有迭代顺序的集合,怎么存进去怎么取出来
  • TreeSet:可以对Set集合中的元素进行排序
  • HashSet:集合数据结构是哈希表,所以存储元素的时候,使用的元素的hashCode来确定位置,如果位置相同,再通过元素的equals来确定是否相同
    • 判断标准对象是否相同:hashCode()、equals()
    • 让元素自身具备比较功能,就需要覆盖Object类,重写hashCode、equals方法
public class SetDemo{
    
    
    public static void main(String[] args){
    
    
        hashSetDemo();
    }
    public void hashSetDemo(){
    
    
        HashSet hs = new HashSet();
        hs.add("hhh");
        hs.add("aaa");
        hs.add("xxx");
        hs.add("xxx");			// 没进去,数据唯一
        Iterator it = it.iterator();
        while(it.hasNext()){
    
    
            System.out.println(it.next());	// 无法保证数据顺序
        }
    }
}

哈希表确定元素是否相同:

  1. 判断的是两个元素的哈希值是否相同,如果相同,再判断两个对象的内容是否相同
  2. 判断哈希值相同,其实判断的是对象的hashCode的方法。判断内容相同,用的是equals方法
  3. 注意:如果哈希值不同,是不需要判断equals

哈希冲突:

  1. 顺延:顺着往下存储
  2. 串联:在同一个位置往外挂一块地址
class Person{
    
    
    String name;
    int age;
    
    @Override
    public boolean equals(Object obj){
    
    
        if(this == obj)			// 同一个对象
            return true;
        if(!(obj instanceof Person))		// 健壮性判断
            throws new ClassCaseException("类型错误!");
        return this.name == obj.name && this.age == obj.age;
    }
    
    @Override
    public int hashCode(){
    
    
        return name.hashCode() + age * 37;
    }
}
  • TreeSet:保证元素的唯一性

    • 1.判断标准对象是否相同:compareTo() 0:相同 > 0、< 0:不同

      让元素自身具备比较功能,就需要实现Comparable接口,覆盖compareTo方法

    • 2.判断标准对象是否相同:实现比较器new Comparetor()

      让集合具备比较功能,定义类实现Comparator接口,覆盖compare方法,实现了该方法以该方法为主

  • 元素自身具备比较功能

/**
 *	以Person对象的年龄进行排序
 */
class Person implements Comparable{
    
    
    String name;
    int age;
    
    @Override
    public int compareTo(Object obj){
    
    
        Person p = (Person)obj;
        if(!(p instanceof Person)){
    
    
            throws new ClassCaseException("类型错误!");
        }
        /*
        if(this.age < p.age){
            return 1;
        }else if(this.age > p.age){
            return -1;
        }else{
            return this.name.compareTo(p.name);
        }
        */
        // 按年龄排
        int tmp = this.age - p.age;
        return tmp == 0 ? this.name.compareTo(p.name) : tmp;
        // 按姓名拍
        int tmp = this.name.compareTo(p.name);
        return tmp == 0 ? this.age - p.age : tmp;
    }
}
  • 如果不要按照对象中具备的自然顺序进行排序,如果对象中不具备自然顺序怎么办?

    - 使用TreeSet集合第二种排序方式:让集合自身具备比较功能

package zimo.demo;
import java.util.Comparator;
import zimo.xx.Person;

/** 
 *	创建一个根据Person类的name进行排序的比较器
 */
public class ComparatorByName implements Comparator {
    
    
    @Override
    public int compare(Object o1, Object o2){
    
    
        Person p1 = (Person)o1;
        Person p2 = (Person)o2;
        
        int tmp = p1.getName().compareTo(p2.getName());
        return tmp == 0 ? p1.getAge : tmp;
    }
}

public class TreeSetComparatorDemo{
    
    
    public static void main(String[] args){
    
    
        TreeSet ts = new TreeSet(new ComparatorByName());
        ts.add(new Person("zimo", 20));
        ts.add(new Person("llx", 13));
        ts.add(new Person("zhangsan", 31));
    }
}
  • 后缀名就是该集合所属的体系
  • 前缀名就是该集合的数据结构
  • array:数组数据结构,查询快,有角标
  • link:链表数据结构,增删快,有add、get、remove + (first、last)方法
  • hash:哈希表结构,唯一性,元素需要覆盖hashCode和equals方法
  • tree:二叉树结构,想实现排序,就想到两个接口,Comparable(对象实现接口),Comparator(比较器)
  • 通常这些集合容器都是不同步的

Map接口集合

一次添加一对元素。Collection集合一次添加一个元素,Map也称双列集合,Collection集合称为单列集合

接口:public interface Map<K,V>,Map集合存储的是键值对,Map集合中必须保证键的唯一性

常用方法:

  1. 添加:

    V put(K key, V value),返回前一个和key关联的值,没有返回null

  2. 删除:

    void clean(),清空map集合

    V remove(K key),根据指定的key删除这个键值对,返回删除的value

  3. 判断:

    boolean containsKey(Object key),判断集合键(key)是否存在

    boolean containsValue(Object value),判断集合值(value)是否存在

    boolean isEmpty(),判断集合是否为空

  4. 获取:

    value get(key),集合通过键(key)取值(value),如果没有该键返回null,通过判断null来确定是否存在该键

    int size(),返回集合键值对个数

package zimo.map.demo;
import java.util.Map;
public class MapDemo{
    
    
    public static void main(String[] args){
    
    
        Map<Integer, String> map = new HashMap<Integer, String>();
        method(map)
    }
    public static void method(Map<Integer, String> map){
    
    
        // 添加元素  存相同键,值会被覆盖,返回旧值
        System.out.println(map.put(1, "zimo"));		// null
        System.out.println(map.put(1, "haha"));		// zimo
        System.out.println(map.put(2, "xixi"));		// zimo
        
        // 删除
        System.out.println(map.remove(1));		    // zimo
        
        // 判断
        System.out.println(map.containsKey(2));		// true
        
        // 获取
        System.out.println(map.get(2));			   // xixi 
        
        // 取出map中所有元素:通过keyset方法获取map中所有的键所在的set集合,
        //				   再通过set迭代器获取到每一个键,在对每一个键取其对应值
        // 方法一:
        Set<Integer> keySet = map.keySet();
        Iterator<Integer> it = keySet.iterator();
        while(it.hasNext()){
    
    
            Integer key = it.next();
            String value = map.get(key);
            System.out.println(key);
        }
        
        // 取出map中所有元素:通过Map转成Set就可以迭代,通过entrySet将键和值的关系作为对象存储到了set集合中,
        //				   而这个映射关系的类型就是Map.Entry类型
        // 方法二:
        Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
        Iterator<Map.Entry<Integer, String>> it = entrySet.iterator();
        while(it.hasNext()){
    
    
            Map.Entry<Integer, String> en = it.next();
            System.out.println(en.getKey() + ":" + en.getValue());
        }
        
        Collection<String> values = map.values();
        Iterator<String> it1 = values.iterator();
        while(it1.hasNext()){
    
    
            System.out.println(it1.next());
        }
    }
}

Map容器取值方法一解析

  • Map常用的子类:

    – Hashtable:内部结构是哈希表,是同步的,不允许null键和null值(1.0存在)

    – Properties:用来存储键值对型配置文件的信息,可以和IO技术相结合

    – HashMap:内部结构是哈希表,不是同步的(允许使用null键和值)

    – TreeMap:内部结构是二叉树,不是同步的,可以对Map集合中的键进行排序

// HashMap存储自定义类型
package zimo.hashmap.demo;
public class HashMapDemo{
    
    
    public static void main(String[] args){
    
    
        // 将学啥对象和学生的归属地通过键值存储到map集合中
        HashMap<Student, String> hm = new HashMap<Student, String>();
        hm.put(new Student("lisi", 38), "北京");
        hm.put(new Student("zimo", 18), "厦门");
        hm.put(new Student("waci", 25), "广东");

        Set<Map.Entry<Student, String>> entrySet = hm.entrySet();
        Iterator<Map.Entry<Student, String>> it = entrySet.iterator();
        while(it.hasNext()){
    
    
            Map.Entry<Integer, String> en = it.next();
            System.out.println(en.getKey().getName + ":" + en.getKey().getAge() + "..." + en.getValue());
        }
    }
}

public class Student extends Person{
    
    
    public Student(){
    
    
        super();
    }
    public Student(String name, int age){
    
    
        super(name,age);
    }
}

public class Person implements Comparable<Person>{
    
    
    String name;
    int age;
    
    Person(){
    
    super();}
    Person(String name, int age){
    
    
        super();
        this.name = name;
        this.age = age;
    }
    public String getName(){
    
    
        return name;
    }
    public int getAge(){
    
    
        return age;
    }
    public void setName(String name){
    
    
        this.name = name;
    }
    public int getAge(int age){
    
    
        this.age = age;
    }
    public int compareTo(Person p){
    
    
        int tmp = this.age - p.age;
        return tmp == 0 ? this.name.compateTo(p.name) : tmp;
    }
    @Override 
    public boolean equals(Object obj){
    
    
        if(this == obj)
            return true;
        if(obj == null)
            return false;
        if(getClass() != obj.getClass)
            return false;
        Person other = (Person)obj;
        if(age != other.age)
            return false;
        if(name == null){
    
    
            if(other.name != null)
                return false;
        }else if(!name.equals(other.name))
            return false;
        return true;
    }
    @Override 
    public int hashCode(){
    
    
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
    }
}

泛型

JDK1.5以后出现的安全机制

  • 好处:
    1. 将运行时期的问题ClassCastException转到了编译时期
    2. 避免了强制转换的麻烦
  • <>:啥时候用?
    • 当操作的引用数据类型不确定的时候,就使用<>。将要操作的引用数据类型传入
    • <>就是一个用于接受具体引用数据类型的参数范围
package zimo.generic.demo;
import java.util.ArrayList;
public class GenericDemo{
    
    
    public static void main(String[] args){
    
    
        ArrayList a1 = new ArrayList();
        ArrayList<String> a2 = new ArrayList<String>();
        a1.add("hhh");
        a1.add("xxx");
        a1.add(45);		// 编译成功
        a2.add("222");
        a2.add(45);		// err:编译失败
        
        Iterator it = a1.iterator();
        Iterator<String> it2 = a2.iterator();
        while(it.next()){
    
    
            System.out.println((String)it.next);	// err 45无法强转成String
            System.out.println(it.next);
        }
    }
}
  • 泛型技术是给编译器使用的技术,用于编译时期,确保了类型的安全。
  • 运行时会将泛型去掉,生成的class文件是不带泛型的,这个称为泛型的擦除

为什么擦除?

  • 为了兼容运行的类加载器

泛型的补偿

  • 在运行时,通过获取元素的类型进行转换动作。不用开发人员进行强制类型转换了
  • Class clazz = "aa".getClass(); clazz.getName();

自定义泛型类

定义泛型要在修饰符后,返回值前声明定义

package zimo.generic.define.demo;
// 1.5后使用泛型来接收类中要操作的引用数据类型
public class Tool<T>{
    
    
    private T t;
    public T getT(){
    
    
        return t;
    }
    public void setT(T t){
    
    
        this.t = t;
    }
    // 将泛型定义在方法上
    public <W> void show(W str){
    
    
        System.out.println("show:" + str.toString());
    }
    // 无法打印
    public void show1(T str){
    
    
        System.out.println("show:" + str.toString());
    }
    // 静态不需要对象,静态方法不能访问类上定义的泛型。如果静态方法使用泛型,只能定义在方法上
    //public static void show1(T str){
    
    
    public static <Z> void show2(Z str){
    
    
        System.out.println("show2:" + str.toString());
    }
    
    public static void main(String[] args){
    
    
        Tool<Student> tool = new Tool<Student>();
        tool.setT(new Student());
        tool.setT(new Worker());			// err
        
        tool.show(new Integer(5));			// ok
        tool.show1(new Integer(2));			// err
        Tool.show2("hhh");				   // ok
        Tool.show2(new Integer(8));			// ok
    }
}


泛型接口

  • 泛型的通配符:
    • " ? "未知类型
  • 可以对类型进行限定:
    • <? extends E>:接收E类型或者E的子类型对象,上限!(存储时用的多)
    • <? super E>:接收E类型或者E的父类型对象,下限!(取出操作时用的多)
package zimo.define.demo;
public class GenericDefineDemo{
    
    
    public static void main(String[] args){
    
    
        ArrayList<String>a1 = new ArrayList<String>();
        ArrayList<Integer>a2 = new ArrayList<Integer>();
        a1.add("abc");
        a2.add(45);
        printCollection(a1);
        printCollection(a2);
    }
}
// 泛型接口,将泛型定义在接口上
interface Inter<T>{
    
    
    public void show(T t);
}

class InterImpl implements Inter<String>{
    
    
    public void show(String str){
    
    
        System.out.println("str : " + str);
    }
}

class InterImpl1<Q> implements Inter<Q>{
    
    
    public void show(Q q){
    
    
        System.out.println("show : " + q);
    }
}

// 迭代打印集合中元素,仅限于不明确类型,并不对类型进行操作的时候
// <?> === <? extends Object>
public static void printCollection(Collection<?> all){
    
    
    Iterator<?> it = a1.iterator();
    while (it.hasNext()){
    
    
        //? aa = it.next();
        //System.out.println(aa);
        System.out.println(it.next());
    }
}

// 迭代打印集合中元素
public static <T> void printCollection1(Collection<T> all){
    
    
    Iterator<T> it = a1.iterator();
    while (it.hasNext()){
    
    
        T aa = it.next();		
        System.out.println(aa);
        //System.out.println(it.next());
    }
}

public static <T> T printCollection2(Collection<T> all){
    
    
    Iterator<T> it = a1.iterator();
    return it.next();		// T能代表一个指定类型,并能去操作
}

// 限制只接收Person的子类集合Sutdent、Worker
public static void printCollection3(Collection<? extends Person> p){
    
    
    Iterator<? extends Person> it = p.iterator();
    while (it.hasNext()){
    
    
        Person pp = it.next();		
        System.out.println(pp);
        //System.out.println(it.next());
    }
}
// 限制只接收Student的父类集合Sutdent、Person
public static void printCollection3(Collection<? super Sutdent> p){
    
    
    Iterator<? super Sutdent> it = p.iterator();
    while (it.hasNext()){
    
    
        System.out.println(it.next());
    }
}

集合使用技巧

  • 是否需要唯一性:
    1. 需要:set集合
      • 是否指定顺序:
        1. 指定顺序:TreeSet
        2. 不需要:HashSet
        3. 和存储时一致的顺序(有序):LinkedHashSet
    2. 不需要:List集合
      • 是否频繁增删:
        1. 需要:LinkedList
        2. 不需要:ArrayList

每个容器的结构和所属体系:看名字前缀数据结构,后缀名是容器框架

容器工具类(Utilities)

Collections(操作集合)

集合框架的工具类,里面的方法是静态的

Collections.sort(list);			 // 对list集合进行重复元素的排序
Collections.swap(list, i, j);	 // 交换list中的i和j值
Collections.swap(list, ComparatorByLength);	  // 通过长度排序
Collections.binarySearch(list, "aa");		 // 二分查找,有序的list查找“aa”
Collections.max(list);			// 找出list中最大值
Collections.reverseOrder();		// 将自然排序的元素逆转
Collections.reverseOrder(new ComparatorByLength());		 // 按长度逆转
Collections.replaceAll(list, "aa", "bb");				//索引list中的aa替换成bb
Collections.fill(list, "aa");	// 将list中所有的元素替换成aa
Collections.shuffle(list);		// 随机打乱list
Collections.synchronizedList(list);		// 返回一个线程安全的list,同步list
Collections.synchronizedMap(Map);		// 返回一个线程安全的Map,同步Map
Collections.synchronizedSet(Set);		// 返回一个线程安全的Set,同步Set
Collections.synchronizedCollection(Collection);		// 返回一个线程安全的Collection,同步Collection
......

当多线程遇上ArrayList,给非同步集合加锁

// 加锁原理
List list = new ArrayList();
//返回一个同步的list
list = MyCollections.synList(list);		

class MyCollections{
    
    
    
    public static List synList(List list){
    
    
        return new MyList(list);
    }
    
    private class MyList implements List{
    
    
        private List list;
        private static final Object lock = new Object();
        MyList(List list){
    
    
            this.list = list;
        }
        public boolean add(Object obj){
    
    
            synchronized(lock){
    
    
                return list.add(obj);
            }
        }
        public boolean remove(Object obj){
    
    
            synchronized(lock){
    
    
                return list.remove(obj);
            }
        }
    }    
}

Arrays

集合框架的工具类,里面的方法是静态的

Arrays.binarySearch();		// 二分查找
Arrays.copyOf();		    // 拷贝
Arrays.equals(a,b);			// 比较两个对象是否相等(相同顺序,相同值)
Arrays.fill();			    // 指定替换
Arrays.sort();			    // 排序
Arrays.toString();			// 转换成字符串
Arrays.asList("aa","BB");	 // 将数组转成list集合

toString()的经典实现

public static String myToString(int[] arr){
    
    
    int iMax = arr.length -1;
    if(iMax == -1)
        return "[]";
    StringBuilder str = new StringBuilder();
    str.append('[');
    for(int i = 0; ; i++){
    
    		// 中间省略条件判断,提高了效率
        str.append(arr[i]);
        if(i == iMax)
            return str.append(']').toString();
        str.append(",")
    }
}

asList():将数组转成集合

  • 可以使用集合的方法操作数组中的元素
  • 数组的长度是固定的,所以对于集合的增删方法是不可以使用的,否则发生UnsupportedOperationException
  • 如果数组中的元素是对象,那么转成集合时,直接将数组中的元素作为集合中的元素进行集合存储
  • 如果数组中的元素是基本类型数值,那么会将该数组作为集合中的元素进行存储
String[] arr = {
    
    "abc", "hhh", "xxx"};	// String对象
List<String> list = Arrays.asList(arr);
list.contains("xxx");		// true
list.add("aaa");			// err:数组的长度是固定的 (add,remove)不能使用

int[] arr1 = {
    
    11,22,33,44};
List list = Arrays.asList(arr1);	// [[i@hashcode]
list.size();		// 1 将arr数组存进去,数组对象arr1是引用类型,其中的值是数据类型无法直接存储

// 数组转集合
List<int[]> list = Arrays.asList(arr1);	// {11,22,33,44}

toArray():集合转成数组

  • Collection接口中的toArray方法
  • 集合转数组:可以对集合中的元素操作方法进行限定。不允许对其进行增删

toArray方法需要传入一个指定类型的数组

  • 长度:
    1. 如果长度小于集合的size,那么该方法会创建一个同类型并和集合相同的size的数组
    2. 如果长度大于集合的size,那么该方法就会使用指定的数组,存储集合中的元素,多余的位置默认null
public class ToArray{
    
    
    public static void main(String[] args){
    
    
        List<String> list = new ArrayList<String>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");

        String[] arr = list.toArray(new String[list.size()]);
        System.out.println(Array.toString(arr));
    }
}

JDK1.5新特性

ForEach语句

  • 格式:for(类型 变量 : Collection集合|数组){}
public static void main(String[] args){
    
    
    List<String> list = new ArrayList<String>();
    list.add("aaa");
    list.add("bbb");
    list.add("ccc");
    // 传统遍历方式
    Iterator<String> it = list.iterator();
    while(it.hasNext()){
    
    
        System.out.println(it.next());
    }
    // 1.5版本后 foreach 简化缩写
    // 遍历集合
    for(String s : list){
    
    
        System.out.println(s);
    }
    // 遍历数组
    int[] arr = {
    
    1,2,3,4,5,6};
    for(int i : arr){
    
    
        System.out.println(i);
    }
}

传统for循环VS高级for(for-each)

  • 传统for循环可以完成对语句执行很多次,因为可以定义控制循环的增量和条件
  • 高级for是一种简化形式,它必须有被遍历的目标。该目标要么是数组,要么是Collection单例集合
  • 对于数组的遍历如果仅仅是获取数组中的元素,可以使用高级for,如果要对数组的角标进行操作,建议使用传统for

可以使用高级for遍历map集合嘛?

  • 不能直接使用,但是可以将map转成单列set集合就可以使用了
public static void main(String[] args){
    
    
    Map<Integer, String> map = new HashMap<Integer, String>();
    map.put(1, "aaaaa");
    map.put(2, "bbbbb");
    map.put(3, "ccccc");
    map.put(4, "ddddd");
    for(Integer key : map.keySet()){
    
    
        String value = map.get(key);
        System.out.println(key + ":" + value);
    }
    
    for(Map.Entry<Integer, String> entry : map.entrySet()){
    
    
        Integer key = entry.getKey();
        String value = entry.getValue();
        System.out.println(key + ":" + value);
    }
}

函数的可变参数:

  • 实际上就是一个数组,但是接收的是数组的元素,自动封装成数组,简化调用者书写
  • 注意事项:可变参数类型,必须定义在参数列表的结尾
public static int add(int[] arr){
    
    
    int sum = 0;
    for(int i = 0; i < arr.length; i++){
    
    
        sum += arr[i];
    }
    return sum;
}
public static int addNew(int... arr){
    
    
    int sum = 0;
    for(int i : arr){
    
    
        sum += i;
    }
    return sum;
}
public static void main(String[] args){
    
    
    int[] a = {
    
    1,3,5,7,9};
    int sum = add(a);
    addNew();
    int sum1 = addNew(1,3,5,7,9);
}

静态导包方式

import java.util.Collections;		// 方式一

// 静态导入,其实导入的是类中的静态成员
import static java.util.Collections.max;		// 方式二

public static void main(String[] args){
    
    
    List<String> list = new ArrayList<String>();
    Collection.sort(list);		// 方式一
    max(list);    // 方式二
}

猜你喜欢

转载自blog.csdn.net/qq_38205875/article/details/107814465