天天看点

JAVA学习笔记-泛型与集合框架一:泛型二:链表三:堆栈四:散列映射五:树集

文章目录

  • 一:泛型
    • 1:泛型类声明
    • 2:使用泛型类声明对象
  • 二:链表
    • 1:LinkedList泛型类
    • 2:链表泛型类的常用方法:
    • 3:遍历链表
    • 4:排序与查找
    • 5:洗牌与旋转
  • 三:堆栈
  • 四:散列映射
    • 1:HashMap

一:泛型

1:泛型类声明

通常用“Class 名称<泛型列表>”来

1:Srudent是泛型类的名称,S就是泛型,没有指定S的数据类型,他可以是任何的对象或者接口,但不能是基本的数据类型:

2:泛型类的类体和普通类一致,均是由成员变量和方法构成的。

2:使用泛型类声明对象

和普通类相比,泛型类声明和创建对象时,会多出一对“<>”,并且<>中的泛型需要用具体的类型替换。如

Cone<Circle> coneOne;
coneOne =new Cone<Circle>(new Circle());
           

【注】java创建泛型的目的是建立具有安全类型的数据结构,如链表,散列表等数据库结构,主要优点有:泛型建立的数据结构不需要进行强制类型转换。

二:链表

链表是由若干称作结点的对象组成的一种数据结构,每个结点含有一个数据和下一个结点的引用(单链表),或者含有一个数据和含有上一个结点的引用和下一个结点的引用。

1:LinkedList泛型类

此泛型类创建的是一个链表结构的用来存储数据的对象。

如:

然后链表对象就可调用

add()

方法对链表进行添加结点的操作:

mylist.add("Hello");
mylist.add("World");
mylist.add("!")
           

创建了一个具有三个结点的链表数据结构。

2:链表泛型类的常用方法:

public boolean add(E element)//向链表末尾添加一个结点
public void add(int index,E element) //向指定位置index添加一个结点
public void clear()//删除链表的所有结点,使得当前链表为空链表
public E remove(int index)//删除指定位置的结点
public boolean remove(E element) //删除首次出现element数据的结点
public E get(int index) //得到指定位置结点的数据
public int indexOf(E eleemnt) //返回含有数据element首次出现的结点的位置
public int lastIndexOf(E element)//返回含有数据element最后出现的结点的位置
public E set(int index,E element) //将链表指定位置index的结点的数据替换为参数element的数据并且返回替换的数据
public int size() //返回链表的长度
public boolean contains(Object element)  //返回某个链表是否含有数据element
           

下面时对泛型LinkedList< e >新增加的一些常用方法

public void addFirst(E element)//向链表的头结点添加新的结点,数据参数为element
public void addLast(E element) //向链表的最后结点添加新节点,数据参数为element
public E getFrist() //得到链表中的第一个结点的数据
public E getLast() //得到链表中最后一个结点的数据
public removeFirst() //删除第一个结点,并且返回数据
public removeLast() //删除最后一个结点,并且返回这个结点的数据
public Object clone() //得到当前链表的一个克隆链表

           

3:遍历链表

链表集合通过迭代器来实现对链表的遍历,链表对象调用

iterator()

方法获取一个iterator对象,这个对象便是链表的迭代器。

例如:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class Test_mian {
  public static void main(String[] args) {
    List<String> list=new LinkedList<>();
    for (int i = 0; i < 60096; i++) {
      list.add("speed"+i);
    }
    Iterator<String> iter=list.iterator();
    long starttime=System.currentTimeMillis();
    while (iter.hasNext()){
      String st=iter.next();
    }
    long EndTime=System.currentTimeMillis();
    long result=EndTime-starttime;
    System.out.println("使用迭代器遍历数据组的时间"+result+"毫秒");
    starttime=System.currentTimeMillis();
    for (int i = 0; i < list.size(); i++) {
      String te=list.get(i);
    }
    EndTime=System.currentTimeMillis();
    result=EndTime-starttime;

    System.out.println("使用get方法遍历数据组的时间"+result+"毫秒");
  }
}

           

运行结果:

