List
数组的长度不可改变,长度在开始的时候就已经固定。
集合的长度可以自己自动扩容。
ArrayList:ArrayList底层是用数组实现的存储。 特点:查询效率高,增删效率低,线程不安全。
LinkedList:LinkedList底层用双向链表实现的存储。特点:查询效率低,增删效率高,线程不安全。
Vector:Vector底层是用数组实现的List,相关的方法都加了同步检查,因此“线程安全,效率低”。
需要线程安全时,用Vector。不存在线程安全问题时,并且查找较多用ArrayList(一般使用它)。不在线程安全问题时,增加或删除元素较多用LinkedList。
创建集合的对象 泛型:限定集合中存储的类型对象 Arraylist<String> list = new Arrays<String>(); JDK7 此时我们创建的是ArraysList集合的对象,而ArraysList是java已经写好的类 类在底层做了处理,打印的不是对象的地址值,二十集和中存储的数据内容 在战时是会用俩个括号将数据包裹 Boolean add(e) 添加 Boolean remove(e) 删除。 set(int idex,e) 设置元素,返回原来的旧值 get(e)查询元素 int size() 返回长度
List:有序,可重复
ArrayList类,LinkedList类Vector类的区别 ArrayList:ArrayList底层是用数组实现的存储。特点:查询效率高,增删效率低,线程不安全。 LinkedList:LinkedList底层用双向链表实现的存储。特点:查询效率低,增删效率高,线程不安全。 Vector:Vector底层是用数组实现的List,相关的方法都加了同步检查,因此“线程安全,效率低”。
需要线程安全时,用Vector。 不存在线程安全问题时,并且查找较多用ArrayList(一般使用它)。 不存在线程安全问题时,增加或删除元素较多用LinkedList。
List 的基本用法:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
/**
* 测试List接口的常用方法
*/
public class ListTest {
public static void main(String[] args) {
test03();
}
//测试isEmpty,add,remove,size,contains,toArrays等常见方法.
//这些方法多位于Collection接口中。
public static void test01(){
//有序、可重复
List list = new ArrayList(); //泛型
System.out.println(list.isEmpty());
list.add("高淇");
System.out.println(list);
System.out.println(list.isEmpty());
list.add("高三");
list.add("高四");
System.out.println(list);
System.out.println("list的大小:"+list.size());
System.out.println("是否包含指定的元素:"+list.contains("高淇"));
list.remove("高四");
System.out.println(list);
Object[] objs = list.toArray();//转化为数组
System.out.println("转化成Object数组:"+ Arrays.toString(objs));
list.clear();
System.out.println(list);
}
//测试和索引操作相关的方法
public static void test02(){
//List存储的是:有序、可重复
List list = new ArrayList();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
System.out.println(list);
list.add(2,"高");
System.out.println(list);
list.remove(2);
System.out.println(list);
list.set(2,"张");
System.out.println(list);
System.out.println(list.get(1));
list.add("B");
System.out.println(list);
System.out.println(list.indexOf("B")); //从左到右找到第一个
System.out.println(list.lastIndexOf("B")); //从尾到头找到第一个
}
//测试两个容器之间的元素处理
public static void test03(){
// List list = new ArrayList();
List list = new LinkedList();
list.add("高淇");
list.add("高qi");
list.add("GQ");
List list2 = new ArrayList();
list2.add("高淇");
list2.add("张三");
list2.add("李四");
System.out.println(list);
System.out.println(list.containsAll(list2));
list.addAll(list2);
System.out.println(list);
// list.removeAll(list2); //删除掉list2和list中存在的元素
// System.out.println(list);
System.out.println("list:"+list);
System.out.println("list2:"+list2);
list.retainAll(list2); //取交集
System.out.println(list);
}
}
实现简单的LinkedList 功能,以及实现MyList接口
public interface myList<E> {
//Element
//List list = new ArrayList();
int size();
boolean isEmpty();
void add(E obj);
public void add(int idex, E obj);
public E get(int idex);
public E set(int idex, E obj);
public boolean contains(E obj);
Object[] toArray();
boolean remove(E obj);
void clear();
void remove(int idex);
}
public class ArrayListTest<E> implements myList<E> {
public int getSize() {
return size;
}
private int size;
private int nowSize;
private Object[] lp;
@Override
public String toString() {
StringBuilder s = new StringBuilder();
s.append("[");
for(int i = 0;i < size;i++)
{
s.append(lp[i] + ",");
}
s.deleteCharAt(s.length() - 1);
s.append("]");
return s.toString();
}
public E get(int idex){
check(idex);
return (E)lp[idex];
}
@Override
public int size() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
public ArrayListTest() {
this.nowSize = 10;
}
public ArrayListTest(int x){
try{
if(x < 0) {
throw new Exception("初始化不能为负数");
}
this.nowSize = x;
} catch (Exception e) {
e.printStackTrace();
}
lp = new Object[nowSize];
}
@Override
public void add(E obj) {
plus();
lp[size] = obj;
size++;
}
@Override
public void add(int idex, E obj) {
check(idex);
plus();
System.arraycopy(lp,idex,lp,idex + 1,size - idex);
lp[idex] = obj;
size++;
}
private void plus(){
if(size == lp.length){//扩容
Object[] newArray = new Object[lp.length * 2 + 1];
System.arraycopy(lp,0,newArray,0,lp.length);
lp = newArray;
}
}
private void check(int idex){
if(idex < 0|| idex >=size)
{
try {
throw new Exception("索引错误");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
@Override
public E set(int idex, E obj) {//替换,并返回旧元素
check(idex);
Object old = lp[idex];
lp[idex] = obj;
return (E) old;
}
@Override
public boolean contains(E obj) {
int i;
for( i = 0;i < size;i++){
if(lp[i].equals(obj))
{
return true;
}
}
return false;
}
@Override
public Object[] toArray() {
return lp;
}
@Override
public boolean remove(E obj) {
for(int i = 0;i<size;i++)
{
if(lp[i].equals(obj))
{
remove(i);
return true;
}
}
return false;
}
@Override
public void clear() {
for(int i = 0;i < size;i++){
lp[i] = null;
}
size = 0;
}
@Override
public void remove(int idex) {
check(idex);
int move = size - (idex + 1);
if(move > 0){
System.arraycopy(lp,idex + 1,lp,idex,size - (idex + 1));
}
size--;
lp[size] = null;
}
public static void main(String[] args) {
ArrayListTest<String> y = new ArrayListTest<>(10);
y.add("sin");
y.add("cos");
y.add("puo");
y.add("pol");
y.add(1,"hduda");
y.add("A");
y.add("B");
y.add("C");
y.add("d");
y.add(2,"E");
y.add("F");
System.out.println(y);
y.set(1,"吴时兴");
System.out.println(y);
y.remove(1);
String z = y.get(1);
System.out.println(z);
System.out.println(y.contains("吴时"));
y.remove("plo");
y.clear();
}
//Arraylist 实现
}
Set
Set 也继承于集合类,可以使用集合类的方法
Set 的特点是 无序,不可重复(Set 不可重复的条件是Equals方法)
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
/**
* 测试Set
* Set:无序、不可重复
*/
public class SetTest {
public static void main(String[] args) {
test02();
}
//Set的常用方法
public static void test01(){
Set s = new HashSet();
s.add("hello");
s.add("world");
s.add("hello"); //相等的元素不会再被加入!
System.out.println(s);
//其他的方法和List一致。因为Set和List都是Collection接口的子接口!
System.out.println(s.size());
System.out.println(s.isEmpty());
}
//Set中不可重复的核心:equals()方法
public static void test02(){
Emp e1 = new Emp(1001,"张三");
Emp e2 = new Emp(1002,"李四");
Emp e3 = new Emp(1001,"王五");
Set s = new HashSet();
s.add(e1);
s.add(e2);
s.add(e3); //相当(equals()返回true)的元素不会再被加入!
System.out.println(s);
}
}
class Emp {
private int id;
private String ename;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Emp emp = (Emp) o;
return id == emp.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
public Emp(int id, String ename) {
this.id = id;
this.ename = ename;
}
@Override
public String toString() {
return "Emp{" +
"id=" + id +
", ename='" + ename + '\'' +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
}
Map
Map就是用来存储“键(key)-值(value)对”的。 Map类中存储的“键值对”通过键来标识,所以“键对象”不能重复。 Map接口的实现类有HashMap、TreeMap HashTable Properties等
HashMap底层实现详解
HashMap 底层实现采用了哈希表,这是一种非常重要的数据结构。对于我们以后理解
很多技术都非常有帮助(比如:redis数据库的核心技术和 HashMap一样),因此,非常
有必要让大家理解。 数据结构中由数组和链表来实现对数据的存储,他们各有特点。
(1)数组:占用空间连续。 寻址容易,查询速度快。但是,增加和删除效率非常低。
(2)链表:占用空间不连续。 寻址困难,查询速度慢。但是,增加和删除效率非常高。
那么,我们能不能结合数组和链表的优点(即查询快,增删效率也高)呢?答案就是
“哈希表”。哈希表的本质就是“数组+链表”。
Enti y对象存储了: key:键对象 value:值对象 next:下一个节点 hash:键对象的hash值
显然每一个Entry对象就是一个单向链表结构,我们使用图形表示一个 Entry对象的典型示
HashMap与Hashta ble的区别 HashMap:线程不安全,效率高。允许key或value为null。 HashTable:线程安全,效率低。不允许key或value为null。
Map 的基本用法测试
import java.util.*;
public class MapTest {
public static void main(String[] args) {
Tes1();
Test2();
test03();
}
public static void Tes1(){
Map m1 = new HashMap();
// Hashtable();
m1.put(2,"one");
m1.put(1,"two");
m1.put(3,"three");
System.out.println(m1.get(2));
m1.put(1,"一");//以equals()方法为核心测试相同,相同替换值
System.out.println(m1);
System.out.println(m1.size());
System.out.println(m1.isEmpty());
System.out.println(m1.containsKey(4));
System.out.println(m1.containsKey(2));
System.out.println(m1.containsValue("一"));
m1.remove(1);
System.out.println(m1);
Map m2 = new HashMap();
m2.put("yi",1);
m2.put("er",2);
m2.put("san",3);
m1.putAll(m2);
System.out.println(m1);
}
public static void Test2(){
List<String> s = new ArrayList<>();
// Set<String> s = new HashSet<>();
s.add("aa");
s.add("bb");
s.add("cc");
//通过索引遍历List (只适用于List)
for(int i=0;i<s.size();i++) {
String temp = s.get(i);
System.out.println(temp);
}
//增强for循环(foreach) (适用于:List、Set)
for(String temp:s) {
System.out.println(temp);
}
//使用Iterator对象 (适用于:List、Set)
for(Iterator<String> iter = s.iterator(); iter.hasNext();) {
String temp = iter.next();
System.out.println(temp);
}
}
//遍历Map(遍历Key、遍历Value)
public static void test03(){
Map<String,String> map = new HashMap<>();
map.put("one","一");
map.put("two","二");
map.put("three","三");
//遍历键
Set<String> keys = map.keySet();
for(String temp:keys) {
// System.out.println(temp);
System.out.println(map.get(temp));
System.out.println(temp+"----"+map.get(temp));
}
//遍历值
Collection<String> values = map.values();
for(String temp:values) {
System.out.println(temp);
}
//使用EntrySet遍历key、value
Set<Map.Entry<String,String>> entrySet = map.entrySet();
for(Map.Entry e:entrySet) {
System.out.println(e.getKey()+"===="+e.getValue());
}
}
}
泛型
·泛型基本概念 泛型的本质就是“数据类型的参数化”,处理的数据类型 不是固定的,而是可以作为参数传入
第一好处:代码可读性更好【不用强制转换】
第二好处:程序更加安全【只要编译时期没有警告,运行时期就不会出现ClassCastException异常】
泛型的基本用法
import java.util.ArrayList;
import java.util.List;
/**
* 测试泛型的基本用法
*/
public class GenericTest1 {
public static void main(String[] args) {
}
public static void test1(){
List<String> list = new ArrayList<>();
list.add("ddd");
// list.add(2332);
Generic1<Integer> g1 = new Generic1<>();
g1.aa(22);
Generic1<String> g2 = new Generic1<>();
g2.aa("hello");
}
}
//定义的一个简单的泛型类
class Generic1<T> {
public T aa(T obj) {
System.out.println(obj);
return obj;
}
public <N> void bb(N obj){
System.out.println(obj);
}
}
interface MyList<E> {
int size();
boolean isEmpty();
void add(E e);
E get(int index);
}
class MyArrayList<E> implements MyList<E> {
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public void add(E e) {
}
@Override
public E get(int index) {
return null;
}