使用迭代器遍历数据组的时间3毫秒
使用get方法遍历数据组的时间2050毫秒

进程已结束,退出代码为 0

           

可见迭代器的遍历速度是远远快于get方法的。

【注】

1:LinkedList与ArrayList的区别在于,LinkedList是链式结构,而ArrayList是顺序结构。

2:对与JDK1.5以前的版本,没有泛型的LinkedList,所以需要对拿到的数据进行强制数据类型转换。

4:排序与查找

Collections类提供的方法:

public static sort(<List<E> list)

可以将链表内的元素进行升序排序。

还可以使用方法

int binarySearch(List<E> list,T key,CompareTo<T> c)

进行折半查找链表是否有和元素key相等的元素,有返回元素所在的位置,否则返回-1;

【注】如果链表中存放的对象不是字符串类型。那么创建链表对象的类必须实现接口:Comparable,其目的是实现接口内的方法:

int compareTo(Object b)

规定对象大小的关系。

例如下面的例子:对一个链表进行排序。

import java.util.*;
class Student implements Comparable{
  int height=0;
  String name;
  Student(String name,int height){
    this.name=name;
    this.height=height;
  }

  @Override
  public int compareTo(Object o) {      //需要对方法compareTo重写规定对象的大小关系
    Student st=(Student) o;
    return (this.height-st.height);
  }
}
public class Test_Main {
  public static void main(String[] args) {
    List<Student> list = new LinkedList<Student>();
    list.add(new Student("张飒", 180));
    list.add(new Student("李刚", 160));
    list.add(new Student("王五", 172));
    Iterator<Student> iter = list.iterator();
    System.out.println("排序前,链表的顺序为:");
    while (iter.hasNext()) {
      Student stu = iter.next();
      System.out.println(stu.name + "身高" + stu.height);
    }
    Collections.sort(list);   //进行拍序
    System.out.println("排序后,链表的顺序为:");
    iter = list.iterator();
    while (iter.hasNext()) {
      Student stu = iter.next();
      System.out.println(stu.name + "身高" + stu.height);
    }
    Student zhaolin = new Student("赵琳", 160);
    int index = Collections.binarySearch(list, zhaolin, null);  //二分法查找链表这是否有与其一致的元素
    if (index > 0) {
      System.out.println(zhaolin.name + "和链表中" + list.get(index).name + "身高相同");
    }
  }
}


           

5:洗牌与旋转

能够将链表的对象进行排序就能将其排好的顺序打乱,Collections提供了方法以下方法,分别实现对链表的重新洗牌(打乱排好的顺序随机),旋转链表(如:1,2,3旋转后为3,1,2),翻转链表(如1,2,3旋转后为3,2,1).

public static void shuffle(List<E> list)//对链表顺序进行重新随机打乱
public static void rotate(List<E> list,int distance)/*旋转链表中的数据,distance取值为正时
向右旋转,否则向左旋转。*/
public static void reverse(List<E> list)//对链表进行翻转。
           

例如:

import java.util.*;

public class Test_Main {
  public static void main(String[] args) {
    List<Integer> list=new LinkedList<>();
    for (int i = 10; i < 50; i+=10) {
      list.add(new Integer(i));
    }
    System.out.println("洗牌前链表内的数据为:");
    Iterator<Integer> iter=list.iterator();         //迭代器用来遍历链表
    while (iter.hasNext()){
      Integer n=iter.next();
      System.out.printf("%d\t",n.intValue());
    }
    Collections.shuffle(list);
    System.out.println("\n洗牌后链表内的数据为:\n");
    iter=list.iterator();
    while (iter.hasNext()){
      Integer n=iter.next();
      System.out.printf("%d\t",n.intValue());
    }
    Collections.rotate(list,1);
    System.out.println("\n向右旋转一次后链表内的数据为:\n");
    iter=list.iterator();
    while (iter.hasNext()){
      Integer n=iter.next();
      System.out.printf("%d\t",n.intValue());
    }
    Collections.reverse(list);
    System.out.println("\n翻转后链表内的数据为:\n");
    iter=list.iterator();
    while (iter.hasNext()){
      Integer n=iter.next();
      System.out.printf("%d\t",n.intValue());
    }

  }
}

           

三:堆栈

堆栈是一种“后进先出”的数据结构,且只能在一段进行输入输出操作的数据结构。输入数据的过程被称为:入栈或者压栈,输出数据的过程为:出栈或者弹栈。

Java中

Stack<E>

泛型类创建一个堆栈对象。

创建的堆栈对象可以使用下面的方法,对堆栈进行具体操作:

public E push(E item) //实现压栈操作
public E pop(E item) //实现出栈操作
public boolean empty() //判断堆栈是否为空
public E peek() //获取堆栈顶端元素,但不会删除顶端元素
public int search(Object data) //返回数据在堆栈中的位置,最顶层为1,依次向下,如果没有找到,返回-1。
           

例如:

import java.util.Stack;

public class Test_Main {
  public static void main(String[] args) {
    Stack<Integer> stack=new Stack<>();
    stack.push(new Integer(1));       //数据1入栈
    stack.push( new Integer(1));      //数据1再次入栈
    int k=1;
    while (k<=10){
      Integer F1=stack.pop();               //F1=1
      int f1=F1.intValue();
      Integer F2=stack.pop();                //F2=1
      int f2=F2.intValue();
      Integer temp=new Integer(f1+f2);     //temp=2
      System.out.println(""+temp.toString());
      stack.push(temp);         //将2入栈
      stack.push(F2);          //1入栈  后进入循环
      k++;
    }
  }
}

           

四:散列映射

1:HashMap<K,V>泛型类

1:HashMap<K,V>泛型类实现了泛型接口Map<K,V>,HashMap<K,V>类中的绝大多数方法都是Map<K,V>接口方法的实现。编程是可以使用接口回调技术,即把HashMap<K,V>对象的引用赋值给Map<K,V>接口变量,接口变量皆可以调用类实现的接口方法。

2:HashMap<K,V>对象采用散列表这种数据结构存储数据。HashMap<K,V>对象一般称为散列映射,用于存储键值对,允许把任何类型的数据的键值对存储起来。键不可以发送冲突,不能有两个相同的键,如果出现,新出现的键值对会替换原先的键值对。散列映射可以自动增大容量。

3:HashMap<K,V>创建的对象被称为散列映射,如:

HashMap<String,Student> hashtable=new HashMap<>();/*其中键必须是String类型,值为Studnet的对象
类型,通常散列映射可以调用`public V put(K key,V value)`将键值对存放到散列表中。*/
           

2:常用方法

- public void clear() //清空散列表
 - public Object clone() //返回当前散列表的一个克隆
 - public boolean containsKey(Object key)//如果键/值使用了参数指定的参数返回true
 - public V get(Object key) //返回Key键对应的值
 - public boolean isEmpty() //判断散列表是否为空
 - public V remove(Object key) //删除散列表映射中键位参数指定的键值对,并返回值
 - public int size() //返回散列表的大小,即键值对的数目

           

3:遍历散列映射

public Collection< V > values()方法返回一个实现Collection< V >接口类创建的对象,可以使用接口回调技术,将该对象的引用赋给接口变量,改接口变量就可以回调方法:

iterator()

获取一个Iterator对象,来对散列映射进行遍历。

4:基于散列表的查询

生活中有一些数据往往需要对其进行频繁的查询,我们可以给这些数据定义一个关键字即为键,存储到散列表中,比起数组和链表,有更快的查询效率。例如

Test_Main.java

public class Test_Main {
  public static void main(String[] args) {
    WindowWord win=new WindowWord();
    win.setTitle("英汉-小词典");
  }
}

           

WindowWord.java

import javax.swing.*;
import java.awt.*;

public class WindowWord extends JFrame {
  JTextField inputText,showText;
  WordPolice police;
  WindowWord(){
    setLayout(new FlowLayout());
    inputText=new JTextField(6);
    showText=new JTextField(6);
    add(inputText);
    add(showText);
    police=new WordPolice();
    police.setJTextFiled(showText);
    inputText.addActionListener(police);
    setBounds(100,100,400,400);
    setVisible(true);
    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  }

}

           

WordPolice.java

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Scanner;

public class WordPolice implements ActionListener {
  JTextField showText;
  HashMap<String,String> hashTable;
  File file=new File("word.txt");
  Scanner sc=null;
  WordPolice(){
    hashTable=new HashMap<>();
    try {
      sc=new Scanner(file);
      while (sc.hasNext()){
        String englishWord=sc.next();
        String chineseWord=sc.next();
        hashTable.put(englishWord,chineseWord);
      }
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }
  }
  public void setJTextFiled(JTextField showText){
    this.showText=showText;
  }
  @Override
  public void actionPerformed(ActionEvent e) {
    String englishWord=e.getActionCommand();
    if(hashTable.containsKey(englishWord)){
      String chineseWord=hashTable.get(englishWord);
      showText.setText(chineseWord);
    }
    else {
      showText.setText("没有此单词");
    }
  }
}

           

运行结果:

JAVA学习笔记-泛型与集合框架一:泛型二:链表三:堆栈四:散列映射五:树集

【注】上面程序的实现前提是建立在已经建立一个word.txt文件,存放着单词的汉语意思如下:

grandness 伟大 swim 游泳 sparrow 麻雀 boy 男孩 sun 太阳 moon 月亮 student 学生
           

五:树集

1:TreeSet< E>()泛型类

TreeSet< E>()泛型类是实现Set< E>接口的类,他的大部分方法是接口方法的实现。TreeSet< E>()泛型类创建的对象被称为树集。树集采用树的数据结构实现对数据的存储,树节点中的数据会按照存放数据的大小顺序一层一层的一次排列。在同一层中从左到右按照字典序的大小递增排列。下一层的杜比上一层的小。

例如:

然后可以调用add方法为树集添加树节点

mytree.add("boy")
mytree.add("zoo")
mytree.add("apple")
mytree.add("girl")
....
           

2:节点大小的关系

树节点的排列顺序和链表的排列顺序是不同的,链表是先来的排在前面,而树节点是按照“大小”顺序一层一层的排列的。

String可以直接调用方法

CompareTo(Objecr str)

实现和其他字符的大小的比较,树集中如果是字符串类型,那么可以完成排序。

3:常用方法

- public boolean add(E o) //向树集的添加结点,数组由参数指定
 - public void clear() //删除树集中的所有结点
 - public void contains(Object o) //检查树集中是否包含参数o,存在返回true否则返回false
 - public E first() //返回树集的第一个结点
 - public E last() //返回树集的最后一个结点
 - public boolean isEmpty() //判断树集是否为空
 - public boolean remove(Object o) //删除树集中存储参数指定对象的最小结点。
 - public int size() //返回树集的几点个数
           

例如:

import java.util.Iterator;
import java.util.TreeSet;

public class Test_main {
  public static void main(String[] args) {
    TreeSet<Student> myTree=new TreeSet<>();
    Student st1,st2,st3,st4;
    st1=new Student(90,"Danny");
    st2=new Student(66,"Tom");
    st3=new Student(86,"Bob");
    st4=new Student(76,"Alice");
    myTree.add(st1);
    myTree.add(st2);
    myTree.add(st3);
    myTree.add(st4);
    Iterator<Student> iter=myTree.iterator();  //迭代器用来遍历树集
    while (iter.hasNext()){
      Student su=iter.next();
      System.out.println(""+su.name+" "+su.english);
    }
  }
}
class Student implements Comparable{  //实现接口Comparable用来定义拍序规则
  int english=0;
  String name;
  Student(int english,String name){
    this.name=name;
    this.english=english;
  }

  @Override
  public int compareTo(Object o) {
    Student st=(Student) o;
    return (this.english-st.english);
  }
}

           

运行结果:

Tom 66
Alice 76
Bob 86
Danny 90

进程已结束,退出代码为 0

           

可见树集的存储过程与链表的存储顺序是不同的。

6:树映射TreeMap<K,V>

TreeMap<K,V>实现了接口Map<K,V>,我们吧TreeMap<K,V>的对象称为树映射,树映射使用方法:

public V put(K key,V value)

方法添加结点,同时存储数据也是“键值对”。

【注】树集中结点的排序顺序是根据结点数据的大小来排列的。然而树映射是根据关键字Key的大小来进行排序的。

例如下面的例子;在一个树映射存放了学生的数学成绩和英语成绩,分别按照数学和英语成绩排序如下:

Test_Main.java

import java.util.Collection;
import java.util.Iterator;
import java.util.TreeMap;

public class Test_Main {
  public static void main(String[] args) {
    TreeMap<studentKey,Student> treeMap=new TreeMap<>();
    String str[]={"Tom","Alice","Bob","Danny"};
    double math[]={89,45,78,76};
    double english[]={67,66,89,56};
    Student student[]=new Student[4];
    for (int i = 0; i <student.length ; i++) {
      student[i]=new Student(str[i],math[i],english[i]);
    }
    studentKey key[]=new studentKey[4];
    for (int i = 0; i < key.length; i++) {
      key[i]=new studentKey(student[i].math);  //关键字按照数学成绩大小排序
    }
    for (int i = 0; i < student.length; i++) {
      treeMap.put(key[i],student[i]);
    }
    int number=treeMap.size();
    System.out.println("树映射中含有:"+number+"个对象数据,按照数学成绩排序:");
    Collection<Student> collection=treeMap.values();
    Iterator<Student> iter=collection.iterator();
    while (iter.hasNext()){
      Student stu=iter.next();
      System.out.println("姓名:"+stu.name+",数学:"+stu.math);
    }
    treeMap.clear();
    for (int i = 0; i < key.length; i++) {
      key[i]=new studentKey(student[i].english);//按照英语排序
    }
    for (int i = 0; i < student.length; i++) {
      treeMap.put(key[i],student[i]);
    }
    number=treeMap.size();
    System.out.println("树映射中含有:"+number+"个对象数据,按照英语成绩排序:");
    collection=treeMap.values();
    iter=collection.iterator();
    while (iter.hasNext()){
      Student stu=iter.next();
      System.out.println("姓名:"+stu.name+",英语:"+stu.englishd);
    }

  }
}
class studentKey implements Comparable{
  double d=0;
  studentKey(double d){
    this.d=d;
  }

  @Override
  public int compareTo(Object o) {
    studentKey sk=(studentKey) o;
    if((this.d-sk.d)==0){
      return -1;
    }
    else {
      return (int)((this.d-sk.d)*1000);
    }

  }
}
class Student{
  String name=null;
  double math,english;
  Student(String s,double math,double english){
    name=s;
    this.math=math;
    this.english=english;
  }

}


           

运行结果:

树映射中含有:4个对象数据,按照数学成绩排序:
姓名:Alice,数学:45.0
姓名:Danny,数学:76.0
姓名:Bob,数学:78.0
姓名:Tom,数学:89.0
树映射中含有:4个对象数据,按照英语成绩排序:
姓名:Danny,英语:56.0
姓名:Alice,英语:66.0
姓名:Tom,英语:67.0
姓名:Bob,英语:89.0

进程已结束,退出代码为 0

           

7:自动装箱与拆箱

所谓的装箱是指:当一个基本类型数据存放到类似链表的数据结构时,系统会自动的将基本数据类型进行转换。而拆箱是指从一个数据结构获取某个对象时,如果该数据是基本数据类型时,系统会自动完成转换。

例如:

import java.util.ArrayList;

public class Test_Main {
  public static void main(String[] args) {
    ArrayList<Integer> list=new ArrayList<>();
    for (int i = 0; i < 10; i++) {
      list.add(i);   //自动装箱,实际上添加到list中的数据时new Integer(i);
    }
    for (int i = 0; i < list.size()-1; i++) {
      int m=list.get(i);  //自动拆箱,获取Integer对象转换为int类型
      System.out.printf("%3d",m);
    }
  }
}

           

继续阅读